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

lightningnetwork / lnd / 13536249039

26 Feb 2025 03:42AM UTC coverage: 57.462% (-1.4%) from 58.835%
13536249039

Pull #8453

github

Roasbeef
peer: update chooseDeliveryScript to gen script if needed

In this commit, we update `chooseDeliveryScript` to generate a new
script if needed. This allows us to fold in a few other lines that
always followed this function into this expanded function.

The tests have been updated accordingly.
Pull Request #8453: [4/4] - multi: integrate new rbf coop close FSM into the existing peer flow

275 of 1318 new or added lines in 22 files covered. (20.86%)

19521 existing lines in 257 files now uncovered.

103858 of 180741 relevant lines covered (57.46%)

24750.23 hits per line

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

79.38
/internal/musig2v040/context.go
1
// Copyright (c) 2013-2022 The btcsuite developers
2

3
package musig2v040
4

5
import (
6
        "fmt"
7

8
        "github.com/btcsuite/btcd/btcec/v2"
9
        "github.com/btcsuite/btcd/btcec/v2/schnorr"
10
)
11

12
var (
13
        // ErrSignersNotSpecified is returned when a caller attempts to create
14
        // a context without specifying either the total number of signers, or
15
        // the complete set of singers.
16
        ErrSignersNotSpecified = fmt.Errorf("total number of signers or all " +
17
                "signers must be known")
18

19
        // ErrSignerNotInKeySet is returned when a the private key for a signer
20
        // isn't included in the set of signing public keys.
21
        ErrSignerNotInKeySet = fmt.Errorf("signing key is not found in key" +
22
                " set")
23

24
        // ErrAlredyHaveAllNonces is called when RegisterPubNonce is called too
25
        // many times for a given signing session.
26
        ErrAlredyHaveAllNonces = fmt.Errorf("already have all nonces")
27

28
        // ErrNotEnoughSigners is returned when a caller attempts to create a
29
        // session from a context, but before all the required signers are
30
        // known.
31
        ErrNotEnoughSigners = fmt.Errorf("not enough signers")
32

33
        // ErrAlredyHaveAllNonces is returned when a caller attempts to
34
        // register a signer, once we already have the total set of known
35
        // signers.
36
        ErrAlreadyHaveAllSigners = fmt.Errorf("all signers registered")
37

38
        // ErrAlredyHaveAllSigs is called when CombineSig is called too many
39
        // times for a given signing session.
40
        ErrAlredyHaveAllSigs = fmt.Errorf("already have all sigs")
41

42
        // ErrSigningContextReuse is returned if a user attempts to sign using
43
        // the same signing context more than once.
44
        ErrSigningContextReuse = fmt.Errorf("nonce already used")
45

46
        // ErrFinalSigInvalid is returned when the combined signature turns out
47
        // to be invalid.
48
        ErrFinalSigInvalid = fmt.Errorf("final signature is invalid")
49

50
        // ErrCombinedNonceUnavailable is returned when a caller attempts to
51
        // sign a partial signature, without first having collected all the
52
        // required combined nonces.
53
        ErrCombinedNonceUnavailable = fmt.Errorf("missing combined nonce")
54

55
        // ErrTaprootInternalKeyUnavailable is returned when a user attempts to
56
        // obtain the
57
        ErrTaprootInternalKeyUnavailable = fmt.Errorf("taproot tweak not used")
58

59
        // ErrNotEnoughSigners is returned if a caller attempts to obtain an
60
        // early nonce when it wasn't specified
61
        ErrNoEarlyNonce = fmt.Errorf("no early nonce available")
62
)
63

64
// Context is a managed signing context for musig2. It takes care of things
65
// like securely generating secret nonces, aggregating keys and nonces, etc.
66
type Context struct {
67
        // signingKey is the key we'll use for signing.
68
        signingKey *btcec.PrivateKey
69

70
        // pubKey is our even-y coordinate public  key.
71
        pubKey *btcec.PublicKey
72

73
        // combinedKey is the aggregated public key.
74
        combinedKey *AggregateKey
75

76
        // uniqueKeyIndex is the index of the second unique key in the keySet.
77
        // This is used to speed up signing and verification computations.
78
        uniqueKeyIndex int
79

80
        // keysHash is the hash of all the keys as defined in musig2.
81
        keysHash []byte
82

83
        // opts is the set of options for the context.
84
        opts *contextOptions
85

86
        // shouldSort keeps track of if the public keys should be sorted before
87
        // any operations.
88
        shouldSort bool
89

90
        // sessionNonce will be populated if the earlyNonce option is true.
91
        // After the first session is created, this nonce will be blanked out.
92
        sessionNonce *Nonces
93
}
94

95
// ContextOption is a functional option argument that allows callers to modify
96
// the musig2 signing is done within a context.
97
type ContextOption func(*contextOptions)
98

99
// contextOptions houses the set of functional options that can be used to
100
// musig2 signing protocol.
101
type contextOptions struct {
102
        // tweaks is the set of optinoal tweaks to apply to the combined public
103
        // key.
104
        tweaks []KeyTweakDesc
105

106
        // taprootTweak specifies the taproot tweak. If specified, then we'll
107
        // use this as the script root for the BIP 341 taproot (x-only) tweak.
108
        // Normally we'd just apply the raw 32 byte tweak, but for taproot, we
109
        // first need to compute the aggregated key before tweaking, and then
110
        // use it as the internal key. This is required as the taproot tweak
111
        // also commits to the public key, which in this case is the aggregated
112
        // key before the tweak.
113
        taprootTweak []byte
114

115
        // bip86Tweak if true, then the weak will just be
116
        // h_tapTweak(internalKey) as there is no true script root.
117
        bip86Tweak bool
118

119
        // keySet is the complete set of signers for this context.
120
        keySet []*btcec.PublicKey
121

122
        // numSigners is the total number of signers that will eventually be a
123
        // part of the context.
124
        numSigners int
125

126
        // earlyNonce determines if a nonce should be generated during context
127
        // creation, to be automatically passed to the created session.
128
        earlyNonce bool
129
}
130

131
// defaultContextOptions returns the default context options.
132
func defaultContextOptions() *contextOptions {
503✔
133
        return &contextOptions{}
503✔
134
}
503✔
135

136
// WithTweakedContext specifies that within the context, the aggregated public
137
// key should be tweaked with the specified tweaks.
138
func WithTweakedContext(tweaks ...KeyTweakDesc) ContextOption {
×
139
        return func(o *contextOptions) {
×
140
                o.tweaks = tweaks
×
141
        }
×
142
}
143

144
// WithTaprootTweakCtx specifies that within this context, the final key should
145
// use the taproot tweak as defined in BIP 341: outputKey = internalKey +
146
// h_tapTweak(internalKey || scriptRoot). In this case, the aggreaged key
147
// before the tweak will be used as the internal key.
148
func WithTaprootTweakCtx(scriptRoot []byte) ContextOption {
1✔
149
        return func(o *contextOptions) {
101✔
150
                o.taprootTweak = scriptRoot
100✔
151
        }
100✔
152
}
153

154
// WithBip86TweakCtx specifies that within this context, the final key should
155
// use the taproot tweak as defined in BIP 341, with the BIP 86 modification:
156
// outputKey = internalKey + h_tapTweak(internalKey)*G. In this case, the
157
// aggreaged key before the tweak will be used as the internal key.
158
func WithBip86TweakCtx() ContextOption {
4✔
159
        return func(o *contextOptions) {
404✔
160
                o.bip86Tweak = true
400✔
161
        }
400✔
162
}
163

164
// WithKnownSigners is an optional parameter that should be used if a session
165
// can be created as soon as all the singers are known.
166
func WithKnownSigners(signers []*btcec.PublicKey) ContextOption {
5✔
167
        return func(o *contextOptions) {
505✔
168
                o.keySet = signers
500✔
169
                o.numSigners = len(signers)
500✔
170
        }
500✔
171
}
172

173
// WithNumSigners is a functional option used to specify that a context should
174
// be created without knowing all the signers. Instead the total number of
175
// signers is specified to ensure that a session can only be created once all
176
// the signers are known.
177
//
178
// NOTE: Either WithKnownSigners or WithNumSigners MUST be specified.
179
func WithNumSigners(n int) ContextOption {
2✔
180
        return func(o *contextOptions) {
4✔
181
                o.numSigners = n
2✔
182
        }
2✔
183
}
184

185
// WithEarlyNonceGen allow a caller to specify that a nonce should be generated
186
// early, before the session is created. This should be used in protocols that
187
// require some partial nonce exchange before all the signers are known.
188
//
189
// NOTE: This option must only be specified with the WithNumSigners option.
190
func WithEarlyNonceGen() ContextOption {
2✔
191
        return func(o *contextOptions) {
4✔
192
                o.earlyNonce = true
2✔
193
        }
2✔
194
}
195

196
// NewContext creates a new signing context with the passed singing key and set
197
// of public keys for each of the other signers.
198
//
199
// NOTE: This struct should be used over the raw Sign API whenever possible.
200
func NewContext(signingKey *btcec.PrivateKey, shouldSort bool,
201
        ctxOpts ...ContextOption) (*Context, error) {
503✔
202

503✔
203
        // First, parse the set of optional context options.
503✔
204
        opts := defaultContextOptions()
503✔
205
        for _, option := range ctxOpts {
1,507✔
206
                option(opts)
1,004✔
207
        }
1,004✔
208

209
        pubKey, err := schnorr.ParsePubKey(
503✔
210
                schnorr.SerializePubKey(signingKey.PubKey()),
503✔
211
        )
503✔
212
        if err != nil {
503✔
213
                return nil, err
×
214
        }
×
215

216
        ctx := &Context{
503✔
217
                signingKey: signingKey,
503✔
218
                pubKey:     pubKey,
503✔
219
                opts:       opts,
503✔
220
                shouldSort: shouldSort,
503✔
221
        }
503✔
222

503✔
223
        switch {
503✔
224

225
        // We know all the signers, so we can compute the aggregated key, along
226
        // with all the other intermediate state we need to do signing and
227
        // verification.
228
        case opts.keySet != nil:
500✔
229
                if err := ctx.combineSignerKeys(); err != nil {
500✔
230
                        return nil, err
×
231
                }
×
232

233
        // The total signers are known, so we add ourselves, and skip key
234
        // aggregation.
235
        case opts.numSigners != 0:
2✔
236
                // Otherwise, we'll add ourselves as the only known signer, and
2✔
237
                // await further calls to RegisterSigner before a session can
2✔
238
                // be created.
2✔
239
                opts.keySet = make([]*btcec.PublicKey, 0, opts.numSigners)
2✔
240
                opts.keySet = append(opts.keySet, pubKey)
2✔
241

2✔
242
                // If early nonce generation is specified, then we'll generate
2✔
243
                // the nonce now to pass in to the session once all the callers
2✔
244
                // are known.
2✔
245
                if opts.earlyNonce {
4✔
246
                        ctx.sessionNonce, err = GenNonces()
2✔
247
                        if err != nil {
2✔
248
                                return nil, err
×
249
                        }
×
250
                }
251

252
        default:
1✔
253
                return nil, ErrSignersNotSpecified
1✔
254
        }
255

256
        return ctx, nil
502✔
257
}
258

259
// combineSignerKeys is used to compute the aggregated signer key once all the
260
// signers are known.
261
func (c *Context) combineSignerKeys() error {
502✔
262
        // As a sanity check, make sure the signing key is actually
502✔
263
        // amongst the sit of signers.
502✔
264
        var keyFound bool
502✔
265
        for _, key := range c.opts.keySet {
25,754✔
266
                if key.IsEqual(c.pubKey) {
25,754✔
267
                        keyFound = true
502✔
268
                        break
502✔
269
                }
270
        }
271
        if !keyFound {
502✔
272
                return ErrSignerNotInKeySet
×
273
        }
×
274

275
        // Now that we know that we're actually a signer, we'll
276
        // generate the key hash finger print and second unique key
277
        // index so we can speed up signing later.
278
        c.keysHash = keyHashFingerprint(c.opts.keySet, c.shouldSort)
502✔
279
        c.uniqueKeyIndex = secondUniqueKeyIndex(
502✔
280
                c.opts.keySet, c.shouldSort,
502✔
281
        )
502✔
282

502✔
283
        keyAggOpts := []KeyAggOption{
502✔
284
                WithKeysHash(c.keysHash),
502✔
285
                WithUniqueKeyIndex(c.uniqueKeyIndex),
502✔
286
        }
502✔
287
        switch {
502✔
288
        case c.opts.bip86Tweak:
400✔
289
                keyAggOpts = append(
400✔
290
                        keyAggOpts, WithBIP86KeyTweak(),
400✔
291
                )
400✔
292
        case c.opts.taprootTweak != nil:
100✔
293
                keyAggOpts = append(
100✔
294
                        keyAggOpts, WithTaprootKeyTweak(c.opts.taprootTweak),
100✔
295
                )
100✔
296
        case len(c.opts.tweaks) != 0:
×
297
                keyAggOpts = append(keyAggOpts, WithKeyTweaks(c.opts.tweaks...))
×
298
        }
299

300
        // Next, we'll use this information to compute the aggregated
301
        // public key that'll be used for signing in practice.
302
        var err error
502✔
303
        c.combinedKey, _, _, err = AggregateKeys(
502✔
304
                c.opts.keySet, c.shouldSort, keyAggOpts...,
502✔
305
        )
502✔
306
        if err != nil {
502✔
307
                return err
×
308
        }
×
309

310
        return nil
502✔
311
}
312

313
// EarlySessionNonce returns the early session nonce, if available.
314
func (c *Context) EarlySessionNonce() (*Nonces, error) {
2✔
315
        if c.sessionNonce == nil {
2✔
316
                return nil, ErrNoEarlyNonce
×
317
        }
×
318

319
        return c.sessionNonce, nil
2✔
320
}
321

322
// RegisterSigner allows a caller to register a signer after the context has
323
// been created. This will be used in scenarios where the total number of
324
// signers is known, but nonce exchange needs to happen before all the signers
325
// are known.
326
//
327
// A bool is returned which indicates if all the signers have been registered.
328
//
329
// NOTE: If the set of keys are not to be sorted during signing, then the
330
// ordering each key is registered with MUST match the desired ordering.
331
func (c *Context) RegisterSigner(pub *btcec.PublicKey) (bool, error) {
3✔
332
        haveAllSigners := len(c.opts.keySet) == c.opts.numSigners
3✔
333
        if haveAllSigners {
4✔
334
                return false, ErrAlreadyHaveAllSigners
1✔
335
        }
1✔
336

337
        c.opts.keySet = append(c.opts.keySet, pub)
2✔
338

2✔
339
        // If we have the expected number of signers at this point, then we can
2✔
340
        // generate the aggregated key and other necessary information.
2✔
341
        haveAllSigners = len(c.opts.keySet) == c.opts.numSigners
2✔
342
        if haveAllSigners {
4✔
343
                if err := c.combineSignerKeys(); err != nil {
2✔
344
                        return false, err
×
345
                }
×
346
        }
347

348
        return haveAllSigners, nil
2✔
349
}
350

351
// NumRegisteredSigners returns the total number of registered signers.
352
func (c *Context) NumRegisteredSigners() int {
2✔
353
        return len(c.opts.keySet)
2✔
354
}
2✔
355

356
// CombinedKey returns the combined public key that will be used to generate
357
// multi-signatures  against.
358
func (c *Context) CombinedKey() (*btcec.PublicKey, error) {
9✔
359
        // If the caller hasn't registered all the signers at this point, then
9✔
360
        // the combined key won't be available.
9✔
361
        if c.combinedKey == nil {
12✔
362
                return nil, ErrNotEnoughSigners
3✔
363
        }
3✔
364

365
        return c.combinedKey.FinalKey, nil
6✔
366
}
367

368
// PubKey returns the public key of the signer of this session.
369
func (c *Context) PubKey() btcec.PublicKey {
2✔
370
        return *c.pubKey
2✔
371
}
2✔
372

373
// SigningKeys returns the set of keys used for signing.
UNCOV
374
func (c *Context) SigningKeys() []*btcec.PublicKey {
×
UNCOV
375
        keys := make([]*btcec.PublicKey, len(c.opts.keySet))
×
UNCOV
376
        copy(keys, c.opts.keySet)
×
UNCOV
377

×
UNCOV
378
        return keys
×
UNCOV
379
}
×
380

381
// TaprootInternalKey returns the internal taproot key, which is the aggregated
382
// key _before_ the tweak is applied. If a taproot tweak was specified, then
383
// CombinedKey() will return the fully tweaked output key, with this method
384
// returning the internal key. If a taproot tweak wasn't specified, then this
385
// method will return an error.
UNCOV
386
func (c *Context) TaprootInternalKey() (*btcec.PublicKey, error) {
×
UNCOV
387
        // If the caller hasn't registered all the signers at this point, then
×
UNCOV
388
        // the combined key won't be available.
×
UNCOV
389
        if c.combinedKey == nil {
×
390
                return nil, ErrNotEnoughSigners
×
391
        }
×
392

UNCOV
393
        if c.opts.taprootTweak == nil && !c.opts.bip86Tweak {
×
394
                return nil, ErrTaprootInternalKeyUnavailable
×
395
        }
×
396

UNCOV
397
        return c.combinedKey.PreTweakedKey, nil
×
398
}
399

400
// SessionOption is a functional option argument that allows callers to modify
401
// the musig2 signing is done within a session.
402
type SessionOption func(*sessionOptions)
403

404
// sessionOptions houses the set of functional options that can be used to
405
// modify the musig2 signing protocol.
406
type sessionOptions struct {
407
        externalNonce *Nonces
408
}
409

410
// defaultSessionOptions returns the default session options.
411
func defaultSessionOptions() *sessionOptions {
503✔
412
        return &sessionOptions{}
503✔
413
}
503✔
414

415
// WithPreGeneratedNonce allows a caller to start a session using a nonce
416
// they've generated themselves. This may be useful in protocols where all the
417
// signer keys may not be known before nonce exchange needs to occur.
418
func WithPreGeneratedNonce(nonce *Nonces) SessionOption {
×
419
        return func(o *sessionOptions) {
×
420
                o.externalNonce = nonce
×
421
        }
×
422
}
423

424
// Session represents a musig2 signing session. A new instance should be
425
// created each time a multi-signature is needed. The session struct handles
426
// nonces management, incremental partial sig vitrifaction, as well as final
427
// signature combination. Errors are returned when unsafe behavior such as
428
// nonce re-use is attempted.
429
//
430
// NOTE: This struct should be used over the raw Sign API whenever possible.
431
type Session struct {
432
        opts *sessionOptions
433

434
        ctx *Context
435

436
        localNonces *Nonces
437

438
        pubNonces [][PubNonceSize]byte
439

440
        combinedNonce *[PubNonceSize]byte
441

442
        msg [32]byte
443

444
        ourSig *PartialSignature
445
        sigs   []*PartialSignature
446

447
        finalSig *schnorr.Signature
448
}
449

450
// NewSession creates a new musig2 signing session.
451
func (c *Context) NewSession(options ...SessionOption) (*Session, error) {
503✔
452
        opts := defaultSessionOptions()
503✔
453
        for _, opt := range options {
503✔
454
                opt(opts)
×
455
        }
×
456

457
        // At this point we verify that we know of all the signers, as
458
        // otherwise we can't proceed with the session. This check is intended
459
        // to catch misuse of the API wherein a caller forgets to register the
460
        // remaining signers if they're doing nonce generation ahead of time.
461
        if len(c.opts.keySet) != c.opts.numSigners {
504✔
462
                return nil, ErrNotEnoughSigners
1✔
463
        }
1✔
464

465
        // If an early nonce was specified, then we'll automatically add the
466
        // corresponding session option for the caller.
467
        var localNonces *Nonces
502✔
468
        if c.sessionNonce != nil {
504✔
469
                // Apply the early nonce to the session, and also blank out the
2✔
470
                // session nonce on the context to ensure it isn't ever re-used
2✔
471
                // for another session.
2✔
472
                localNonces = c.sessionNonce
2✔
473
                c.sessionNonce = nil
2✔
474
        } else if opts.externalNonce != nil {
502✔
475
                // Otherwise if there's a custom nonce passed in via the
×
476
                // session options, then use that instead.
×
477
                localNonces = opts.externalNonce
×
478
        }
×
479

480
        // Now that we know we have enough signers, we'll either use the caller
481
        // specified nonce, or generate a fresh set.
482
        var err error
502✔
483
        if localNonces == nil {
1,002✔
484
                // At this point we need to generate a fresh nonce. We'll pass
500✔
485
                // in some auxiliary information to strengthen the nonce
500✔
486
                // generated.
500✔
487
                localNonces, err = GenNonces(
500✔
488
                        WithNonceSecretKeyAux(c.signingKey),
500✔
489
                        WithNonceCombinedKeyAux(c.combinedKey.FinalKey),
500✔
490
                )
500✔
491
                if err != nil {
500✔
492
                        return nil, err
×
493
                }
×
494
        }
495

496
        s := &Session{
502✔
497
                opts:        opts,
502✔
498
                ctx:         c,
502✔
499
                localNonces: localNonces,
502✔
500
                pubNonces:   make([][PubNonceSize]byte, 0, c.opts.numSigners),
502✔
501
                sigs:        make([]*PartialSignature, 0, c.opts.numSigners),
502✔
502
        }
502✔
503

502✔
504
        s.pubNonces = append(s.pubNonces, localNonces.PubNonce)
502✔
505

502✔
506
        return s, nil
502✔
507
}
508

509
// PublicNonce returns the public nonce for a signer. This should be sent to
510
// other parties before signing begins, so they can compute the aggregated
511
// public nonce.
512
func (s *Session) PublicNonce() [PubNonceSize]byte {
49,500✔
513
        return s.localNonces.PubNonce
49,500✔
514
}
49,500✔
515

516
// NumRegisteredNonces returns the total number of nonces that have been
517
// regsitered so far.
UNCOV
518
func (s *Session) NumRegisteredNonces() int {
×
UNCOV
519
        return len(s.pubNonces)
×
UNCOV
520
}
×
521

522
// RegisterPubNonce should be called for each public nonce from the set of
523
// signers. This method returns true once all the public nonces have been
524
// accounted for.
525
func (s *Session) RegisterPubNonce(nonce [PubNonceSize]byte) (bool, error) {
49,503✔
526
        // If we already have all the nonces, then this method was called too
49,503✔
527
        // many times.
49,503✔
528
        haveAllNonces := len(s.pubNonces) == s.ctx.opts.numSigners
49,503✔
529
        if haveAllNonces {
49,504✔
530
                return false, ErrAlredyHaveAllNonces
1✔
531
        }
1✔
532

533
        // Add this nonce and check again if we already have tall the nonces we
534
        // need.
535
        s.pubNonces = append(s.pubNonces, nonce)
49,502✔
536
        haveAllNonces = len(s.pubNonces) == s.ctx.opts.numSigners
49,502✔
537

49,502✔
538
        // If we have all the nonces, then we can go ahead and combine them
49,502✔
539
        // now.
49,502✔
540
        if haveAllNonces {
50,004✔
541
                combinedNonce, err := AggregateNonces(s.pubNonces)
502✔
542
                if err != nil {
502✔
543
                        return false, err
×
544
                }
×
545

546
                s.combinedNonce = &combinedNonce
502✔
547
        }
548

549
        return haveAllNonces, nil
49,502✔
550
}
551

552
// Sign generates a partial signature for the target message, using the target
553
// context. If this method is called more than once per context, then an error
554
// is returned, as that means a nonce was re-used.
555
func (s *Session) Sign(msg [32]byte,
556
        signOpts ...SignOption) (*PartialSignature, error) {
1,003✔
557

1,003✔
558
        switch {
1,003✔
559
        // If no local nonce is present, then this means we already signed, so
560
        // we'll return an error to prevent nonce re-use.
561
        case s.localNonces == nil:
500✔
562
                return nil, ErrSigningContextReuse
500✔
563

564
        // We also need to make sure we have the combined nonce, otherwise this
565
        // function was called too early.
566
        case s.combinedNonce == nil:
1✔
567
                return nil, ErrCombinedNonceUnavailable
1✔
568
        }
569

570
        switch {
502✔
571
        case s.ctx.opts.bip86Tweak:
400✔
572
                signOpts = append(
400✔
573
                        signOpts, WithBip86SignTweak(),
400✔
574
                )
400✔
575
        case s.ctx.opts.taprootTweak != nil:
100✔
576
                signOpts = append(
100✔
577
                        signOpts, WithTaprootSignTweak(s.ctx.opts.taprootTweak),
100✔
578
                )
100✔
579
        case len(s.ctx.opts.tweaks) != 0:
×
580
                signOpts = append(signOpts, WithTweaks(s.ctx.opts.tweaks...))
×
581
        }
582

583
        partialSig, err := Sign(
502✔
584
                s.localNonces.SecNonce, s.ctx.signingKey, *s.combinedNonce,
502✔
585
                s.ctx.opts.keySet, msg, signOpts...,
502✔
586
        )
502✔
587

502✔
588
        // Now that we've generated our signature, we'll make sure to blank out
502✔
589
        // our signing nonce.
502✔
590
        s.localNonces = nil
502✔
591

502✔
592
        if err != nil {
502✔
593
                return nil, err
×
594
        }
×
595

596
        s.msg = msg
502✔
597

502✔
598
        s.ourSig = partialSig
502✔
599
        s.sigs = append(s.sigs, partialSig)
502✔
600

502✔
601
        return partialSig, nil
502✔
602
}
603

604
// CombineSig buffers a partial signature received from a signing party. The
605
// method returns true once all the signatures are available, and can be
606
// combined into the final signature.
607
func (s *Session) CombineSig(sig *PartialSignature) (bool, error) {
497✔
608
        // First check if we already have all the signatures we need. We
497✔
609
        // already accumulated our own signature when we generated the sig.
497✔
610
        haveAllSigs := len(s.sigs) == len(s.ctx.opts.keySet)
497✔
611
        if haveAllSigs {
498✔
612
                return false, ErrAlredyHaveAllSigs
1✔
613
        }
1✔
614

615
        // TODO(roasbeef): incremental check for invalid sig, or just detect at
616
        // the very end?
617

618
        // Accumulate this sig, and check again if we have all the sigs we
619
        // need.
620
        s.sigs = append(s.sigs, sig)
496✔
621
        haveAllSigs = len(s.sigs) == len(s.ctx.opts.keySet)
496✔
622

496✔
623
        // If we have all the signatures, then we can combine them all into the
496✔
624
        // final signature.
496✔
625
        if haveAllSigs {
502✔
626
                var combineOpts []CombineOption
6✔
627
                switch {
6✔
628
                case s.ctx.opts.bip86Tweak:
4✔
629
                        combineOpts = append(
4✔
630
                                combineOpts, WithBip86TweakedCombine(
4✔
631
                                        s.msg, s.ctx.opts.keySet,
4✔
632
                                        s.ctx.shouldSort,
4✔
633
                                ),
4✔
634
                        )
4✔
635
                case s.ctx.opts.taprootTweak != nil:
1✔
636
                        combineOpts = append(
1✔
637
                                combineOpts, WithTaprootTweakedCombine(
1✔
638
                                        s.msg, s.ctx.opts.keySet,
1✔
639
                                        s.ctx.opts.taprootTweak, s.ctx.shouldSort,
1✔
640
                                ),
1✔
641
                        )
1✔
642
                case len(s.ctx.opts.tweaks) != 0:
×
643
                        combineOpts = append(
×
644
                                combineOpts, WithTweakedCombine(
×
645
                                        s.msg, s.ctx.opts.keySet,
×
646
                                        s.ctx.opts.tweaks, s.ctx.shouldSort,
×
647
                                ),
×
648
                        )
×
649
                }
650

651
                finalSig := CombineSigs(s.ourSig.R, s.sigs, combineOpts...)
6✔
652

6✔
653
                // We'll also verify the signature at this point to ensure it's
6✔
654
                // valid.
6✔
655
                //
6✔
656
                // TODO(roasbef): allow skipping?
6✔
657
                if !finalSig.Verify(s.msg[:], s.ctx.combinedKey.FinalKey) {
6✔
658
                        return false, ErrFinalSigInvalid
×
659
                }
×
660

661
                s.finalSig = finalSig
6✔
662
        }
663

664
        return haveAllSigs, nil
496✔
665
}
666

667
// FinalSig returns the final combined multi-signature, if present.
668
func (s *Session) FinalSig() *schnorr.Signature {
6✔
669
        return s.finalSig
6✔
670
}
6✔
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