2
0
mirror of https://github.com/lightninglabs/loop synced 2024-11-04 06:00:21 +00:00
loop/utils/musig.go
2024-01-31 10:28:21 +01:00

83 lines
2.0 KiB
Go

package utils
import (
"fmt"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
"github.com/lightningnetwork/lnd/input"
)
// MuSig2Sign will create a MuSig2 signature for the passed message using the
// passed private keys.
func MuSig2Sign(version input.MuSig2Version, privKeys []*btcec.PrivateKey,
pubKeys []*btcec.PublicKey, tweaks *input.MuSig2Tweaks,
msg [32]byte) ([]byte, error) {
// Next we'll create MuSig2 sessions for each individual private
// signing key.
sessions := make([]input.MuSig2Session, len(privKeys))
for i, signingKey := range privKeys {
_, muSigSession, err := input.MuSig2CreateContext(
version, signingKey, pubKeys, tweaks, nil,
)
if err != nil {
return nil, fmt.Errorf("error creating "+
"signing context: %v", err)
}
sessions[i] = muSigSession
}
// Next we'll pass around all public nonces to all MuSig2 sessions so
// that they become usable for creating the partial signatures.
for i := 0; i < len(privKeys); i++ {
nonce := sessions[i].PublicNonce()
for j := 0; j < len(privKeys); j++ {
if i == j {
// Step over if it's the same session.
continue
}
_, err := sessions[j].RegisterPubNonce(nonce)
if err != nil {
return nil, fmt.Errorf("error sharing "+
"MuSig2 nonces: %v", err)
}
}
}
// Now that the sessions are properly set up, we can generate
// each partial signature.
signatures := make([]*musig2.PartialSignature, len(privKeys))
for i, session := range sessions {
sig, err := input.MuSig2Sign(session, msg, true)
if err != nil {
return nil, err
}
signatures[i] = sig
}
// Now that we have all partial sigs we can just combine them to
// get the final signature.
var haveAllSigs bool
for i := 1; i < len(signatures); i++ {
var err error
haveAllSigs, err = input.MuSig2CombineSig(
sessions[0], signatures[i],
)
if err != nil {
return nil, err
}
}
if !haveAllSigs {
return nil, fmt.Errorf("combinging MuSig2 signatures " +
"failed")
}
return sessions[0].FinalSig().Serialize(), nil
}