Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

misc: group key testing #717

Merged
merged 5 commits into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions asset/asset.go
Original file line number Diff line number Diff line change
Expand Up @@ -513,7 +513,7 @@ type GroupKeyReveal struct {
func (g *GroupKeyReveal) GroupPubKey(assetID ID) (*btcec.PublicKey, error) {
rawKey, err := g.RawKey.ToPubKey()
if err != nil {
return nil, err
return nil, fmt.Errorf("group reveal raw key invalid: %w", err)
}

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

if newAsset.GroupKey != nil {
return nil, fmt.Errorf("asset already has group key")
}

if initialGen.Type != newAsset.Type {
return nil, fmt.Errorf("asset group type mismatch")
}
Expand Down Expand Up @@ -1208,9 +1212,10 @@ func (a *Asset) Copy() *Asset {

if a.GroupKey != nil {
assetCopy.GroupKey = &GroupKey{
RawKey: a.GroupKey.RawKey,
GroupPubKey: a.GroupKey.GroupPubKey,
Witness: a.GroupKey.Witness,
RawKey: a.GroupKey.RawKey,
GroupPubKey: a.GroupKey.GroupPubKey,
TapscriptRoot: a.GroupKey.TapscriptRoot,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Witness: a.GroupKey.Witness,
}
}

Expand Down
172 changes: 171 additions & 1 deletion asset/asset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,102 @@ func TestGroupKeyIsEqual(t *testing.T) {
}
}

// TestGenesisAssetClassification tests that the multiple forms of genesis asset
// are recognized correctly.
func TestGenesisAssetClassification(t *testing.T) {
t.Parallel()

baseGen := RandGenesis(t, Normal)
baseScriptKey := RandScriptKey(t)
baseAsset := RandAssetWithValues(t, baseGen, nil, baseScriptKey)
assetValidGroup := RandAsset(t, Collectible)
assetNeedsWitness := baseAsset.Copy()
assetNeedsWitness.GroupKey = &GroupKey{
GroupPubKey: *test.RandPubKey(t),
}
nonGenAsset := baseAsset.Copy()
nonGenAsset.PrevWitnesses = []Witness{{
PrevID: &PrevID{
OutPoint: wire.OutPoint{
Hash: hashBytes1,
Index: 1,
},
ID: hashBytes1,
ScriptKey: ToSerialized(pubKey),
},
TxWitness: sigWitness,
SplitCommitment: nil,
}}
groupMemberNonGen := nonGenAsset.Copy()
groupMemberNonGen.GroupKey = &GroupKey{
GroupPubKey: *test.RandPubKey(t),
}
splitAsset := nonGenAsset.Copy()
splitAsset.PrevWitnesses[0].TxWitness = nil
splitAsset.PrevWitnesses[0].SplitCommitment = &SplitCommitment{}

tests := []struct {
name string
genAsset *Asset
isGenesis, needsWitness, hasWitness bool
}{
{
name: "group anchor with witness",
genAsset: assetValidGroup,
isGenesis: false,
needsWitness: false,
hasWitness: true,
},
{
name: "ungrouped genesis asset",
genAsset: baseAsset,
isGenesis: true,
needsWitness: false,
hasWitness: false,
},
{
name: "group anchor without witness",
genAsset: assetNeedsWitness,
isGenesis: true,
needsWitness: true,
hasWitness: false,
},
{
name: "non-genesis asset",
genAsset: nonGenAsset,
isGenesis: false,
needsWitness: false,
hasWitness: false,
},
{
name: "non-genesis grouped asset",
genAsset: groupMemberNonGen,
isGenesis: false,
needsWitness: false,
hasWitness: false,
},
{
name: "split asset",
genAsset: splitAsset,
isGenesis: false,
needsWitness: false,
hasWitness: false,
},
}

for _, testCase := range tests {
testCase := testCase
a := testCase.genAsset

hasGenWitness := a.HasGenesisWitness()
require.Equal(t, testCase.isGenesis, hasGenWitness)
needsGroupWitness := a.NeedsGenesisWitnessForGroup()
require.Equal(t, testCase.needsWitness, needsGroupWitness)
hasGroupWitness := a.HasGenesisWitnessForGroup()
require.Equal(t, testCase.hasWitness, hasGroupWitness)
}
}

// TestValidateAssetName tests that asset names are validated correctly.
func TestValidateAssetName(t *testing.T) {
t.Parallel()
Expand Down Expand Up @@ -510,11 +606,12 @@ func TestAssetGroupKey(t *testing.T) {
t.Parallel()

privKey, err := btcec.NewPrivateKey()
groupPub := privKey.PubKey()
require.NoError(t, err)
privKeyCopy := btcec.PrivKeyFromScalar(&privKey.Key)
genSigner := NewMockGenesisSigner(privKeyCopy)
genBuilder := MockGroupTxBuilder{}
fakeKeyDesc := test.PubToKeyDesc(privKeyCopy.PubKey())
fakeKeyDesc := test.PubToKeyDesc(groupPub)
fakeScriptKey := NewScriptKeyBip86(fakeKeyDesc)

g := Genesis{
Expand Down Expand Up @@ -544,6 +641,79 @@ func TestAssetGroupKey(t *testing.T) {
t, schnorr.SerializePubKey(tweakedKey.PubKey()),
schnorr.SerializePubKey(&keyGroup.GroupPubKey),
)

// Group key tweaking should fail when given invalid tweaks.
badTweak := test.RandBytes(33)
_, err = GroupPubKey(groupPub, badTweak, badTweak)
require.Error(t, err)

_, err = GroupPubKey(groupPub, groupTweak[:], badTweak)
require.Error(t, err)
}

// TestDeriveGroupKey tests that group key derivation fails for assets that are
// not eligible to be group anchors.
func TestDeriveGroupKey(t *testing.T) {
t.Parallel()

groupPriv := test.RandPrivKey(t)
groupPub := groupPriv.PubKey()
groupKeyDesc := test.PubToKeyDesc(groupPub)
genSigner := NewMockGenesisSigner(groupPriv)
genBuilder := MockGroupTxBuilder{}

baseGen := RandGenesis(t, Normal)
collectGen := RandGenesis(t, Collectible)
baseScriptKey := RandScriptKey(t)
protoAsset := RandAssetWithValues(t, baseGen, nil, baseScriptKey)
nonGenProtoAsset := protoAsset.Copy()
nonGenProtoAsset.PrevWitnesses = []Witness{{
PrevID: &PrevID{
OutPoint: wire.OutPoint{
Hash: hashBytes1,
Index: 1,
},
ID: hashBytes1,
ScriptKey: ToSerialized(pubKey),
},
TxWitness: sigWitness,
SplitCommitment: nil,
}}
groupedProtoAsset := protoAsset.Copy()
groupedProtoAsset.GroupKey = &GroupKey{
GroupPubKey: *groupPub,
}

// A prototype asset is required for building the genesis virtual TX.
_, err := DeriveGroupKey(
genSigner, &genBuilder, groupKeyDesc, baseGen, nil,
)
require.Error(t, err)

// The prototype asset must have a genesis witness.
_, err = DeriveGroupKey(
genSigner, &genBuilder, groupKeyDesc, baseGen, nonGenProtoAsset,
)
require.Error(t, err)

// The prototype asset must not have a group key set.
_, err = DeriveGroupKey(
genSigner, &genBuilder, groupKeyDesc, baseGen, groupedProtoAsset,
)
require.Error(t, err)

// The anchor genesis used for signing must have the same asset type
// as the prototype asset being signed.
_, err = DeriveGroupKey(
genSigner, &genBuilder, groupKeyDesc, collectGen, protoAsset,
)
require.Error(t, err)

groupKey, err := DeriveGroupKey(
genSigner, &genBuilder, groupKeyDesc, baseGen, protoAsset,
)
require.NoError(t, err)
require.NotNil(t, groupKey)
}

// TestAssetWitness tests that the asset group witness can be serialized and
Expand Down
12 changes: 11 additions & 1 deletion asset/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,7 @@ func (m *MockGroupTxBuilder) BuildGenesisTx(newAsset *Asset) (*wire.MsgTx,
// First, we check that the passed asset is a genesis grouped asset
// that has no group witness.
if !newAsset.NeedsGenesisWitnessForGroup() {
return nil, nil, fmt.Errorf("asset is not a genesis grouped" +
return nil, nil, fmt.Errorf("asset is not a genesis grouped " +
"asset")
}

Expand Down Expand Up @@ -323,6 +323,16 @@ func RandID(t testing.TB) ID {
return a
}

// RandAssetType creates a random asset type.
func RandAssetType(t testing.TB) Type {
isCollectible := test.RandBool()
if isCollectible {
return Collectible
}

return Normal
}

// NewAssetNoErr creates an asset and fails the test if asset creation fails.
func NewAssetNoErr(t testing.TB, gen Genesis, amt, locktime, relocktime uint64,
scriptKey ScriptKey, groupKey *GroupKey, opts ...NewAssetOpt) *Asset {
Expand Down
Loading
Loading