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

lightningnetwork / lnd / 13586005509

28 Feb 2025 10:14AM UTC coverage: 68.629% (+9.9%) from 58.77%
13586005509

Pull #9521

github

web-flow
Merge 37d3a70a5 into 8532955b3
Pull Request #9521: unit: remove GOACC, use Go 1.20 native coverage functionality

129950 of 189351 relevant lines covered (68.63%)

23726.46 hits per line

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

100.0
/internal/musig2v040/keys.go
1
// Copyright 2013-2022 The btcsuite developers
2

3
package musig2v040
4

5
import (
6
        "bytes"
7
        "fmt"
8
        "sort"
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
        // KeyAggTagList is the tagged hash tag used to compute the hash of the
18
        // list of sorted public keys.
19
        KeyAggTagList = []byte("KeyAgg list")
20

21
        // KeyAggTagCoeff is the tagged hash tag used to compute the key
22
        // aggregation coefficient for each key.
23
        KeyAggTagCoeff = []byte("KeyAgg coefficient")
24

25
        // ErrTweakedKeyIsInfinity is returned if while tweaking a key, we end
26
        // up with the point at infinity.
27
        ErrTweakedKeyIsInfinity = fmt.Errorf("tweaked key is infinity point")
28

29
        // ErrTweakedKeyOverflows is returned if a tweaking key is larger than
30
        // 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141.
31
        ErrTweakedKeyOverflows = fmt.Errorf("tweaked key is to large")
32
)
33

34
// sortableKeys defines a type of slice of public keys that implements the sort
35
// interface for BIP 340 keys.
36
type sortableKeys []*btcec.PublicKey
37

38
// Less reports whether the element with index i must sort before the element
39
// with index j.
40
func (s sortableKeys) Less(i, j int) bool {
37✔
41
        // TODO(roasbeef): more efficient way to compare...
37✔
42
        keyIBytes := schnorr.SerializePubKey(s[i])
37✔
43
        keyJBytes := schnorr.SerializePubKey(s[j])
37✔
44

37✔
45
        return bytes.Compare(keyIBytes, keyJBytes) == -1
37✔
46
}
37✔
47

48
// Swap swaps the elements with indexes i and j.
49
func (s sortableKeys) Swap(i, j int) {
10✔
50
        s[i], s[j] = s[j], s[i]
10✔
51
}
10✔
52

53
// Len is the number of elements in the collection.
54
func (s sortableKeys) Len() int {
27✔
55
        return len(s)
27✔
56
}
27✔
57

58
// sortKeys takes a set of schnorr public keys and returns a new slice that is
59
// a copy of the keys sorted in lexicographical order bytes on the x-only
60
// pubkey serialization.
61
func sortKeys(keys []*btcec.PublicKey) []*btcec.PublicKey {
23✔
62
        keySet := sortableKeys(keys)
23✔
63
        if sort.IsSorted(keySet) {
42✔
64
                return keys
19✔
65
        }
19✔
66

67
        sort.Sort(keySet)
7✔
68
        return keySet
7✔
69
}
70

71
// keyHashFingerprint computes the tagged hash of the series of (sorted) public
72
// keys passed as input. This is used to compute the aggregation coefficient
73
// for each key. The final computation is:
74
//   - H(tag=KeyAgg list, pk1 || pk2..)
75
func keyHashFingerprint(keys []*btcec.PublicKey, sort bool) []byte {
1,561✔
76
        if sort {
1,571✔
77
                keys = sortKeys(keys)
10✔
78
        }
10✔
79

80
        // We'll create a single buffer and slice into that so the bytes buffer
81
        // doesn't continually need to grow the underlying buffer.
82
        keyAggBuf := make([]byte, 32*len(keys))
1,561✔
83
        keyBytes := bytes.NewBuffer(keyAggBuf[0:0])
1,561✔
84
        for _, key := range keys {
152,203✔
85
                keyBytes.Write(schnorr.SerializePubKey(key))
150,642✔
86
        }
150,642✔
87

88
        h := chainhash.TaggedHash(KeyAggTagList, keyBytes.Bytes())
1,561✔
89
        return h[:]
1,561✔
90
}
91

92
// keyBytesEqual returns true if two keys are the same from the PoV of BIP
93
// 340's 32-byte x-only public keys.
94
func keyBytesEqual(a, b *btcec.PublicKey) bool {
154,783✔
95
        return bytes.Equal(
154,783✔
96
                schnorr.SerializePubKey(a),
154,783✔
97
                schnorr.SerializePubKey(b),
154,783✔
98
        )
154,783✔
99
}
154,783✔
100

101
// aggregationCoefficient computes the key aggregation coefficient for the
102
// specified target key. The coefficient is computed as:
103
//   - H(tag=KeyAgg coefficient, keyHashFingerprint(pks) || pk)
104
func aggregationCoefficient(keySet []*btcec.PublicKey,
105
        targetKey *btcec.PublicKey, keysHash []byte,
106
        secondKeyIdx int) *btcec.ModNScalar {
151,672✔
107

151,672✔
108
        var mu btcec.ModNScalar
151,672✔
109

151,672✔
110
        // If this is the second key, then this coefficient is just one.
151,672✔
111
        if secondKeyIdx != -1 && keyBytesEqual(keySet[secondKeyIdx], targetKey) {
153,247✔
112
                return mu.SetInt(1)
1,575✔
113
        }
1,575✔
114

115
        // Otherwise, we'll compute the full finger print hash for this given
116
        // key and then use that to compute the coefficient tagged hash:
117
        //  * H(tag=KeyAgg coefficient, keyHashFingerprint(pks, pk) || pk)
118
        var coefficientBytes [64]byte
150,100✔
119
        copy(coefficientBytes[:], keysHash[:])
150,100✔
120
        copy(coefficientBytes[32:], schnorr.SerializePubKey(targetKey))
150,100✔
121

150,100✔
122
        muHash := chainhash.TaggedHash(KeyAggTagCoeff, coefficientBytes[:])
150,100✔
123

150,100✔
124
        mu.SetByteSlice(muHash[:])
150,100✔
125

150,100✔
126
        return &mu
150,100✔
127
}
128

129
// secondUniqueKeyIndex returns the index of the second unique key. If all keys
130
// are the same, then a value of -1 is returned.
131
func secondUniqueKeyIndex(keySet []*btcec.PublicKey, sort bool) int {
1,561✔
132
        if sort {
1,571✔
133
                keySet = sortKeys(keySet)
10✔
134
        }
10✔
135

136
        // Find the first key that isn't the same as the very first key (second
137
        // unique key).
138
        for i := range keySet {
4,680✔
139
                if !keyBytesEqual(keySet[i], keySet[0]) {
4,677✔
140
                        return i
1,558✔
141
                }
1,558✔
142
        }
143

144
        // A value of negative one is used to indicate that all the keys in the
145
        // sign set are actually equal, which in practice actually makes musig2
146
        // useless, but we need a value to distinguish this case.
147
        return -1
3✔
148
}
149

150
// KeyTweakDesc describes a tweak to be applied to the aggregated public key
151
// generation and signing process. The IsXOnly specifies if the target key
152
// should be converted to an x-only public key before tweaking.
153
type KeyTweakDesc struct {
154
        // Tweak is the 32-byte value that will modify the public key.
155
        Tweak [32]byte
156

157
        // IsXOnly if true, then the public key will be mapped to an x-only key
158
        // before the tweaking operation is applied.
159
        IsXOnly bool
160
}
161

162
// KeyAggOption is a functional option argument that allows callers to specify
163
// more or less information that has been pre-computed to the main routine.
164
type KeyAggOption func(*keyAggOption)
165

166
// keyAggOption houses the set of functional options that modify key
167
// aggregation.
168
type keyAggOption struct {
169
        // keyHash is the output of keyHashFingerprint for a given set of keys.
170
        keyHash []byte
171

172
        // uniqueKeyIndex is the pre-computed index of the second unique key.
173
        uniqueKeyIndex *int
174

175
        // tweaks specifies a series of tweaks to be applied to the aggregated
176
        // public key.
177
        tweaks []KeyTweakDesc
178

179
        // taprootTweak controls if the tweaks above should be applied in a BIP
180
        // 340 style.
181
        taprootTweak bool
182

183
        // bip86Tweak specifies that the taproot tweak should be done in a BIP
184
        // 86 style, where we don't expect an actual tweak and instead just
185
        // commit to the public key itself.
186
        bip86Tweak bool
187
}
188

189
// WithKeysHash allows key aggregation to be optimize, by allowing the caller
190
// to specify the hash of all the keys.
191
func WithKeysHash(keyHash []byte) KeyAggOption {
1,538✔
192
        return func(o *keyAggOption) {
3,076✔
193
                o.keyHash = keyHash
1,538✔
194
        }
1,538✔
195
}
196

197
// WithUniqueKeyIndex allows the caller to specify the index of the second
198
// unique key.
199
func WithUniqueKeyIndex(idx int) KeyAggOption {
1,548✔
200
        return func(o *keyAggOption) {
3,096✔
201
                i := idx
1,548✔
202
                o.uniqueKeyIndex = &i
1,548✔
203
        }
1,548✔
204
}
205

206
// WithKeyTweaks allows a caller to specify a series of 32-byte tweaks that
207
// should be applied to the final aggregated public key.
208
func WithKeyTweaks(tweaks ...KeyTweakDesc) KeyAggOption {
18✔
209
        return func(o *keyAggOption) {
36✔
210
                o.tweaks = tweaks
18✔
211
        }
18✔
212
}
213

214
// WithTaprootKeyTweak specifies that within this context, the final key should
215
// use the taproot tweak as defined in BIP 341: outputKey = internalKey +
216
// h_tapTweak(internalKey || scriptRoot). In this case, the aggregated key
217
// before the tweak will be used as the internal key.
218
//
219
// This option should be used instead of WithKeyTweaks when the aggregated key
220
// is intended to be used as a taproot output key that commits to a script
221
// root.
222
func WithTaprootKeyTweak(scriptRoot []byte) KeyAggOption {
304✔
223
        return func(o *keyAggOption) {
608✔
224
                var tweak [32]byte
304✔
225
                copy(tweak[:], scriptRoot[:])
304✔
226

304✔
227
                o.tweaks = []KeyTweakDesc{
304✔
228
                        {
304✔
229
                                Tweak:   tweak,
304✔
230
                                IsXOnly: true,
304✔
231
                        },
304✔
232
                }
304✔
233
                o.taprootTweak = true
304✔
234
        }
304✔
235
}
236

237
// WithBIP86KeyTweak specifies that then during key aggregation, the BIP 86
238
// tweak which just commits to the hash of the serialized public key should be
239
// used. This option should be used when signing with a key that was derived
240
// using BIP 86.
241
func WithBIP86KeyTweak() KeyAggOption {
1,212✔
242
        return func(o *keyAggOption) {
2,424✔
243
                o.tweaks = []KeyTweakDesc{
1,212✔
244
                        {
1,212✔
245
                                IsXOnly: true,
1,212✔
246
                        },
1,212✔
247
                }
1,212✔
248
                o.taprootTweak = true
1,212✔
249
                o.bip86Tweak = true
1,212✔
250
        }
1,212✔
251
}
252

253
// defaultKeyAggOptions returns the set of default arguments for key
254
// aggregation.
255
func defaultKeyAggOptions() *keyAggOption {
1,560✔
256
        return &keyAggOption{}
1,560✔
257
}
1,560✔
258

259
// hasEvenY returns true if the affine representation of the passed jacobian
260
// point has an even y coordinate.
261
//
262
// TODO(roasbeef): double check, can just check the y coord even not jacobian?
263
func hasEvenY(pJ btcec.JacobianPoint) bool {
1,530✔
264
        pJ.ToAffine()
1,530✔
265
        p := btcec.NewPublicKey(&pJ.X, &pJ.Y)
1,530✔
266
        keyBytes := p.SerializeCompressed()
1,530✔
267
        return keyBytes[0] == secp.PubKeyFormatCompressedEven
1,530✔
268
}
1,530✔
269

270
// tweakKey applies a tweaks to the passed public key using the specified
271
// tweak. The parityAcc and tweakAcc are returned (in that order) which
272
// includes the accumulate ration of the parity factor and the tweak multiplied
273
// by the parity factor. The xOnly bool specifies if this is to be an x-only
274
// tweak or not.
275
func tweakKey(keyJ btcec.JacobianPoint, parityAcc btcec.ModNScalar, tweak [32]byte,
276
        tweakAcc btcec.ModNScalar,
277
        xOnly bool) (btcec.JacobianPoint, btcec.ModNScalar, btcec.ModNScalar, error) {
1,547✔
278

1,547✔
279
        // First we'll compute the new parity factor for this key. If the key has
1,547✔
280
        // an odd y coordinate (not even), then we'll need to negate it (multiply
1,547✔
281
        // by -1 mod n, in this case).
1,547✔
282
        var parityFactor btcec.ModNScalar
1,547✔
283
        if xOnly && !hasEvenY(keyJ) {
2,167✔
284
                parityFactor.SetInt(1).Negate()
620✔
285
        } else {
1,549✔
286
                parityFactor.SetInt(1)
929✔
287
        }
929✔
288

289
        // Next, map the tweak into a mod n integer so we can use it for
290
        // manipulations below.
291
        tweakInt := new(btcec.ModNScalar)
1,547✔
292
        overflows := tweakInt.SetBytes(&tweak)
1,547✔
293
        if overflows == 1 {
1,548✔
294
                return keyJ, parityAcc, tweakAcc, ErrTweakedKeyOverflows
1✔
295
        }
1✔
296

297
        // Next, we'll compute: Q_i = g*Q + t*G, where g is our parityFactor and t
298
        // is the tweakInt above. We'll space things out a bit to make it easier to
299
        // follow.
300
        //
301
        // First compute t*G:
302
        var tweakedGenerator btcec.JacobianPoint
1,546✔
303
        btcec.ScalarBaseMultNonConst(tweakInt, &tweakedGenerator)
1,546✔
304

1,546✔
305
        // Next compute g*Q:
1,546✔
306
        btcec.ScalarMultNonConst(&parityFactor, &keyJ, &keyJ)
1,546✔
307

1,546✔
308
        // Finally add both of them together to get our final
1,546✔
309
        // tweaked point.
1,546✔
310
        btcec.AddNonConst(&tweakedGenerator, &keyJ, &keyJ)
1,546✔
311

1,546✔
312
        // As a sanity check, make sure that we didn't just end up with the
1,546✔
313
        // point at infinity.
1,546✔
314
        if keyJ == infinityPoint {
1,547✔
315
                return keyJ, parityAcc, tweakAcc, ErrTweakedKeyIsInfinity
1✔
316
        }
1✔
317

318
        // As a final wrap up step, we'll accumulate the parity
319
        // factor and also this tweak into the final set of accumulators.
320
        parityAcc.Mul(&parityFactor)
1,545✔
321
        tweakAcc.Mul(&parityFactor).Add(tweakInt)
1,545✔
322

1,545✔
323
        return keyJ, parityAcc, tweakAcc, nil
1,545✔
324
}
325

326
// AggregateKey is a final aggregated key along with a possible version of the
327
// key without any tweaks applied.
328
type AggregateKey struct {
329
        // FinalKey is the final aggregated key which may include one or more
330
        // tweaks applied to it.
331
        FinalKey *btcec.PublicKey
332

333
        // PreTweakedKey is the aggregated *before* any tweaks have been
334
        // applied.  This should be used as the internal key in taproot
335
        // contexts.
336
        PreTweakedKey *btcec.PublicKey
337
}
338

339
// AggregateKeys takes a list of possibly unsorted keys and returns a single
340
// aggregated key as specified by the musig2 key aggregation algorithm. A nil
341
// value can be passed for keyHash, which causes this function to re-derive it.
342
// In addition to the combined public key, the parity accumulator and the tweak
343
// accumulator are returned as well.
344
func AggregateKeys(keys []*btcec.PublicKey, sort bool,
345
        keyOpts ...KeyAggOption) (
346
        *AggregateKey, *btcec.ModNScalar, *btcec.ModNScalar, error) {
1,560✔
347

1,560✔
348
        // First, parse the set of optional signing options.
1,560✔
349
        opts := defaultKeyAggOptions()
1,560✔
350
        for _, option := range keyOpts {
6,171✔
351
                option(opts)
4,611✔
352
        }
4,611✔
353

354
        // Sort the set of public key so we know we're working with them in
355
        // sorted order for all the routines below.
356
        if sort {
1,569✔
357
                keys = sortKeys(keys)
9✔
358
        }
9✔
359

360
        // The caller may provide the hash of all the keys as an optimization
361
        // during signing, as it already needs to be computed.
362
        if opts.keyHash == nil {
1,585✔
363
                opts.keyHash = keyHashFingerprint(keys, sort)
25✔
364
        }
25✔
365

366
        // A caller may also specify the unique key index themselves so we
367
        // don't need to re-compute it.
368
        if opts.uniqueKeyIndex == nil {
1,575✔
369
                idx := secondUniqueKeyIndex(keys, sort)
15✔
370
                opts.uniqueKeyIndex = &idx
15✔
371
        }
15✔
372

373
        // For each key, we'll compute the intermediate blinded key: a_i*P_i,
374
        // where a_i is the aggregation coefficient for that key, and P_i is
375
        // the key itself, then accumulate that (addition) into the main final
376
        // key: P = P_1 + P_2 ... P_N.
377
        var finalKeyJ btcec.JacobianPoint
1,560✔
378
        for _, key := range keys {
152,201✔
379
                // Port the key over to Jacobian coordinates as we need it in
150,641✔
380
                // this format for the routines below.
150,641✔
381
                var keyJ btcec.JacobianPoint
150,641✔
382
                key.AsJacobian(&keyJ)
150,641✔
383

150,641✔
384
                // Compute the aggregation coefficient for the key, then
150,641✔
385
                // multiply it by the key itself: P_i' = a_i*P_i.
150,641✔
386
                var tweakedKeyJ btcec.JacobianPoint
150,641✔
387
                a := aggregationCoefficient(
150,641✔
388
                        keys, key, opts.keyHash, *opts.uniqueKeyIndex,
150,641✔
389
                )
150,641✔
390
                btcec.ScalarMultNonConst(a, &keyJ, &tweakedKeyJ)
150,641✔
391

150,641✔
392
                // Finally accumulate this into the final key in an incremental
150,641✔
393
                // fashion.
150,641✔
394
                btcec.AddNonConst(&finalKeyJ, &tweakedKeyJ, &finalKeyJ)
150,641✔
395
        }
150,641✔
396

397
        // We'll copy over the key at this point, since this represents the
398
        // aggregated key before any tweaks have been applied. This'll be used
399
        // as the internal key for script path proofs.
400
        finalKeyJ.ToAffine()
1,560✔
401
        combinedKey := btcec.NewPublicKey(&finalKeyJ.X, &finalKeyJ.Y)
1,560✔
402

1,560✔
403
        // At this point, if this is a taproot tweak, then we'll modify the
1,560✔
404
        // base tweak value to use the BIP 341 tweak value.
1,560✔
405
        if opts.taprootTweak {
3,073✔
406
                // Emulate the same behavior as txscript.ComputeTaprootOutputKey
1,513✔
407
                // which only operates on the x-only public key.
1,513✔
408
                key, _ := schnorr.ParsePubKey(schnorr.SerializePubKey(
1,513✔
409
                        combinedKey,
1,513✔
410
                ))
1,513✔
411

1,513✔
412
                // We only use the actual tweak bytes if we're not committing
1,513✔
413
                // to a BIP-0086 key only spend output. Otherwise, we just
1,513✔
414
                // commit to the internal key and an empty byte slice as the
1,513✔
415
                // root hash.
1,513✔
416
                tweakBytes := []byte{}
1,513✔
417
                if !opts.bip86Tweak {
1,817✔
418
                        tweakBytes = opts.tweaks[0].Tweak[:]
304✔
419
                }
304✔
420

421
                // Compute the taproot key tagged hash of:
422
                // h_tapTweak(internalKey || scriptRoot). We only do this for
423
                // the first one, as you can only specify a single tweak when
424
                // using the taproot mode with this API.
425
                tapTweakHash := chainhash.TaggedHash(
1,513✔
426
                        chainhash.TagTapTweak, schnorr.SerializePubKey(key),
1,513✔
427
                        tweakBytes,
1,513✔
428
                )
1,513✔
429
                opts.tweaks[0].Tweak = *tapTweakHash
1,513✔
430
        }
431

432
        var (
1,560✔
433
                err       error
1,560✔
434
                tweakAcc  btcec.ModNScalar
1,560✔
435
                parityAcc btcec.ModNScalar
1,560✔
436
        )
1,560✔
437
        parityAcc.SetInt(1)
1,560✔
438

1,560✔
439
        // In this case we have a set of tweaks, so we'll incrementally apply
1,560✔
440
        // each one, until we have our final tweaked key, and the related
1,560✔
441
        // accumulators.
1,560✔
442
        for i := 1; i <= len(opts.tweaks); i++ {
3,107✔
443
                finalKeyJ, parityAcc, tweakAcc, err = tweakKey(
1,547✔
444
                        finalKeyJ, parityAcc, opts.tweaks[i-1].Tweak, tweakAcc,
1,547✔
445
                        opts.tweaks[i-1].IsXOnly,
1,547✔
446
                )
1,547✔
447
                if err != nil {
1,549✔
448
                        return nil, nil, nil, err
2✔
449
                }
2✔
450
        }
451

452
        finalKeyJ.ToAffine()
1,558✔
453
        finalKey := btcec.NewPublicKey(&finalKeyJ.X, &finalKeyJ.Y)
1,558✔
454

1,558✔
455
        return &AggregateKey{
1,558✔
456
                PreTweakedKey: combinedKey,
1,558✔
457
                FinalKey:      finalKey,
1,558✔
458
        }, &parityAcc, &tweakAcc, nil
1,558✔
459
}
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