From aa63d265361b7c8b4749996a4fe44494db099f4e Mon Sep 17 00:00:00 2001 From: Roberto Bayardo Date: Wed, 16 Nov 2022 10:31:07 -0800 Subject: [PATCH] move more CL eip-4844 methods from prysm to shared lib --- crypto/kzg/kzg.go | 12 +---- crypto/kzg/kzg_bytes.go | 98 ++++++++++++++++++++++++++++++++++++++++- 2 files changed, 98 insertions(+), 12 deletions(-) diff --git a/crypto/kzg/kzg.go b/crypto/kzg/kzg.go index b0a22d42d04f..26e58f6a6723 100644 --- a/crypto/kzg/kzg.go +++ b/crypto/kzg/kzg.go @@ -185,20 +185,10 @@ func ComputeAggregatedPolyAndCommitment(blobs Polynomials, commitments KZGCommit return aggregatedPoly, aggregatedCommitmentG1, &evaluationChallenge, nil } -type commitmentSequenceImpl []KZGCommitment - -func (s commitmentSequenceImpl) At(i int) KZGCommitment { - return s[i] -} - -func (s commitmentSequenceImpl) Len() int { - return len(s) -} - // ComputeAggregateKZGProofFromPolynomials implements compute_aggregate_kzg_proof from the EIP-4844 // consensus spec, only operating over blobs that are already parsed into a polynomial. func ComputeAggregateKZGProofFromPolynomials(blobs Polynomials) (KZGProof, error) { - commitments := make(commitmentSequenceImpl, len(blobs)) + commitments := make(KZGCommitmentSequenceImpl, len(blobs)) for i, b := range blobs { commitments[i] = PolynomialToKZGCommitment(Polynomial(b)) } diff --git a/crypto/kzg/kzg_bytes.go b/crypto/kzg/kzg_bytes.go index 16f0357388ef..aef1722aff75 100644 --- a/crypto/kzg/kzg_bytes.go +++ b/crypto/kzg/kzg_bytes.go @@ -1,12 +1,14 @@ package kzg import ( + "bytes" "crypto/sha256" "errors" "fmt" "github.com/ethereum/go-ethereum/params" "github.com/protolambda/go-kzg/bls" + "github.com/protolambda/ztyp/codec" ) // The custom types from EIP-4844 consensus spec: @@ -39,8 +41,22 @@ type KZGCommitmentSequence interface { At(int) KZGCommitment } +type KZGCommitmentSequenceImpl []KZGCommitment + +func (s KZGCommitmentSequenceImpl) At(i int) KZGCommitment { + return s[i] +} + +func (s KZGCommitmentSequenceImpl) Len() int { + return len(s) +} + const ( - PrecompileInputLength = 192 + BlobTxType = 5 + PrecompileInputLength = 192 + BlobVersionedHashesOffset = 258 // offset the versioned_hash_offset in a serialized blob tx + + blobMessageLen = 192 // size in bytes of "message" within the serialized blob tx ) var ( @@ -180,3 +196,83 @@ func ValidateBlobsSidecar(slot Slot, beaconBlockRoot Root, expectedKZGCommitment } return nil } + +// TxPeekBlobVersionedHashes implements tx_peek_blob_versioned_hashes from EIP-4844 consensus spec: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/beacon-chain.md#tx_peek_blob_versioned_hashes +// +// Format of the blob tx relevant to this function is as follows: +// 0: type (value should always be BlobTxType, 1 byte) +// 1: message offset (value should always be 69, 4 bytes) +// 5: ECDSA signature (65 bytes) +// 70: start of "message" (192 bytes) +// 258: start of the versioned hash offset within "message" (4 bytes) +// 262-: rest of the tx following message +func TxPeekBlobVersionedHashes(tx []byte) ([]VersionedHash, error) { + // we start our reader at the versioned hash offset within the serialized tx + if len(tx) < BlobVersionedHashesOffset { + return nil, errors.New("blob tx invalid: too short") + } + if tx[0] != BlobTxType { + return nil, errors.New("invalid blob tx type") + } + dr := codec.NewDecodingReader(bytes.NewReader(tx[BlobVersionedHashesOffset:]), uint64(len(tx)-BlobVersionedHashesOffset)) + + // read the offset to the versioned hashes + var offset uint32 + offset, err := dr.ReadOffset() + if err != nil { + return nil, fmt.Errorf("could not read versioned hashes offset: %v", err) + } + + // Advance dr to the versioned hash list. We subtract blobMessageLen from the offset here to + // account for the fact that the offset is relative to the position of "message" (70) and we + // are currently positioned at the end of it (262). + skip := uint64(offset) - blobMessageLen + skipped, err := dr.Skip(skip) + if err != nil { + return nil, fmt.Errorf("could not skip to versioned hashes: %v", err) + } + if skip != uint64(skipped) { + return nil, fmt.Errorf("did not skip to versioned hashes. want %v got %v", skip, skipped) + } + + // read the list of hashes one by one until we hit the end of the data + hashes := []VersionedHash{} + tmp := make([]byte, 32) + for dr.Scope() > 0 { + if _, err = dr.Read(tmp); err != nil { + return nil, fmt.Errorf("could not read versioned hashes: %v", err) + } + var h VersionedHash + copy(h[:], tmp) + hashes = append(hashes, h) + } + + return hashes, nil +} + +// VerifyKZGCommitmentsAgainstTransactions implements verify_kzg_commitments_against_transactions +// from the EIP-4844 consensus spec: +// https://github.com/ethereum/consensus-specs/blob/dev/specs/eip4844/beacon-chain.md#verify_kzg_commitments_against_transactions +func VerifyKZGCommitmentsAgainstTransactions(transactions [][]byte, kzgCommitments KZGCommitmentSequence) error { + var versionedHashes []VersionedHash + var err error + for _, tx := range transactions { + if tx[0] == BlobTxType { + versionedHashes, err = TxPeekBlobVersionedHashes(tx) + if err != nil { + return err + } + } + } + if kzgCommitments.Len() != len(versionedHashes) { + return errors.New("invalid number of blob versioned hashes") + } + for i := 0; i < kzgCommitments.Len(); i++ { + h := KZGToVersionedHash(kzgCommitments.At(i)) + if h != versionedHashes[i] { + return errors.New("invalid version hashes vs kzg") + } + } + return nil +}