Skip to content

Commit 15e7552

Browse files
committed
multi: move GenChallengeNUMS
To avoid a circular package dependency between the address and proof package, we move the GenChallengeNUMS function into the assets package. That function is the only reference the proof package has to the address package, so the move removes that dependency.
1 parent 1589ddc commit 15e7552

File tree

5 files changed

+117
-108
lines changed

5 files changed

+117
-108
lines changed

address/address.go

Lines changed: 0 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import (
1414
"github.com/btcsuite/btcd/chaincfg/chainhash"
1515
"github.com/btcsuite/btcd/txscript"
1616
"github.com/btcsuite/btcd/wire"
17-
"github.com/decred/dcrd/dcrec/secp256k1/v4"
1817
"github.com/lightninglabs/taproot-assets/asset"
1918
"github.com/lightninglabs/taproot-assets/commitment"
2019
"github.com/lightninglabs/taproot-assets/fn"
@@ -537,48 +536,3 @@ func DecodeAddress(addr string, net *ChainParams) (*Tap, error) {
537536

538537
return &a, nil
539538
}
540-
541-
// GenChallengeNUMS generates a variant of the NUMS script key that is modified
542-
// by the provided challenge.
543-
//
544-
// The resulting scriptkey is:
545-
// res := NUMS + challenge*G
546-
func GenChallengeNUMS(challengeBytesOpt fn.Option[[32]byte]) asset.ScriptKey {
547-
var (
548-
nums, g, res btcec.JacobianPoint
549-
challenge secp256k1.ModNScalar
550-
)
551-
552-
if challengeBytesOpt.IsNone() {
553-
return asset.NUMSScriptKey
554-
}
555-
556-
var challengeBytes [32]byte
557-
558-
challengeBytesOpt.WhenSome(func(b [32]byte) {
559-
challengeBytes = b
560-
})
561-
562-
// Convert the NUMS key to a Jacobian point.
563-
asset.NUMSPubKey.AsJacobian(&nums)
564-
565-
// Multiply G by 1 to get G as a Jacobian point.
566-
secp256k1.ScalarBaseMultNonConst(
567-
new(secp256k1.ModNScalar).SetInt(1), &g,
568-
)
569-
570-
// Convert the challenge to a scalar.
571-
challenge.SetByteSlice(challengeBytes[:])
572-
573-
// Calculate res = challenge * G.
574-
secp256k1.ScalarMultNonConst(&challenge, &g, &res)
575-
576-
// Calculate res = nums + res.
577-
secp256k1.AddNonConst(&nums, &res, &res)
578-
579-
res.ToAffine()
580-
581-
resultPubKey := btcec.NewPublicKey(&res.X, &res.Y)
582-
583-
return asset.NewScriptKey(resultPubKey)
584-
}

address/address_test.go

Lines changed: 0 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"github.com/btcsuite/btcd/chaincfg"
1111
"github.com/btcsuite/btcd/txscript"
1212
"github.com/btcsuite/btcd/wire"
13-
"github.com/decred/dcrd/dcrec/secp256k1/v4"
1413
"github.com/lightninglabs/taproot-assets/asset"
1514
"github.com/lightninglabs/taproot-assets/commitment"
1615
"github.com/lightninglabs/taproot-assets/fn"
@@ -502,64 +501,6 @@ func TestBIPTestVectors(t *testing.T) {
502501
}
503502
}
504503

505-
// TestGenChallengeNUMS tests the generation of NUMS challenges.
506-
func TestGenChallengeNUMS(t *testing.T) {
507-
t.Parallel()
508-
509-
gx, gy := secp256k1.Params().Gx, secp256k1.Params().Gy
510-
511-
// addG is a helper function that adds G to the given public key.
512-
addG := func(p *btcec.PublicKey) *btcec.PublicKey {
513-
x, y := secp256k1.S256().Add(p.X(), p.Y(), gx, gy)
514-
var xFieldVal, yFieldVal secp256k1.FieldVal
515-
xFieldVal.SetByteSlice(x.Bytes())
516-
yFieldVal.SetByteSlice(y.Bytes())
517-
return btcec.NewPublicKey(&xFieldVal, &yFieldVal)
518-
}
519-
520-
testCases := []struct {
521-
name string
522-
challenge fn.Option[[32]byte]
523-
expectedKey asset.ScriptKey
524-
}{
525-
{
526-
name: "no challenge",
527-
challenge: fn.None[[32]byte](),
528-
expectedKey: asset.NUMSScriptKey,
529-
},
530-
{
531-
name: "challenge is scalar 1",
532-
challenge: fn.Some([32]byte{
533-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
534-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
535-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
536-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
537-
}),
538-
expectedKey: asset.NewScriptKey(addG(asset.NUMSPubKey)),
539-
},
540-
{
541-
name: "challenge is scalar 2",
542-
challenge: fn.Some([32]byte{
543-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
544-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
545-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
546-
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
547-
}),
548-
expectedKey: asset.NewScriptKey(
549-
addG(addG(asset.NUMSPubKey)),
550-
),
551-
},
552-
}
553-
554-
for _, tc := range testCases {
555-
result := GenChallengeNUMS(tc.challenge)
556-
require.Equal(
557-
t, tc.expectedKey.PubKey.SerializeCompressed(),
558-
result.PubKey.SerializeCompressed(),
559-
)
560-
}
561-
}
562-
563504
// runBIPTestVector runs the tests in a single BIP test vector file.
564505
func runBIPTestVector(t *testing.T, testVectors *TestVectors) {
565506
for _, validCase := range testVectors.ValidTestCases {

asset/witness.go

Lines changed: 50 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
package asset
22

3-
import "github.com/btcsuite/btcd/btcec/v2"
3+
import (
4+
"github.com/btcsuite/btcd/btcec/v2"
5+
"github.com/decred/dcrd/dcrec/secp256k1/v4"
6+
"github.com/lightninglabs/taproot-assets/fn"
7+
)
48

59
// IsSplitCommitWitness returns true if the witness is a split-commitment
610
// witness.
@@ -34,3 +38,48 @@ func IsBurnKey(scriptKey *btcec.PublicKey, witness Witness) bool {
3438

3539
return scriptKey.IsEqual(DeriveBurnKey(prevID))
3640
}
41+
42+
// GenChallengeNUMS generates a variant of the NUMS script key that is modified
43+
// by the provided challenge.
44+
//
45+
// The resulting scriptkey is:
46+
// res := NUMS + challenge*G
47+
func GenChallengeNUMS(challengeBytesOpt fn.Option[[32]byte]) ScriptKey {
48+
var (
49+
nums, g, res btcec.JacobianPoint
50+
challenge secp256k1.ModNScalar
51+
)
52+
53+
if challengeBytesOpt.IsNone() {
54+
return NUMSScriptKey
55+
}
56+
57+
var challengeBytes [32]byte
58+
59+
challengeBytesOpt.WhenSome(func(b [32]byte) {
60+
challengeBytes = b
61+
})
62+
63+
// Convert the NUMS key to a Jacobian point.
64+
NUMSPubKey.AsJacobian(&nums)
65+
66+
// Multiply G by 1 to get G as a Jacobian point.
67+
secp256k1.ScalarBaseMultNonConst(
68+
new(secp256k1.ModNScalar).SetInt(1), &g,
69+
)
70+
71+
// Convert the challenge to a scalar.
72+
challenge.SetByteSlice(challengeBytes[:])
73+
74+
// Calculate res = challenge * G.
75+
secp256k1.ScalarMultNonConst(&challenge, &g, &res)
76+
77+
// Calculate res = nums + res.
78+
secp256k1.AddNonConst(&nums, &res, &res)
79+
80+
res.ToAffine()
81+
82+
resultPubKey := btcec.NewPublicKey(&res.X, &res.Y)
83+
84+
return NewScriptKey(resultPubKey)
85+
}

asset/witness_test.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package asset
2+
3+
import (
4+
"testing"
5+
6+
"github.com/btcsuite/btcd/btcec/v2"
7+
"github.com/decred/dcrd/dcrec/secp256k1/v4"
8+
"github.com/lightninglabs/taproot-assets/fn"
9+
"github.com/stretchr/testify/require"
10+
)
11+
12+
// TestGenChallengeNUMS tests the generation of NUMS challenges.
13+
func TestGenChallengeNUMS(t *testing.T) {
14+
t.Parallel()
15+
16+
gx, gy := secp256k1.Params().Gx, secp256k1.Params().Gy
17+
18+
// addG is a helper function that adds G to the given public key.
19+
addG := func(p *btcec.PublicKey) *btcec.PublicKey {
20+
x, y := secp256k1.S256().Add(p.X(), p.Y(), gx, gy)
21+
var xFieldVal, yFieldVal secp256k1.FieldVal
22+
xFieldVal.SetByteSlice(x.Bytes())
23+
yFieldVal.SetByteSlice(y.Bytes())
24+
return btcec.NewPublicKey(&xFieldVal, &yFieldVal)
25+
}
26+
27+
testCases := []struct {
28+
name string
29+
challenge fn.Option[[32]byte]
30+
expectedKey ScriptKey
31+
}{
32+
{
33+
name: "no challenge",
34+
challenge: fn.None[[32]byte](),
35+
expectedKey: NUMSScriptKey,
36+
},
37+
{
38+
name: "challenge is scalar 1",
39+
challenge: fn.Some([32]byte{
40+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
41+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
42+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
43+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
44+
}),
45+
expectedKey: NewScriptKey(addG(NUMSPubKey)),
46+
},
47+
{
48+
name: "challenge is scalar 2",
49+
challenge: fn.Some([32]byte{
50+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
51+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
52+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
53+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
54+
}),
55+
expectedKey: NewScriptKey(addG(addG(NUMSPubKey))),
56+
},
57+
}
58+
59+
for _, tc := range testCases {
60+
result := GenChallengeNUMS(tc.challenge)
61+
require.Equal(
62+
t, tc.expectedKey.PubKey.SerializeCompressed(),
63+
result.PubKey.SerializeCompressed(),
64+
)
65+
}
66+
}

proof/verifier.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@ import (
1313
"github.com/btcsuite/btcd/txscript"
1414
"github.com/btcsuite/btcd/wire"
1515
"github.com/davecgh/go-spew/spew"
16-
"github.com/lightninglabs/taproot-assets/address"
1716
"github.com/lightninglabs/taproot-assets/asset"
1817
"github.com/lightninglabs/taproot-assets/commitment"
1918
"github.com/lightninglabs/taproot-assets/fn"
@@ -385,7 +384,7 @@ func CreateOwnershipProofAsset(ownedAsset *asset.Asset,
385384
// This is handled by CopySpendTemplate.
386385
outputAsset := ownedAsset.CopySpendTemplate()
387386

388-
outputAsset.ScriptKey = address.GenChallengeNUMS(challengeBytes)
387+
outputAsset.ScriptKey = asset.GenChallengeNUMS(challengeBytes)
389388
outputAsset.PrevWitnesses = []asset.Witness{{
390389
PrevID: &prevId,
391390
}}

0 commit comments

Comments
 (0)