From 7fa10ee7a40c70467de9e068c7a4dc0de3ee24d4 Mon Sep 17 00:00:00 2001 From: Slyghtning Date: Thu, 25 Jan 2024 15:31:34 +0100 Subject: [PATCH] utils: add MuSig2Sign function --- utils/musig.go | 82 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+) create mode 100644 utils/musig.go diff --git a/utils/musig.go b/utils/musig.go new file mode 100644 index 0000000..d744233 --- /dev/null +++ b/utils/musig.go @@ -0,0 +1,82 @@ +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 +}