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

Refactor GroupKey unit tests. #1350

Merged
merged 7 commits into from
Feb 7, 2025
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
286 changes: 0 additions & 286 deletions asset/asset_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,11 @@ import (
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/lightninglabs/taproot-assets/fn"
"github.com/lightninglabs/taproot-assets/internal/test"
"github.com/lightninglabs/taproot-assets/mssmt"
"github.com/lightningnetwork/lnd/input"
"github.com/lightningnetwork/lnd/keychain"
"github.com/lightningnetwork/lnd/tlv"
"github.com/stretchr/testify/require"
"pgregory.net/rapid"
Expand Down Expand Up @@ -111,134 +108,6 @@ var (
}
)

// TestGroupKeyIsEqual tests that GroupKey.IsEqual is correct.
func TestGroupKeyIsEqual(t *testing.T) {
t.Parallel()

testKey := &GroupKey{
RawKey: keychain.KeyDescriptor{
// Fill in some non-defaults.
KeyLocator: keychain.KeyLocator{
Family: keychain.KeyFamilyMultiSig,
Index: 1,
},
PubKey: pubKey,
},
GroupPubKey: *pubKey,
Witness: sigWitness,
}

pubKeyCopy := *pubKey

tests := []struct {
a, b *GroupKey
equal bool
}{
{
a: nil,
b: nil,
equal: true,
},
{
a: &GroupKey{},
b: &GroupKey{},
equal: true,
},
{
a: nil,
b: &GroupKey{},
equal: false,
},
{
a: testKey,
b: &GroupKey{
GroupPubKey: *pubKey,
},
equal: false,
},
{
a: testKey,
b: &GroupKey{
GroupPubKey: testKey.GroupPubKey,
Witness: testKey.Witness,
},
equal: false,
},
{
a: testKey,
b: &GroupKey{
RawKey: keychain.KeyDescriptor{
KeyLocator: testKey.RawKey.KeyLocator,
PubKey: nil,
},

GroupPubKey: testKey.GroupPubKey,
Witness: testKey.Witness,
},
equal: false,
},
{
a: testKey,
b: &GroupKey{
RawKey: keychain.KeyDescriptor{
PubKey: &pubKeyCopy,
},

GroupPubKey: testKey.GroupPubKey,
Witness: testKey.Witness,
},
equal: false,
},
{
a: testKey,
b: &GroupKey{
RawKey: keychain.KeyDescriptor{
KeyLocator: testKey.RawKey.KeyLocator,
PubKey: &pubKeyCopy,
},

GroupPubKey: testKey.GroupPubKey,
Witness: testKey.Witness,
},
equal: true,
},
{
a: &GroupKey{
GroupPubKey: testKey.GroupPubKey,
Witness: testKey.Witness,
},
b: &GroupKey{
GroupPubKey: testKey.GroupPubKey,
Witness: testKey.Witness,
},
equal: true,
},
{
a: &GroupKey{
RawKey: keychain.KeyDescriptor{
KeyLocator: testKey.RawKey.KeyLocator,
},
GroupPubKey: testKey.GroupPubKey,
Witness: testKey.Witness,
},
b: &GroupKey{
RawKey: keychain.KeyDescriptor{
KeyLocator: testKey.RawKey.KeyLocator,
},
GroupPubKey: testKey.GroupPubKey,
Witness: testKey.Witness,
},
equal: true,
},
}

for _, testCase := range tests {
testCase := testCase
require.Equal(t, testCase.equal, testCase.a.IsEqual(testCase.b))
require.Equal(t, testCase.equal, testCase.b.IsEqual(testCase.a))
}
}

// TestGenesisAssetClassification tests that the multiple forms of genesis asset
// are recognized correctly.
func TestGenesisAssetClassification(t *testing.T) {
Expand Down Expand Up @@ -858,161 +727,6 @@ func TestAssetID(t *testing.T) {
require.NotEqual(t, id[:], differentID[:])
}

// TestAssetGroupKey tests that the asset key group is derived correctly.
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(groupPub)
fakeScriptKey := NewScriptKeyBip86(fakeKeyDesc)

g := Genesis{
FirstPrevOut: wire.OutPoint{
Hash: hashBytes1,
Index: 99,
},
Tag: "normal asset 1",
MetaHash: [MetaHashLen]byte{1, 2, 3},
OutputIndex: 21,
Type: Collectible,
}
groupTweak := g.ID()

internalKey := input.TweakPrivKey(privKeyCopy, groupTweak[:])
tweakedKey := txscript.TweakTaprootPrivKey(*internalKey, nil)

// TweakTaprootPrivKey modifies the private key that is passed in! We
// need to provide a copy to arrive at the same result.
protoAsset := NewAssetNoErr(t, g, 1, 0, 0, fakeScriptKey, nil)
groupReq := NewGroupKeyRequestNoErr(
t, fakeKeyDesc, fn.None[ExternalKey](), g, protoAsset, nil,
fn.None[chainhash.Hash](),
)
genTx, err := groupReq.BuildGroupVirtualTx(&genBuilder)
require.NoError(t, err)

keyGroup, err := DeriveGroupKey(genSigner, *genTx, *groupReq, nil)
require.NoError(t, err)

require.Equal(
t, schnorr.SerializePubKey(tweakedKey.PubKey()),
schnorr.SerializePubKey(&keyGroup.GroupPubKey),
)

// We should also be able to reproduce the correct tweak with a non-nil
// tapscript root.
tapTweak := test.RandBytes(32)
tweakedKey = txscript.TweakTaprootPrivKey(*internalKey, tapTweak)

groupReq = NewGroupKeyRequestNoErr(
t, test.PubToKeyDesc(privKey.PubKey()), fn.None[ExternalKey](),
g, protoAsset, tapTweak, fn.None[chainhash.Hash](),
)
genTx, err = groupReq.BuildGroupVirtualTx(&genBuilder)
require.NoError(t, err)

keyGroup, err = DeriveGroupKey(genSigner, *genTx, *groupReq, nil)
require.NoError(t, err)

require.Equal(
t, schnorr.SerializePubKey(tweakedKey.PubKey()),
schnorr.SerializePubKey(&keyGroup.GroupPubKey),
)

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

_, err = GroupPubKeyV0(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()
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,
}
groupReq := GroupKeyRequest{
RawKey: groupKeyDesc,
AnchorGen: baseGen,
}

// A prototype asset is required for building the genesis virtual TX.
_, err := groupReq.BuildGroupVirtualTx(&genBuilder)
require.ErrorContains(t, err, "grouped asset cannot be nil")

// The prototype asset must have a genesis witness.
groupReq.NewAsset = nonGenProtoAsset
_, err = groupReq.BuildGroupVirtualTx(&genBuilder)
require.ErrorContains(t, err, "asset is not a genesis asset")

// The prototype asset must not have a group key set.
groupReq.NewAsset = groupedProtoAsset
_, err = groupReq.BuildGroupVirtualTx(&genBuilder)
require.ErrorContains(t, err, "asset already has group key")

// The anchor genesis used for signing must have the same asset type
// as the prototype asset being signed.
groupReq.AnchorGen = collectGen
groupReq.NewAsset = protoAsset
_, err = groupReq.BuildGroupVirtualTx(&genBuilder)
require.ErrorContains(t, err, "asset group type mismatch")

// The group key request must include an internal key.
groupReq.AnchorGen = baseGen
groupReq.RawKey.PubKey = nil
_, err = groupReq.BuildGroupVirtualTx(&genBuilder)
require.ErrorContains(t, err, "missing group internal key")

// The tapscript root in the group key request must be exactly 32 bytes
// if present.
groupReq.RawKey = groupKeyDesc
groupReq.TapscriptRoot = test.RandBytes(33)
_, err = groupReq.BuildGroupVirtualTx(&genBuilder)
require.ErrorContains(t, err, "tapscript root must be 32 bytes")

groupReq.TapscriptRoot = test.RandBytes(32)
genTx, err := groupReq.BuildGroupVirtualTx(&genBuilder)
require.NoError(t, err)

groupKey, err := DeriveGroupKey(genSigner, *genTx, groupReq, nil)
require.NoError(t, err)
require.NotNil(t, groupKey)
}

// TestAssetWitnesses tests that the asset group witness can be serialized and
// parsed correctly, and that signature detection works correctly.
func TestAssetWitnesses(t *testing.T) {
Expand Down
Loading
Loading