From a8c05022b0fccb1c14539c04999144aa72937c4a Mon Sep 17 00:00:00 2001 From: Ian Shim Date: Wed, 11 Dec 2024 18:28:11 -0800 Subject: [PATCH] inabox v2 verifyblob --- contracts/script/SetUpEigenDA.s.sol | 1 + inabox/deploy/config_types.go | 1 + inabox/tests/integration_suite_test.go | 4 + inabox/tests/integration_v2_test.go | 225 +++++++++++++++++++++++-- 4 files changed, 220 insertions(+), 11 deletions(-) diff --git a/contracts/script/SetUpEigenDA.s.sol b/contracts/script/SetUpEigenDA.s.sol index 8fef32148a..f2d555df76 100644 --- a/contracts/script/SetUpEigenDA.s.sol +++ b/contracts/script/SetUpEigenDA.s.sol @@ -179,6 +179,7 @@ contract SetupEigenDA is EigenDADeployer, EigenLayerUtils { vm.serializeAddress(output, "operatorStateRetriever", address(operatorStateRetriever)); vm.serializeAddress(output, "blsApkRegistry" , address(apkRegistry)); vm.serializeAddress(output, "registryCoordinator", address(registryCoordinator)); + vm.serializeAddress(output, "blobVerifier", address(eigenDABlobVerifier)); string memory finalJson = vm.serializeString(output, "object", output); diff --git a/inabox/deploy/config_types.go b/inabox/deploy/config_types.go index 2d1f04d5ef..eec02c0d95 100644 --- a/inabox/deploy/config_types.go +++ b/inabox/deploy/config_types.go @@ -103,6 +103,7 @@ type EigenDAContract struct { OperatorStateRetreiver string `json:"operatorStateRetriever"` BlsApkRegistry string `json:"blsApkRegistry"` RegistryCoordinator string `json:"registryCoordinator"` + BlobVerifier string `json:"blobVerifier"` } type Stakes struct { diff --git a/inabox/tests/integration_suite_test.go b/inabox/tests/integration_suite_test.go index 9eb1703e87..a4f4422709 100644 --- a/inabox/tests/integration_suite_test.go +++ b/inabox/tests/integration_suite_test.go @@ -14,6 +14,7 @@ import ( clientsv2 "github.com/Layr-Labs/eigenda/api/clients/v2" "github.com/Layr-Labs/eigenda/common" "github.com/Layr-Labs/eigenda/common/geth" + verifierbindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" rollupbindings "github.com/Layr-Labs/eigenda/contracts/bindings/MockRollup" "github.com/Layr-Labs/eigenda/core" "github.com/Layr-Labs/eigenda/core/eth" @@ -47,6 +48,7 @@ var ( ethClient common.EthClient rpcClient common.RPCEthClient mockRollup *rollupbindings.ContractMockRollup + verifierContract *verifierbindings.ContractEigenDABlobVerifier retrievalClient clients.RetrievalClient retrievalClientV2 clientsv2.RetrievalClient numConfirmations int = 3 @@ -137,6 +139,8 @@ var _ = BeforeSuite(func() { mockRollup, err = rollupbindings.NewContractMockRollup(gcommon.HexToAddress(testConfig.MockRollup), ethClient) Expect(err).To(BeNil()) + verifierContract, err = verifierbindings.NewContractEigenDABlobVerifier(gcommon.HexToAddress(testConfig.EigenDA.BlobVerifier), ethClient) + Expect(err).To(BeNil()) err = setupRetrievalClient(testConfig) Expect(err).To(BeNil()) } diff --git a/inabox/tests/integration_v2_test.go b/inabox/tests/integration_v2_test.go index c020e62535..a860e4c82e 100644 --- a/inabox/tests/integration_v2_test.go +++ b/inabox/tests/integration_v2_test.go @@ -4,16 +4,19 @@ import ( "bytes" "context" "crypto/rand" + "fmt" + "math/big" "time" "github.com/Layr-Labs/eigenda/api/clients/v2" - commonpb "github.com/Layr-Labs/eigenda/api/grpc/common/v2" disperserpb "github.com/Layr-Labs/eigenda/api/grpc/disperser/v2" + verifierbindings "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDABlobVerifier" "github.com/Layr-Labs/eigenda/core" auth "github.com/Layr-Labs/eigenda/core/auth/v2" corev2 "github.com/Layr-Labs/eigenda/core/v2" dispv2 "github.com/Layr-Labs/eigenda/disperser/common/v2" "github.com/Layr-Labs/eigenda/encoding/utils/codec" + "github.com/ethereum/go-ethereum/accounts/abi/bind" . "github.com/onsi/ginkgo/v2" . "github.com/onsi/gomega" "github.com/wealdtech/go-merkletree/v2" @@ -64,8 +67,10 @@ var _ = Describe("Inabox v2 Integration", func() { var reply2 *disperserpb.BlobStatusReply var blobCert1 *corev2.BlobCertificate var blobCert2 *corev2.BlobCertificate - var batchHeader1 *commonpb.BatchHeader - var batchHeader2 *commonpb.BatchHeader + var signedBatch1 *disperserpb.SignedBatch + var signedBatch2 *disperserpb.SignedBatch + var blobVerification1 *disperserpb.BlobVerificationInfo + var blobVerification2 *disperserpb.BlobVerificationInfo for loop := true; loop; { select { case <-ctx.Done(): @@ -87,7 +92,8 @@ var _ = Describe("Inabox v2 Integration", func() { continue } - batchHeader1 = reply1.GetSignedBatch().GetHeader() + signedBatch1 = reply1.GetSignedBatch() + batchHeader1 := signedBatch1.GetHeader() Expect(batchHeader1).To(Not(BeNil())) Expect(batchHeader1.GetBatchRoot()).To(Not(BeNil())) Expect(batchHeader1.GetReferenceBlockNumber()).To(BeNumerically(">", 0)) @@ -103,8 +109,8 @@ var _ = Describe("Inabox v2 Integration", func() { Expect(blobVerification.GetBlobCertificate()).To(Not(BeNil())) blobCert1, err = corev2.BlobCertificateFromProtobuf(blobVerification.GetBlobCertificate()) Expect(err).To(BeNil()) - inclusionProofBytes := blobVerification.GetInclusionProof() - blobIndex := blobVerification.GetBlobIndex() + inclusionProofBytes := blobVerification1.GetInclusionProof() + blobIndex := blobVerification1.GetBlobIndex() proof, err := core.DeserializeMerkleProof(inclusionProofBytes, uint64(blobIndex)) Expect(err).To(BeNil()) certHash, err := blobCert1.Hash() @@ -115,7 +121,8 @@ var _ = Describe("Inabox v2 Integration", func() { Expect(err).To(BeNil()) Expect(verified).To(BeTrue()) - batchHeader2 = reply2.GetSignedBatch().GetHeader() + signedBatch2 = reply2.GetSignedBatch() + batchHeader2 := signedBatch2.GetHeader() Expect(batchHeader2).To(Not(BeNil())) Expect(batchHeader2.GetBatchRoot()).To(Not(BeNil())) Expect(batchHeader2.GetReferenceBlockNumber()).To(BeNumerically(">", 0)) @@ -131,8 +138,8 @@ var _ = Describe("Inabox v2 Integration", func() { Expect(blobVerification.GetBlobCertificate()).To(Not(BeNil())) blobCert2, err = corev2.BlobCertificateFromProtobuf(blobVerification.GetBlobCertificate()) Expect(err).To(BeNil()) - inclusionProofBytes = blobVerification.GetInclusionProof() - blobIndex = blobVerification.GetBlobIndex() + inclusionProofBytes = blobVerification2.GetInclusionProof() + blobIndex = blobVerification2.GetBlobIndex() proof, err = core.DeserializeMerkleProof(inclusionProofBytes, uint64(blobIndex)) Expect(err).To(BeNil()) certHash, err = blobCert2.Hash() @@ -140,12 +147,62 @@ var _ = Describe("Inabox v2 Integration", func() { verified, err = merkletree.VerifyProofUsing(certHash[:], false, proof, [][]byte{batchHeader2.BatchRoot}, keccak256.New()) Expect(err).To(BeNil()) Expect(verified).To(BeTrue()) - // TODO(ian-shim): verify the blob onchain using a mock rollup contract loop = false } } - // Test retrieval from relay + // necessary to ensure that reference block number < current block number + mineAnvilBlocks(1) + + // test onchain verification + batchHeader1 := signedBatch1.GetHeader() + attestation, err := convertAttestation(signedBatch1.GetAttestation()) + Expect(err).To(BeNil()) + proof, err := convertBlobVerificationInfo(blobVerification1) + Expect(err).To(BeNil()) + deserializedProof, err := core.DeserializeMerkleProof(proof.InclusionProof, uint64(proof.BlobIndex)) + Expect(err).To(BeNil()) + certHash, err := blobCert1.Hash() + Expect(err).To(BeNil()) + verified, err := merkletree.VerifyProofUsing(certHash[:], false, deserializedProof, [][]byte{batchHeader1.BatchRoot}, keccak256.New()) + Expect(err).To(BeNil()) + Expect(verified).To(BeTrue()) + + var batchRoot [32]byte + copy(batchRoot[:], batchHeader1.BatchRoot) + err = verifierContract.VerifyBlobV2FromSignedBatch( + &bind.CallOpts{}, + verifierbindings.SignedBatch{ + BatchHeader: verifierbindings.BatchHeaderV2{ + BatchRoot: batchRoot, + ReferenceBlockNumber: uint32(batchHeader1.ReferenceBlockNumber), + }, + Attestation: *attestation, + }, + *proof, + ) + Expect(err).To(BeNil()) + + batchHeader2 := signedBatch2.GetHeader() + attestation, err = convertAttestation(signedBatch2.GetAttestation()) + Expect(err).To(BeNil()) + proof, err = convertBlobVerificationInfo(blobVerification2) + Expect(err).To(BeNil()) + copy(batchRoot[:], batchHeader2.BatchRoot) + err = verifierContract.VerifyBlobV2FromSignedBatch( + &bind.CallOpts{}, + verifierbindings.SignedBatch{ + BatchHeader: verifierbindings.BatchHeaderV2{ + BatchRoot: batchRoot, + ReferenceBlockNumber: uint32(batchHeader2.ReferenceBlockNumber), + }, + Attestation: *attestation, + }, + *proof, + ) + Expect(err).To(BeNil()) + + // test retrieval from relay relayClient, err := clients.NewRelayClient(&clients.RelayClientConfig{ Sockets: relays, }, logger) @@ -177,6 +234,7 @@ var _ = Describe("Inabox v2 Integration", func() { } } + // Test retrieval from DA network b, err := retrievalClientV2.GetBlob(ctx, blobCert1.BlobHeader, batchHeader1.ReferenceBlockNumber, 0) Expect(err).To(BeNil()) restored := bytes.TrimRight(b, "\x00") @@ -195,3 +253,148 @@ var _ = Describe("Inabox v2 Integration", func() { Expect(restored).To(BeNil()) }) }) + +func convertBlobVerificationInfo(verificationInfo *disperserpb.BlobVerificationInfo) (*verifierbindings.BlobVerificationProofV2, error) { + blobCertificate, err := corev2.BlobCertificateFromProtobuf(verificationInfo.GetBlobCertificate()) + if err != nil { + return nil, err + } + paymentHeaderHash, err := blobCertificate.BlobHeader.PaymentMetadata.Hash() + if err != nil { + return nil, err + } + + inclusionProof := verificationInfo.GetInclusionProof() + blobIndex := verificationInfo.GetBlobIndex() + + commitX := big.NewInt(0) + blobCertificate.BlobHeader.BlobCommitments.Commitment.X.BigInt(commitX) + commitY := big.NewInt(0) + blobCertificate.BlobHeader.BlobCommitments.Commitment.Y.BigInt(commitY) + lengthCommitX0 := big.NewInt(0) + blobCertificate.BlobHeader.BlobCommitments.LengthCommitment.X.A0.BigInt(lengthCommitX0) + lengthCommitX1 := big.NewInt(0) + blobCertificate.BlobHeader.BlobCommitments.LengthCommitment.X.A1.BigInt(lengthCommitX1) + lengthCommitY0 := big.NewInt(0) + blobCertificate.BlobHeader.BlobCommitments.LengthCommitment.Y.A0.BigInt(lengthCommitY0) + lengthCommitY1 := big.NewInt(0) + blobCertificate.BlobHeader.BlobCommitments.LengthCommitment.Y.A1.BigInt(lengthCommitY1) + lengthProofX0 := big.NewInt(0) + blobCertificate.BlobHeader.BlobCommitments.LengthProof.X.A0.BigInt(lengthProofX0) + lengthProofX1 := big.NewInt(0) + blobCertificate.BlobHeader.BlobCommitments.LengthProof.X.A1.BigInt(lengthProofX1) + lengthProofY0 := big.NewInt(0) + blobCertificate.BlobHeader.BlobCommitments.LengthProof.Y.A0.BigInt(lengthProofY0) + lengthProofY1 := big.NewInt(0) + blobCertificate.BlobHeader.BlobCommitments.LengthProof.Y.A1.BigInt(lengthProofY1) + return &verifierbindings.BlobVerificationProofV2{ + BlobCertificate: verifierbindings.BlobCertificate{ + BlobHeader: verifierbindings.BlobHeaderV2{ + Version: uint16(blobCertificate.BlobHeader.BlobVersion), + QuorumNumbers: blobCertificate.BlobHeader.QuorumNumbers, + Commitment: verifierbindings.BlobCommitment{ + Commitment: verifierbindings.BN254G1Point{ + X: commitX, + Y: commitY, + }, + LengthCommitment: verifierbindings.BN254G2Point{ + X: [2]*big.Int{lengthCommitX0, lengthCommitX1}, + Y: [2]*big.Int{lengthCommitY0, lengthCommitY1}, + }, + LengthProof: verifierbindings.BN254G2Point{ + X: [2]*big.Int{lengthProofX0, lengthProofX1}, + Y: [2]*big.Int{lengthProofY0, lengthProofY1}, + }, + DataLength: uint32(blobCertificate.BlobHeader.BlobCommitments.Length), + }, + PaymentHeaderHash: paymentHeaderHash, + }, + RelayKeys: blobCertificate.RelayKeys, + }, + InclusionProof: inclusionProof, + BlobIndex: blobIndex, + }, nil +} + +func convertAttestation(attestation *disperserpb.Attestation) (*verifierbindings.Attestation, error) { + if attestation == nil { + return nil, fmt.Errorf("attestation is nil") + } + nonSignerPubkeys := make([]verifierbindings.BN254G1Point, 0) + for _, pubkey := range attestation.GetNonSignerPubkeys() { + pk, err := convertG1Point(pubkey) + if err != nil { + return nil, err + } + nonSignerPubkeys = append(nonSignerPubkeys, *pk) + } + + quorumApks := make([]verifierbindings.BN254G1Point, 0) + for _, apk := range attestation.GetQuorumApks() { + apk, err := convertG1Point(apk) + if err != nil { + return nil, err + } + quorumApks = append(quorumApks, *apk) + } + + if attestation.GetSigma() == nil { + return nil, fmt.Errorf("attestation sigma is nil") + } + sigma, err := convertG1Point(attestation.GetSigma()) + if err != nil { + return nil, err + } + + if attestation.GetApkG2() == nil { + return nil, fmt.Errorf("attestation apkG2 is nil") + } + apkg2, err := convertG2Point(attestation.GetApkG2()) + if err != nil { + return nil, err + } + + return &verifierbindings.Attestation{ + NonSignerPubkeys: nonSignerPubkeys, + QuorumApks: quorumApks, + Sigma: *sigma, + ApkG2: *apkg2, + QuorumNumbers: attestation.GetQuorumNumbers(), + }, nil +} + +func convertG1Point(data []byte) (*verifierbindings.BN254G1Point, error) { + point, err := new(core.G1Point).Deserialize(data) + if err != nil { + return nil, err + } + x := big.NewInt(0) + y := big.NewInt(0) + + point.X.BigInt(x) + point.Y.BigInt(y) + return &verifierbindings.BN254G1Point{ + X: x, + Y: y, + }, nil +} + +func convertG2Point(data []byte) (*verifierbindings.BN254G2Point, error) { + point, err := new(core.G2Point).Deserialize(data) + if err != nil { + return nil, err + } + x0 := big.NewInt(0) + x1 := big.NewInt(0) + y0 := big.NewInt(0) + y1 := big.NewInt(0) + + point.X.A0.BigInt(x0) + point.X.A1.BigInt(x1) + point.Y.A0.BigInt(y0) + point.Y.A1.BigInt(y1) + return &verifierbindings.BN254G2Point{ + X: [2]*big.Int{x0, x1}, + Y: [2]*big.Int{y0, y1}, + }, nil +}