Skip to content

Commit 7fa10ee

Browse files
committed
utils: add MuSig2Sign function
1 parent 5201b49 commit 7fa10ee

File tree

1 file changed

+82
-0
lines changed

1 file changed

+82
-0
lines changed

utils/musig.go

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
package utils
2+
3+
import (
4+
"fmt"
5+
6+
"github.com/btcsuite/btcd/btcec/v2"
7+
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
8+
"github.com/lightningnetwork/lnd/input"
9+
)
10+
11+
// MuSig2Sign will create a MuSig2 signature for the passed message using the
12+
// passed private keys.
13+
func MuSig2Sign(version input.MuSig2Version, privKeys []*btcec.PrivateKey,
14+
pubKeys []*btcec.PublicKey, tweaks *input.MuSig2Tweaks,
15+
msg [32]byte) ([]byte, error) {
16+
17+
// Next we'll create MuSig2 sessions for each individual private
18+
// signing key.
19+
sessions := make([]input.MuSig2Session, len(privKeys))
20+
for i, signingKey := range privKeys {
21+
_, muSigSession, err := input.MuSig2CreateContext(
22+
version, signingKey, pubKeys, tweaks, nil,
23+
)
24+
if err != nil {
25+
return nil, fmt.Errorf("error creating "+
26+
"signing context: %v", err)
27+
}
28+
29+
sessions[i] = muSigSession
30+
}
31+
32+
// Next we'll pass around all public nonces to all MuSig2 sessions so
33+
// that they become usable for creating the partial signatures.
34+
for i := 0; i < len(privKeys); i++ {
35+
nonce := sessions[i].PublicNonce()
36+
37+
for j := 0; j < len(privKeys); j++ {
38+
if i == j {
39+
// Step over if it's the same session.
40+
continue
41+
}
42+
43+
_, err := sessions[j].RegisterPubNonce(nonce)
44+
if err != nil {
45+
return nil, fmt.Errorf("error sharing "+
46+
"MuSig2 nonces: %v", err)
47+
}
48+
}
49+
}
50+
51+
// Now that the sessions are properly set up, we can generate
52+
// each partial signature.
53+
signatures := make([]*musig2.PartialSignature, len(privKeys))
54+
for i, session := range sessions {
55+
sig, err := input.MuSig2Sign(session, msg, true)
56+
if err != nil {
57+
return nil, err
58+
}
59+
60+
signatures[i] = sig
61+
}
62+
63+
// Now that we have all partial sigs we can just combine them to
64+
// get the final signature.
65+
var haveAllSigs bool
66+
for i := 1; i < len(signatures); i++ {
67+
var err error
68+
haveAllSigs, err = input.MuSig2CombineSig(
69+
sessions[0], signatures[i],
70+
)
71+
if err != nil {
72+
return nil, err
73+
}
74+
}
75+
76+
if !haveAllSigs {
77+
return nil, fmt.Errorf("combinging MuSig2 signatures " +
78+
"failed")
79+
}
80+
81+
return sessions[0].FinalSig().Serialize(), nil
82+
}

0 commit comments

Comments
 (0)