Skip to content

Commit

Permalink
KZG Commitment inclusion proof verifier (#13174)
Browse files Browse the repository at this point in the history
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
  • Loading branch information
potuz and prylabs-bulldozer[bot] authored Nov 8, 2023
1 parent 3097601 commit e46f9c5
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 5 deletions.
29 changes: 28 additions & 1 deletion consensus-types/blocks/kzg.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,39 @@ 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
)

var (
errInvalidIndex = errors.New("index out of bounds")
errInvalidIndex = errors.New("index out of bounds")
errInvalidBodyRoot = errors.New("invalid Beacon Block Body root")
errInvalidInclusionProof = errors.New("invalid KZG commitment inclusion proof")
)

// VerifyKZGIncusionProof verifies the Merkle proof in a Blob sidecar against
// the beacon block body root.
func VerifyKZGInclusionProof(blob ROBlob) error {
if blob.SignedBlockHeader == nil {
return errNilBlockHeader
}
if blob.SignedBlockHeader.Header == nil {
return errNilBlockHeader
}
root := blob.SignedBlockHeader.Header.BodyRoot
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:])
gohashtree.HashChunks(chunks, chunks)
verified := trie.VerifyMerkleProof(root, chunks[0][:], blob.Index+KZGOffset, blob.CommitmentInclusionProof)
if !verified {
return errInvalidInclusionProof
}
return nil
}

// MerkleProofKZGCommitment constructs a Merkle proof of inclusion of the KZG
// commitment of index `index` into the Beacon Block with the given `body`
func MerkleProofKZGCommitment(body interfaces.ReadOnlyBeaconBlockBody, index int) ([][]byte, error) {
Expand Down
64 changes: 64 additions & 0 deletions consensus-types/blocks/kzg_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -128,3 +128,67 @@ func Benchmark_MerkleProofKZGCommitment(b *testing.B) {
require.NoError(b, err)
}
}

func Test_VerifyKZGInclusionProof(t *testing.T) {
kzgs := make([][]byte, 3)
kzgs[0] = make([]byte, 48)
_, err := rand.Read(kzgs[0])
require.NoError(t, err)
kzgs[1] = make([]byte, 48)
_, err = rand.Read(kzgs[1])
require.NoError(t, err)
kzgs[2] = make([]byte, 48)
_, err = rand.Read(kzgs[2])
require.NoError(t, err)
pbBody := &ethpb.BeaconBlockBodyDeneb{
SyncAggregate: &ethpb.SyncAggregate{
SyncCommitteeBits: make([]byte, fieldparams.SyncAggregateSyncCommitteeBytesLength),
SyncCommitteeSignature: make([]byte, fieldparams.BLSSignatureLength),
},
ExecutionPayload: &enginev1.ExecutionPayloadDeneb{
ParentHash: make([]byte, fieldparams.RootLength),
FeeRecipient: make([]byte, 20),
StateRoot: make([]byte, fieldparams.RootLength),
ReceiptsRoot: make([]byte, fieldparams.RootLength),
LogsBloom: make([]byte, 256),
PrevRandao: make([]byte, fieldparams.RootLength),
BaseFeePerGas: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
Transactions: make([][]byte, 0),
ExtraData: make([]byte, 0),
},
Eth1Data: &ethpb.Eth1Data{
DepositRoot: make([]byte, fieldparams.RootLength),
BlockHash: make([]byte, fieldparams.RootLength),
},
BlobKzgCommitments: kzgs,
}

body, err := NewBeaconBlockBody(pbBody)
require.NoError(t, err)
root, err := body.HashTreeRoot()
require.NoError(t, err)
index := 1
proof, err := MerkleProofKZGCommitment(body, index)
require.NoError(t, err)

header := &ethpb.BeaconBlockHeader{
BodyRoot: root[:],
ParentRoot: make([]byte, 32),
StateRoot: make([]byte, 32),
}
signedHeader := &ethpb.SignedBeaconBlockHeader{
Header: header,
}
sidecar := &ethpb.BlobSidecar{
Index: uint64(index),
KzgCommitment: kzgs[index],
CommitmentInclusionProof: proof,
SignedBlockHeader: signedHeader,
}
blob, err := NewROBlob(sidecar)
require.NoError(t, err)
require.NoError(t, VerifyKZGInclusionProof(blob))
proof[2] = make([]byte, 32)
require.ErrorIs(t, errInvalidInclusionProof, VerifyKZGInclusionProof(blob))
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@ import (
"github.com/prysmaticlabs/prysm/v4/testing/util"
)

const kzgOffset = 54 * field_params.MaxBlobCommitmentsPerBlock

// SingleMerkleProof is the format used to read spectest Merkle Proof test data.
type SingleMerkleProof struct {
Leaf string `json:"leaf"`
Expand Down Expand Up @@ -83,10 +81,10 @@ func runSingleMerkleProofTests(t *testing.T, config, forkOrPhase string, unmarsh
if err != nil {
return
}
if index < kzgOffset || index > kzgOffset+field_params.MaxBlobsPerBlock {
if index < consensus_blocks.KZGOffset || index > consensus_blocks.KZGOffset+field_params.MaxBlobsPerBlock {
return
}
localProof, err := consensus_blocks.MerkleProofKZGCommitment(body, int(index-kzgOffset))
localProof, err := consensus_blocks.MerkleProofKZGCommitment(body, int(index-consensus_blocks.KZGOffset))
require.NoError(t, err)
require.Equal(t, len(branch), len(localProof))
for i, root := range localProof {
Expand Down

0 comments on commit e46f9c5

Please sign in to comment.