Skip to content

Commit

Permalink
proof: test genesis, group key reveal verification
Browse files Browse the repository at this point in the history
  • Loading branch information
jharveyb committed Nov 14, 2023
1 parent 947272d commit a1bd7ce
Show file tree
Hide file tree
Showing 5 changed files with 143 additions and 58 deletions.
2 changes: 1 addition & 1 deletion proof/append_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -110,7 +110,7 @@ func runAppendTransitionTest(t *testing.T, assetType asset.Type, amt uint64,

// Start with a minted genesis asset.
genesisProof, senderPrivKey := genRandomGenesisWithProof(
t, assetType, &amt, nil, true, nil, nil, assetVersion,
t, assetType, &amt, nil, true, nil, nil, nil, nil, assetVersion,
)
genesisBlob, err := EncodeAsProofFile(&genesisProof)
require.NoError(t, err)
Expand Down
32 changes: 21 additions & 11 deletions proof/mint_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,8 @@ func TestNewMintingBlobs(t *testing.T) {
assetGenesis := asset.RandGenesis(t, asset.Collectible)
assetGenesis.MetaHash = metaReveal.MetaHash()
assetGenesis.OutputIndex = 0
protoAsset := asset.NewAssetNoErr(
t, assetGenesis, 1, 0, 0,
asset.NewScriptKeyBip86(genesisScriptKey), nil,
)

assetGroupKey := asset.RandGroupKey(t, assetGenesis, protoAsset)
tapCommitment, _, err := commitment.Mint(
assetGenesis, assetGroupKey, &commitment.AssetDetails{
assetGenesis, nil, &commitment.AssetDetails{
Type: asset.Collectible,
ScriptKey: genesisScriptKey,
Amount: nil,
Expand All @@ -53,6 +47,23 @@ func TestNewMintingBlobs(t *testing.T) {
)
require.NoError(t, err)

// Add a group anchor with a custom tapscript root to the set of minted
// assets. We cannot make this type of asset with commitment.Mint, so
// we create it manually and then insert it into the tap commitment.
groupedGenesis := asset.RandGenesis(t, asset.Normal)
groupedGenesis.FirstPrevOut = assetGenesis.FirstPrevOut
groupedGenesis.MetaHash = metaReveal.MetaHash()
groupedGenesis.OutputIndex = 0
// Issue here with one branch of useHashLock
groupedAsset := asset.AssetCustomGroupKey(
t, test.RandBool(), false, false, true, groupedGenesis,
)

groupedAssetTree, err := commitment.NewAssetCommitment(groupedAsset)
require.NoError(t, err)
err = tapCommitment.Upsert(groupedAssetTree)
require.NoError(t, err)

internalKey := test.SchnorrPubKey(t, genesisPrivKey)
tapscriptRoot := tapCommitment.TapscriptRoot(nil)
taprootKey := txscript.ComputeTaprootOutputKey(
Expand Down Expand Up @@ -89,11 +100,10 @@ func TestNewMintingBlobs(t *testing.T) {
0, chaincfg.MainNetParams.GenesisHash, merkleRoot, 0, 0,
)

newAsset := tapCommitment.CommittedAssets()[0]
assetScriptKey := newAsset.ScriptKey

assetScriptKey := asset.NewScriptKeyBip86(genesisScriptKey)
metaReveals := map[asset.SerializedKey]*MetaReveal{
asset.ToSerialized(assetScriptKey.PubKey): metaReveal,
asset.ToSerialized(assetScriptKey.PubKey): metaReveal,
asset.ToSerialized(groupedAsset.ScriptKey.PubKey): metaReveal,
}

// The NewMintingBlobs will return an error if the generated proof is
Expand Down
8 changes: 1 addition & 7 deletions proof/proof.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ var (
// proof for a genesis asset has a non-zero meta hash, but doesn't have
// a meta reveal.
ErrGenesisRevealMetaRevealRequired = errors.New("genesis meta reveal " +
"reveal required")
"required")

// ErrGenesisRevealMetaHashMismatch is an error returned if an asset
// proof for a genesis asset has a genesis reveal where the meta hash
Expand All @@ -70,12 +70,6 @@ var (
ErrGenesisRevealOutputIndexMismatch = errors.New("genesis reveal " +
"output index mismatch")

// ErrGenesisRevealTypeMismatch is an error returned if an asset proof
// for a genesis asset has a genesis reveal where the asset type doesn't
// match the proof TLV field.
ErrGenesisRevealTypeMismatch = errors.New("genesis reveal type " +
"mismatch")

// ErrNonGenesisAssetWithGroupKeyReveal is an error returned if an asset
// proof for a non-genesis asset contains a group key reveal.
ErrNonGenesisAssetWithGroupKeyReveal = errors.New("non genesis asset " +
Expand Down
131 changes: 111 additions & 20 deletions proof/proof_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
"github.com/davecgh/go-spew/spew"
"github.com/decred/dcrd/dcrec/secp256k1/v4"
"github.com/lightninglabs/taproot-assets/asset"
"github.com/lightninglabs/taproot-assets/commitment"
"github.com/lightninglabs/taproot-assets/internal/test"
Expand Down Expand Up @@ -338,8 +339,9 @@ func TestProofEncoding(t *testing.T) {

func genRandomGenesisWithProof(t testing.TB, assetType asset.Type,
amt *uint64, tapscriptPreimage *commitment.TapscriptPreimage,
noMetaHash bool, metaReveal *MetaReveal,
genesisMutator genMutator,
noMetaHash bool, metaReveal *MetaReveal, genesisMutator genMutator,
genesisRevealMutator genRevealMutator,
groupRevealMutator groupRevealMutator,
assetVersion asset.Version) (Proof, *btcec.PrivateKey) {

t.Helper()
Expand Down Expand Up @@ -372,13 +374,17 @@ func genRandomGenesisWithProof(t testing.TB, assetType asset.Type,
asset.WithAssetVersion(assetVersion),
)
assetGroupKey := asset.RandGroupKey(t, assetGenesis, protoAsset)
groupKeyReveal := asset.GroupKeyReveal{
groupKeyReveal := &asset.GroupKeyReveal{
RawKey: asset.ToSerialized(
assetGroupKey.RawKey.PubKey,
),
TapscriptRoot: assetGroupKey.TapscriptRoot,
}

if groupRevealMutator != nil {
groupRevealMutator(groupKeyReveal)
}

tapCommitment, assets, err := commitment.Mint(
assetGenesis, assetGroupKey, &commitment.AssetDetails{
Type: assetType,
Expand Down Expand Up @@ -436,6 +442,11 @@ func genRandomGenesisWithProof(t testing.TB, assetType asset.Type,
txMerkleProof, err := NewTxMerkleProof([]*wire.MsgTx{genesisTx}, 0)
require.NoError(t, err)

genReveal := &assetGenesis
if genesisRevealMutator != nil {
genReveal = genesisRevealMutator(genReveal)
}

return Proof{
PrevOut: assetGenesis.FirstPrevOut,
BlockHeader: *blockHeader,
Expand All @@ -455,13 +466,17 @@ func genRandomGenesisWithProof(t testing.TB, assetType asset.Type,
MetaReveal: metaReveal,
ExclusionProofs: nil,
AdditionalInputs: nil,
GenesisReveal: &assetGenesis,
GroupKeyReveal: &groupKeyReveal,
GenesisReveal: genReveal,
GroupKeyReveal: groupKeyReveal,
}, genesisPrivKey
}

type genMutator func(*asset.Genesis)

type groupRevealMutator func(*asset.GroupKeyReveal)

type genRevealMutator func(*asset.Genesis) *asset.Genesis

func TestGenesisProofVerification(t *testing.T) {
t.Parallel()

Expand All @@ -476,15 +491,18 @@ func TestGenesisProofVerification(t *testing.T) {
amount := uint64(5000)

testCases := []struct {
name string
assetType asset.Type
amount *uint64
assetVersion asset.Version
tapscriptPreimage *commitment.TapscriptPreimage
metaReveal *MetaReveal
noMetaHash bool
genesisMutator genMutator
expectedErr error
name string
assetType asset.Type
amount *uint64
assetVersion asset.Version
tapscriptPreimage *commitment.TapscriptPreimage
metaReveal *MetaReveal
noMetaHash bool
noGroup bool
genesisMutator genMutator
genesisRevealMutator genRevealMutator
groupRevealMutator groupRevealMutator
expectedErr error
}{
{
name: "collectible genesis",
Expand Down Expand Up @@ -584,6 +602,78 @@ func TestGenesisProofVerification(t *testing.T) {
assetType: asset.Collectible,
expectedErr: ErrGenesisRevealMetaRevealRequired,
},
{
name: "missing genesis reveal",
assetType: asset.Collectible,
noMetaHash: true,
genesisRevealMutator: func(
g *asset.Genesis) *asset.Genesis {

return nil
},
expectedErr: ErrGenesisRevealRequired,
},
{
name: "genesis reveal asset ID mismatch",
assetType: asset.Normal,
amount: &amount,
noMetaHash: true,
genesisRevealMutator: func(
g *asset.Genesis) *asset.Genesis {

gCopy := *g
gCopy.Tag += "mismatch"
return &gCopy
},
expectedErr: ErrGenesisRevealAssetIDMismatch,
},
{
name: "genesis reveal prev out mismatch",
assetType: asset.Collectible,
genesisRevealMutator: func(
g *asset.Genesis) *asset.Genesis {

gCopy := *g
gCopy.FirstPrevOut = test.RandOp(t)
return &gCopy
},
expectedErr: ErrGenesisRevealPrevOutMismatch,
},
{
name: "genesis reveal output index mismatch",
assetType: asset.Normal,
amount: &amount,
noMetaHash: true,
genesisRevealMutator: func(
g *asset.Genesis) *asset.Genesis {

gCopy := *g
gCopy.OutputIndex = uint32(
test.RandInt[int32](),
)
return &gCopy
},
expectedErr: ErrGenesisRevealOutputIndexMismatch,
},
{
name: "group key reveal invalid key",
assetType: asset.Collectible,
noMetaHash: true,
groupRevealMutator: func(gkr *asset.GroupKeyReveal) {
gkr.RawKey[0] = 0x01
},
expectedErr: secp256k1.ErrPubKeyInvalidFormat,
},
{
name: "group key reveal mismatched tweaked key",
assetType: asset.Normal,
amount: &amount,
noMetaHash: true,
groupRevealMutator: func(gkr *asset.GroupKeyReveal) {
gkr.TapscriptRoot = test.RandBytes(32)
},
expectedErr: ErrGroupKeyRevealMismatch,
},
}

testVectors := &TestVectors{}
Expand All @@ -595,6 +685,7 @@ func TestGenesisProofVerification(t *testing.T) {
tt, tc.assetType, tc.amount,
tc.tapscriptPreimage, tc.noMetaHash,
tc.metaReveal, tc.genesisMutator,
tc.genesisRevealMutator, tc.groupRevealMutator,
tc.assetVersion,
)
_, err := genesisProof.Verify(
Expand Down Expand Up @@ -635,7 +726,7 @@ func TestProofBlockHeaderVerification(t *testing.T) {
t.Parallel()

proof, _ := genRandomGenesisWithProof(
t, asset.Collectible, nil, nil, true, nil, nil, 0,
t, asset.Collectible, nil, nil, true, nil, nil, nil, nil, 0,
)

// Create a base reference for the block header and block height. We
Expand Down Expand Up @@ -793,7 +884,7 @@ func TestProofReplacement(t *testing.T) {
amt := uint64(i + 1)
assetVersion := asset.Version(i % 2)
lotsOfProofs[i], _ = genRandomGenesisWithProof(
t, asset.Normal, &amt, nil, false, nil, nil,
t, asset.Normal, &amt, nil, false, nil, nil, nil, nil,
assetVersion,
)
}
Expand Down Expand Up @@ -822,7 +913,7 @@ func TestProofReplacement(t *testing.T) {
// We'll generate a random proof, and then replace a random
// proof in the file with it.
proof, _ := genRandomGenesisWithProof(
t, asset.Normal, &amt, nil, false, nil, nil,
t, asset.Normal, &amt, nil, false, nil, nil, nil, nil,
assetVersion,
)
idx := test.RandIntn(numProofs)
Expand All @@ -836,15 +927,15 @@ func TestProofReplacement(t *testing.T) {
// boundary conditions).
amt := uint64(1337)
firstProof, _ := genRandomGenesisWithProof(
t, asset.Normal, &amt, nil, false, nil, nil, asset.V1,
t, asset.Normal, &amt, nil, false, nil, nil, nil, nil, asset.V1,
)
err = f.ReplaceProofAt(0, firstProof)
require.NoError(t, err)
assertIndex(0, 1337)

amt = uint64(2016)
lastProof, _ := genRandomGenesisWithProof(
t, asset.Normal, &amt, nil, false, nil, nil, asset.V0,
t, asset.Normal, &amt, nil, false, nil, nil, nil, nil, asset.V0,
)
err = f.ReplaceProofAt(uint32(f.NumProofs()-1), lastProof)
require.NoError(t, err)
Expand All @@ -870,7 +961,7 @@ func BenchmarkProofEncoding(b *testing.B) {

// Start with a minted genesis asset.
genesisProof, _ := genRandomGenesisWithProof(
b, asset.Normal, &amt, nil, false, nil, nil, asset.V0,
b, asset.Normal, &amt, nil, false, nil, nil, nil, nil, asset.V0,
)

// We create a file with 10k proofs (the same one) and test encoding/
Expand Down
28 changes: 9 additions & 19 deletions proof/verifier.go
Original file line number Diff line number Diff line change
Expand Up @@ -285,20 +285,12 @@ func (p *Proof) verifyGenesisReveal() error {
return ErrGenesisRevealRequired
}

// The genesis reveal determines the ID of an asset, so make sure it is
// consistent.
assetID := p.Asset.ID()
if reveal.ID() != assetID {
return ErrGenesisRevealAssetIDMismatch
}

// We also make sure the genesis reveal is consistent with the TLV
// fields in the state transition proof.
// Make sure the genesis reveal is consistent with the TLV fields in
// the state transition proof.
if reveal.FirstPrevOut != p.PrevOut {
return ErrGenesisRevealPrevOutMismatch
}

// TODO(roasbeef): enforce practical limit on size of meta reveal
// If this asset has an empty meta reveal, then the meta hash must be
// empty. Otherwise, the meta hash must match the meta reveal.
var proofMeta [asset.MetaHashLen]byte
Expand All @@ -318,8 +310,13 @@ func (p *Proof) verifyGenesisReveal() error {
return ErrGenesisRevealOutputIndexMismatch
}

if reveal.Type != p.Asset.Type {
return ErrGenesisRevealTypeMismatch
// The genesis reveal determines the ID of an asset, so make sure it is
// consistent. Since the asset ID commits to all fields of the genesis,
// this is equivalent to checking equality for the genesis tag and type
// fields that have not yet been verified.
assetID := p.Asset.ID()
if reveal.ID() != assetID {
return ErrGenesisRevealAssetIDMismatch
}

return nil
Expand All @@ -341,14 +338,7 @@ func (p *Proof) verfyGenesisGroupKey(groupVerifier GroupVerifier) error {
// the same key as the group key specified for the asset.
func (p *Proof) verifyGroupKeyReveal() error {
groupKey := p.Asset.GroupKey
if groupKey == nil {
return ErrGroupKeyRequired
}

reveal := p.GroupKeyReveal
if reveal == nil {
return ErrGroupKeyRevealRequired
}

revealedKey, err := reveal.GroupPubKey(p.Asset.ID())
if err != nil {
Expand Down

0 comments on commit a1bd7ce

Please sign in to comment.