• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 13236757158

10 Feb 2025 08:39AM UTC coverage: 57.649% (-1.2%) from 58.815%
13236757158

Pull #9493

github

ziggie1984
lncli: for some cmds we don't replace the data of the response.

For some cmds it is not very practical to replace the json output
because we might pipe it into other commands. For example when
creating the route we want to pipe it into sendtoRoute.
Pull Request #9493: For some lncli cmds we should not replace the content with other data

0 of 9 new or added lines in 2 files covered. (0.0%)

19535 existing lines in 252 files now uncovered.

103517 of 179563 relevant lines covered (57.65%)

24878.49 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

90.84
/internal/musig2v040/sign.go
1
// Copyright 2013-2022 The btcsuite developers
2

3
package musig2v040
4

5
import (
6
        "bytes"
7
        "fmt"
8
        "io"
9

10
        "github.com/btcsuite/btcd/btcec/v2"
11
        "github.com/btcsuite/btcd/btcec/v2/schnorr"
12
        "github.com/btcsuite/btcd/chaincfg/chainhash"
13
        secp "github.com/decred/dcrd/dcrec/secp256k1/v4"
14
)
15

16
var (
17
        // NonceBlindTag is that tag used to construct the value b, which
18
        // blinds the second public nonce of each party.
19
        NonceBlindTag = []byte("MuSig/noncecoef")
20

21
        // ChallengeHashTag is the tag used to construct the challenge hash
22
        ChallengeHashTag = []byte("BIP0340/challenge")
23

24
        // ErrNoncePointAtInfinity is returned if during signing, the fully
25
        // combined public nonce is the point at infinity.
26
        ErrNoncePointAtInfinity = fmt.Errorf("signing nonce is the infinity " +
27
                "point")
28

29
        // ErrPrivKeyZero is returned when the private key for signing is
30
        // actually zero.
31
        ErrPrivKeyZero = fmt.Errorf("priv key is zero")
32

33
        // ErrPartialSigInvalid is returned when a partial is found to be
34
        // invalid.
35
        ErrPartialSigInvalid = fmt.Errorf("partial signature is invalid")
36

37
        // ErrSecretNonceZero is returned when a secret nonce is passed in a
38
        // zero.
39
        ErrSecretNonceZero = fmt.Errorf("secret nonce is blank")
40
)
41

42
// infinityPoint is the jacobian representation of the point at infinity.
43
var infinityPoint btcec.JacobianPoint
44

45
// PartialSignature reprints a partial (s-only) musig2 multi-signature. This
46
// isn't a valid schnorr signature by itself, as it needs to be aggregated
47
// along with the other partial signatures to be completed.
48
type PartialSignature struct {
49
        S *btcec.ModNScalar
50

51
        R *btcec.PublicKey
52
}
53

54
// NewPartialSignature returns a new instances of the partial sig struct.
55
func NewPartialSignature(s *btcec.ModNScalar,
56
        r *btcec.PublicKey) PartialSignature {
510✔
57

510✔
58
        return PartialSignature{
510✔
59
                S: s,
510✔
60
                R: r,
510✔
61
        }
510✔
62
}
510✔
63

64
// Encode writes a serialized version of the partial signature to the passed
65
// io.Writer
66
func (p *PartialSignature) Encode(w io.Writer) error {
×
67
        var sBytes [32]byte
×
68
        p.S.PutBytes(&sBytes)
×
69

×
70
        if _, err := w.Write(sBytes[:]); err != nil {
×
71
                return err
×
72
        }
×
73

74
        return nil
×
75
}
76

77
// Decode attempts to parse a serialized PartialSignature stored in the passed
78
// io reader.
79
func (p *PartialSignature) Decode(r io.Reader) error {
21✔
80
        p.S = new(btcec.ModNScalar)
21✔
81

21✔
82
        var sBytes [32]byte
21✔
83
        if _, err := io.ReadFull(r, sBytes[:]); err != nil {
21✔
84
                return nil
×
85
        }
×
86

87
        overflows := p.S.SetBytes(&sBytes)
21✔
88
        if overflows == 1 {
23✔
89
                return ErrPartialSigInvalid
2✔
90
        }
2✔
91

92
        return nil
19✔
93
}
94

95
// SignOption is a functional option argument that allows callers to modify the
96
// way we generate musig2 schnorr signatures.
97
type SignOption func(*signOptions)
98

99
// signOptions houses the set of functional options that can be used to modify
100
// the method used to generate the musig2 partial signature.
101
type signOptions struct {
102
        // fastSign determines if we'll skip the check at the end of the
103
        // routine where we attempt to verify the produced signature.
104
        fastSign bool
105

106
        // sortKeys determines if the set of keys should be sorted before doing
107
        // key aggregation.
108
        sortKeys bool
109

110
        // tweaks specifies a series of tweaks to be applied to the aggregated
111
        // public key, which also partially carries over into the signing
112
        // process.
113
        tweaks []KeyTweakDesc
114

115
        // taprootTweak specifies a taproot specific tweak.  of the tweaks
116
        // specified above. Normally we'd just apply the raw 32 byte tweak, but
117
        // for taproot, we first need to compute the aggregated key before
118
        // tweaking, and then use it as the internal key. This is required as
119
        // the taproot tweak also commits to the public key, which in this case
120
        // is the aggregated key before the tweak.
121
        taprootTweak []byte
122

123
        // bip86Tweak specifies that the taproot tweak should be done in a BIP
124
        // 86 style, where we don't expect an actual tweak and instead just
125
        // commit to the public key itself.
126
        bip86Tweak bool
127
}
128

129
// defaultSignOptions returns the default set of signing operations.
130
func defaultSignOptions() *signOptions {
1,033✔
131
        return &signOptions{}
1,033✔
132
}
1,033✔
133

134
// WithFastSign forces signing to skip the extra verification step at the end.
135
// Performance sensitive applications may opt to use this option to speed up
136
// the signing operation.
137
func WithFastSign() SignOption {
×
138
        return func(o *signOptions) {
×
139
                o.fastSign = true
×
140
        }
×
141
}
142

143
// WithSortedKeys determines if the set of signing public keys are to be sorted
144
// or not before doing key aggregation.
UNCOV
145
func WithSortedKeys() SignOption {
×
UNCOV
146
        return func(o *signOptions) {
×
UNCOV
147
                o.sortKeys = true
×
UNCOV
148
        }
×
149
}
150

151
// WithTweaks determines if the aggregated public key used should apply a
152
// series of tweaks before key aggregation.
153
func WithTweaks(tweaks ...KeyTweakDesc) SignOption {
8✔
154
        return func(o *signOptions) {
20✔
155
                o.tweaks = tweaks
12✔
156
        }
12✔
157
}
158

159
// WithTaprootSignTweak allows a caller to specify a tweak that should be used
160
// in a bip 340 manner when signing. This differs from WithTweaks as the tweak
161
// will be assumed to always be x-only and the intermediate aggregate key
162
// before tweaking will be used to generate part of the tweak (as the taproot
163
// tweak also commits to the internal key).
164
//
165
// This option should be used in the taproot context to create a valid
166
// signature for the keypath spend for taproot, when the output key is actually
167
// committing to a script path, or some other data.
168
func WithTaprootSignTweak(scriptRoot []byte) SignOption {
100✔
169
        return func(o *signOptions) {
300✔
170
                o.taprootTweak = scriptRoot
200✔
171
        }
200✔
172
}
173

174
// WithBip86SignTweak allows a caller to specify a tweak that should be used in
175
// a bip 340 manner when signing, factoring in BIP 86 as well. This differs
176
// from WithTaprootSignTweak as no true script root will be committed to,
177
// instead we just commit to the internal key.
178
//
179
// This option should be used in the taproot context to create a valid
180
// signature for the keypath spend for taproot, when the output key was
181
// generated using BIP 86.
182
func WithBip86SignTweak() SignOption {
400✔
183
        return func(o *signOptions) {
1,200✔
184
                o.bip86Tweak = true
800✔
185
        }
800✔
186
}
187

188
// Sign generates a musig2 partial signature given the passed key set, secret
189
// nonce, public nonce, and private keys. This method returns an error if the
190
// generated nonces are either too large, or end up mapping to the point at
191
// infinity.
192
func Sign(secNonce [SecNonceSize]byte, privKey *btcec.PrivateKey,
193
        combinedNonce [PubNonceSize]byte, pubKeys []*btcec.PublicKey,
194
        msg [32]byte, signOpts ...SignOption) (*PartialSignature, error) {
513✔
195

513✔
196
        // First, parse the set of optional signing options.
513✔
197
        opts := defaultSignOptions()
513✔
198
        for _, option := range signOpts {
1,017✔
199
                option(opts)
504✔
200
        }
504✔
201

202
        // Compute the hash of all the keys here as we'll need it do aggregate
203
        // the keys and also at the final step of signing.
204
        keysHash := keyHashFingerprint(pubKeys, opts.sortKeys)
513✔
205
        uniqueKeyIndex := secondUniqueKeyIndex(pubKeys, opts.sortKeys)
513✔
206

513✔
207
        keyAggOpts := []KeyAggOption{
513✔
208
                WithKeysHash(keysHash), WithUniqueKeyIndex(uniqueKeyIndex),
513✔
209
        }
513✔
210
        switch {
513✔
211
        case opts.bip86Tweak:
400✔
212
                keyAggOpts = append(
400✔
213
                        keyAggOpts, WithBIP86KeyTweak(),
400✔
214
                )
400✔
215
        case opts.taprootTweak != nil:
100✔
216
                keyAggOpts = append(
100✔
217
                        keyAggOpts, WithTaprootKeyTweak(opts.taprootTweak),
100✔
218
                )
100✔
219
        case len(opts.tweaks) != 0:
4✔
220
                keyAggOpts = append(keyAggOpts, WithKeyTweaks(opts.tweaks...))
4✔
221
        }
222

223
        // Next we'll construct the aggregated public key based on the set of
224
        // signers.
225
        combinedKey, parityAcc, _, err := AggregateKeys(
513✔
226
                pubKeys, opts.sortKeys, keyAggOpts...,
513✔
227
        )
513✔
228
        if err != nil {
513✔
229
                return nil, err
×
230
        }
×
231

232
        // Next we'll compute the value b, that blinds our second public
233
        // nonce:
234
        //  * b = h(tag=NonceBlindTag, combinedNonce || combinedKey || m).
235
        var (
513✔
236
                nonceMsgBuf  bytes.Buffer
513✔
237
                nonceBlinder btcec.ModNScalar
513✔
238
        )
513✔
239
        nonceMsgBuf.Write(combinedNonce[:])
513✔
240
        nonceMsgBuf.Write(schnorr.SerializePubKey(combinedKey.FinalKey))
513✔
241
        nonceMsgBuf.Write(msg[:])
513✔
242
        nonceBlindHash := chainhash.TaggedHash(
513✔
243
                NonceBlindTag, nonceMsgBuf.Bytes(),
513✔
244
        )
513✔
245
        nonceBlinder.SetByteSlice(nonceBlindHash[:])
513✔
246

513✔
247
        // Next, we'll parse the public nonces into R1 and R2.
513✔
248
        r1J, err := btcec.ParseJacobian(
513✔
249
                combinedNonce[:btcec.PubKeyBytesLenCompressed],
513✔
250
        )
513✔
251
        if err != nil {
514✔
252
                return nil, err
1✔
253
        }
1✔
254
        r2J, err := btcec.ParseJacobian(
512✔
255
                combinedNonce[btcec.PubKeyBytesLenCompressed:],
512✔
256
        )
512✔
257
        if err != nil {
514✔
258
                return nil, err
2✔
259
        }
2✔
260

261
        // With our nonce blinding value, we'll now combine both the public
262
        // nonces, using the blinding factor to tweak the second nonce:
263
        //  * R = R_1 + b*R_2
264
        var nonce btcec.JacobianPoint
510✔
265
        btcec.ScalarMultNonConst(&nonceBlinder, &r2J, &r2J)
510✔
266
        btcec.AddNonConst(&r1J, &r2J, &nonce)
510✔
267

510✔
268
        // If the combined nonce it eh point at infinity, then we'll bail out.
510✔
269
        if nonce == infinityPoint {
511✔
270
                G := btcec.Generator()
1✔
271
                G.AsJacobian(&nonce)
1✔
272
        }
1✔
273

274
        // Next we'll parse out our two secret nonces, which we'll be using in
275
        // the core signing process below.
276
        var k1, k2 btcec.ModNScalar
510✔
277
        k1.SetByteSlice(secNonce[:btcec.PrivKeyBytesLen])
510✔
278
        k2.SetByteSlice(secNonce[btcec.PrivKeyBytesLen:])
510✔
279

510✔
280
        if k1.IsZero() || k2.IsZero() {
510✔
281
                return nil, ErrSecretNonceZero
×
282
        }
×
283

284
        nonce.ToAffine()
510✔
285

510✔
286
        nonceKey := btcec.NewPublicKey(&nonce.X, &nonce.Y)
510✔
287

510✔
288
        // If the nonce R has an odd y coordinate, then we'll negate both our
510✔
289
        // secret nonces.
510✔
290
        if nonce.Y.IsOdd() {
815✔
291
                k1.Negate()
305✔
292
                k2.Negate()
305✔
293
        }
305✔
294

295
        privKeyScalar := privKey.Key
510✔
296
        if privKeyScalar.IsZero() {
510✔
297
                return nil, ErrPrivKeyZero
×
298
        }
×
299

300
        pubKey := privKey.PubKey()
510✔
301
        pubKeyYIsOdd := func() bool {
1,020✔
302
                pubKeyBytes := pubKey.SerializeCompressed()
510✔
303
                return pubKeyBytes[0] == secp.PubKeyFormatCompressedOdd
510✔
304
        }()
510✔
305
        combinedKeyYIsOdd := func() bool {
1,020✔
306
                combinedKeyBytes := combinedKey.FinalKey.SerializeCompressed()
510✔
307
                return combinedKeyBytes[0] == secp.PubKeyFormatCompressedOdd
510✔
308
        }()
510✔
309

310
        // Next we'll compute our two parity factors for Q the combined public
311
        // key, and P, the public key we're signing with. If the keys are odd,
312
        // then we'll negate them.
313
        parityCombinedKey := new(btcec.ModNScalar).SetInt(1)
510✔
314
        paritySignKey := new(btcec.ModNScalar).SetInt(1)
510✔
315
        if combinedKeyYIsOdd {
714✔
316
                parityCombinedKey.Negate()
204✔
317
        }
204✔
318
        if pubKeyYIsOdd {
773✔
319
                paritySignKey.Negate()
263✔
320
        }
263✔
321

322
        // Before we sign below, we'll multiply by our various parity factors
323
        // to ensure that the signing key is properly negated (if necessary):
324
        //  * d = gvâ‹…gaccvâ‹…gpâ‹…d'
325
        privKeyScalar.Mul(parityCombinedKey).Mul(paritySignKey).Mul(parityAcc)
510✔
326

510✔
327
        // Next we'll create the challenge hash that commits to the combined
510✔
328
        // nonce, combined public key and also the message:
510✔
329
        // * e = H(tag=ChallengeHashTag, R || Q || m) mod n
510✔
330
        var challengeMsg bytes.Buffer
510✔
331
        challengeMsg.Write(schnorr.SerializePubKey(nonceKey))
510✔
332
        challengeMsg.Write(schnorr.SerializePubKey(combinedKey.FinalKey))
510✔
333
        challengeMsg.Write(msg[:])
510✔
334
        challengeBytes := chainhash.TaggedHash(
510✔
335
                ChallengeHashTag, challengeMsg.Bytes(),
510✔
336
        )
510✔
337
        var e btcec.ModNScalar
510✔
338
        e.SetByteSlice(challengeBytes[:])
510✔
339

510✔
340
        // Next, we'll compute a, our aggregation coefficient for the key that
510✔
341
        // we're signing with.
510✔
342
        a := aggregationCoefficient(pubKeys, pubKey, keysHash, uniqueKeyIndex)
510✔
343

510✔
344
        // With mu constructed, we can finally generate our partial signature
510✔
345
        // as: s = (k1_1 + b*k_2 + e*a*d) mod n.
510✔
346
        s := new(btcec.ModNScalar)
510✔
347
        s.Add(&k1).Add(k2.Mul(&nonceBlinder)).Add(e.Mul(a).Mul(&privKeyScalar))
510✔
348

510✔
349
        sig := NewPartialSignature(s, nonceKey)
510✔
350

510✔
351
        // If we're not in fast sign mode, then we'll also validate our partial
510✔
352
        // signature.
510✔
353
        if !opts.fastSign {
1,020✔
354
                pubNonce := secNonceToPubNonce(secNonce)
510✔
355
                sigValid := sig.Verify(
510✔
356
                        pubNonce, combinedNonce, pubKeys, pubKey, msg,
510✔
357
                        signOpts...,
510✔
358
                )
510✔
359
                if !sigValid {
510✔
360
                        return nil, fmt.Errorf("sig is invalid!")
×
361
                }
×
362
        }
363

364
        return &sig, nil
510✔
365
}
366

367
// Verify implements partial signature verification given the public nonce for
368
// the signer, aggregate nonce, signer set and finally the message being
369
// signed.
370
func (p *PartialSignature) Verify(pubNonce [PubNonceSize]byte,
371
        combinedNonce [PubNonceSize]byte, keySet []*btcec.PublicKey,
372
        signingKey *btcec.PublicKey, msg [32]byte, signOpts ...SignOption) bool {
510✔
373

510✔
374
        pubKey := schnorr.SerializePubKey(signingKey)
510✔
375

510✔
376
        return verifyPartialSig(
510✔
377
                p, pubNonce, combinedNonce, keySet, pubKey, msg, signOpts...,
510✔
378
        ) == nil
510✔
379
}
510✔
380

381
// verifyPartialSig attempts to verify a partial schnorr signature given the
382
// necessary parameters. This is the internal version of Verify that returns
383
// detailed errors.  signed.
384
func verifyPartialSig(partialSig *PartialSignature, pubNonce [PubNonceSize]byte,
385
        combinedNonce [PubNonceSize]byte, keySet []*btcec.PublicKey,
386
        pubKey []byte, msg [32]byte, signOpts ...SignOption) error {
520✔
387

520✔
388
        opts := defaultSignOptions()
520✔
389
        for _, option := range signOpts {
1,028✔
390
                option(opts)
508✔
391
        }
508✔
392

393
        // First we'll map the internal partial signature back into something
394
        // we can manipulate.
395
        s := partialSig.S
520✔
396

520✔
397
        // Next we'll parse out the two public nonces into something we can
520✔
398
        // use.
520✔
399
        //
520✔
400

520✔
401
        // Compute the hash of all the keys here as we'll need it do aggregate
520✔
402
        // the keys and also at the final step of verification.
520✔
403
        keysHash := keyHashFingerprint(keySet, opts.sortKeys)
520✔
404
        uniqueKeyIndex := secondUniqueKeyIndex(keySet, opts.sortKeys)
520✔
405

520✔
406
        keyAggOpts := []KeyAggOption{
520✔
407
                WithKeysHash(keysHash), WithUniqueKeyIndex(uniqueKeyIndex),
520✔
408
        }
520✔
409
        switch {
520✔
410
        case opts.bip86Tweak:
400✔
411
                keyAggOpts = append(
400✔
412
                        keyAggOpts, WithBIP86KeyTweak(),
400✔
413
                )
400✔
414
        case opts.taprootTweak != nil:
100✔
415
                keyAggOpts = append(
100✔
416
                        keyAggOpts, WithTaprootKeyTweak(opts.taprootTweak),
100✔
417
                )
100✔
418
        case len(opts.tweaks) != 0:
8✔
419
                keyAggOpts = append(keyAggOpts, WithKeyTweaks(opts.tweaks...))
8✔
420
        }
421

422
        // Next we'll construct the aggregated public key based on the set of
423
        // signers.
424
        combinedKey, parityAcc, _, err := AggregateKeys(
520✔
425
                keySet, opts.sortKeys, keyAggOpts...,
520✔
426
        )
520✔
427
        if err != nil {
520✔
428
                return err
×
429
        }
×
430

431
        // Next we'll compute the value b, that blinds our second public
432
        // nonce:
433
        //  * b = h(tag=NonceBlindTag, combinedNonce || combinedKey || m).
434
        var (
520✔
435
                nonceMsgBuf  bytes.Buffer
520✔
436
                nonceBlinder btcec.ModNScalar
520✔
437
        )
520✔
438
        nonceMsgBuf.Write(combinedNonce[:])
520✔
439
        nonceMsgBuf.Write(schnorr.SerializePubKey(combinedKey.FinalKey))
520✔
440
        nonceMsgBuf.Write(msg[:])
520✔
441
        nonceBlindHash := chainhash.TaggedHash(NonceBlindTag, nonceMsgBuf.Bytes())
520✔
442
        nonceBlinder.SetByteSlice(nonceBlindHash[:])
520✔
443

520✔
444
        r1J, err := btcec.ParseJacobian(
520✔
445
                combinedNonce[:btcec.PubKeyBytesLenCompressed],
520✔
446
        )
520✔
447
        if err != nil {
520✔
448
                return err
×
449
        }
×
450
        r2J, err := btcec.ParseJacobian(
520✔
451
                combinedNonce[btcec.PubKeyBytesLenCompressed:],
520✔
452
        )
520✔
453
        if err != nil {
520✔
454
                return err
×
455
        }
×
456

457
        // With our nonce blinding value, we'll now combine both the public
458
        // nonces, using the blinding factor to tweak the second nonce:
459
        //  * R = R_1 + b*R_2
460

461
        var nonce btcec.JacobianPoint
520✔
462
        btcec.ScalarMultNonConst(&nonceBlinder, &r2J, &r2J)
520✔
463
        btcec.AddNonConst(&r1J, &r2J, &nonce)
520✔
464

520✔
465
        // Next, we'll parse out the set of public nonces this signer used to
520✔
466
        // generate the signature.
520✔
467
        pubNonce1J, err := btcec.ParseJacobian(
520✔
468
                pubNonce[:btcec.PubKeyBytesLenCompressed],
520✔
469
        )
520✔
470
        if err != nil {
520✔
471
                return err
×
472
        }
×
473
        pubNonce2J, err := btcec.ParseJacobian(
520✔
474
                pubNonce[btcec.PubKeyBytesLenCompressed:],
520✔
475
        )
520✔
476
        if err != nil {
520✔
477
                return err
×
478
        }
×
479

480
        // If the nonce is the infinity point we set it to the Generator.
481
        if nonce == infinityPoint {
522✔
482
                btcec.GeneratorJacobian(&nonce)
2✔
483
        } else {
520✔
484
                nonce.ToAffine()
518✔
485
        }
518✔
486

487
        // We'll perform a similar aggregation and blinding operator as we did
488
        // above for the combined nonces: R' = R_1' + b*R_2'.
489
        var pubNonceJ btcec.JacobianPoint
520✔
490

520✔
491
        btcec.ScalarMultNonConst(&nonceBlinder, &pubNonce2J, &pubNonce2J)
520✔
492
        btcec.AddNonConst(&pubNonce1J, &pubNonce2J, &pubNonceJ)
520✔
493

520✔
494
        pubNonceJ.ToAffine()
520✔
495

520✔
496
        // If the combined nonce used in the challenge hash has an odd y
520✔
497
        // coordinate, then we'll negate our final public nonce.
520✔
498
        if nonce.Y.IsOdd() {
830✔
499
                pubNonceJ.Y.Negate(1)
310✔
500
                pubNonceJ.Y.Normalize()
310✔
501
        }
310✔
502

503
        // Next we'll create the challenge hash that commits to the combined
504
        // nonce, combined public key and also the message:
505
        //  * e = H(tag=ChallengeHashTag, R || Q || m) mod n
506
        var challengeMsg bytes.Buffer
520✔
507
        challengeMsg.Write(schnorr.SerializePubKey(btcec.NewPublicKey(
520✔
508
                &nonce.X, &nonce.Y,
520✔
509
        )))
520✔
510
        challengeMsg.Write(schnorr.SerializePubKey(combinedKey.FinalKey))
520✔
511
        challengeMsg.Write(msg[:])
520✔
512
        challengeBytes := chainhash.TaggedHash(
520✔
513
                ChallengeHashTag, challengeMsg.Bytes(),
520✔
514
        )
520✔
515
        var e btcec.ModNScalar
520✔
516
        e.SetByteSlice(challengeBytes[:])
520✔
517

520✔
518
        signingKey, err := schnorr.ParsePubKey(pubKey)
520✔
519
        if err != nil {
520✔
520
                return err
×
521
        }
×
522

523
        // Next, we'll compute a, our aggregation coefficient for the key that
524
        // we're signing with.
525
        a := aggregationCoefficient(keySet, signingKey, keysHash, uniqueKeyIndex)
520✔
526

520✔
527
        // If the combined key has an odd y coordinate, then we'll negate
520✔
528
        // parity factor for the signing key.
520✔
529
        paritySignKey := new(btcec.ModNScalar).SetInt(1)
520✔
530
        combinedKeyBytes := combinedKey.FinalKey.SerializeCompressed()
520✔
531
        if combinedKeyBytes[0] == secp.PubKeyFormatCompressedOdd {
730✔
532
                paritySignKey.Negate()
210✔
533
        }
210✔
534

535
        // Next, we'll construct the final parity factor by multiplying the
536
        // sign key parity factor with the accumulated parity factor for all
537
        // the keys.
538
        finalParityFactor := paritySignKey.Mul(parityAcc)
520✔
539

520✔
540
        // Now we'll multiply the parity factor by our signing key, which'll
520✔
541
        // take care of the amount of negation needed.
520✔
542
        var signKeyJ btcec.JacobianPoint
520✔
543
        signingKey.AsJacobian(&signKeyJ)
520✔
544
        btcec.ScalarMultNonConst(finalParityFactor, &signKeyJ, &signKeyJ)
520✔
545

520✔
546
        // In the final set, we'll check that: s*G == R' + e*a*P.
520✔
547
        var sG, rP btcec.JacobianPoint
520✔
548
        btcec.ScalarBaseMultNonConst(s, &sG)
520✔
549
        btcec.ScalarMultNonConst(e.Mul(a), &signKeyJ, &rP)
520✔
550
        btcec.AddNonConst(&rP, &pubNonceJ, &rP)
520✔
551

520✔
552
        sG.ToAffine()
520✔
553
        rP.ToAffine()
520✔
554

520✔
555
        if sG != rP {
522✔
556
                return ErrPartialSigInvalid
2✔
557
        }
2✔
558

559
        return nil
518✔
560
}
561

562
// CombineOption is a functional option argument that allows callers to modify the
563
// way we combine musig2 schnorr signatures.
564
type CombineOption func(*combineOptions)
565

566
// combineOptions houses the set of functional options that can be used to
567
// modify the method used to combine the musig2 partial signatures.
568
type combineOptions struct {
569
        msg [32]byte
570

571
        combinedKey *btcec.PublicKey
572

573
        tweakAcc *btcec.ModNScalar
574
}
575

576
// defaultCombineOptions returns the default set of signing operations.
577
func defaultCombineOptions() *combineOptions {
10✔
578
        return &combineOptions{}
10✔
579
}
10✔
580

581
// WithTweakedCombine is a functional option that allows callers to specify
582
// that the signature was produced using a tweaked aggregated public key. In
583
// order to properly aggregate the partial signatures, the caller must specify
584
// enough information to reconstruct the challenge, and also the final
585
// accumulated tweak value.
586
func WithTweakedCombine(msg [32]byte, keys []*btcec.PublicKey,
587
        tweaks []KeyTweakDesc, sort bool) CombineOption {
2✔
588

2✔
589
        return func(o *combineOptions) {
4✔
590
                combinedKey, _, tweakAcc, _ := AggregateKeys(
2✔
591
                        keys, sort, WithKeyTweaks(tweaks...),
2✔
592
                )
2✔
593

2✔
594
                o.msg = msg
2✔
595
                o.combinedKey = combinedKey.FinalKey
2✔
596
                o.tweakAcc = tweakAcc
2✔
597
        }
2✔
598
}
599

600
// WithTaprootTweakedCombine is similar to the WithTweakedCombine option, but
601
// assumes a BIP 341 context where the final tweaked key is to be used as the
602
// output key, where the internal key is the aggregated key pre-tweak.
603
//
604
// This option should be used over WithTweakedCombine when attempting to
605
// aggregate signatures for a top-level taproot keyspend, where the output key
606
// commits to a script root.
607
func WithTaprootTweakedCombine(msg [32]byte, keys []*btcec.PublicKey,
608
        scriptRoot []byte, sort bool) CombineOption {
1✔
609

1✔
610
        return func(o *combineOptions) {
2✔
611
                combinedKey, _, tweakAcc, _ := AggregateKeys(
1✔
612
                        keys, sort, WithTaprootKeyTweak(scriptRoot),
1✔
613
                )
1✔
614

1✔
615
                o.msg = msg
1✔
616
                o.combinedKey = combinedKey.FinalKey
1✔
617
                o.tweakAcc = tweakAcc
1✔
618
        }
1✔
619
}
620

621
// WithBip86TweakedCombine is similar to the WithTaprootTweakedCombine option,
622
// but assumes a BIP 341 + BIP 86 context where the final tweaked key is to be
623
// used as the output key, where the internal key is the aggregated key
624
// pre-tweak.
625
//
626
// This option should be used over WithTaprootTweakedCombine when attempting to
627
// aggregate signatures for a top-level taproot keyspend, where the output key
628
// was generated using BIP 86.
629
func WithBip86TweakedCombine(msg [32]byte, keys []*btcec.PublicKey,
630
        sort bool) CombineOption {
4✔
631

4✔
632
        return func(o *combineOptions) {
8✔
633
                combinedKey, _, tweakAcc, _ := AggregateKeys(
4✔
634
                        keys, sort, WithBIP86KeyTweak(),
4✔
635
                )
4✔
636

4✔
637
                o.msg = msg
4✔
638
                o.combinedKey = combinedKey.FinalKey
4✔
639
                o.tweakAcc = tweakAcc
4✔
640
        }
4✔
641
}
642

643
// CombineSigs combines the set of public keys given the final aggregated
644
// nonce, and the series of partial signatures for each nonce.
645
func CombineSigs(combinedNonce *btcec.PublicKey,
646
        partialSigs []*PartialSignature,
647
        combineOpts ...CombineOption) *schnorr.Signature {
10✔
648

10✔
649
        // First, parse the set of optional combine options.
10✔
650
        opts := defaultCombineOptions()
10✔
651
        for _, option := range combineOpts {
17✔
652
                option(opts)
7✔
653
        }
7✔
654

655
        // If signer keys and tweaks are specified, then we need to carry out
656
        // some intermediate steps before we can combine the signature.
657
        var tweakProduct *btcec.ModNScalar
10✔
658
        if opts.combinedKey != nil && opts.tweakAcc != nil {
17✔
659
                // Next, we'll construct the parity factor of the combined key,
7✔
660
                // negating it if the combined key has an even y coordinate.
7✔
661
                parityFactor := new(btcec.ModNScalar).SetInt(1)
7✔
662
                combinedKeyBytes := opts.combinedKey.SerializeCompressed()
7✔
663
                if combinedKeyBytes[0] == secp.PubKeyFormatCompressedOdd {
10✔
664
                        parityFactor.Negate()
3✔
665
                }
3✔
666

667
                // Next we'll reconstruct e the challenge has based on the
668
                // nonce and combined public key.
669
                //  * e = H(tag=ChallengeHashTag, R || Q || m) mod n
670
                var challengeMsg bytes.Buffer
7✔
671
                challengeMsg.Write(schnorr.SerializePubKey(combinedNonce))
7✔
672
                challengeMsg.Write(schnorr.SerializePubKey(opts.combinedKey))
7✔
673
                challengeMsg.Write(opts.msg[:])
7✔
674
                challengeBytes := chainhash.TaggedHash(
7✔
675
                        ChallengeHashTag, challengeMsg.Bytes(),
7✔
676
                )
7✔
677
                var e btcec.ModNScalar
7✔
678
                e.SetByteSlice(challengeBytes[:])
7✔
679

7✔
680
                tweakProduct = new(btcec.ModNScalar).Set(&e)
7✔
681
                tweakProduct.Mul(opts.tweakAcc).Mul(parityFactor)
7✔
682
        }
683

684
        // Finally, the tweak factor also needs to be re-computed as well.
685
        var combinedSig btcec.ModNScalar
10✔
686
        for _, partialSig := range partialSigs {
520✔
687
                combinedSig.Add(partialSig.S)
510✔
688
        }
510✔
689

690
        // If the tweak product was set above, then we'll need to add the value
691
        // at the very end in order to produce a valid signature under the
692
        // final tweaked key.
693
        if tweakProduct != nil {
17✔
694
                combinedSig.Add(tweakProduct)
7✔
695
        }
7✔
696

697
        // TODO(roasbeef): less verbose way to get the x coord...
698
        var nonceJ btcec.JacobianPoint
10✔
699
        combinedNonce.AsJacobian(&nonceJ)
10✔
700
        nonceJ.ToAffine()
10✔
701

10✔
702
        return schnorr.NewSignature(&nonceJ.X, &combinedSig)
10✔
703
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc