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

lightningnetwork / lnd / 13157733617

05 Feb 2025 12:49PM UTC coverage: 57.712% (-1.1%) from 58.82%
13157733617

Pull #9447

github

yyforyongyu
sweep: rename methods for clarity

We now rename "third party" to "unknown" as the inputs can be spent via
an older sweeping tx, a third party (anchor), or a remote party (pin).
In fee bumper we don't have the info to distinguish the above cases, and
leave them to be further handled by the sweeper as it has more context.
Pull Request #9447: sweep: start tracking input spending status in the fee bumper

83 of 87 new or added lines in 2 files covered. (95.4%)

19472 existing lines in 252 files now uncovered.

103634 of 179570 relevant lines covered (57.71%)

24840.31 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