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

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

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

95.2
/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 {
3✔
41
        // TODO(roasbeef): more efficient way to compare...
3✔
42
        keyIBytes := schnorr.SerializePubKey(s[i])
3✔
43
        keyJBytes := schnorr.SerializePubKey(s[j])
3✔
44

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

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

53
// Len is the number of elements in the collection.
54
func (s sortableKeys) Len() int {
3✔
55
        return len(s)
3✔
56
}
3✔
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 {
3✔
62
        keySet := sortableKeys(keys)
3✔
63
        if sort.IsSorted(keySet) {
6✔
64
                return keys
3✔
65
        }
3✔
66

67
        sort.Sort(keySet)
3✔
68
        return keySet
3✔
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 {
3✔
76
        if sort {
6✔
77
                keys = sortKeys(keys)
3✔
78
        }
3✔
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))
3✔
83
        keyBytes := bytes.NewBuffer(keyAggBuf[0:0])
3✔
84
        for _, key := range keys {
6✔
85
                keyBytes.Write(schnorr.SerializePubKey(key))
3✔
86
        }
3✔
87

88
        h := chainhash.TaggedHash(KeyAggTagList, keyBytes.Bytes())
3✔
89
        return h[:]
3✔
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 {
3✔
95
        return bytes.Equal(
3✔
96
                schnorr.SerializePubKey(a),
3✔
97
                schnorr.SerializePubKey(b),
3✔
98
        )
3✔
99
}
3✔
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 {
3✔
107

3✔
108
        var mu btcec.ModNScalar
3✔
109

3✔
110
        // If this is the second key, then this coefficient is just one.
3✔
111
        if secondKeyIdx != -1 && keyBytesEqual(keySet[secondKeyIdx], targetKey) {
6✔
112
                return mu.SetInt(1)
3✔
113
        }
3✔
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
3✔
119
        copy(coefficientBytes[:], keysHash[:])
3✔
120
        copy(coefficientBytes[32:], schnorr.SerializePubKey(targetKey))
3✔
121

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

3✔
124
        mu.SetByteSlice(muHash[:])
3✔
125

3✔
126
        return &mu
3✔
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 {
3✔
132
        if sort {
6✔
133
                keySet = sortKeys(keySet)
3✔
134
        }
3✔
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 {
6✔
139
                if !keyBytesEqual(keySet[i], keySet[0]) {
6✔
140
                        return i
3✔
141
                }
3✔
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.
UNCOV
147
        return -1
×
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 {
3✔
192
        return func(o *keyAggOption) {
6✔
193
                o.keyHash = keyHash
3✔
194
        }
3✔
195
}
196

197
// WithUniqueKeyIndex allows the caller to specify the index of the second
198
// unique key.
199
func WithUniqueKeyIndex(idx int) KeyAggOption {
3✔
200
        return func(o *keyAggOption) {
6✔
201
                i := idx
3✔
202
                o.uniqueKeyIndex = &i
3✔
203
        }
3✔
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.
UNCOV
208
func WithKeyTweaks(tweaks ...KeyTweakDesc) KeyAggOption {
×
UNCOV
209
        return func(o *keyAggOption) {
×
UNCOV
210
                o.tweaks = tweaks
×
UNCOV
211
        }
×
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 {
3✔
223
        return func(o *keyAggOption) {
6✔
224
                var tweak [32]byte
3✔
225
                copy(tweak[:], scriptRoot[:])
3✔
226

3✔
227
                o.tweaks = []KeyTweakDesc{
3✔
228
                        {
3✔
229
                                Tweak:   tweak,
3✔
230
                                IsXOnly: true,
3✔
231
                        },
3✔
232
                }
3✔
233
                o.taprootTweak = true
3✔
234
        }
3✔
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 {
3✔
242
        return func(o *keyAggOption) {
6✔
243
                o.tweaks = []KeyTweakDesc{
3✔
244
                        {
3✔
245
                                IsXOnly: true,
3✔
246
                        },
3✔
247
                }
3✔
248
                o.taprootTweak = true
3✔
249
                o.bip86Tweak = true
3✔
250
        }
3✔
251
}
252

253
// defaultKeyAggOptions returns the set of default arguments for key
254
// aggregation.
255
func defaultKeyAggOptions() *keyAggOption {
3✔
256
        return &keyAggOption{}
3✔
257
}
3✔
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 {
3✔
264
        pJ.ToAffine()
3✔
265
        p := btcec.NewPublicKey(&pJ.X, &pJ.Y)
3✔
266
        keyBytes := p.SerializeCompressed()
3✔
267
        return keyBytes[0] == secp.PubKeyFormatCompressedEven
3✔
268
}
3✔
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) {
3✔
278

3✔
279
        // First we'll compute the new parity factor for this key. If the key has
3✔
280
        // an odd y coordinate (not even), then we'll need to negate it (multiply
3✔
281
        // by -1 mod n, in this case).
3✔
282
        var parityFactor btcec.ModNScalar
3✔
283
        if xOnly && !hasEvenY(keyJ) {
6✔
284
                parityFactor.SetInt(1).Negate()
3✔
285
        } else {
6✔
286
                parityFactor.SetInt(1)
3✔
287
        }
3✔
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)
3✔
292
        overflows := tweakInt.SetBytes(&tweak)
3✔
293
        if overflows == 1 {
3✔
UNCOV
294
                return keyJ, parityAcc, tweakAcc, ErrTweakedKeyOverflows
×
UNCOV
295
        }
×
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
3✔
303
        btcec.ScalarBaseMultNonConst(tweakInt, &tweakedGenerator)
3✔
304

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

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

3✔
312
        // As a sanity check, make sure that we didn't just end up with the
3✔
313
        // point at infinity.
3✔
314
        if keyJ == infinityPoint {
3✔
UNCOV
315
                return keyJ, parityAcc, tweakAcc, ErrTweakedKeyIsInfinity
×
UNCOV
316
        }
×
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)
3✔
321
        tweakAcc.Mul(&parityFactor).Add(tweakInt)
3✔
322

3✔
323
        return keyJ, parityAcc, tweakAcc, nil
3✔
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) {
3✔
347

3✔
348
        // First, parse the set of optional signing options.
3✔
349
        opts := defaultKeyAggOptions()
3✔
350
        for _, option := range keyOpts {
6✔
351
                option(opts)
3✔
352
        }
3✔
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 {
6✔
357
                keys = sortKeys(keys)
3✔
358
        }
3✔
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 {
6✔
363
                opts.keyHash = keyHashFingerprint(keys, sort)
3✔
364
        }
3✔
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 {
6✔
369
                idx := secondUniqueKeyIndex(keys, sort)
3✔
370
                opts.uniqueKeyIndex = &idx
3✔
371
        }
3✔
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
3✔
378
        for _, key := range keys {
6✔
379
                // Port the key over to Jacobian coordinates as we need it in
3✔
380
                // this format for the routines below.
3✔
381
                var keyJ btcec.JacobianPoint
3✔
382
                key.AsJacobian(&keyJ)
3✔
383

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

3✔
392
                // Finally accumulate this into the final key in an incremental
3✔
393
                // fashion.
3✔
394
                btcec.AddNonConst(&finalKeyJ, &tweakedKeyJ, &finalKeyJ)
3✔
395
        }
3✔
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()
3✔
401
        combinedKey := btcec.NewPublicKey(&finalKeyJ.X, &finalKeyJ.Y)
3✔
402

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

3✔
412
                // We only use the actual tweak bytes if we're not committing
3✔
413
                // to a BIP-0086 key only spend output. Otherwise, we just
3✔
414
                // commit to the internal key and an empty byte slice as the
3✔
415
                // root hash.
3✔
416
                tweakBytes := []byte{}
3✔
417
                if !opts.bip86Tweak {
6✔
418
                        tweakBytes = opts.tweaks[0].Tweak[:]
3✔
419
                }
3✔
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(
3✔
426
                        chainhash.TagTapTweak, schnorr.SerializePubKey(key),
3✔
427
                        tweakBytes,
3✔
428
                )
3✔
429
                opts.tweaks[0].Tweak = *tapTweakHash
3✔
430
        }
431

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

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

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

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