From a0d78085dc500510324ea8b1b99271f879d9935a Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Fri, 3 Jan 2025 17:10:38 -0500 Subject: [PATCH 01/14] Draft blob verification Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 290 +++++++++++++++++++ 1 file changed, 290 insertions(+) create mode 100644 api/clients/v2/verification/blob_verifier.go diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go new file mode 100644 index 000000000..641a05230 --- /dev/null +++ b/api/clients/v2/verification/blob_verifier.go @@ -0,0 +1,290 @@ +package verification + +import ( + "context" + "fmt" + commonv1 "github.com/Layr-Labs/eigenda/api/grpc/common" + commonv2 "github.com/Layr-Labs/eigenda/api/grpc/common/v2" + disperser "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" + verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" + "github.com/Layr-Labs/eigenda/core" + "github.com/ethereum/go-ethereum/accounts/abi/bind" + ethcommon "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/ethclient" + "math" + "math/big" +) + +// BlobVerifier is responsible for making eth calls to verify blobs that have been received by the client +// +// Blob verification is not threadsafe. +type BlobVerifier struct { + // the eth client that calls will be made to + ethClient *ethclient.Client + // + blobVerifierCaller *verifierBindings.ContractEigenDABlobVerifierCaller +} + +func NewBlobVerifier( + ethRpcUrl string, + verifyBlobV2FromSignedBatchAddress string) (*BlobVerifier, error) { + + client, err := ethclient.Dial(ethRpcUrl) + if err != nil { + return nil, fmt.Errorf("failed to dial ETH RPC node: %s", err) + } + + verifierCaller, err := verifierBindings.NewContractEigenDABlobVerifierCaller(ethcommon.HexToAddress(verifyBlobV2FromSignedBatchAddress), client) + + if err != nil { + client.Close() + + return nil, fmt.Errorf("bind to verifier contract at %s: %s", verifyBlobV2FromSignedBatchAddress, err) + } + + return &BlobVerifier{ + ethClient: client, + blobVerifierCaller: verifierCaller, + }, nil +} + +func (v *BlobVerifier) VerifyBlobV2FromSignedBatch( + ctx context.Context, + signedBatch *disperser.SignedBatch, + blobVerificationProof *disperser.BlobVerificationInfo, +) (bool, error) { + + convertedSignedBatch, err := convertSignedBatch(signedBatch) + if err != nil { + return false, fmt.Errorf("convert signed batch: %s", err) + } + + convertedBlobVerificationProof, err := convertBlobVerificationProof(blobVerificationProof) + if err != nil { + return false, fmt.Errorf("convert blob verification proof: %s", err) + } + + err = v.blobVerifierCaller.VerifyBlobV2FromSignedBatch( + &bind.CallOpts{Context: ctx}, + *convertedSignedBatch, + *convertedBlobVerificationProof) + + if err != nil { + return false, fmt.Errorf("verify blob v2 from signed batch: %s", err) + } + + return true, nil +} + +// Close closes the eth client. This method is threadsafe. +func (v *BlobVerifier) Close() { + v.ethClient.Close() +} + +func convertSignedBatch(inputSignedBatch *disperser.SignedBatch) (*verifierBindings.SignedBatch, error) { + + convertedBatchHeader, err := convertBatchHeader(inputSignedBatch.GetHeader()) + if err != nil { + return nil, fmt.Errorf("convert batch header: %s", err) + } + + convertedAttestation, err := convertAttestation(inputSignedBatch.Attestation) + if err != nil { + return nil, fmt.Errorf("convert attestation: %s", err) + } + + outputSignedBatch := &verifierBindings.SignedBatch{ + BatchHeader: *convertedBatchHeader, + Attestation: *convertedAttestation, + } + + return outputSignedBatch, nil +} + +func convertBatchHeader(inputBatchHeader *commonv2.BatchHeader) (*verifierBindings.BatchHeaderV2, error) { + var outputBatchRoot [32]byte + + inputBatchRoot := inputBatchHeader.GetBatchRoot() + if len(inputBatchRoot) != 32 { + return nil, fmt.Errorf("BatchRoot must be 32 bytes (length was %d)", len(inputBatchRoot)) + } + copy(outputBatchRoot[:], inputBatchRoot[:]) + + inputReferenceBlockNumber := inputBatchHeader.GetReferenceBlockNumber() + if inputReferenceBlockNumber > math.MaxUint32 { + return nil, fmt.Errorf( + "ReferenceBlockNumber overflow: value was %d, but max allowable value is %d", + inputReferenceBlockNumber, + math.MaxUint32) + } + + convertedHeader := &verifierBindings.BatchHeaderV2{ + BatchRoot: outputBatchRoot, + ReferenceBlockNumber: uint32(inputReferenceBlockNumber), + } + + return convertedHeader, nil +} + +func convertAttestation(inputAttestation *disperser.Attestation) (*verifierBindings.Attestation, error) { + nonSignerPubkeys, err := repeatedBytesToG1Points(inputAttestation.NonSignerPubkeys) + if err != nil { + return nil, fmt.Errorf("convert non signer pubkeys to g1 points: %s", err) + } + + quorumApks, err := repeatedBytesToG1Points(inputAttestation.QuorumApks) + if err != nil { + return nil, fmt.Errorf("convert quorum apks to g1 points: %s", err) + } + + sigma, err := bytesToBN254G1Point(inputAttestation.Sigma) + if err != nil { + return nil, fmt.Errorf("convert sigma to g1 point: %s", err) + } + + apkG2, err := bytesToBN254G2Point(inputAttestation.ApkG2) + if err != nil { + return nil, fmt.Errorf("convert apk g2 to g2 point: %s", err) + } + + convertedAttestation := &verifierBindings.Attestation{ + NonSignerPubkeys: nonSignerPubkeys, + QuorumApks: quorumApks, + Sigma: *sigma, + ApkG2: *apkG2, + QuorumNumbers: inputAttestation.QuorumNumbers, + } + + return convertedAttestation, nil +} + +func convertBlobVerificationProof(inputBlobVerificationProof *disperser.BlobVerificationInfo) (*verifierBindings.BlobVerificationProofV2, error) { + convertedBlobCertificate, err := convertBlobCertificate(inputBlobVerificationProof.BlobCertificate) + if err != nil { + return nil, fmt.Errorf("convert blob certificate: %s", err) + } + + return &verifierBindings.BlobVerificationProofV2{ + BlobCertificate: *convertedBlobCertificate, + BlobIndex: inputBlobVerificationProof.BlobIndex, + InclusionProof: inputBlobVerificationProof.InclusionProof, + }, nil +} + +func convertBlobCertificate(inputBlobCertificate *commonv2.BlobCertificate) (*verifierBindings.BlobCertificate, error) { + convertedBlobHeader, err := convertBlobHeader(inputBlobCertificate.GetBlobHeader()) + if err != nil { + return nil, fmt.Errorf("convert blob header: %s", err) + } + + return &verifierBindings.BlobCertificate{ + BlobHeader: *convertedBlobHeader, + RelayKeys: inputBlobCertificate.GetRelays(), + }, nil +} + +func convertBlobHeader(inputBlobHeader *commonv2.BlobHeader) (*verifierBindings.BlobHeaderV2, error) { + inputVersion := inputBlobHeader.Version + if inputVersion > math.MaxUint16 { + return nil, fmt.Errorf( + "version overflow: value was %d, but max allowable value is %d", + inputVersion, + math.MaxUint16) + } + + var quorumNumbers []byte + for _, quorumNumber := range inputBlobHeader.QuorumNumbers { + if quorumNumber > math.MaxUint8 { + return nil, fmt.Errorf("quorum number overflow: value was %d, but max allowable value is %d", quorumNumber, uint8(math.MaxUint8)) + } + + quorumNumbers = append(quorumNumbers, byte(quorumNumber)) + } + + convertedBlobCommitment, err := convertBlobCommitment(inputBlobHeader.Commitment) + if err != nil { + return nil, fmt.Errorf("convert blob commitment: %s", err) + } + + paymentHeaderHash, err := core.ConvertToPaymentMetadata(inputBlobHeader.PaymentHeader).Hash() + if err != nil { + return nil, fmt.Errorf("hash payment header: %s", err) + } + + return &verifierBindings.BlobHeaderV2{ + Version: uint16(inputVersion), + QuorumNumbers: quorumNumbers, + Commitment: *convertedBlobCommitment, + PaymentHeaderHash: paymentHeaderHash, + }, nil +} + +func convertBlobCommitment(inputCommitment *commonv1.BlobCommitment) (*verifierBindings.BlobCommitment, error) { + convertedCommitment, err := bytesToBN254G1Point(inputCommitment.Commitment) + if err != nil { + return nil, fmt.Errorf("convert commitment to g1 point: %s", err) + } + + convertedLengthCommitment, err := bytesToBN254G2Point(inputCommitment.LengthCommitment) + if err != nil { + return nil, fmt.Errorf("convert length commitment to g2 point: %s", err) + } + + convertedLengthProof, err := bytesToBN254G2Point(inputCommitment.LengthProof) + if err != nil { + return nil, fmt.Errorf("convert length proof to g2 point: %s", err) + } + + return &verifierBindings.BlobCommitment{ + Commitment: *convertedCommitment, + LengthCommitment: *convertedLengthCommitment, + LengthProof: *convertedLengthProof, + DataLength: inputCommitment.Length, + }, nil +} + +func repeatedBytesToG1Points(repeatedBytes [][]byte) ([]verifierBindings.BN254G1Point, error) { + var outputPoints []verifierBindings.BN254G1Point + for _, bytes := range repeatedBytes { + g1Point, err := bytesToBN254G1Point(bytes) + if err != nil { + return nil, fmt.Errorf("deserialize g1 point: %s", err) + } + + outputPoints = append(outputPoints, *g1Point) + } + + return outputPoints, nil +} + +func bytesToBN254G1Point(bytes []byte) (*verifierBindings.BN254G1Point, error) { + g1Point, err := new(core.G1Point).Deserialize(bytes) + if err != nil { + return nil, fmt.Errorf("deserialize g1 point: %s", err) + } + + return &verifierBindings.BN254G1Point{ + X: g1Point.X.BigInt(new(big.Int)), + Y: g1Point.Y.BigInt(new(big.Int)), + }, nil +} + +func bytesToBN254G2Point(bytes []byte) (*verifierBindings.BN254G2Point, error) { + g2Point, err := new(core.G2Point).Deserialize(bytes) + if err != nil { + return nil, fmt.Errorf("deserialize g2 point: %s", err) + } + + var x [2]*big.Int + x[0] = g2Point.X.A0.BigInt(new(big.Int)) + x[1] = g2Point.X.A1.BigInt(new(big.Int)) + + var y [2]*big.Int + y[0] = g2Point.Y.A0.BigInt(new(big.Int)) + y[1] = g2Point.Y.A1.BigInt(new(big.Int)) + + return &verifierBindings.BN254G2Point{ + X: x, + Y: y, + }, nil +} From dcbcc07ef45a3f2bc8fd560403ce4e5c5c2e8c38 Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Mon, 6 Jan 2025 11:23:43 -0500 Subject: [PATCH 02/14] Try rearranging conversion methods Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 253 ++----------------- api/grpc/common/conversion_utils.go | 71 ++++++ api/grpc/common/v2/conversion_utils.go | 84 ++++++ api/grpc/disperser/v2/conversion_utils.go | 90 +++++++ 4 files changed, 271 insertions(+), 227 deletions(-) create mode 100644 api/grpc/common/conversion_utils.go create mode 100644 api/grpc/common/v2/conversion_utils.go create mode 100644 api/grpc/disperser/v2/conversion_utils.go diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go index 641a05230..ebbcf1ecd 100644 --- a/api/clients/v2/verification/blob_verifier.go +++ b/api/clients/v2/verification/blob_verifier.go @@ -3,16 +3,11 @@ package verification import ( "context" "fmt" - commonv1 "github.com/Layr-Labs/eigenda/api/grpc/common" - commonv2 "github.com/Layr-Labs/eigenda/api/grpc/common/v2" disperser "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" - "github.com/Layr-Labs/eigenda/core" "github.com/ethereum/go-ethereum/accounts/abi/bind" ethcommon "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/ethclient" - "math" - "math/big" ) // BlobVerifier is responsible for making eth calls to verify blobs that have been received by the client @@ -21,47 +16,59 @@ import ( type BlobVerifier struct { // the eth client that calls will be made to ethClient *ethclient.Client - // + // go binding around the verifyBlobV2FromSignedBatch ethereum contract blobVerifierCaller *verifierBindings.ContractEigenDABlobVerifierCaller } +// NewBlobVerifier constructs a BlobVerifier func NewBlobVerifier( +// the eth RPC URL that will be connected to in this constructor ethRpcUrl string, +// the hex address of the verifyBlobV2FromSignedBatch contract verifyBlobV2FromSignedBatchAddress string) (*BlobVerifier, error) { - client, err := ethclient.Dial(ethRpcUrl) + ethClient, err := ethclient.Dial(ethRpcUrl) if err != nil { - return nil, fmt.Errorf("failed to dial ETH RPC node: %s", err) + return nil, fmt.Errorf("dial ETH RPC node: %s", err) } - verifierCaller, err := verifierBindings.NewContractEigenDABlobVerifierCaller(ethcommon.HexToAddress(verifyBlobV2FromSignedBatchAddress), client) + verifierCaller, err := verifierBindings.NewContractEigenDABlobVerifierCaller( + ethcommon.HexToAddress(verifyBlobV2FromSignedBatchAddress), + ethClient) if err != nil { - client.Close() + ethClient.Close() return nil, fmt.Errorf("bind to verifier contract at %s: %s", verifyBlobV2FromSignedBatchAddress, err) } return &BlobVerifier{ - ethClient: client, + ethClient: ethClient, blobVerifierCaller: verifierCaller, }, nil } +// VerifyBlobV2FromSignedBatch makes a call to the verifyBlobV2FromSignedBatch contract +// +// This method returns nil if the blob is successfully verified. Otherwise, it returns an error. +// +// This method is not threadsafe. func (v *BlobVerifier) VerifyBlobV2FromSignedBatch( ctx context.Context, +// The signed batch that contains the blob being verified. This is obtained from the disperser, and is used +// to verify that the described blob actually exists in a valid batch. signedBatch *disperser.SignedBatch, +// Contains all necessary information about the blob, so that it can be verified. blobVerificationProof *disperser.BlobVerificationInfo, -) (bool, error) { - - convertedSignedBatch, err := convertSignedBatch(signedBatch) +) error { + convertedSignedBatch, err := signedBatch.ToBinding() if err != nil { - return false, fmt.Errorf("convert signed batch: %s", err) + return fmt.Errorf("convert signed batch: %s", err) } - convertedBlobVerificationProof, err := convertBlobVerificationProof(blobVerificationProof) + convertedBlobVerificationProof, err := blobVerificationProof.ToBinding() if err != nil { - return false, fmt.Errorf("convert blob verification proof: %s", err) + return fmt.Errorf("convert blob verification proof: %s", err) } err = v.blobVerifierCaller.VerifyBlobV2FromSignedBatch( @@ -70,221 +77,13 @@ func (v *BlobVerifier) VerifyBlobV2FromSignedBatch( *convertedBlobVerificationProof) if err != nil { - return false, fmt.Errorf("verify blob v2 from signed batch: %s", err) + return fmt.Errorf("verify blob v2 from signed batch: %s", err) } - return true, nil + return nil } // Close closes the eth client. This method is threadsafe. func (v *BlobVerifier) Close() { v.ethClient.Close() } - -func convertSignedBatch(inputSignedBatch *disperser.SignedBatch) (*verifierBindings.SignedBatch, error) { - - convertedBatchHeader, err := convertBatchHeader(inputSignedBatch.GetHeader()) - if err != nil { - return nil, fmt.Errorf("convert batch header: %s", err) - } - - convertedAttestation, err := convertAttestation(inputSignedBatch.Attestation) - if err != nil { - return nil, fmt.Errorf("convert attestation: %s", err) - } - - outputSignedBatch := &verifierBindings.SignedBatch{ - BatchHeader: *convertedBatchHeader, - Attestation: *convertedAttestation, - } - - return outputSignedBatch, nil -} - -func convertBatchHeader(inputBatchHeader *commonv2.BatchHeader) (*verifierBindings.BatchHeaderV2, error) { - var outputBatchRoot [32]byte - - inputBatchRoot := inputBatchHeader.GetBatchRoot() - if len(inputBatchRoot) != 32 { - return nil, fmt.Errorf("BatchRoot must be 32 bytes (length was %d)", len(inputBatchRoot)) - } - copy(outputBatchRoot[:], inputBatchRoot[:]) - - inputReferenceBlockNumber := inputBatchHeader.GetReferenceBlockNumber() - if inputReferenceBlockNumber > math.MaxUint32 { - return nil, fmt.Errorf( - "ReferenceBlockNumber overflow: value was %d, but max allowable value is %d", - inputReferenceBlockNumber, - math.MaxUint32) - } - - convertedHeader := &verifierBindings.BatchHeaderV2{ - BatchRoot: outputBatchRoot, - ReferenceBlockNumber: uint32(inputReferenceBlockNumber), - } - - return convertedHeader, nil -} - -func convertAttestation(inputAttestation *disperser.Attestation) (*verifierBindings.Attestation, error) { - nonSignerPubkeys, err := repeatedBytesToG1Points(inputAttestation.NonSignerPubkeys) - if err != nil { - return nil, fmt.Errorf("convert non signer pubkeys to g1 points: %s", err) - } - - quorumApks, err := repeatedBytesToG1Points(inputAttestation.QuorumApks) - if err != nil { - return nil, fmt.Errorf("convert quorum apks to g1 points: %s", err) - } - - sigma, err := bytesToBN254G1Point(inputAttestation.Sigma) - if err != nil { - return nil, fmt.Errorf("convert sigma to g1 point: %s", err) - } - - apkG2, err := bytesToBN254G2Point(inputAttestation.ApkG2) - if err != nil { - return nil, fmt.Errorf("convert apk g2 to g2 point: %s", err) - } - - convertedAttestation := &verifierBindings.Attestation{ - NonSignerPubkeys: nonSignerPubkeys, - QuorumApks: quorumApks, - Sigma: *sigma, - ApkG2: *apkG2, - QuorumNumbers: inputAttestation.QuorumNumbers, - } - - return convertedAttestation, nil -} - -func convertBlobVerificationProof(inputBlobVerificationProof *disperser.BlobVerificationInfo) (*verifierBindings.BlobVerificationProofV2, error) { - convertedBlobCertificate, err := convertBlobCertificate(inputBlobVerificationProof.BlobCertificate) - if err != nil { - return nil, fmt.Errorf("convert blob certificate: %s", err) - } - - return &verifierBindings.BlobVerificationProofV2{ - BlobCertificate: *convertedBlobCertificate, - BlobIndex: inputBlobVerificationProof.BlobIndex, - InclusionProof: inputBlobVerificationProof.InclusionProof, - }, nil -} - -func convertBlobCertificate(inputBlobCertificate *commonv2.BlobCertificate) (*verifierBindings.BlobCertificate, error) { - convertedBlobHeader, err := convertBlobHeader(inputBlobCertificate.GetBlobHeader()) - if err != nil { - return nil, fmt.Errorf("convert blob header: %s", err) - } - - return &verifierBindings.BlobCertificate{ - BlobHeader: *convertedBlobHeader, - RelayKeys: inputBlobCertificate.GetRelays(), - }, nil -} - -func convertBlobHeader(inputBlobHeader *commonv2.BlobHeader) (*verifierBindings.BlobHeaderV2, error) { - inputVersion := inputBlobHeader.Version - if inputVersion > math.MaxUint16 { - return nil, fmt.Errorf( - "version overflow: value was %d, but max allowable value is %d", - inputVersion, - math.MaxUint16) - } - - var quorumNumbers []byte - for _, quorumNumber := range inputBlobHeader.QuorumNumbers { - if quorumNumber > math.MaxUint8 { - return nil, fmt.Errorf("quorum number overflow: value was %d, but max allowable value is %d", quorumNumber, uint8(math.MaxUint8)) - } - - quorumNumbers = append(quorumNumbers, byte(quorumNumber)) - } - - convertedBlobCommitment, err := convertBlobCommitment(inputBlobHeader.Commitment) - if err != nil { - return nil, fmt.Errorf("convert blob commitment: %s", err) - } - - paymentHeaderHash, err := core.ConvertToPaymentMetadata(inputBlobHeader.PaymentHeader).Hash() - if err != nil { - return nil, fmt.Errorf("hash payment header: %s", err) - } - - return &verifierBindings.BlobHeaderV2{ - Version: uint16(inputVersion), - QuorumNumbers: quorumNumbers, - Commitment: *convertedBlobCommitment, - PaymentHeaderHash: paymentHeaderHash, - }, nil -} - -func convertBlobCommitment(inputCommitment *commonv1.BlobCommitment) (*verifierBindings.BlobCommitment, error) { - convertedCommitment, err := bytesToBN254G1Point(inputCommitment.Commitment) - if err != nil { - return nil, fmt.Errorf("convert commitment to g1 point: %s", err) - } - - convertedLengthCommitment, err := bytesToBN254G2Point(inputCommitment.LengthCommitment) - if err != nil { - return nil, fmt.Errorf("convert length commitment to g2 point: %s", err) - } - - convertedLengthProof, err := bytesToBN254G2Point(inputCommitment.LengthProof) - if err != nil { - return nil, fmt.Errorf("convert length proof to g2 point: %s", err) - } - - return &verifierBindings.BlobCommitment{ - Commitment: *convertedCommitment, - LengthCommitment: *convertedLengthCommitment, - LengthProof: *convertedLengthProof, - DataLength: inputCommitment.Length, - }, nil -} - -func repeatedBytesToG1Points(repeatedBytes [][]byte) ([]verifierBindings.BN254G1Point, error) { - var outputPoints []verifierBindings.BN254G1Point - for _, bytes := range repeatedBytes { - g1Point, err := bytesToBN254G1Point(bytes) - if err != nil { - return nil, fmt.Errorf("deserialize g1 point: %s", err) - } - - outputPoints = append(outputPoints, *g1Point) - } - - return outputPoints, nil -} - -func bytesToBN254G1Point(bytes []byte) (*verifierBindings.BN254G1Point, error) { - g1Point, err := new(core.G1Point).Deserialize(bytes) - if err != nil { - return nil, fmt.Errorf("deserialize g1 point: %s", err) - } - - return &verifierBindings.BN254G1Point{ - X: g1Point.X.BigInt(new(big.Int)), - Y: g1Point.Y.BigInt(new(big.Int)), - }, nil -} - -func bytesToBN254G2Point(bytes []byte) (*verifierBindings.BN254G2Point, error) { - g2Point, err := new(core.G2Point).Deserialize(bytes) - if err != nil { - return nil, fmt.Errorf("deserialize g2 point: %s", err) - } - - var x [2]*big.Int - x[0] = g2Point.X.A0.BigInt(new(big.Int)) - x[1] = g2Point.X.A1.BigInt(new(big.Int)) - - var y [2]*big.Int - y[0] = g2Point.Y.A0.BigInt(new(big.Int)) - y[1] = g2Point.Y.A1.BigInt(new(big.Int)) - - return &verifierBindings.BN254G2Point{ - X: x, - Y: y, - }, nil -} diff --git a/api/grpc/common/conversion_utils.go b/api/grpc/common/conversion_utils.go new file mode 100644 index 000000000..8ed1d1d02 --- /dev/null +++ b/api/grpc/common/conversion_utils.go @@ -0,0 +1,71 @@ +package common + +import ( + "fmt" + verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" + "github.com/consensys/gnark-crypto/ecc/bn254" + "math/big" +) + +// ToBinding converts a BlobCommitment into a contractEigenDABlobVerifier.BlobCommitment +func (c *BlobCommitment) ToBinding() (*verifierBindings.BlobCommitment, error) { + convertedCommitment, err := BytesToBN254G1Point(c.GetCommitment()) + if err != nil { + return nil, fmt.Errorf("convert commitment to g1 point: %s", err) + } + + convertedLengthCommitment, err := BytesToBN254G2Point(c.GetLengthCommitment()) + if err != nil { + return nil, fmt.Errorf("convert length commitment to g2 point: %s", err) + } + + convertedLengthProof, err := BytesToBN254G2Point(c.GetLengthProof()) + if err != nil { + return nil, fmt.Errorf("convert length proof to g2 point: %s", err) + } + + return &verifierBindings.BlobCommitment{ + Commitment: *convertedCommitment, + LengthCommitment: *convertedLengthCommitment, + LengthProof: *convertedLengthProof, + DataLength: c.GetLength(), + }, nil +} + +// BytesToBN254G1Point accepts a byte array, and converts it into a contractEigenDABlobVerifier.BN254G1Point +func BytesToBN254G1Point(bytes []byte) (*verifierBindings.BN254G1Point, error) { + var g1Point bn254.G1Affine + _, err := g1Point.SetBytes(bytes) + + if err != nil { + return nil, fmt.Errorf("deserialize g1 point: %s", err) + } + + return &verifierBindings.BN254G1Point{ + X: g1Point.X.BigInt(new(big.Int)), + Y: g1Point.Y.BigInt(new(big.Int)), + }, nil +} + +// BytesToBN254G2Point accepts a byte array, and converts it into a contractEigenDABlobVerifier.BN254G2Point +func BytesToBN254G2Point(bytes []byte) (*verifierBindings.BN254G2Point, error) { + var g2Point bn254.G2Affine + _, err := g2Point.SetBytes(bytes) + + if err != nil { + return nil, fmt.Errorf("deserialize g2 point: %s", err) + } + + var x [2]*big.Int + x[0] = g2Point.X.A0.BigInt(new(big.Int)) + x[1] = g2Point.X.A1.BigInt(new(big.Int)) + + var y [2]*big.Int + y[0] = g2Point.Y.A0.BigInt(new(big.Int)) + y[1] = g2Point.Y.A1.BigInt(new(big.Int)) + + return &verifierBindings.BN254G2Point{ + X: x, + Y: y, + }, nil +} diff --git a/api/grpc/common/v2/conversion_utils.go b/api/grpc/common/v2/conversion_utils.go new file mode 100644 index 000000000..a25a5ff7b --- /dev/null +++ b/api/grpc/common/v2/conversion_utils.go @@ -0,0 +1,84 @@ +package v2 + +import ( + "fmt" + verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" + "github.com/Layr-Labs/eigenda/core" + "math" +) + +// ToBinding converts a BatchHeader into a contractEigenDABlobVerifier.BatchHeaderV2 +func (h *BatchHeader) ToBinding() (*verifierBindings.BatchHeaderV2, error) { + var outputBatchRoot [32]byte + + inputBatchRoot := h.GetBatchRoot() + if len(inputBatchRoot) != 32 { + return nil, fmt.Errorf("BatchRoot must be 32 bytes (length was %d)", len(inputBatchRoot)) + } + copy(outputBatchRoot[:], inputBatchRoot[:]) + + inputReferenceBlockNumber := h.GetReferenceBlockNumber() + if inputReferenceBlockNumber > math.MaxUint32 { + return nil, fmt.Errorf( + "ReferenceBlockNumber overflow: value was %d, but max allowable value is %d", + inputReferenceBlockNumber, + math.MaxUint32) + } + + convertedHeader := &verifierBindings.BatchHeaderV2{ + BatchRoot: outputBatchRoot, + ReferenceBlockNumber: uint32(inputReferenceBlockNumber), + } + + return convertedHeader, nil +} + +// ToBinding converts a BlobCertificate into a contractEigenDABlobVerifier.BlobCertificate +func (c *BlobCertificate) ToBinding() (*verifierBindings.BlobCertificate, error) { + convertedBlobHeader, err := c.GetBlobHeader().toBinding() + if err != nil { + return nil, fmt.Errorf("convert blob header: %s", err) + } + + return &verifierBindings.BlobCertificate{ + BlobHeader: *convertedBlobHeader, + RelayKeys: c.GetRelays(), + }, nil +} + +// toBinding converts a BlobHeader into a contractEigenDABlobVerifier.BlobHeaderV2 +func (h *BlobHeader) toBinding() (*verifierBindings.BlobHeaderV2, error) { + inputVersion := h.GetVersion() + if inputVersion > math.MaxUint16 { + return nil, fmt.Errorf( + "version overflow: value was %d, but max allowable value is %d", + inputVersion, + math.MaxUint16) + } + + var quorumNumbers []byte + for _, quorumNumber := range h.GetQuorumNumbers() { + if quorumNumber > math.MaxUint8 { + return nil, fmt.Errorf("quorum number overflow: value was %d, but max allowable value is %d", quorumNumber, uint8(math.MaxUint8)) + } + + quorumNumbers = append(quorumNumbers, byte(quorumNumber)) + } + + convertedBlobCommitment, err := h.GetCommitment().ToBinding() + if err != nil { + return nil, fmt.Errorf("convert blob commitment: %s", err) + } + + paymentHeaderHash, err := core.ConvertToPaymentMetadata(h.GetPaymentHeader()).Hash() + if err != nil { + return nil, fmt.Errorf("hash payment header: %s", err) + } + + return &verifierBindings.BlobHeaderV2{ + Version: uint16(inputVersion), + QuorumNumbers: quorumNumbers, + Commitment: *convertedBlobCommitment, + PaymentHeaderHash: paymentHeaderHash, + }, nil +} diff --git a/api/grpc/disperser/v2/conversion_utils.go b/api/grpc/disperser/v2/conversion_utils.go new file mode 100644 index 000000000..fbeb08009 --- /dev/null +++ b/api/grpc/disperser/v2/conversion_utils.go @@ -0,0 +1,90 @@ +package v2 + +import ( + "fmt" + "github.com/Layr-Labs/eigenda/api/grpc/common" + verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" +) + +// ToBinding converts a SignedBatch into a contractEigenDABlobVerifier.SignedBatch +func (b *SignedBatch) ToBinding() (*verifierBindings.SignedBatch, error) { + convertedBatchHeader, err := b.GetHeader().ToBinding() + if err != nil { + return nil, fmt.Errorf("convert batch header: %s", err) + } + + convertedAttestation, err := b.GetAttestation().toBinding() + if err != nil { + return nil, fmt.Errorf("convert attestation: %s", err) + } + + outputSignedBatch := &verifierBindings.SignedBatch{ + BatchHeader: *convertedBatchHeader, + Attestation: *convertedAttestation, + } + + return outputSignedBatch, nil +} + +// toBinding converts an Attestation into a contractEigenDABlobVerifier.Attestation +func (a *Attestation) toBinding() (*verifierBindings.Attestation, error) { + nonSignerPubkeys, err := repeatedBytesToG1Points(a.GetNonSignerPubkeys()) + if err != nil { + return nil, fmt.Errorf("convert non signer pubkeys to g1 points: %s", err) + } + + quorumApks, err := repeatedBytesToG1Points(a.GetQuorumApks()) + if err != nil { + return nil, fmt.Errorf("convert quorum apks to g1 points: %s", err) + } + + sigma, err := common.BytesToBN254G1Point(a.GetSigma()) + if err != nil { + return nil, fmt.Errorf("convert sigma to g1 point: %s", err) + } + + apkG2, err := common.BytesToBN254G2Point(a.GetApkG2()) + if err != nil { + return nil, fmt.Errorf("convert apk g2 to g2 point: %s", err) + } + + convertedAttestation := &verifierBindings.Attestation{ + NonSignerPubkeys: nonSignerPubkeys, + QuorumApks: quorumApks, + Sigma: *sigma, + ApkG2: *apkG2, + QuorumNumbers: a.GetQuorumNumbers(), + } + + return convertedAttestation, nil +} + +// ToBinding converts a BlobVerificationInfo into a contractEigenDABlobVerifier.BlobVerificationProofV2 +func (i *BlobVerificationInfo) ToBinding() (*verifierBindings.BlobVerificationProofV2, error) { + convertedBlobCertificate, err := i.GetBlobCertificate().ToBinding() + + if err != nil { + return nil, fmt.Errorf("convert blob certificate: %s", err) + } + + return &verifierBindings.BlobVerificationProofV2{ + BlobCertificate: *convertedBlobCertificate, + BlobIndex: i.GetBlobIndex(), + InclusionProof: i.GetInclusionProof(), + }, nil +} + +// repeatedBytesToG1Points accepts an array of byte arrays, and returns an array of contractEigenDABlobVerifier.BN254G1Point +func repeatedBytesToG1Points(repeatedBytes [][]byte) ([]verifierBindings.BN254G1Point, error) { + var outputPoints []verifierBindings.BN254G1Point + for _, bytes := range repeatedBytes { + g1Point, err := common.BytesToBN254G1Point(bytes) + if err != nil { + return nil, fmt.Errorf("deserialize g1 point: %s", err) + } + + outputPoints = append(outputPoints, *g1Point) + } + + return outputPoints, nil +} From 2e99455b5f22d72eafc62d67e42a6faaaf18d199 Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Mon, 6 Jan 2025 13:18:46 -0500 Subject: [PATCH 03/14] Fix style Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 11 ++++++----- api/grpc/common/conversion_utils.go | 3 +-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go index ebbcf1ecd..a10655323 100644 --- a/api/clients/v2/verification/blob_verifier.go +++ b/api/clients/v2/verification/blob_verifier.go @@ -3,6 +3,7 @@ package verification import ( "context" "fmt" + disperser "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" "github.com/ethereum/go-ethereum/accounts/abi/bind" @@ -22,9 +23,9 @@ type BlobVerifier struct { // NewBlobVerifier constructs a BlobVerifier func NewBlobVerifier( -// the eth RPC URL that will be connected to in this constructor + // the eth RPC URL that will be connected to ethRpcUrl string, -// the hex address of the verifyBlobV2FromSignedBatch contract + // the hex address of the verifyBlobV2FromSignedBatch contract verifyBlobV2FromSignedBatchAddress string) (*BlobVerifier, error) { ethClient, err := ethclient.Dial(ethRpcUrl) @@ -55,10 +56,10 @@ func NewBlobVerifier( // This method is not threadsafe. func (v *BlobVerifier) VerifyBlobV2FromSignedBatch( ctx context.Context, -// The signed batch that contains the blob being verified. This is obtained from the disperser, and is used -// to verify that the described blob actually exists in a valid batch. + // The signed batch that contains the blob being verified. This is obtained from the disperser, and is used + // to verify that the described blob actually exists in a valid batch. signedBatch *disperser.SignedBatch, -// Contains all necessary information about the blob, so that it can be verified. + // Contains all necessary information about the blob, so that it can be verified. blobVerificationProof *disperser.BlobVerificationInfo, ) error { convertedSignedBatch, err := signedBatch.ToBinding() diff --git a/api/grpc/common/conversion_utils.go b/api/grpc/common/conversion_utils.go index 8ed1d1d02..8811a3079 100644 --- a/api/grpc/common/conversion_utils.go +++ b/api/grpc/common/conversion_utils.go @@ -56,11 +56,10 @@ func BytesToBN254G2Point(bytes []byte) (*verifierBindings.BN254G2Point, error) { return nil, fmt.Errorf("deserialize g2 point: %s", err) } - var x [2]*big.Int + var x, y [2]*big.Int x[0] = g2Point.X.A0.BigInt(new(big.Int)) x[1] = g2Point.X.A1.BigInt(new(big.Int)) - var y [2]*big.Int y[0] = g2Point.Y.A0.BigInt(new(big.Int)) y[1] = g2Point.Y.A1.BigInt(new(big.Int)) From 90e3e432c7fb2945b78430cae2c052df696cb52e Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Tue, 7 Jan 2025 10:04:59 -0500 Subject: [PATCH 04/14] Pass in eth client instead of connecting in constructor Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 30 ++++++-------------- 1 file changed, 9 insertions(+), 21 deletions(-) diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go index a10655323..63425571e 100644 --- a/api/clients/v2/verification/blob_verifier.go +++ b/api/clients/v2/verification/blob_verifier.go @@ -4,11 +4,12 @@ import ( "context" "fmt" + "github.com/Layr-Labs/eigenda/common" + disperser "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" "github.com/ethereum/go-ethereum/accounts/abi/bind" - ethcommon "github.com/ethereum/go-ethereum/common" - "github.com/ethereum/go-ethereum/ethclient" + gethcommon "github.com/ethereum/go-ethereum/common" ) // BlobVerifier is responsible for making eth calls to verify blobs that have been received by the client @@ -16,30 +17,22 @@ import ( // Blob verification is not threadsafe. type BlobVerifier struct { // the eth client that calls will be made to - ethClient *ethclient.Client + ethClient *common.EthClient // go binding around the verifyBlobV2FromSignedBatch ethereum contract blobVerifierCaller *verifierBindings.ContractEigenDABlobVerifierCaller } // NewBlobVerifier constructs a BlobVerifier func NewBlobVerifier( - // the eth RPC URL that will be connected to - ethRpcUrl string, - // the hex address of the verifyBlobV2FromSignedBatch contract - verifyBlobV2FromSignedBatchAddress string) (*BlobVerifier, error) { - - ethClient, err := ethclient.Dial(ethRpcUrl) - if err != nil { - return nil, fmt.Errorf("dial ETH RPC node: %s", err) - } + ethClient *common.EthClient, // the eth client, which should already be set up + verifyBlobV2FromSignedBatchAddress string, // the hex address of the verifyBlobV2FromSignedBatch contract +) (*BlobVerifier, error) { verifierCaller, err := verifierBindings.NewContractEigenDABlobVerifierCaller( - ethcommon.HexToAddress(verifyBlobV2FromSignedBatchAddress), - ethClient) + gethcommon.HexToAddress(verifyBlobV2FromSignedBatchAddress), + *ethClient) if err != nil { - ethClient.Close() - return nil, fmt.Errorf("bind to verifier contract at %s: %s", verifyBlobV2FromSignedBatchAddress, err) } @@ -83,8 +76,3 @@ func (v *BlobVerifier) VerifyBlobV2FromSignedBatch( return nil } - -// Close closes the eth client. This method is threadsafe. -func (v *BlobVerifier) Close() { - v.ethClient.Close() -} From 7c6984ec6924775393b3d3f2e8adb1c56b5e954a Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Tue, 7 Jan 2025 10:08:36 -0500 Subject: [PATCH 05/14] Sort imports Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/grpc/common/conversion_utils.go | 3 ++- api/grpc/common/v2/conversion_utils.go | 3 ++- api/grpc/disperser/v2/conversion_utils.go | 1 + 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/api/grpc/common/conversion_utils.go b/api/grpc/common/conversion_utils.go index 8811a3079..68c1499e8 100644 --- a/api/grpc/common/conversion_utils.go +++ b/api/grpc/common/conversion_utils.go @@ -2,9 +2,10 @@ package common import ( "fmt" + "math/big" + verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" "github.com/consensys/gnark-crypto/ecc/bn254" - "math/big" ) // ToBinding converts a BlobCommitment into a contractEigenDABlobVerifier.BlobCommitment diff --git a/api/grpc/common/v2/conversion_utils.go b/api/grpc/common/v2/conversion_utils.go index a25a5ff7b..6636c42ae 100644 --- a/api/grpc/common/v2/conversion_utils.go +++ b/api/grpc/common/v2/conversion_utils.go @@ -2,9 +2,10 @@ package v2 import ( "fmt" + "math" + verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" "github.com/Layr-Labs/eigenda/core" - "math" ) // ToBinding converts a BatchHeader into a contractEigenDABlobVerifier.BatchHeaderV2 diff --git a/api/grpc/disperser/v2/conversion_utils.go b/api/grpc/disperser/v2/conversion_utils.go index fbeb08009..bd5f2fc29 100644 --- a/api/grpc/disperser/v2/conversion_utils.go +++ b/api/grpc/disperser/v2/conversion_utils.go @@ -2,6 +2,7 @@ package v2 import ( "fmt" + "github.com/Layr-Labs/eigenda/api/grpc/common" verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" ) From ec56c396331ded9d636c6fae0305a1b8c0eec62b Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Tue, 7 Jan 2025 10:11:15 -0500 Subject: [PATCH 06/14] Remove unnecessary member Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 3 --- 1 file changed, 3 deletions(-) diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go index 63425571e..e5eaf535d 100644 --- a/api/clients/v2/verification/blob_verifier.go +++ b/api/clients/v2/verification/blob_verifier.go @@ -16,8 +16,6 @@ import ( // // Blob verification is not threadsafe. type BlobVerifier struct { - // the eth client that calls will be made to - ethClient *common.EthClient // go binding around the verifyBlobV2FromSignedBatch ethereum contract blobVerifierCaller *verifierBindings.ContractEigenDABlobVerifierCaller } @@ -37,7 +35,6 @@ func NewBlobVerifier( } return &BlobVerifier{ - ethClient: ethClient, blobVerifierCaller: verifierCaller, }, nil } From b44b1195763eddbaa5c5ff3ecca1d6827ca1621c Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Tue, 7 Jan 2025 10:15:59 -0500 Subject: [PATCH 07/14] Remove incorrect comment Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go index e5eaf535d..ab5214c7a 100644 --- a/api/clients/v2/verification/blob_verifier.go +++ b/api/clients/v2/verification/blob_verifier.go @@ -13,8 +13,6 @@ import ( ) // BlobVerifier is responsible for making eth calls to verify blobs that have been received by the client -// -// Blob verification is not threadsafe. type BlobVerifier struct { // go binding around the verifyBlobV2FromSignedBatch ethereum contract blobVerifierCaller *verifierBindings.ContractEigenDABlobVerifierCaller From 877729470dc02f45a1713aef4d27400d3836cdff Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Tue, 7 Jan 2025 10:28:51 -0500 Subject: [PATCH 08/14] Clean up comment Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 2 -- 1 file changed, 2 deletions(-) diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go index ab5214c7a..7d79ed016 100644 --- a/api/clients/v2/verification/blob_verifier.go +++ b/api/clients/v2/verification/blob_verifier.go @@ -40,8 +40,6 @@ func NewBlobVerifier( // VerifyBlobV2FromSignedBatch makes a call to the verifyBlobV2FromSignedBatch contract // // This method returns nil if the blob is successfully verified. Otherwise, it returns an error. -// -// This method is not threadsafe. func (v *BlobVerifier) VerifyBlobV2FromSignedBatch( ctx context.Context, // The signed batch that contains the blob being verified. This is obtained from the disperser, and is used From 2e79dc6f4fe7ab01ea1c6ca4da785b05df80fc7b Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Tue, 7 Jan 2025 11:34:28 -0500 Subject: [PATCH 09/14] Move utility as suggested in review Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 4 +- api/grpc/common/conversion_utils.go | 71 ------ api/grpc/common/v2/conversion_utils.go | 85 ------- api/grpc/disperser/v2/conversion_utils.go | 91 ------- .../EigenDABlobVerifier/conversion_utils.go | 227 ++++++++++++++++++ 5 files changed, 229 insertions(+), 249 deletions(-) delete mode 100644 api/grpc/common/conversion_utils.go delete mode 100644 api/grpc/common/v2/conversion_utils.go delete mode 100644 api/grpc/disperser/v2/conversion_utils.go create mode 100644 contracts/bindings/EigenDABlobVerifier/conversion_utils.go diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go index 7d79ed016..190373d34 100644 --- a/api/clients/v2/verification/blob_verifier.go +++ b/api/clients/v2/verification/blob_verifier.go @@ -48,12 +48,12 @@ func (v *BlobVerifier) VerifyBlobV2FromSignedBatch( // Contains all necessary information about the blob, so that it can be verified. blobVerificationProof *disperser.BlobVerificationInfo, ) error { - convertedSignedBatch, err := signedBatch.ToBinding() + convertedSignedBatch, err := verifierBindings.ConvertSignedBatch(signedBatch) if err != nil { return fmt.Errorf("convert signed batch: %s", err) } - convertedBlobVerificationProof, err := blobVerificationProof.ToBinding() + convertedBlobVerificationProof, err := verifierBindings.ConvertVerificationProof(blobVerificationProof) if err != nil { return fmt.Errorf("convert blob verification proof: %s", err) } diff --git a/api/grpc/common/conversion_utils.go b/api/grpc/common/conversion_utils.go deleted file mode 100644 index 68c1499e8..000000000 --- a/api/grpc/common/conversion_utils.go +++ /dev/null @@ -1,71 +0,0 @@ -package common - -import ( - "fmt" - "math/big" - - verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" - "github.com/consensys/gnark-crypto/ecc/bn254" -) - -// ToBinding converts a BlobCommitment into a contractEigenDABlobVerifier.BlobCommitment -func (c *BlobCommitment) ToBinding() (*verifierBindings.BlobCommitment, error) { - convertedCommitment, err := BytesToBN254G1Point(c.GetCommitment()) - if err != nil { - return nil, fmt.Errorf("convert commitment to g1 point: %s", err) - } - - convertedLengthCommitment, err := BytesToBN254G2Point(c.GetLengthCommitment()) - if err != nil { - return nil, fmt.Errorf("convert length commitment to g2 point: %s", err) - } - - convertedLengthProof, err := BytesToBN254G2Point(c.GetLengthProof()) - if err != nil { - return nil, fmt.Errorf("convert length proof to g2 point: %s", err) - } - - return &verifierBindings.BlobCommitment{ - Commitment: *convertedCommitment, - LengthCommitment: *convertedLengthCommitment, - LengthProof: *convertedLengthProof, - DataLength: c.GetLength(), - }, nil -} - -// BytesToBN254G1Point accepts a byte array, and converts it into a contractEigenDABlobVerifier.BN254G1Point -func BytesToBN254G1Point(bytes []byte) (*verifierBindings.BN254G1Point, error) { - var g1Point bn254.G1Affine - _, err := g1Point.SetBytes(bytes) - - if err != nil { - return nil, fmt.Errorf("deserialize g1 point: %s", err) - } - - return &verifierBindings.BN254G1Point{ - X: g1Point.X.BigInt(new(big.Int)), - Y: g1Point.Y.BigInt(new(big.Int)), - }, nil -} - -// BytesToBN254G2Point accepts a byte array, and converts it into a contractEigenDABlobVerifier.BN254G2Point -func BytesToBN254G2Point(bytes []byte) (*verifierBindings.BN254G2Point, error) { - var g2Point bn254.G2Affine - _, err := g2Point.SetBytes(bytes) - - if err != nil { - return nil, fmt.Errorf("deserialize g2 point: %s", err) - } - - var x, y [2]*big.Int - x[0] = g2Point.X.A0.BigInt(new(big.Int)) - x[1] = g2Point.X.A1.BigInt(new(big.Int)) - - y[0] = g2Point.Y.A0.BigInt(new(big.Int)) - y[1] = g2Point.Y.A1.BigInt(new(big.Int)) - - return &verifierBindings.BN254G2Point{ - X: x, - Y: y, - }, nil -} diff --git a/api/grpc/common/v2/conversion_utils.go b/api/grpc/common/v2/conversion_utils.go deleted file mode 100644 index 6636c42ae..000000000 --- a/api/grpc/common/v2/conversion_utils.go +++ /dev/null @@ -1,85 +0,0 @@ -package v2 - -import ( - "fmt" - "math" - - verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" - "github.com/Layr-Labs/eigenda/core" -) - -// ToBinding converts a BatchHeader into a contractEigenDABlobVerifier.BatchHeaderV2 -func (h *BatchHeader) ToBinding() (*verifierBindings.BatchHeaderV2, error) { - var outputBatchRoot [32]byte - - inputBatchRoot := h.GetBatchRoot() - if len(inputBatchRoot) != 32 { - return nil, fmt.Errorf("BatchRoot must be 32 bytes (length was %d)", len(inputBatchRoot)) - } - copy(outputBatchRoot[:], inputBatchRoot[:]) - - inputReferenceBlockNumber := h.GetReferenceBlockNumber() - if inputReferenceBlockNumber > math.MaxUint32 { - return nil, fmt.Errorf( - "ReferenceBlockNumber overflow: value was %d, but max allowable value is %d", - inputReferenceBlockNumber, - math.MaxUint32) - } - - convertedHeader := &verifierBindings.BatchHeaderV2{ - BatchRoot: outputBatchRoot, - ReferenceBlockNumber: uint32(inputReferenceBlockNumber), - } - - return convertedHeader, nil -} - -// ToBinding converts a BlobCertificate into a contractEigenDABlobVerifier.BlobCertificate -func (c *BlobCertificate) ToBinding() (*verifierBindings.BlobCertificate, error) { - convertedBlobHeader, err := c.GetBlobHeader().toBinding() - if err != nil { - return nil, fmt.Errorf("convert blob header: %s", err) - } - - return &verifierBindings.BlobCertificate{ - BlobHeader: *convertedBlobHeader, - RelayKeys: c.GetRelays(), - }, nil -} - -// toBinding converts a BlobHeader into a contractEigenDABlobVerifier.BlobHeaderV2 -func (h *BlobHeader) toBinding() (*verifierBindings.BlobHeaderV2, error) { - inputVersion := h.GetVersion() - if inputVersion > math.MaxUint16 { - return nil, fmt.Errorf( - "version overflow: value was %d, but max allowable value is %d", - inputVersion, - math.MaxUint16) - } - - var quorumNumbers []byte - for _, quorumNumber := range h.GetQuorumNumbers() { - if quorumNumber > math.MaxUint8 { - return nil, fmt.Errorf("quorum number overflow: value was %d, but max allowable value is %d", quorumNumber, uint8(math.MaxUint8)) - } - - quorumNumbers = append(quorumNumbers, byte(quorumNumber)) - } - - convertedBlobCommitment, err := h.GetCommitment().ToBinding() - if err != nil { - return nil, fmt.Errorf("convert blob commitment: %s", err) - } - - paymentHeaderHash, err := core.ConvertToPaymentMetadata(h.GetPaymentHeader()).Hash() - if err != nil { - return nil, fmt.Errorf("hash payment header: %s", err) - } - - return &verifierBindings.BlobHeaderV2{ - Version: uint16(inputVersion), - QuorumNumbers: quorumNumbers, - Commitment: *convertedBlobCommitment, - PaymentHeaderHash: paymentHeaderHash, - }, nil -} diff --git a/api/grpc/disperser/v2/conversion_utils.go b/api/grpc/disperser/v2/conversion_utils.go deleted file mode 100644 index bd5f2fc29..000000000 --- a/api/grpc/disperser/v2/conversion_utils.go +++ /dev/null @@ -1,91 +0,0 @@ -package v2 - -import ( - "fmt" - - "github.com/Layr-Labs/eigenda/api/grpc/common" - verifierBindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" -) - -// ToBinding converts a SignedBatch into a contractEigenDABlobVerifier.SignedBatch -func (b *SignedBatch) ToBinding() (*verifierBindings.SignedBatch, error) { - convertedBatchHeader, err := b.GetHeader().ToBinding() - if err != nil { - return nil, fmt.Errorf("convert batch header: %s", err) - } - - convertedAttestation, err := b.GetAttestation().toBinding() - if err != nil { - return nil, fmt.Errorf("convert attestation: %s", err) - } - - outputSignedBatch := &verifierBindings.SignedBatch{ - BatchHeader: *convertedBatchHeader, - Attestation: *convertedAttestation, - } - - return outputSignedBatch, nil -} - -// toBinding converts an Attestation into a contractEigenDABlobVerifier.Attestation -func (a *Attestation) toBinding() (*verifierBindings.Attestation, error) { - nonSignerPubkeys, err := repeatedBytesToG1Points(a.GetNonSignerPubkeys()) - if err != nil { - return nil, fmt.Errorf("convert non signer pubkeys to g1 points: %s", err) - } - - quorumApks, err := repeatedBytesToG1Points(a.GetQuorumApks()) - if err != nil { - return nil, fmt.Errorf("convert quorum apks to g1 points: %s", err) - } - - sigma, err := common.BytesToBN254G1Point(a.GetSigma()) - if err != nil { - return nil, fmt.Errorf("convert sigma to g1 point: %s", err) - } - - apkG2, err := common.BytesToBN254G2Point(a.GetApkG2()) - if err != nil { - return nil, fmt.Errorf("convert apk g2 to g2 point: %s", err) - } - - convertedAttestation := &verifierBindings.Attestation{ - NonSignerPubkeys: nonSignerPubkeys, - QuorumApks: quorumApks, - Sigma: *sigma, - ApkG2: *apkG2, - QuorumNumbers: a.GetQuorumNumbers(), - } - - return convertedAttestation, nil -} - -// ToBinding converts a BlobVerificationInfo into a contractEigenDABlobVerifier.BlobVerificationProofV2 -func (i *BlobVerificationInfo) ToBinding() (*verifierBindings.BlobVerificationProofV2, error) { - convertedBlobCertificate, err := i.GetBlobCertificate().ToBinding() - - if err != nil { - return nil, fmt.Errorf("convert blob certificate: %s", err) - } - - return &verifierBindings.BlobVerificationProofV2{ - BlobCertificate: *convertedBlobCertificate, - BlobIndex: i.GetBlobIndex(), - InclusionProof: i.GetInclusionProof(), - }, nil -} - -// repeatedBytesToG1Points accepts an array of byte arrays, and returns an array of contractEigenDABlobVerifier.BN254G1Point -func repeatedBytesToG1Points(repeatedBytes [][]byte) ([]verifierBindings.BN254G1Point, error) { - var outputPoints []verifierBindings.BN254G1Point - for _, bytes := range repeatedBytes { - g1Point, err := common.BytesToBN254G1Point(bytes) - if err != nil { - return nil, fmt.Errorf("deserialize g1 point: %s", err) - } - - outputPoints = append(outputPoints, *g1Point) - } - - return outputPoints, nil -} diff --git a/contracts/bindings/EigenDABlobVerifier/conversion_utils.go b/contracts/bindings/EigenDABlobVerifier/conversion_utils.go new file mode 100644 index 000000000..164256ee1 --- /dev/null +++ b/contracts/bindings/EigenDABlobVerifier/conversion_utils.go @@ -0,0 +1,227 @@ +package contractEigenDABlobVerifier + +import ( + "fmt" + "math" + "math/big" + + "github.com/Layr-Labs/eigenda/api/grpc/common" + commonv2 "github.com/Layr-Labs/eigenda/api/grpc/common/v2" + disperserv2 "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" + "github.com/Layr-Labs/eigenda/core" + "github.com/consensys/gnark-crypto/ecc/bn254" +) + +func ConvertSignedBatch(inputBatch *disperserv2.SignedBatch) (*SignedBatch, error) { + convertedBatchHeader, err := convertBatchHeader(inputBatch.GetHeader()) + if err != nil { + return nil, fmt.Errorf("convert batch header: %s", err) + } + + convertedAttestation, err := convertAttestation(inputBatch.GetAttestation()) + if err != nil { + return nil, fmt.Errorf("convert attestation: %s", err) + } + + outputSignedBatch := &SignedBatch{ + BatchHeader: *convertedBatchHeader, + Attestation: *convertedAttestation, + } + + return outputSignedBatch, nil +} + +func convertBatchHeader(inputHeader *commonv2.BatchHeader) (*BatchHeaderV2, error) { + var outputBatchRoot [32]byte + + inputBatchRoot := inputHeader.GetBatchRoot() + if len(inputBatchRoot) != 32 { + return nil, fmt.Errorf("BatchRoot must be 32 bytes (length was %d)", len(inputBatchRoot)) + } + copy(outputBatchRoot[:], inputBatchRoot[:]) + + inputReferenceBlockNumber := inputHeader.GetReferenceBlockNumber() + if inputReferenceBlockNumber > math.MaxUint32 { + return nil, fmt.Errorf( + "ReferenceBlockNumber overflow: value was %d, but max allowable value is %d", + inputReferenceBlockNumber, + math.MaxUint32) + } + + convertedHeader := &BatchHeaderV2{ + BatchRoot: outputBatchRoot, + ReferenceBlockNumber: uint32(inputReferenceBlockNumber), + } + + return convertedHeader, nil +} + +func convertAttestation(inputAttestation *disperserv2.Attestation) (*Attestation, error) { + nonSignerPubkeys, err := repeatedBytesToG1Points(inputAttestation.GetNonSignerPubkeys()) + if err != nil { + return nil, fmt.Errorf("convert non signer pubkeys to g1 points: %s", err) + } + + quorumApks, err := repeatedBytesToG1Points(inputAttestation.GetQuorumApks()) + if err != nil { + return nil, fmt.Errorf("convert quorum apks to g1 points: %s", err) + } + + sigma, err := bytesToBN254G1Point(inputAttestation.GetSigma()) + if err != nil { + return nil, fmt.Errorf("convert sigma to g1 point: %s", err) + } + + apkG2, err := bytesToBN254G2Point(inputAttestation.GetApkG2()) + if err != nil { + return nil, fmt.Errorf("convert apk g2 to g2 point: %s", err) + } + + convertedAttestation := &Attestation{ + NonSignerPubkeys: nonSignerPubkeys, + QuorumApks: quorumApks, + Sigma: *sigma, + ApkG2: *apkG2, + QuorumNumbers: inputAttestation.GetQuorumNumbers(), + } + + return convertedAttestation, nil +} + +func ConvertVerificationProof(inputVerificationInfo *disperserv2.BlobVerificationInfo) (*BlobVerificationProofV2, error) { + convertedBlobCertificate, err := convertBlobCertificate(inputVerificationInfo.GetBlobCertificate()) + + if err != nil { + return nil, fmt.Errorf("convert blob certificate: %s", err) + } + + return &BlobVerificationProofV2{ + BlobCertificate: *convertedBlobCertificate, + BlobIndex: inputVerificationInfo.GetBlobIndex(), + InclusionProof: inputVerificationInfo.GetInclusionProof(), + }, nil +} + +func convertBlobCertificate(inputCertificate *commonv2.BlobCertificate) (*BlobCertificate, error) { + convertedBlobHeader, err := convertBlobHeader(inputCertificate.GetBlobHeader()) + if err != nil { + return nil, fmt.Errorf("convert blob header: %s", err) + } + + return &BlobCertificate{ + BlobHeader: *convertedBlobHeader, + RelayKeys: inputCertificate.GetRelays(), + }, nil +} + +func convertBlobHeader(inputHeader *commonv2.BlobHeader) (*BlobHeaderV2, error) { + inputVersion := inputHeader.GetVersion() + if inputVersion > math.MaxUint16 { + return nil, fmt.Errorf( + "version overflow: value was %d, but max allowable value is %d", + inputVersion, + math.MaxUint16) + } + + var quorumNumbers []byte + for _, quorumNumber := range inputHeader.GetQuorumNumbers() { + if quorumNumber > math.MaxUint8 { + return nil, fmt.Errorf( + "quorum number overflow: value was %d, but max allowable value is %d", + quorumNumber, + uint8(math.MaxUint8)) + } + + quorumNumbers = append(quorumNumbers, byte(quorumNumber)) + } + + convertedBlobCommitment, err := convertBlobCommitment(inputHeader.GetCommitment()) + if err != nil { + return nil, fmt.Errorf("convert blob commitment: %s", err) + } + + paymentHeaderHash, err := core.ConvertToPaymentMetadata(inputHeader.GetPaymentHeader()).Hash() + if err != nil { + return nil, fmt.Errorf("hash payment header: %s", err) + } + + return &BlobHeaderV2{ + Version: uint16(inputVersion), + QuorumNumbers: quorumNumbers, + Commitment: *convertedBlobCommitment, + PaymentHeaderHash: paymentHeaderHash, + }, nil +} + +func convertBlobCommitment(inputCommitment *common.BlobCommitment) (*BlobCommitment, error) { + convertedCommitment, err := bytesToBN254G1Point(inputCommitment.GetCommitment()) + if err != nil { + return nil, fmt.Errorf("convert commitment to g1 point: %s", err) + } + + convertedLengthCommitment, err := bytesToBN254G2Point(inputCommitment.GetLengthCommitment()) + if err != nil { + return nil, fmt.Errorf("convert length commitment to g2 point: %s", err) + } + + convertedLengthProof, err := bytesToBN254G2Point(inputCommitment.GetLengthProof()) + if err != nil { + return nil, fmt.Errorf("convert length proof to g2 point: %s", err) + } + + return &BlobCommitment{ + Commitment: *convertedCommitment, + LengthCommitment: *convertedLengthCommitment, + LengthProof: *convertedLengthProof, + DataLength: inputCommitment.GetLength(), + }, nil +} + +func bytesToBN254G1Point(bytes []byte) (*BN254G1Point, error) { + var g1Point bn254.G1Affine + _, err := g1Point.SetBytes(bytes) + + if err != nil { + return nil, fmt.Errorf("deserialize g1 point: %s", err) + } + + return &BN254G1Point{ + X: g1Point.X.BigInt(new(big.Int)), + Y: g1Point.Y.BigInt(new(big.Int)), + }, nil +} + +func bytesToBN254G2Point(bytes []byte) (*BN254G2Point, error) { + var g2Point bn254.G2Affine + _, err := g2Point.SetBytes(bytes) + + if err != nil { + return nil, fmt.Errorf("deserialize g2 point: %s", err) + } + + var x, y [2]*big.Int + x[0] = g2Point.X.A0.BigInt(new(big.Int)) + x[1] = g2Point.X.A1.BigInt(new(big.Int)) + + y[0] = g2Point.Y.A0.BigInt(new(big.Int)) + y[1] = g2Point.Y.A1.BigInt(new(big.Int)) + + return &BN254G2Point{ + X: x, + Y: y, + }, nil +} + +func repeatedBytesToG1Points(repeatedBytes [][]byte) ([]BN254G1Point, error) { + var outputPoints []BN254G1Point + for _, bytes := range repeatedBytes { + g1Point, err := bytesToBN254G1Point(bytes) + if err != nil { + return nil, fmt.Errorf("deserialize g1 point: %s", err) + } + + outputPoints = append(outputPoints, *g1Point) + } + + return outputPoints, nil +} From ca8d9d74a74b847b885a233185e44ab3661f49ba Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Tue, 7 Jan 2025 12:48:44 -0500 Subject: [PATCH 10/14] Fix doc terminology Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go index 190373d34..069be5234 100644 --- a/api/clients/v2/verification/blob_verifier.go +++ b/api/clients/v2/verification/blob_verifier.go @@ -12,24 +12,25 @@ import ( gethcommon "github.com/ethereum/go-ethereum/common" ) -// BlobVerifier is responsible for making eth calls to verify blobs that have been received by the client +// BlobVerifier is responsible for making eth calls against the BlobVerifier contract to ensure cryptographic and +// structural integrity of V2 certificates type BlobVerifier struct { - // go binding around the verifyBlobV2FromSignedBatch ethereum contract + // go binding around the EigenDABlobVerifier ethereum contract blobVerifierCaller *verifierBindings.ContractEigenDABlobVerifierCaller } // NewBlobVerifier constructs a BlobVerifier func NewBlobVerifier( - ethClient *common.EthClient, // the eth client, which should already be set up - verifyBlobV2FromSignedBatchAddress string, // the hex address of the verifyBlobV2FromSignedBatch contract + ethClient *common.EthClient, // the eth client, which should already be set up + blobVerifierAddress string, // the hex address of the EigenDABlobVerifier contract ) (*BlobVerifier, error) { verifierCaller, err := verifierBindings.NewContractEigenDABlobVerifierCaller( - gethcommon.HexToAddress(verifyBlobV2FromSignedBatchAddress), + gethcommon.HexToAddress(blobVerifierAddress), *ethClient) if err != nil { - return nil, fmt.Errorf("bind to verifier contract at %s: %s", verifyBlobV2FromSignedBatchAddress, err) + return nil, fmt.Errorf("bind to verifier contract at %s: %s", blobVerifierAddress, err) } return &BlobVerifier{ @@ -37,7 +38,7 @@ func NewBlobVerifier( }, nil } -// VerifyBlobV2FromSignedBatch makes a call to the verifyBlobV2FromSignedBatch contract +// VerifyBlobV2FromSignedBatch calls the verifyBlobV2FromSignedBatch view function on the EigenDABlobVerifier contract // // This method returns nil if the blob is successfully verified. Otherwise, it returns an error. func (v *BlobVerifier) VerifyBlobV2FromSignedBatch( From c752e5b1b186773cac3bd541d88e5f40d5a13a7e Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Tue, 7 Jan 2025 16:05:12 -0500 Subject: [PATCH 11/14] Mention timeout responsiblity Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go index 069be5234..2d57dc68b 100644 --- a/api/clients/v2/verification/blob_verifier.go +++ b/api/clients/v2/verification/blob_verifier.go @@ -41,6 +41,8 @@ func NewBlobVerifier( // VerifyBlobV2FromSignedBatch calls the verifyBlobV2FromSignedBatch view function on the EigenDABlobVerifier contract // // This method returns nil if the blob is successfully verified. Otherwise, it returns an error. +// +// It is the responsibility of the caller to configure a timeout on the ctx, if a timeout is required. func (v *BlobVerifier) VerifyBlobV2FromSignedBatch( ctx context.Context, // The signed batch that contains the blob being verified. This is obtained from the disperser, and is used From f43c7cebdc7b4f3b8e98790a70a46574bf68a5c8 Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Wed, 8 Jan 2025 09:44:45 -0500 Subject: [PATCH 12/14] Add additional comment Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- contracts/bindings/EigenDABlobVerifier/conversion_utils.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/bindings/EigenDABlobVerifier/conversion_utils.go b/contracts/bindings/EigenDABlobVerifier/conversion_utils.go index 164256ee1..73e99c196 100644 --- a/contracts/bindings/EigenDABlobVerifier/conversion_utils.go +++ b/contracts/bindings/EigenDABlobVerifier/conversion_utils.go @@ -193,6 +193,8 @@ func bytesToBN254G1Point(bytes []byte) (*BN254G1Point, error) { func bytesToBN254G2Point(bytes []byte) (*BN254G2Point, error) { var g2Point bn254.G2Affine + + // SetBytes checks that the result is in the correct subgroup _, err := g2Point.SetBytes(bytes) if err != nil { From 66249bcaece421283828f8d8652538238d55fc39 Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:00:33 -0500 Subject: [PATCH 13/14] Fix int ordering for G2 points Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- .../bindings/EigenDABlobVerifier/conversion_utils.go | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/contracts/bindings/EigenDABlobVerifier/conversion_utils.go b/contracts/bindings/EigenDABlobVerifier/conversion_utils.go index 73e99c196..9789387ff 100644 --- a/contracts/bindings/EigenDABlobVerifier/conversion_utils.go +++ b/contracts/bindings/EigenDABlobVerifier/conversion_utils.go @@ -202,11 +202,13 @@ func bytesToBN254G2Point(bytes []byte) (*BN254G2Point, error) { } var x, y [2]*big.Int - x[0] = g2Point.X.A0.BigInt(new(big.Int)) - x[1] = g2Point.X.A1.BigInt(new(big.Int)) + // Order is intentionally reversed when constructing BN254G2Point + // (see https://github.com/Layr-Labs/eigenlayer-middleware/blob/512ce7326f35e8060b9d46e23f9c159c0000b546/src/libraries/BN254.sol#L43) + x[0] = g2Point.X.A1.BigInt(new(big.Int)) + x[1] = g2Point.X.A0.BigInt(new(big.Int)) - y[0] = g2Point.Y.A0.BigInt(new(big.Int)) - y[1] = g2Point.Y.A1.BigInt(new(big.Int)) + y[0] = g2Point.Y.A1.BigInt(new(big.Int)) + y[1] = g2Point.Y.A0.BigInt(new(big.Int)) return &BN254G2Point{ X: x, From 8bba429aea90afe9366b87d94cb961c6eac459b4 Mon Sep 17 00:00:00 2001 From: litt3 <102969658+litt3@users.noreply.github.com> Date: Thu, 9 Jan 2025 11:04:54 -0500 Subject: [PATCH 14/14] Add link to verifier contract Signed-off-by: litt3 <102969658+litt3@users.noreply.github.com> --- api/clients/v2/verification/blob_verifier.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/api/clients/v2/verification/blob_verifier.go b/api/clients/v2/verification/blob_verifier.go index 2d57dc68b..d6a11d350 100644 --- a/api/clients/v2/verification/blob_verifier.go +++ b/api/clients/v2/verification/blob_verifier.go @@ -14,6 +14,8 @@ import ( // BlobVerifier is responsible for making eth calls against the BlobVerifier contract to ensure cryptographic and // structural integrity of V2 certificates +// +// The blob verifier contract is located at https://github.com/Layr-Labs/eigenda/blob/master/contracts/src/core/EigenDABlobVerifier.sol type BlobVerifier struct { // go binding around the EigenDABlobVerifier ethereum contract blobVerifierCaller *verifierBindings.ContractEigenDABlobVerifierCaller