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
|
bodyLength = 12 // The number of elements in the BeaconBlockBody Container
|
||||||
logBodyLength = 4 // The log 2 of bodyLength
|
logBodyLength = 4 // The log 2 of bodyLength
|
||||||
kzgPosition = 11 // The index of the KZG commitment list in the Body
|
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 (
|
var (
|
||||||
@ -37,9 +38,7 @@ func VerifyKZGInclusionProof(blob ROBlob) error {
|
|||||||
if len(root) != field_params.RootLength {
|
if len(root) != field_params.RootLength {
|
||||||
return errInvalidBodyRoot
|
return errInvalidBodyRoot
|
||||||
}
|
}
|
||||||
chunks := make([][32]byte, 2)
|
chunks := makeChunk(blob.KzgCommitment)
|
||||||
copy(chunks[0][:], blob.KzgCommitment)
|
|
||||||
copy(chunks[1][:], blob.KzgCommitment[field_params.RootLength:])
|
|
||||||
gohashtree.HashChunks(chunks, chunks)
|
gohashtree.HashChunks(chunks, chunks)
|
||||||
verified := trie.VerifyMerkleProof(root, chunks[0][:], blob.Index+KZGOffset, blob.CommitmentInclusionProof)
|
verified := trie.VerifyMerkleProof(root, chunks[0][:], blob.Index+KZGOffset, blob.CommitmentInclusionProof)
|
||||||
if !verified {
|
if !verified {
|
||||||
@ -85,15 +84,21 @@ func MerkleProofKZGCommitment(body interfaces.ReadOnlyBeaconBlockBody, index int
|
|||||||
func leavesFromCommitments(commitments [][]byte) [][]byte {
|
func leavesFromCommitments(commitments [][]byte) [][]byte {
|
||||||
leaves := make([][]byte, len(commitments))
|
leaves := make([][]byte, len(commitments))
|
||||||
for i, kzg := range commitments {
|
for i, kzg := range commitments {
|
||||||
chunk := make([][32]byte, 2)
|
chunk := makeChunk(kzg)
|
||||||
copy(chunk[0][:], kzg)
|
|
||||||
copy(chunk[1][:], kzg[field_params.RootLength:])
|
|
||||||
gohashtree.HashChunks(chunk, chunk)
|
gohashtree.HashChunks(chunk, chunk)
|
||||||
leaves[i] = chunk[0][:]
|
leaves[i] = chunk[0][:]
|
||||||
}
|
}
|
||||||
return leaves
|
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
|
// bodyProof returns the Merkle proof of the subtree up to the root of the KZG
|
||||||
// commitment list.
|
// commitment list.
|
||||||
func bodyProof(commitments [][]byte, index int) ([][]byte, error) {
|
func bodyProof(commitments [][]byte, index int) ([][]byte, error) {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
package blocks
|
package blocks
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math/rand"
|
"crypto/rand"
|
||||||
|
"errors"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"github.com/prysmaticlabs/gohashtree"
|
"github.com/prysmaticlabs/gohashtree"
|
||||||
@ -74,14 +75,79 @@ func Test_MerkleProofKZGCommitment(t *testing.T) {
|
|||||||
proof, err := MerkleProofKZGCommitment(body, index)
|
proof, err := MerkleProofKZGCommitment(body, index)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
chunk := make([][32]byte, 2)
|
// Test the logic of topProof in MerkleProofKZGCommitment.
|
||||||
copy(chunk[0][:], kzgs[index])
|
commitmentsRoot, err := getBlobKzgCommitmentsRoot(kzgs)
|
||||||
copy(chunk[1][:], kzgs[index][32:])
|
require.NoError(t, err)
|
||||||
gohashtree.HashChunks(chunk, chunk)
|
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()
|
root, err := body.HashTreeRoot()
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
kzgOffset := 54 * fieldparams.MaxBlobCommitmentsPerBlock
|
// Partially verify if the commitments root is in the body root.
|
||||||
require.Equal(t, true, trie.VerifyMerkleProof(root[:], chunk[0][:], uint64(index+kzgOffset), proof))
|
// 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) {
|
func Benchmark_MerkleProofKZGCommitment(b *testing.B) {
|
||||||
|
Loading…
Reference in New Issue
Block a user