Merkle Proof Support for BeaconState Finalized Root and Sync Committees (#10029)

This commit is contained in:
Raul Jordan
2021-12-19 20:02:42 -05:00
committed by GitHub
parent 7f857ae23a
commit d173a6e695
14 changed files with 438 additions and 11 deletions

View File

@@ -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))

View File

@@ -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")
}
}