Skip to content

Commit 6a18d30

Browse files
authored
Merge pull request #717 from lightninglabs/group_key_testing
misc: group key testing
2 parents a21efde + 8f77090 commit 6a18d30

File tree

13 files changed

+490
-127
lines changed

13 files changed

+490
-127
lines changed

asset/asset.go

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -513,7 +513,7 @@ type GroupKeyReveal struct {
513513
func (g *GroupKeyReveal) GroupPubKey(assetID ID) (*btcec.PublicKey, error) {
514514
rawKey, err := g.RawKey.ToPubKey()
515515
if err != nil {
516-
return nil, err
516+
return nil, fmt.Errorf("group reveal raw key invalid: %w", err)
517517
}
518518

519519
return GroupPubKey(rawKey, assetID[:], g.TapscriptRoot)
@@ -814,6 +814,10 @@ func DeriveGroupKey(genSigner GenesisSigner, genBuilder GenesisTxBuilder,
814814
return nil, fmt.Errorf("asset is not a genesis asset")
815815
}
816816

817+
if newAsset.GroupKey != nil {
818+
return nil, fmt.Errorf("asset already has group key")
819+
}
820+
817821
if initialGen.Type != newAsset.Type {
818822
return nil, fmt.Errorf("asset group type mismatch")
819823
}
@@ -1208,9 +1212,10 @@ func (a *Asset) Copy() *Asset {
12081212

12091213
if a.GroupKey != nil {
12101214
assetCopy.GroupKey = &GroupKey{
1211-
RawKey: a.GroupKey.RawKey,
1212-
GroupPubKey: a.GroupKey.GroupPubKey,
1213-
Witness: a.GroupKey.Witness,
1215+
RawKey: a.GroupKey.RawKey,
1216+
GroupPubKey: a.GroupKey.GroupPubKey,
1217+
TapscriptRoot: a.GroupKey.TapscriptRoot,
1218+
Witness: a.GroupKey.Witness,
12141219
}
12151220
}
12161221

asset/asset_test.go

Lines changed: 171 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,102 @@ func TestGroupKeyIsEqual(t *testing.T) {
231231
}
232232
}
233233

234+
// TestGenesisAssetClassification tests that the multiple forms of genesis asset
235+
// are recognized correctly.
236+
func TestGenesisAssetClassification(t *testing.T) {
237+
t.Parallel()
238+
239+
baseGen := RandGenesis(t, Normal)
240+
baseScriptKey := RandScriptKey(t)
241+
baseAsset := RandAssetWithValues(t, baseGen, nil, baseScriptKey)
242+
assetValidGroup := RandAsset(t, Collectible)
243+
assetNeedsWitness := baseAsset.Copy()
244+
assetNeedsWitness.GroupKey = &GroupKey{
245+
GroupPubKey: *test.RandPubKey(t),
246+
}
247+
nonGenAsset := baseAsset.Copy()
248+
nonGenAsset.PrevWitnesses = []Witness{{
249+
PrevID: &PrevID{
250+
OutPoint: wire.OutPoint{
251+
Hash: hashBytes1,
252+
Index: 1,
253+
},
254+
ID: hashBytes1,
255+
ScriptKey: ToSerialized(pubKey),
256+
},
257+
TxWitness: sigWitness,
258+
SplitCommitment: nil,
259+
}}
260+
groupMemberNonGen := nonGenAsset.Copy()
261+
groupMemberNonGen.GroupKey = &GroupKey{
262+
GroupPubKey: *test.RandPubKey(t),
263+
}
264+
splitAsset := nonGenAsset.Copy()
265+
splitAsset.PrevWitnesses[0].TxWitness = nil
266+
splitAsset.PrevWitnesses[0].SplitCommitment = &SplitCommitment{}
267+
268+
tests := []struct {
269+
name string
270+
genAsset *Asset
271+
isGenesis, needsWitness, hasWitness bool
272+
}{
273+
{
274+
name: "group anchor with witness",
275+
genAsset: assetValidGroup,
276+
isGenesis: false,
277+
needsWitness: false,
278+
hasWitness: true,
279+
},
280+
{
281+
name: "ungrouped genesis asset",
282+
genAsset: baseAsset,
283+
isGenesis: true,
284+
needsWitness: false,
285+
hasWitness: false,
286+
},
287+
{
288+
name: "group anchor without witness",
289+
genAsset: assetNeedsWitness,
290+
isGenesis: true,
291+
needsWitness: true,
292+
hasWitness: false,
293+
},
294+
{
295+
name: "non-genesis asset",
296+
genAsset: nonGenAsset,
297+
isGenesis: false,
298+
needsWitness: false,
299+
hasWitness: false,
300+
},
301+
{
302+
name: "non-genesis grouped asset",
303+
genAsset: groupMemberNonGen,
304+
isGenesis: false,
305+
needsWitness: false,
306+
hasWitness: false,
307+
},
308+
{
309+
name: "split asset",
310+
genAsset: splitAsset,
311+
isGenesis: false,
312+
needsWitness: false,
313+
hasWitness: false,
314+
},
315+
}
316+
317+
for _, testCase := range tests {
318+
testCase := testCase
319+
a := testCase.genAsset
320+
321+
hasGenWitness := a.HasGenesisWitness()
322+
require.Equal(t, testCase.isGenesis, hasGenWitness)
323+
needsGroupWitness := a.NeedsGenesisWitnessForGroup()
324+
require.Equal(t, testCase.needsWitness, needsGroupWitness)
325+
hasGroupWitness := a.HasGenesisWitnessForGroup()
326+
require.Equal(t, testCase.hasWitness, hasGroupWitness)
327+
}
328+
}
329+
234330
// TestValidateAssetName tests that asset names are validated correctly.
235331
func TestValidateAssetName(t *testing.T) {
236332
t.Parallel()
@@ -510,11 +606,12 @@ func TestAssetGroupKey(t *testing.T) {
510606
t.Parallel()
511607

512608
privKey, err := btcec.NewPrivateKey()
609+
groupPub := privKey.PubKey()
513610
require.NoError(t, err)
514611
privKeyCopy := btcec.PrivKeyFromScalar(&privKey.Key)
515612
genSigner := NewMockGenesisSigner(privKeyCopy)
516613
genBuilder := MockGroupTxBuilder{}
517-
fakeKeyDesc := test.PubToKeyDesc(privKeyCopy.PubKey())
614+
fakeKeyDesc := test.PubToKeyDesc(groupPub)
518615
fakeScriptKey := NewScriptKeyBip86(fakeKeyDesc)
519616

520617
g := Genesis{
@@ -544,6 +641,79 @@ func TestAssetGroupKey(t *testing.T) {
544641
t, schnorr.SerializePubKey(tweakedKey.PubKey()),
545642
schnorr.SerializePubKey(&keyGroup.GroupPubKey),
546643
)
644+
645+
// Group key tweaking should fail when given invalid tweaks.
646+
badTweak := test.RandBytes(33)
647+
_, err = GroupPubKey(groupPub, badTweak, badTweak)
648+
require.Error(t, err)
649+
650+
_, err = GroupPubKey(groupPub, groupTweak[:], badTweak)
651+
require.Error(t, err)
652+
}
653+
654+
// TestDeriveGroupKey tests that group key derivation fails for assets that are
655+
// not eligible to be group anchors.
656+
func TestDeriveGroupKey(t *testing.T) {
657+
t.Parallel()
658+
659+
groupPriv := test.RandPrivKey(t)
660+
groupPub := groupPriv.PubKey()
661+
groupKeyDesc := test.PubToKeyDesc(groupPub)
662+
genSigner := NewMockGenesisSigner(groupPriv)
663+
genBuilder := MockGroupTxBuilder{}
664+
665+
baseGen := RandGenesis(t, Normal)
666+
collectGen := RandGenesis(t, Collectible)
667+
baseScriptKey := RandScriptKey(t)
668+
protoAsset := RandAssetWithValues(t, baseGen, nil, baseScriptKey)
669+
nonGenProtoAsset := protoAsset.Copy()
670+
nonGenProtoAsset.PrevWitnesses = []Witness{{
671+
PrevID: &PrevID{
672+
OutPoint: wire.OutPoint{
673+
Hash: hashBytes1,
674+
Index: 1,
675+
},
676+
ID: hashBytes1,
677+
ScriptKey: ToSerialized(pubKey),
678+
},
679+
TxWitness: sigWitness,
680+
SplitCommitment: nil,
681+
}}
682+
groupedProtoAsset := protoAsset.Copy()
683+
groupedProtoAsset.GroupKey = &GroupKey{
684+
GroupPubKey: *groupPub,
685+
}
686+
687+
// A prototype asset is required for building the genesis virtual TX.
688+
_, err := DeriveGroupKey(
689+
genSigner, &genBuilder, groupKeyDesc, baseGen, nil,
690+
)
691+
require.Error(t, err)
692+
693+
// The prototype asset must have a genesis witness.
694+
_, err = DeriveGroupKey(
695+
genSigner, &genBuilder, groupKeyDesc, baseGen, nonGenProtoAsset,
696+
)
697+
require.Error(t, err)
698+
699+
// The prototype asset must not have a group key set.
700+
_, err = DeriveGroupKey(
701+
genSigner, &genBuilder, groupKeyDesc, baseGen, groupedProtoAsset,
702+
)
703+
require.Error(t, err)
704+
705+
// The anchor genesis used for signing must have the same asset type
706+
// as the prototype asset being signed.
707+
_, err = DeriveGroupKey(
708+
genSigner, &genBuilder, groupKeyDesc, collectGen, protoAsset,
709+
)
710+
require.Error(t, err)
711+
712+
groupKey, err := DeriveGroupKey(
713+
genSigner, &genBuilder, groupKeyDesc, baseGen, protoAsset,
714+
)
715+
require.NoError(t, err)
716+
require.NotNil(t, groupKey)
547717
}
548718

549719
// TestAssetWitness tests that the asset group witness can be serialized and

asset/mock.go

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -175,7 +175,7 @@ func (m *MockGroupTxBuilder) BuildGenesisTx(newAsset *Asset) (*wire.MsgTx,
175175
// First, we check that the passed asset is a genesis grouped asset
176176
// that has no group witness.
177177
if !newAsset.NeedsGenesisWitnessForGroup() {
178-
return nil, nil, fmt.Errorf("asset is not a genesis grouped" +
178+
return nil, nil, fmt.Errorf("asset is not a genesis grouped " +
179179
"asset")
180180
}
181181

@@ -323,6 +323,16 @@ func RandID(t testing.TB) ID {
323323
return a
324324
}
325325

326+
// RandAssetType creates a random asset type.
327+
func RandAssetType(t testing.TB) Type {
328+
isCollectible := test.RandBool()
329+
if isCollectible {
330+
return Collectible
331+
}
332+
333+
return Normal
334+
}
335+
326336
// NewAssetNoErr creates an asset and fails the test if asset creation fails.
327337
func NewAssetNoErr(t testing.TB, gen Genesis, amt, locktime, relocktime uint64,
328338
scriptKey ScriptKey, groupKey *GroupKey, opts ...NewAssetOpt) *Asset {

0 commit comments

Comments
 (0)