Skip to content

Commit

Permalink
feat: DA Cert Verification
Browse files Browse the repository at this point in the history
  • Loading branch information
ethenotethan committed Jun 19, 2024
1 parent 2221b6b commit 81740a4
Show file tree
Hide file tree
Showing 8 changed files with 348 additions and 12 deletions.
59 changes: 58 additions & 1 deletion common/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package common

import (
"fmt"
"math/big"
"strconv"
"strings"

Expand All @@ -12,7 +13,63 @@ var (
ErrInvalidDomainType = fmt.Errorf("invalid domain type")
)

type Certificate = disperser.BlobInfo
// G1Point struct to represent G1Point in Solidity
type G1Point struct {
X *big.Int
Y *big.Int
}

// QuorumBlobParam struct to represent QuorumBlobParam in Solidity
type QuorumBlobParam struct {
QuorumNumber uint8
AdversaryThresholdPercentage uint8
ConfirmationThresholdPercentage uint8
ChunkLength uint32
}

// BlobHeader struct to represent BlobHeader in Solidity
type BlobHeader struct {
Commitment G1Point
DataLength uint32
QuorumBlobParams []QuorumBlobParam
}

type Certificate disperser.BlobInfo

func (c *Certificate) BlobIndex() uint32 {
return c.BlobVerificationProof.BlobIndex
}

func (c *Certificate) BatchHeaderRoot() []byte {
return c.BlobVerificationProof.BatchMetadata.BatchHeader.BatchRoot
}

func (c *Certificate) ReadBlobHeader() BlobHeader {
// parse quorum params

qps := make([]QuorumBlobParam, len(c.BlobHeader.BlobQuorumParams))
for i, qp := range c.BlobHeader.BlobQuorumParams {
qps[i] = QuorumBlobParam{
QuorumNumber: uint8(qp.QuorumNumber),
AdversaryThresholdPercentage: uint8(qp.AdversaryThresholdPercentage),
ConfirmationThresholdPercentage: uint8(qp.ConfirmationThresholdPercentage),
ChunkLength: qp.ChunkLength,
}
}

return BlobHeader{
Commitment: G1Point{
X: new(big.Int).SetBytes(c.BlobHeader.Commitment.X),
Y: new(big.Int).SetBytes(c.BlobHeader.Commitment.Y),
},
DataLength: c.BlobHeader.DataLength,
QuorumBlobParams: qps,
}
}

func (c *Certificate) Proof() *disperser.BlobVerificationProof {
return c.BlobVerificationProof
}

// DomainType is a enumeration type for the different data domains for which a
// blob can exist between
Expand Down
Binary file added srs_cache/dimE512.coset1
Binary file not shown.
20 changes: 17 additions & 3 deletions verify/cert.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,27 @@ func (cv *CertVerifier) VerifyBatch(header *binding.IEigenDAServiceManagerBatchH
return nil
}

// 2 - (TODO) merkle proof verification
// VerifyMerkleProof
func (cv *CertVerifier) VerifyMerkleProof(inclusionProof []byte, root []byte, blobIndex uint32, blobHeader proxy_common.BlobHeader) error {
leafHash, err := HashEncodeBlobHeader(blobHeader)
if err != nil {
return err
}

generatedRoot, err := ProcessInclusionProof(inclusionProof, leafHash, uint64(blobIndex))
if err != nil {
return err
}

equal := proxy_common.EqualSlices(root, generatedRoot.Bytes())
if !equal {
return fmt.Errorf("root hash mismatch, expected: %x, got: %x", root, generatedRoot)
}

func (cv *CertVerifier) VerifyMerkleProof(inclusionProof []byte, rootHash []byte, leafHash []byte, index uint64) error {
return nil
}

// 3 - (TODO) verify blob security params
func (cv *CertVerifier) Verify(inclusionProof []byte, rootHash []byte, leafHash []byte, index uint64) error {
func (cv *CertVerifier) VerifyBlobParams(inclusionProof []byte, rootHash []byte, leafHash []byte, index uint64) error {
return nil
}
48 changes: 48 additions & 0 deletions verify/hasher.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package verify
import (
"encoding/binary"

common "github.com/Layr-Labs/eigenda-proxy/common"
binding "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDAServiceManager"
"github.com/ethereum/go-ethereum/accounts/abi"
geth_common "github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -95,3 +96,50 @@ func HashBatchHashedMetadata(batchHeaderHash [32]byte, signatoryRecordHash [32]b

return headerHash, nil
}

// HashBlobHeader function to hash BlobHeader
func HashBlobHeader(blobHeader common.BlobHeader) (geth_common.Hash, error) {

blobHeaderType, err := abi.NewType("tuple", "", []abi.ArgumentMarshaling{
{Name: "commitment", Type: "tuple", Components: []abi.ArgumentMarshaling{
{Name: "X", Type: "uint256"},
{Name: "Y", Type: "uint256"},
}},
{Name: "dataLength", Type: "uint32"},
{Name: "quorumBlobParams", Type: "tuple[]", Components: []abi.ArgumentMarshaling{
{Name: "quorumNumber", Type: "uint8"},
{Name: "adversaryThresholdPercentage", Type: "uint8"},
{Name: "confirmationThresholdPercentage", Type: "uint8"},
{Name: "chunkLength", Type: "uint32"},
}},
})
if err != nil {
return geth_common.Hash{}, err
}

// Create ABI arguments
arguments := abi.Arguments{
{Type: blobHeaderType},
}

// Pack the BlobHeader
bytes, err := arguments.Pack(blobHeader)
if err != nil {
return geth_common.Hash{}, err
}
// Hash the packed bytes using Keccak256
hash := crypto.Keccak256Hash(bytes)
return hash, nil
}

// Function to hash and encode header
func HashEncodeBlobHeader(header common.BlobHeader) (geth_common.Hash, error) {
// Hash the BlobHeader
blobHash, err := HashBlobHeader(header)
if err != nil {
return geth_common.Hash{}, err
}

finalHash := crypto.Keccak256Hash(blobHash.Bytes())
return finalHash, nil
}
76 changes: 76 additions & 0 deletions verify/hasher_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
package verify

import (
"math/big"
"testing"

"github.com/Layr-Labs/eigenda-proxy/common"
eigenda_common "github.com/Layr-Labs/eigenda/api/grpc/common"
"github.com/Layr-Labs/eigenda/api/grpc/disperser"
binding "github.com/Layr-Labs/eigenda/contracts/bindings/EigenDAServiceManager"
"github.com/ethereum/go-ethereum/crypto"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -57,3 +61,75 @@ func TestHashBatchMetadata(t *testing.T) {
require.Equal(t, actual.String(), expected)

}

func TestHashBlobHeader(t *testing.T) {
expected := "0xba4675a31c9bf6b2f7abfdcedd34b74645cb7332b35db39bff00ae8516a67393"

// [[1,1],2,[[2,4,5,6]]]
header := &disperser.BlobHeader{
Commitment: &eigenda_common.G1Commitment{
X: big.NewInt(1).Bytes(),
Y: big.NewInt(1).Bytes(),
},
DataLength: 2,
BlobQuorumParams: []*disperser.BlobQuorumParam{
{
QuorumNumber: 2,
AdversaryThresholdPercentage: 4,
ConfirmationThresholdPercentage: 5,
ChunkLength: 6,
},
{
QuorumNumber: 2,
AdversaryThresholdPercentage: 4,
ConfirmationThresholdPercentage: 5,
ChunkLength: 6,
},
},
}

cert := &common.Certificate{
BlobHeader: header,
}

actual, err := HashBlobHeader(cert.ReadBlobHeader())

require.NoError(t, err)
require.Equal(t, expected, actual.String())
}

func TestHashEncodeBlobHeader(t *testing.T) {
expected := "0xf15f43fa44bae9b74cd2f88f8f838e09ff7ab5d50f2170f07b98479eb7da98ba"

// [[1,1],2,[[2,4,5,6]]]
header := &disperser.BlobHeader{
Commitment: &eigenda_common.G1Commitment{
X: big.NewInt(1).Bytes(),
Y: big.NewInt(1).Bytes(),
},
DataLength: 2,
BlobQuorumParams: []*disperser.BlobQuorumParam{
{
QuorumNumber: 2,
AdversaryThresholdPercentage: 4,
ConfirmationThresholdPercentage: 5,
ChunkLength: 6,
},
{
QuorumNumber: 2,
AdversaryThresholdPercentage: 4,
ConfirmationThresholdPercentage: 5,
ChunkLength: 6,
},
},
}

cert := &common.Certificate{
BlobHeader: header,
}

actual, err := HashEncodeBlobHeader(cert.ReadBlobHeader())

require.NoError(t, err)
require.Equal(t, expected, actual.String())
}
33 changes: 33 additions & 0 deletions verify/merkle.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package verify

import (
"errors"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
)

// ProcessInclusionProof processes the Merkle proof
func ProcessInclusionProof(proof []byte, leaf common.Hash, index uint64) (common.Hash, error) {
if len(proof) == 0 || len(proof)%32 != 0 {
return common.Hash{}, errors.New("proof length should be a multiple of 32 bytes or 256 bits")
}

computedHash := leaf
for i := 0; i < len(proof); i += 32 {
var proofElement common.Hash
copy(proofElement[:], proof[i:i+32])

var combined []byte
if index%2 == 0 { // right
combined = append(computedHash.Bytes(), proofElement.Bytes()...)
} else { // left
combined = append(proofElement.Bytes(), computedHash.Bytes()...)
}

computedHash = crypto.Keccak256Hash(combined)
index = index / 2
}

return computedHash, nil
}
41 changes: 41 additions & 0 deletions verify/merkle_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package verify

import (
"testing"

"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/stretchr/testify/require"
)

func TestProcessInclusionProofPass(t *testing.T) {
proof, err := hexutil.Decode("0xc455c1ea0e725d7ea3e5f29e9f48be8fc2787bb0a914d5a86710ba302c166ac4f626d76f67f1055bb960a514fb8923af2078fd84085d712655b58a19612e8cd15c3e4ac1cef57acde3438dbcf63f47c9fefe1221344c4d5c1a4943dd0d1803091ca81a270909dc0e146841441c9bd0e08e69ce6168181a3e4060ffacf3627480bec6abdd8d7bb92b49d33f180c42f49e041752aaded9c403db3a17b85e48a11e9ea9a08763f7f383dab6d25236f1b77c12b4c49c5cdbcbea32554a604e3f1d2f466851cb43fe73617b3d01e665e4c019bf930f92dea7394c25ed6a1e200d051fb0c30a2193c459f1cfef00bf1ba6656510d16725a4d1dc031cb759dbc90bab427b0f60ddc6764681924dda848824605a4f08b7f526fe6bd4572458c94e83fbf2150f2eeb28d3011ec921996dc3e69efa52d5fcf3182b20b56b5857a926aa66605808079b4d52c0c0cfe06923fa92e65eeca2c3e6126108e8c1babf5ac522f4d7")
require.NoError(t, err)

leaf := common.HexToHash("0xf6106e6ae4631e68abe0fa898cedbe97dbae6c7efb1b088c5aa2e8b91190ff96")
index := uint64(580)

expectedRoot, err := hexutil.Decode("0x7390b8023db8248123dcaeca57fa6c9340bef639e204f2278fc7ec3d46ad071b")
require.NoError(t, err)

actualRoot, err := ProcessInclusionProof(proof, leaf, index)
require.NoError(t, err)

require.Equal(t, expectedRoot, actualRoot.Bytes())
}

func TestProcessInclusionProofFail(t *testing.T) {
proof, err := hexutil.Decode("0xc455c1ea0e725d7ea3e5f29e9f48be8fc2787bb0a914d5a86710ba302c166ac4f626d76f67f1055bb960a514fb8923af2078fd84085d712655b58a19612e8cd15c3e4ac1cef57acde3438dbcf63f47c9fefe1221344c4d5c1a4943dd0d1803091ca81a270909dc0e146841441c9bd0e08e69ce6168181a3e4060ffacf3627480bec6abdd8d7bb92b49d33f180c42f49e041752aaded9c403db3a17b85e48a11e9ea9a08763f7f383dab6d25236f1b77c12b4c49c5cdbcbea32554a604e3f1d2f466851cb43fe73617b3d01e665e4c019bf930f92dea7394c25ed6a1e200d051fb0c30a2193c459f1cfef00bf1ba6656510d16725a4d1dc031cb759dbc90bab427b0f60ddc6764681924dda848824605a4f08b7f526fe6bd4572458c94e83fbf2150f2eeb28d3011ec921996dc3e69efa52d5fcf3182b20b56b5857a926aa66605808079b4d52c0c0cfe06923fa92e65eeca2c3e6126108e8c1babf5ac522f4d7")
require.NoError(t, err)

leaf := common.HexToHash("0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
index := uint64(580)

expectedRoot, err := hexutil.Decode("0x7390b8023db8248123dcaeca57fa6c9340bef639e204f2278fc7ec3d46ad071b")
require.NoError(t, err)

actualRoot, err := ProcessInclusionProof(proof, leaf, index)
require.NoError(t, err)

require.NotEqual(t, expectedRoot, actualRoot.Bytes())
}
Loading

0 comments on commit 81740a4

Please sign in to comment.