diff --git a/beacon-chain/core/blocks/deposit.go b/beacon-chain/core/blocks/deposit.go index 7e7c9ec58f..9864d7598e 100644 --- a/beacon-chain/core/blocks/deposit.go +++ b/beacon-chain/core/blocks/deposit.go @@ -222,7 +222,7 @@ func verifyDeposit(beaconState state.ReadOnlyBeaconState, deposit *ethpb.Deposit if err != nil { return errors.Wrap(err, "could not tree hash deposit data") } - if ok := trie.VerifyMerkleBranch( + if ok := trie.VerifyMerkleProofWithDepth( receiptRoot, leaf[:], int(beaconState.Eth1DepositIndex()), diff --git a/beacon-chain/state/fieldtrie/field_trie_helpers.go b/beacon-chain/state/fieldtrie/field_trie_helpers.go index 9a37f661ae..c12097f9ca 100644 --- a/beacon-chain/state/fieldtrie/field_trie_helpers.go +++ b/beacon-chain/state/fieldtrie/field_trie_helpers.go @@ -15,6 +15,21 @@ import ( "github.com/prysmaticlabs/prysm/runtime/version" ) +// ProofFromMerkleLayers creates a proof starting at the leaf index of the state Merkle layers. +func ProofFromMerkleLayers(layers [][][]byte, startingLeafIndex types.FieldIndex) [][]byte { + // The merkle tree structure looks as follows: + // [[r1, r2, r3, r4], [parent1, parent2], [root]] + proof := make([][]byte, 0) + currentIndex := startingLeafIndex + for i := 0; i < len(layers)-1; i++ { + neighborIdx := currentIndex ^ 1 + neighbor := layers[i][neighborIdx] + proof = append(proof, neighbor) + currentIndex = currentIndex / 2 + } + return proof +} + func (f *FieldTrie) validateIndices(idxs []uint64) error { length := f.length if f.dataType == types.CompressedArray { diff --git a/beacon-chain/state/phase0.go b/beacon-chain/state/phase0.go index f00d24aba2..25f06c3eed 100644 --- a/beacon-chain/state/phase0.go +++ b/beacon-chain/state/phase0.go @@ -18,6 +18,14 @@ type BeaconState interface { Copy() BeaconState HashTreeRoot(ctx context.Context) ([32]byte, error) FutureForkStub + StateProver +} + +// StateProver defines the ability to create Merkle proofs for beacon state fields. +type StateProver interface { + FinalizedRootProof() ([][]byte, error) + CurrentSyncCommitteeProof() ([][]byte, error) + NextSyncCommitteeProof() ([][]byte, error) } // ReadOnlyBeaconState defines a struct which only has read access to beacon state methods. diff --git a/beacon-chain/state/v1/BUILD.bazel b/beacon-chain/state/v1/BUILD.bazel index eeb49e774d..6da917f934 100644 --- a/beacon-chain/state/v1/BUILD.bazel +++ b/beacon-chain/state/v1/BUILD.bazel @@ -13,6 +13,7 @@ go_library( "getters_randao.go", "getters_state.go", "getters_validator.go", + "proofs.go", "readonly_validator.go", "setters_attestation.go", "setters_block.go", @@ -75,6 +76,7 @@ go_test( "getters_block_test.go", "getters_test.go", "getters_validator_test.go", + "proofs_test.go", "readonly_validator_test.go", "references_test.go", "setters_attestation_test.go", @@ -90,6 +92,7 @@ go_test( "//config/features:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", + "//container/trie:go_default_library", "//encoding/bytesutil:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//runtime/interop:go_default_library", diff --git a/beacon-chain/state/v1/proofs.go b/beacon-chain/state/v1/proofs.go new file mode 100644 index 0000000000..1ad340579a --- /dev/null +++ b/beacon-chain/state/v1/proofs.go @@ -0,0 +1,47 @@ +package v1 + +import ( + "encoding/binary" + + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie" + "github.com/prysmaticlabs/prysm/encoding/bytesutil" +) + +const ( + finalizedRootIndex = uint64(105) // Precomputed value. +) + +// FinalizedRootGeneralizedIndex for the beacon state. +func FinalizedRootGeneralizedIndex() uint64 { + return finalizedRootIndex +} + +// CurrentSyncCommitteeProof from the state's Merkle trie representation. +func (*BeaconState) CurrentSyncCommitteeProof() ([][]byte, error) { + return nil, errors.New("CurrentSyncCommitteeProof() unsupported for v1 beacon state") +} + +// NextSyncCommitteeProof from the state's Merkle trie representation. +func (*BeaconState) NextSyncCommitteeProof() ([][]byte, error) { + return nil, errors.New("NextSyncCommitteeProof() unsupported for v1 beacon state") +} + +// FinalizedRootProof crafts a Merkle proof for the finalized root +// contained within the finalized checkpoint of a beacon state. +func (b *BeaconState) FinalizedRootProof() ([][]byte, error) { + b.lock.RLock() + defer b.lock.RUnlock() + cpt := b.state.FinalizedCheckpoint + // The epoch field of a finalized checkpoint is the neighbor + // index of the finalized root field in its Merkle tree representation + // of the checkpoint. This neighbor is the first element added to the proof. + epochBuf := make([]byte, 8) + binary.LittleEndian.PutUint64(epochBuf, uint64(cpt.Epoch)) + epochRoot := bytesutil.ToBytes32(epochBuf) + proof := make([][]byte, 0) + proof = append(proof, epochRoot[:]) + branch := fieldtrie.ProofFromMerkleLayers(b.merkleLayers, finalizedCheckpoint) + proof = append(proof, branch...) + return proof, nil +} diff --git a/beacon-chain/state/v1/proofs_test.go b/beacon-chain/state/v1/proofs_test.go new file mode 100644 index 0000000000..15ab78185a --- /dev/null +++ b/beacon-chain/state/v1/proofs_test.go @@ -0,0 +1,34 @@ +package v1_test + +import ( + "context" + "testing" + + v1 "github.com/prysmaticlabs/prysm/beacon-chain/state/v1" + "github.com/prysmaticlabs/prysm/container/trie" + "github.com/prysmaticlabs/prysm/testing/require" + "github.com/prysmaticlabs/prysm/testing/util" +) + +func TestBeaconStateMerkleProofs(t *testing.T) { + ctx := context.Background() + st, _ := util.DeterministicGenesisState(t, 256) + htr, err := st.HashTreeRoot(ctx) + require.NoError(t, err) + t.Run("current sync committee", func(t *testing.T) { + _, err := st.CurrentSyncCommitteeProof() + require.ErrorContains(t, "unsupported", err) + }) + t.Run("next sync committee", func(t *testing.T) { + _, err := st.NextSyncCommitteeProof() + require.ErrorContains(t, "unsupported", err) + }) + t.Run("finalized root", func(t *testing.T) { + finalizedRoot := st.FinalizedCheckpoint().Root + proof, err := st.FinalizedRootProof() + require.NoError(t, err) + gIndex := v1.FinalizedRootGeneralizedIndex() + valid := trie.VerifyMerkleProof(htr[:], finalizedRoot, gIndex, proof) + require.Equal(t, true, valid) + }) +} diff --git a/beacon-chain/state/v2/BUILD.bazel b/beacon-chain/state/v2/BUILD.bazel index ee88efd29a..2fc8b6ae74 100644 --- a/beacon-chain/state/v2/BUILD.bazel +++ b/beacon-chain/state/v2/BUILD.bazel @@ -15,6 +15,7 @@ go_library( "getters_state.go", "getters_sync_committee.go", "getters_validator.go", + "proofs.go", "setters_block.go", "setters_checkpoint.go", "setters_eth1.go", @@ -67,6 +68,7 @@ go_test( "getters_block_test.go", "getters_test.go", "getters_validator_test.go", + "proofs_test.go", "setters_test.go", "state_trie_test.go", ], @@ -78,10 +80,13 @@ go_test( "//config/features:go_default_library", "//config/fieldparams:go_default_library", "//config/params:go_default_library", + "//container/trie:go_default_library", + "//crypto/bls:go_default_library", "//encoding/bytesutil:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//testing/assert:go_default_library", "//testing/require:go_default_library", + "//testing/util:go_default_library", "@com_github_prysmaticlabs_eth2_types//:go_default_library", "@com_github_prysmaticlabs_go_bitfield//:go_default_library", ], diff --git a/beacon-chain/state/v2/proofs.go b/beacon-chain/state/v2/proofs.go new file mode 100644 index 0000000000..322d94c538 --- /dev/null +++ b/beacon-chain/state/v2/proofs.go @@ -0,0 +1,60 @@ +package v2 + +import ( + "encoding/binary" + + "github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie" + "github.com/prysmaticlabs/prysm/encoding/bytesutil" +) + +const ( + finalizedRootIndex = uint64(105) // Precomputed value. +) + +// FinalizedRootGeneralizedIndex for the beacon state. +func FinalizedRootGeneralizedIndex() uint64 { + return finalizedRootIndex +} + +// CurrentSyncCommitteeGeneralizedIndex for the beacon state. +func CurrentSyncCommitteeGeneralizedIndex() uint64 { + return uint64(currentSyncCommittee) +} + +// NextSyncCommitteeGeneralizedIndex for the beacon state. +func NextSyncCommitteeGeneralizedIndex() uint64 { + return uint64(nextSyncCommittee) +} + +// CurrentSyncCommitteeProof from the state's Merkle trie representation. +func (b *BeaconState) CurrentSyncCommitteeProof() ([][]byte, error) { + b.lock.RLock() + defer b.lock.RUnlock() + return fieldtrie.ProofFromMerkleLayers(b.merkleLayers, currentSyncCommittee), nil +} + +// NextSyncCommitteeProof from the state's Merkle trie representation. +func (b *BeaconState) NextSyncCommitteeProof() ([][]byte, error) { + b.lock.RLock() + defer b.lock.RUnlock() + return fieldtrie.ProofFromMerkleLayers(b.merkleLayers, nextSyncCommittee), nil +} + +// FinalizedRootProof crafts a Merkle proof for the finalized root +// contained within the finalized checkpoint of a beacon state. +func (b *BeaconState) FinalizedRootProof() ([][]byte, error) { + b.lock.RLock() + defer b.lock.RUnlock() + cpt := b.state.FinalizedCheckpoint + // The epoch field of a finalized checkpoint is the neighbor + // index of the finalized root field in its Merkle tree representation + // of the checkpoint. This neighbor is the first element added to the proof. + epochBuf := make([]byte, 8) + binary.LittleEndian.PutUint64(epochBuf, uint64(cpt.Epoch)) + epochRoot := bytesutil.ToBytes32(epochBuf) + proof := make([][]byte, 0) + proof = append(proof, epochRoot[:]) + branch := fieldtrie.ProofFromMerkleLayers(b.merkleLayers, finalizedCheckpoint) + proof = append(proof, branch...) + return proof, nil +} diff --git a/beacon-chain/state/v2/proofs_test.go b/beacon-chain/state/v2/proofs_test.go new file mode 100644 index 0000000000..83bf7aaab2 --- /dev/null +++ b/beacon-chain/state/v2/proofs_test.go @@ -0,0 +1,75 @@ +package v2_test + +import ( + "context" + "testing" + + v2 "github.com/prysmaticlabs/prysm/beacon-chain/state/v2" + "github.com/prysmaticlabs/prysm/container/trie" + "github.com/prysmaticlabs/prysm/crypto/bls" + "github.com/prysmaticlabs/prysm/testing/require" + "github.com/prysmaticlabs/prysm/testing/util" +) + +func TestBeaconStateMerkleProofs(t *testing.T) { + ctx := context.Background() + st, _ := util.DeterministicGenesisStateAltair(t, 256) + htr, err := st.HashTreeRoot(ctx) + require.NoError(t, err) + t.Run("current sync committee", func(t *testing.T) { + sc, err := st.CurrentSyncCommittee() + require.NoError(t, err) + + // Verify the Merkle proof. + scRoot, err := sc.HashTreeRoot() + require.NoError(t, err) + proof, err := st.CurrentSyncCommitteeProof() + require.NoError(t, err) + valid := trie.VerifyMerkleProof(htr[:], scRoot[:], v2.CurrentSyncCommitteeGeneralizedIndex(), proof) + require.Equal(t, true, valid) + }) + t.Run("next sync committee", func(t *testing.T) { + nextSC, err := st.NextSyncCommittee() + require.NoError(t, err) + proof, err := st.NextSyncCommitteeProof() + require.NoError(t, err) + + // Verify the Merkle proof. + nextSCRoot, err := nextSC.HashTreeRoot() + require.NoError(t, err) + valid := trie.VerifyMerkleProof(htr[:], nextSCRoot[:], v2.NextSyncCommitteeGeneralizedIndex(), proof) + require.Equal(t, true, valid) + + // Edit the sync committee. + privKey, err := bls.RandKey() + require.NoError(t, err) + nextSC.AggregatePubkey = privKey.PublicKey().Marshal() + require.NoError(t, st.SetNextSyncCommittee(nextSC)) + + // Verifying the old Merkle proof for the new value should fail. + nextSCRoot, err = nextSC.HashTreeRoot() + require.NoError(t, err) + valid = trie.VerifyMerkleProof(htr[:], nextSCRoot[:], v2.NextSyncCommitteeGeneralizedIndex(), proof) + require.Equal(t, false, valid) + + // Generating a new, valid proof should pass. + proof, err = st.NextSyncCommitteeProof() + require.NoError(t, err) + htr, err = st.HashTreeRoot(ctx) + require.NoError(t, err) + valid = trie.VerifyMerkleProof(htr[:], nextSCRoot[:], v2.NextSyncCommitteeGeneralizedIndex(), proof) + require.Equal(t, true, valid) + }) + t.Run("finalized root", func(t *testing.T) { + finalizedRoot := st.FinalizedCheckpoint().Root + + // Verify the Merkle proof. + htr, err = st.HashTreeRoot(ctx) + require.NoError(t, err) + proof, err := st.FinalizedRootProof() + require.NoError(t, err) + gIndex := v2.FinalizedRootGeneralizedIndex() + valid := trie.VerifyMerkleProof(htr[:], finalizedRoot, gIndex, proof) + require.Equal(t, true, valid) + }) +} diff --git a/beacon-chain/state/v3/BUILD.bazel b/beacon-chain/state/v3/BUILD.bazel index ee4dc00e96..a86e8072af 100644 --- a/beacon-chain/state/v3/BUILD.bazel +++ b/beacon-chain/state/v3/BUILD.bazel @@ -16,6 +16,7 @@ go_library( "getters_state.go", "getters_sync_committee.go", "getters_validator.go", + "proofs.go", "setters_block.go", "setters_checkpoint.go", "setters_eth1.go", @@ -67,6 +68,7 @@ go_test( "getters_block_test.go", "getters_test.go", "getters_validator_test.go", + "proofs_test.go", "setters_test.go", "state_trie_test.go", ], @@ -77,10 +79,13 @@ go_test( "//beacon-chain/state/v1:go_default_library", "//config/features:go_default_library", "//config/params:go_default_library", + "//container/trie:go_default_library", + "//crypto/bls:go_default_library", "//encoding/bytesutil:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//testing/assert:go_default_library", "//testing/require:go_default_library", + "//testing/util:go_default_library", "@com_github_prysmaticlabs_eth2_types//:go_default_library", "@com_github_prysmaticlabs_go_bitfield//:go_default_library", ], diff --git a/beacon-chain/state/v3/proofs.go b/beacon-chain/state/v3/proofs.go new file mode 100644 index 0000000000..7924ccb308 --- /dev/null +++ b/beacon-chain/state/v3/proofs.go @@ -0,0 +1,60 @@ +package v3 + +import ( + "encoding/binary" + + "github.com/prysmaticlabs/prysm/beacon-chain/state/fieldtrie" + "github.com/prysmaticlabs/prysm/encoding/bytesutil" +) + +const ( + finalizedRootIndex = uint64(105) // Precomputed value. +) + +// FinalizedRootGeneralizedIndex for the beacon state. +func FinalizedRootGeneralizedIndex() uint64 { + return finalizedRootIndex +} + +// CurrentSyncCommitteeGeneralizedIndex for the beacon state. +func CurrentSyncCommitteeGeneralizedIndex() uint64 { + return uint64(currentSyncCommittee) +} + +// NextSyncCommitteeGeneralizedIndex for the beacon state. +func NextSyncCommitteeGeneralizedIndex() uint64 { + return uint64(nextSyncCommittee) +} + +// CurrentSyncCommitteeProof from the state's Merkle trie representation. +func (b *BeaconState) CurrentSyncCommitteeProof() ([][]byte, error) { + b.lock.RLock() + defer b.lock.RUnlock() + return fieldtrie.ProofFromMerkleLayers(b.merkleLayers, currentSyncCommittee), nil +} + +// NextSyncCommitteeProof from the state's Merkle trie representation. +func (b *BeaconState) NextSyncCommitteeProof() ([][]byte, error) { + b.lock.RLock() + defer b.lock.RUnlock() + return fieldtrie.ProofFromMerkleLayers(b.merkleLayers, nextSyncCommittee), nil +} + +// FinalizedRootProof crafts a Merkle proof for the finalized root +// contained within the finalized checkpoint of a beacon state. +func (b *BeaconState) FinalizedRootProof() ([][]byte, error) { + b.lock.RLock() + defer b.lock.RUnlock() + cpt := b.state.FinalizedCheckpoint + // The epoch field of a finalized checkpoint is the neighbor + // index of the finalized root field in its Merkle tree representation + // of the checkpoint. This neighbor is the first element added to the proof. + epochBuf := make([]byte, 8) + binary.LittleEndian.PutUint64(epochBuf, uint64(cpt.Epoch)) + epochRoot := bytesutil.ToBytes32(epochBuf) + proof := make([][]byte, 0) + proof = append(proof, epochRoot[:]) + branch := fieldtrie.ProofFromMerkleLayers(b.merkleLayers, finalizedCheckpoint) + proof = append(proof, branch...) + return proof, nil +} diff --git a/beacon-chain/state/v3/proofs_test.go b/beacon-chain/state/v3/proofs_test.go new file mode 100644 index 0000000000..b683023a63 --- /dev/null +++ b/beacon-chain/state/v3/proofs_test.go @@ -0,0 +1,75 @@ +package v3_test + +import ( + "context" + "testing" + + v3 "github.com/prysmaticlabs/prysm/beacon-chain/state/v3" + "github.com/prysmaticlabs/prysm/container/trie" + "github.com/prysmaticlabs/prysm/crypto/bls" + "github.com/prysmaticlabs/prysm/testing/require" + "github.com/prysmaticlabs/prysm/testing/util" +) + +func TestBeaconStateMerkleProofs(t *testing.T) { + ctx := context.Background() + st, _ := util.DeterministicGenesisStateAltair(t, 256) + htr, err := st.HashTreeRoot(ctx) + require.NoError(t, err) + t.Run("current sync committee", func(t *testing.T) { + sc, err := st.CurrentSyncCommittee() + require.NoError(t, err) + + // Verify the Merkle proof. + scRoot, err := sc.HashTreeRoot() + require.NoError(t, err) + proof, err := st.CurrentSyncCommitteeProof() + require.NoError(t, err) + valid := trie.VerifyMerkleProof(htr[:], scRoot[:], v3.CurrentSyncCommitteeGeneralizedIndex(), proof) + require.Equal(t, true, valid) + }) + t.Run("next sync committee", func(t *testing.T) { + nextSC, err := st.NextSyncCommittee() + require.NoError(t, err) + proof, err := st.NextSyncCommitteeProof() + require.NoError(t, err) + + // Verify the Merkle proof. + nextSCRoot, err := nextSC.HashTreeRoot() + require.NoError(t, err) + valid := trie.VerifyMerkleProof(htr[:], nextSCRoot[:], v3.NextSyncCommitteeGeneralizedIndex(), proof) + require.Equal(t, true, valid) + + // Edit the sync committee. + privKey, err := bls.RandKey() + require.NoError(t, err) + nextSC.AggregatePubkey = privKey.PublicKey().Marshal() + require.NoError(t, st.SetNextSyncCommittee(nextSC)) + + // Verifying the old Merkle proof for the new value should fail. + nextSCRoot, err = nextSC.HashTreeRoot() + require.NoError(t, err) + valid = trie.VerifyMerkleProof(htr[:], nextSCRoot[:], v3.NextSyncCommitteeGeneralizedIndex(), proof) + require.Equal(t, false, valid) + + // Generating a new, valid proof should pass. + proof, err = st.NextSyncCommitteeProof() + require.NoError(t, err) + htr, err = st.HashTreeRoot(ctx) + require.NoError(t, err) + valid = trie.VerifyMerkleProof(htr[:], nextSCRoot[:], v3.NextSyncCommitteeGeneralizedIndex(), proof) + require.Equal(t, true, valid) + }) + t.Run("finalized root", func(t *testing.T) { + finalizedRoot := st.FinalizedCheckpoint().Root + + // Verify the Merkle proof. + htr, err = st.HashTreeRoot(ctx) + require.NoError(t, err) + proof, err := st.FinalizedRootProof() + require.NoError(t, err) + gIndex := v3.FinalizedRootGeneralizedIndex() + valid := trie.VerifyMerkleProof(htr[:], finalizedRoot, gIndex, proof) + require.Equal(t, true, valid) + }) +} diff --git a/container/trie/sparse_merkle.go b/container/trie/sparse_merkle.go index 26815b29ef..cedb2c2995 100644 --- a/container/trie/sparse_merkle.go +++ b/container/trie/sparse_merkle.go @@ -180,8 +180,8 @@ func (m *SparseMerkleTrie) ToProto() *protodb.SparseMerkleTrie { return trie } -// VerifyMerkleBranch verifies a Merkle branch against a root of a trie. -func VerifyMerkleBranch(root, item []byte, merkleIndex int, proof [][]byte, depth uint64) bool { +// VerifyMerkleProofWithDepth verifies a Merkle branch against a root of a trie. +func VerifyMerkleProofWithDepth(root, item []byte, merkleIndex int, proof [][]byte, depth uint64) bool { if len(proof) != int(depth)+1 { return false } @@ -197,6 +197,20 @@ func VerifyMerkleBranch(root, item []byte, merkleIndex int, proof [][]byte, dept return bytes.Equal(root, node[:]) } +// VerifyMerkleProof given a trie root, a leaf, the generalized merkle index +// of the leaf in the trie, and the proof itself. +func VerifyMerkleProof(root, item []byte, merkleIndex uint64, proof [][]byte) bool { + node := bytesutil.ToBytes32(item) + for i := 0; i < len(proof); i++ { + if (merkleIndex / math.PowerOf2(uint64(i)) % 2) != 0 { + node = hash.Hash(append(proof[i], node[:]...)) + } else { + node = hash.Hash(append(node[:], proof[i]...)) + } + } + return bytes.Equal(root, node[:]) +} + // Copy performs a deep copy of the trie. func (m *SparseMerkleTrie) Copy() *SparseMerkleTrie { dstBranches := make([][][]byte, len(m.branches)) diff --git a/container/trie/sparse_merkle_test.go b/container/trie/sparse_merkle_test.go index 6aa0f179d2..2c1fd2709c 100644 --- a/container/trie/sparse_merkle_test.go +++ b/container/trie/sparse_merkle_test.go @@ -87,6 +87,32 @@ func TestGenerateTrieFromItems_NoItemsProvided(t *testing.T) { } } +func TestMerkleTrie_VerifyMerkleProofWithDepth(t *testing.T) { + items := [][]byte{ + []byte("A"), + []byte("B"), + []byte("C"), + []byte("D"), + []byte("E"), + []byte("F"), + []byte("G"), + []byte("H"), + } + m, err := trie.GenerateTrieFromItems(items, params.BeaconConfig().DepositContractTreeDepth) + require.NoError(t, err) + proof, err := m.MerkleProof(0) + require.NoError(t, err) + require.Equal(t, int(params.BeaconConfig().DepositContractTreeDepth)+1, len(proof)) + root := m.HashTreeRoot() + if ok := trie.VerifyMerkleProofWithDepth(root[:], items[0], 0, proof, params.BeaconConfig().DepositContractTreeDepth); !ok { + t.Error("First Merkle proof did not verify") + } + proof, err = m.MerkleProof(3) + require.NoError(t, err) + require.Equal(t, true, trie.VerifyMerkleProofWithDepth(root[:], items[3], 3, proof, params.BeaconConfig().DepositContractTreeDepth)) + require.Equal(t, false, trie.VerifyMerkleProofWithDepth(root[:], []byte("buzz"), 3, proof, params.BeaconConfig().DepositContractTreeDepth)) +} + func TestMerkleTrie_VerifyMerkleProof(t *testing.T) { items := [][]byte{ []byte("A"), @@ -104,13 +130,13 @@ func TestMerkleTrie_VerifyMerkleProof(t *testing.T) { require.NoError(t, err) require.Equal(t, int(params.BeaconConfig().DepositContractTreeDepth)+1, len(proof)) root := m.HashTreeRoot() - if ok := trie.VerifyMerkleBranch(root[:], items[0], 0, proof, params.BeaconConfig().DepositContractTreeDepth); !ok { + if ok := trie.VerifyMerkleProof(root[:], items[0], 0, proof); !ok { t.Error("First Merkle proof did not verify") } proof, err = m.MerkleProof(3) require.NoError(t, err) - require.Equal(t, true, trie.VerifyMerkleBranch(root[:], items[3], 3, proof, params.BeaconConfig().DepositContractTreeDepth)) - require.Equal(t, false, trie.VerifyMerkleBranch(root[:], []byte("buzz"), 3, proof, params.BeaconConfig().DepositContractTreeDepth)) + require.Equal(t, true, trie.VerifyMerkleProof(root[:], items[3], 3, proof)) + require.Equal(t, false, trie.VerifyMerkleProof(root[:], []byte("buzz"), 3, proof)) } func TestMerkleTrie_NegativeIndexes(t *testing.T) { @@ -144,17 +170,17 @@ func TestMerkleTrie_VerifyMerkleProof_TrieUpdated(t *testing.T) { proof, err := m.MerkleProof(0) require.NoError(t, err) root := m.HashTreeRoot() - require.Equal(t, true, trie.VerifyMerkleBranch(root[:], items[0], 0, proof, depth)) + require.Equal(t, true, trie.VerifyMerkleProofWithDepth(root[:], items[0], 0, proof, depth)) // Now we update the trie. assert.NoError(t, m.Insert([]byte{5}, 3)) proof, err = m.MerkleProof(3) require.NoError(t, err) root = m.HashTreeRoot() - if ok := trie.VerifyMerkleBranch(root[:], []byte{5}, 3, proof, depth); !ok { + if ok := trie.VerifyMerkleProofWithDepth(root[:], []byte{5}, 3, proof, depth); !ok { t.Error("Second Merkle proof did not verify") } - if ok := trie.VerifyMerkleBranch(root[:], []byte{4}, 3, proof, depth); ok { + if ok := trie.VerifyMerkleProofWithDepth(root[:], []byte{4}, 3, proof, depth); ok { t.Error("Old item should not verify") } @@ -253,7 +279,7 @@ func BenchmarkGenerateProof(b *testing.B) { } } -func BenchmarkVerifyMerkleBranch(b *testing.B) { +func BenchmarkVerifyMerkleProofWithDepth(b *testing.B) { b.StopTimer() items := [][]byte{ []byte("A"), @@ -272,7 +298,7 @@ func BenchmarkVerifyMerkleBranch(b *testing.B) { root := m.HashTreeRoot() b.StartTimer() for i := 0; i < b.N; i++ { - if ok := trie.VerifyMerkleBranch(root[:], items[2], 2, proof, params.BeaconConfig().DepositContractTreeDepth); !ok { + if ok := trie.VerifyMerkleProofWithDepth(root[:], items[2], 2, proof, params.BeaconConfig().DepositContractTreeDepth); !ok { b.Error("Merkle proof did not verify") } }