@@ -3,13 +3,17 @@ package tapchannel
33import (
44 "bytes"
55 "crypto/rand"
6+ "encoding/binary"
67 "encoding/hex"
78 "fmt"
9+ "math"
810 "testing"
911
1012 "github.com/btcsuite/btcd/btcec/v2"
1113 "github.com/btcsuite/btcd/txscript"
14+ "github.com/decred/dcrd/dcrec/secp256k1/v4"
1215 "github.com/lightninglabs/taproot-assets/asset"
16+ "github.com/lightninglabs/taproot-assets/internal/test"
1317 cmsg "github.com/lightninglabs/taproot-assets/tapchannelmsg"
1418 "github.com/lightningnetwork/lnd/input"
1519 "github.com/lightningnetwork/lnd/lnwire"
@@ -163,3 +167,230 @@ func makeCommitSig(t *testing.T, numAssetIDs, numHTLCs int) *lnwire.CommitSig {
163167
164168 return msg
165169}
170+
171+ // TestHtlcIndexAsScriptKeyTweak tests the HtlcIndexAsScriptKeyTweak function.
172+ func TestHtlcIndexAsScriptKeyTweak (t * testing.T ) {
173+ var (
174+ buf = make ([]byte , 8 )
175+ maxUint64MinusOne = new (secp256k1.ModNScalar )
176+ maxUint64 = new (secp256k1.ModNScalar )
177+ )
178+ binary .BigEndian .PutUint64 (buf , math .MaxUint64 - 1 )
179+ _ = maxUint64MinusOne .SetByteSlice (buf )
180+
181+ binary .BigEndian .PutUint64 (buf , math .MaxUint64 )
182+ _ = maxUint64 .SetByteSlice (buf )
183+
184+ testCases := []struct {
185+ name string
186+ index uint64
187+ result * secp256k1.ModNScalar
188+ }{
189+ {
190+ name : "index 0" ,
191+ index : 0 ,
192+ result : new (secp256k1.ModNScalar ).SetInt (1 ),
193+ },
194+ {
195+ name : "index math.MaxUint32-1" ,
196+ index : math .MaxUint32 - 1 ,
197+ result : new (secp256k1.ModNScalar ).SetInt (
198+ math .MaxUint32 ,
199+ ),
200+ },
201+ {
202+ name : "index math.MaxUint64-2" ,
203+ index : math .MaxUint64 - 2 ,
204+ result : maxUint64MinusOne ,
205+ },
206+ {
207+ name : "index math.MaxUint64-1" ,
208+ index : math .MaxUint64 - 1 ,
209+ result : maxUint64 ,
210+ },
211+ {
212+ name : "index math.MaxUint64, wraps around to 1" ,
213+ index : math .MaxUint64 ,
214+ result : new (secp256k1.ModNScalar ).SetInt (1 ),
215+ },
216+ }
217+
218+ for _ , tc := range testCases {
219+ t .Run (tc .name , func (t * testing.T ) {
220+ tweak := HtlcIndexAsScriptKeyTweak (tc .index )
221+ require .Equal (t , tc .result , tweak )
222+ })
223+ }
224+ }
225+
226+ // TestTweakPubKeyWithIndex tests the TweakPubKeyWithIndex function.
227+ func TestTweakPubKeyWithIndex (t * testing.T ) {
228+ randNum := test .RandInt [uint32 ]()
229+
230+ makePubKey := func (tweak uint64 ) * btcec.PublicKey {
231+ var (
232+ buf = make ([]byte , 8 )
233+ scalar = new (secp256k1.ModNScalar )
234+ )
235+ binary .BigEndian .PutUint64 (buf , uint64 (randNum )+ tweak )
236+ _ = scalar .SetByteSlice (buf )
237+ return secp256k1 .NewPrivateKey (scalar ).PubKey ()
238+ }
239+ startKey := makePubKey (0 )
240+
241+ testCases := []struct {
242+ name string
243+ pubKey * btcec.PublicKey
244+ index uint64
245+ result * btcec.PublicKey
246+ }{
247+ {
248+ name : "index 0" ,
249+ pubKey : startKey ,
250+ index : 0 ,
251+ result : makePubKey (1 ),
252+ },
253+ {
254+ name : "index 1" ,
255+ pubKey : startKey ,
256+ index : 1 ,
257+ result : makePubKey (2 ),
258+ },
259+ {
260+ name : "index 99" ,
261+ pubKey : startKey ,
262+ index : 99 ,
263+ result : makePubKey (100 ),
264+ },
265+ {
266+ name : "index math.MaxUint32-1" ,
267+ pubKey : startKey ,
268+ index : math .MaxUint32 - 1 ,
269+ result : makePubKey (math .MaxUint32 ),
270+ },
271+ }
272+
273+ for _ , tc := range testCases {
274+ t .Run (tc .name , func (t * testing.T ) {
275+ tweakedKey := TweakPubKeyWithIndex (tc .pubKey , tc .index )
276+ require .Equal (
277+ t , tc .result .SerializeCompressed (),
278+ tweakedKey .SerializeCompressed (),
279+ )
280+ })
281+ }
282+ }
283+
284+ // TestTweakHtlcTree tests the TweakHtlcTree function.
285+ func TestTweakHtlcTree (t * testing.T ) {
286+ randTree := txscript .AssembleTaprootScriptTree (
287+ test .RandTapLeaf (nil ), test .RandTapLeaf (nil ),
288+ test .RandTapLeaf (nil ),
289+ )
290+ randRoot := randTree .RootNode .TapHash ()
291+ randNum := test .RandInt [uint32 ]()
292+
293+ makePubKey := func (tweak uint64 ) * btcec.PublicKey {
294+ var (
295+ buf = make ([]byte , 8 )
296+ scalar = new (secp256k1.ModNScalar )
297+ )
298+ binary .BigEndian .PutUint64 (buf , uint64 (randNum )+ tweak )
299+ _ = scalar .SetByteSlice (buf )
300+ return secp256k1 .NewPrivateKey (scalar ).PubKey ()
301+ }
302+ makeTaprootKey := func (tweak uint64 ) * btcec.PublicKey {
303+ return txscript .ComputeTaprootOutputKey (
304+ makePubKey (tweak ), randRoot [:],
305+ )
306+ }
307+ startKey := makePubKey (0 )
308+ startTaprootKey := makeTaprootKey (0 )
309+
310+ testCases := []struct {
311+ name string
312+ tree input.ScriptTree
313+ index uint64
314+ result input.ScriptTree
315+ }{
316+ {
317+ name : "index 0" ,
318+ tree : input.ScriptTree {
319+ InternalKey : startKey ,
320+ TaprootKey : startTaprootKey ,
321+ TapscriptTree : randTree ,
322+ TapscriptRoot : randRoot [:],
323+ },
324+ index : 0 ,
325+ result : input.ScriptTree {
326+ InternalKey : makePubKey (1 ),
327+ TaprootKey : makeTaprootKey (1 ),
328+ TapscriptTree : randTree ,
329+ TapscriptRoot : randRoot [:],
330+ },
331+ },
332+ {
333+ name : "index 1" ,
334+ tree : input.ScriptTree {
335+ InternalKey : startKey ,
336+ TaprootKey : startTaprootKey ,
337+ TapscriptTree : randTree ,
338+ TapscriptRoot : randRoot [:],
339+ },
340+ index : 1 ,
341+ result : input.ScriptTree {
342+ InternalKey : makePubKey (2 ),
343+ TaprootKey : makeTaprootKey (2 ),
344+ TapscriptTree : randTree ,
345+ TapscriptRoot : randRoot [:],
346+ },
347+ },
348+ {
349+ name : "index 99" ,
350+ tree : input.ScriptTree {
351+ InternalKey : startKey ,
352+ TaprootKey : startTaprootKey ,
353+ TapscriptTree : randTree ,
354+ TapscriptRoot : randRoot [:],
355+ },
356+ index : 99 ,
357+ result : input.ScriptTree {
358+ InternalKey : makePubKey (100 ),
359+ TaprootKey : makeTaprootKey (100 ),
360+ TapscriptTree : randTree ,
361+ TapscriptRoot : randRoot [:],
362+ },
363+ },
364+ {
365+ name : "index math.MaxUint32-1" ,
366+ tree : input.ScriptTree {
367+ InternalKey : startKey ,
368+ TaprootKey : startTaprootKey ,
369+ TapscriptTree : randTree ,
370+ TapscriptRoot : randRoot [:],
371+ },
372+ index : math .MaxUint32 - 1 ,
373+ result : input.ScriptTree {
374+ InternalKey : makePubKey (math .MaxUint32 ),
375+ TaprootKey : makeTaprootKey (math .MaxUint32 ),
376+ TapscriptTree : randTree ,
377+ TapscriptRoot : randRoot [:],
378+ },
379+ },
380+ }
381+
382+ for _ , tc := range testCases {
383+ t .Run (tc .name , func (t * testing.T ) {
384+ tweakedTree := TweakHtlcTree (tc .tree , tc .index )
385+ require .Equal (
386+ t , tc .result .InternalKey .SerializeCompressed (),
387+ tweakedTree .InternalKey .SerializeCompressed (),
388+ )
389+ require .Equal (
390+ t , tc .result .TaprootKey .SerializeCompressed (),
391+ tweakedTree .TaprootKey .SerializeCompressed (),
392+ )
393+ require .Equal (t , tc .result , tweakedTree )
394+ })
395+ }
396+ }
0 commit comments