mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 03:30:35 +00:00
chore(kzg): Additional tests for KZG commitments (#13758)
* add a test explaining kzgRootIndex * minor * minor
This commit is contained in:
parent
357211b7d9
commit
d779e65d4e
@ -15,7 +15,8 @@ const (
|
||||
bodyLength = 12 // The number of elements in the BeaconBlockBody Container
|
||||
logBodyLength = 4 // The log 2 of bodyLength
|
||||
kzgPosition = 11 // The index of the KZG commitment list in the Body
|
||||
KZGOffset = 54 * field_params.MaxBlobCommitmentsPerBlock
|
||||
kzgRootIndex = 54 // The Merkle index of the KZG commitment list's root in the Body's Merkle tree
|
||||
KZGOffset = kzgRootIndex * field_params.MaxBlobCommitmentsPerBlock
|
||||
)
|
||||
|
||||
var (
|
||||
@ -37,9 +38,7 @@ func VerifyKZGInclusionProof(blob ROBlob) error {
|
||||
if len(root) != field_params.RootLength {
|
||||
return errInvalidBodyRoot
|
||||
}
|
||||
chunks := make([][32]byte, 2)
|
||||
copy(chunks[0][:], blob.KzgCommitment)
|
||||
copy(chunks[1][:], blob.KzgCommitment[field_params.RootLength:])
|
||||
chunks := makeChunk(blob.KzgCommitment)
|
||||
gohashtree.HashChunks(chunks, chunks)
|
||||
verified := trie.VerifyMerkleProof(root, chunks[0][:], blob.Index+KZGOffset, blob.CommitmentInclusionProof)
|
||||
if !verified {
|
||||
@ -85,15 +84,21 @@ func MerkleProofKZGCommitment(body interfaces.ReadOnlyBeaconBlockBody, index int
|
||||
func leavesFromCommitments(commitments [][]byte) [][]byte {
|
||||
leaves := make([][]byte, len(commitments))
|
||||
for i, kzg := range commitments {
|
||||
chunk := make([][32]byte, 2)
|
||||
copy(chunk[0][:], kzg)
|
||||
copy(chunk[1][:], kzg[field_params.RootLength:])
|
||||
chunk := makeChunk(kzg)
|
||||
gohashtree.HashChunks(chunk, chunk)
|
||||
leaves[i] = chunk[0][:]
|
||||
}
|
||||
return leaves
|
||||
}
|
||||
|
||||
// makeChunk constructs a chunk from a KZG commitment.
|
||||
func makeChunk(commitment []byte) [][32]byte {
|
||||
chunk := make([][32]byte, 2)
|
||||
copy(chunk[0][:], commitment)
|
||||
copy(chunk[1][:], commitment[field_params.RootLength:])
|
||||
return chunk
|
||||
}
|
||||
|
||||
// bodyProof returns the Merkle proof of the subtree up to the root of the KZG
|
||||
// commitment list.
|
||||
func bodyProof(commitments [][]byte, index int) ([][]byte, error) {
|
||||
|
@ -1,7 +1,8 @@
|
||||
package blocks
|
||||
|
||||
import (
|
||||
"math/rand"
|
||||
"crypto/rand"
|
||||
"errors"
|
||||
"testing"
|
||||
|
||||
"github.com/prysmaticlabs/gohashtree"
|
||||
@ -74,14 +75,79 @@ func Test_MerkleProofKZGCommitment(t *testing.T) {
|
||||
proof, err := MerkleProofKZGCommitment(body, index)
|
||||
require.NoError(t, err)
|
||||
|
||||
chunk := make([][32]byte, 2)
|
||||
copy(chunk[0][:], kzgs[index])
|
||||
copy(chunk[1][:], kzgs[index][32:])
|
||||
gohashtree.HashChunks(chunk, chunk)
|
||||
// Test the logic of topProof in MerkleProofKZGCommitment.
|
||||
commitmentsRoot, err := getBlobKzgCommitmentsRoot(kzgs)
|
||||
require.NoError(t, err)
|
||||
bodyMembersRoots, err := topLevelRoots(body)
|
||||
require.NoError(t, err, "Failed to get top level roots")
|
||||
bodySparse, err := trie.GenerateTrieFromItems(
|
||||
bodyMembersRoots,
|
||||
logBodyLength,
|
||||
)
|
||||
require.NoError(t, err, "Failed to generate trie from member roots")
|
||||
require.Equal(t, bodyLength, bodySparse.NumOfItems())
|
||||
topProof, err := bodySparse.MerkleProof(kzgPosition)
|
||||
require.NoError(t, err, "Failed to generate Merkle proof")
|
||||
require.DeepEqual(t,
|
||||
topProof[:len(topProof)-1],
|
||||
proof[fieldparams.LogMaxBlobCommitments+1:],
|
||||
)
|
||||
|
||||
root, err := body.HashTreeRoot()
|
||||
require.NoError(t, err)
|
||||
kzgOffset := 54 * fieldparams.MaxBlobCommitmentsPerBlock
|
||||
require.Equal(t, true, trie.VerifyMerkleProof(root[:], chunk[0][:], uint64(index+kzgOffset), proof))
|
||||
// Partially verify if the commitments root is in the body root.
|
||||
// Proof of the commitment length is not needed.
|
||||
require.Equal(t, true, trie.VerifyMerkleProof(root[:], commitmentsRoot[:], kzgPosition, topProof[:len(topProof)-1]))
|
||||
|
||||
chunk := makeChunk(kzgs[index])
|
||||
gohashtree.HashChunks(chunk, chunk)
|
||||
require.Equal(t, true, trie.VerifyMerkleProof(root[:], chunk[0][:], uint64(index+KZGOffset), proof))
|
||||
}
|
||||
|
||||
// This test explains the calculation of the KZG commitment root's Merkle index
|
||||
// in the Body's Merkle tree based on the index of the KZG commitment list in the Body.
|
||||
func Test_KZGRootIndex(t *testing.T) {
|
||||
// Level of the KZG commitment root's parent.
|
||||
kzgParentRootLevel, err := ceilLog2(kzgPosition)
|
||||
require.NoError(t, err)
|
||||
// Merkle index of the KZG commitment root's parent.
|
||||
// The parent's left child is the KZG commitment root,
|
||||
// and its right child is the KZG commitment size.
|
||||
kzgParentRootIndex := kzgPosition + (1 << kzgParentRootLevel)
|
||||
// The KZG commitment root is the left child of its parent.
|
||||
// Its Merkle index is the double of its parent's Merkle index.
|
||||
require.Equal(t, 2*kzgParentRootIndex, kzgRootIndex)
|
||||
}
|
||||
|
||||
// ceilLog2 returns the smallest integer greater than or equal to
|
||||
// the base-2 logarithm of x.
|
||||
func ceilLog2(x uint32) (uint32, error) {
|
||||
if x == 0 {
|
||||
return 0, errors.New("log2(0) is undefined")
|
||||
}
|
||||
var y uint32
|
||||
if (x & (x - 1)) == 0 {
|
||||
y = 0
|
||||
} else {
|
||||
y = 1
|
||||
}
|
||||
for x > 1 {
|
||||
x >>= 1
|
||||
y += 1
|
||||
}
|
||||
return y, nil
|
||||
}
|
||||
|
||||
func getBlobKzgCommitmentsRoot(commitments [][]byte) ([32]byte, error) {
|
||||
commitmentsLeaves := leavesFromCommitments(commitments)
|
||||
commitmentsSparse, err := trie.GenerateTrieFromItems(
|
||||
commitmentsLeaves,
|
||||
fieldparams.LogMaxBlobCommitments,
|
||||
)
|
||||
if err != nil {
|
||||
return [32]byte{}, err
|
||||
}
|
||||
return commitmentsSparse.HashTreeRoot()
|
||||
}
|
||||
|
||||
func Benchmark_MerkleProofKZGCommitment(b *testing.B) {
|
||||
|
Loading…
Reference in New Issue
Block a user