From fd11da82f8f7a36c497a2fa43a7c89346bb8b4ce Mon Sep 17 00:00:00 2001 From: Ian Shim Date: Fri, 25 Oct 2024 11:40:09 -0700 Subject: [PATCH] v2 blob header signer --- core/auth.go | 41 ++++++++++++ core/auth/auth_test.go | 4 +- core/auth/authenticator.go | 14 ++--- core/auth/signer.go | 2 + core/auth/v2/auth_test.go | 113 +++++++++++++++++++++------------- core/auth/v2/authenticator.go | 37 +++++------ core/auth/v2/signer.go | 18 +++--- core/v2/auth.go | 4 +- disperser/apiserver/server.go | 2 +- 9 files changed, 147 insertions(+), 88 deletions(-) diff --git a/core/auth.go b/core/auth.go index 1348be4c93..f4aadb96fe 100644 --- a/core/auth.go +++ b/core/auth.go @@ -1,5 +1,15 @@ package core +import ( + "bytes" + "errors" + "fmt" + + geth "github.com/ethereum/go-ethereum/common" + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" +) + type BlobRequestAuthenticator interface { AuthenticateBlobRequest(header BlobAuthHeader) error } @@ -8,3 +18,34 @@ type BlobRequestSigner interface { SignBlobRequest(header BlobAuthHeader) ([]byte, error) GetAccountID() (string, error) } + +func VerifySignature(message []byte, accountAddr geth.Address, sig []byte) error { + // Ensure the signature is 65 bytes (Recovery ID is the last byte) + if len(sig) != 65 { + return fmt.Errorf("signature length is unexpected: %d", len(sig)) + } + + publicKeyBytes, err := hexutil.Decode(accountAddr.Hex()) + if err != nil { + return fmt.Errorf("failed to decode public key (%v): %v", accountAddr.Hex(), err) + } + + // Decode public key + pubKey, err := crypto.UnmarshalPubkey(publicKeyBytes) + if err != nil { + return fmt.Errorf("failed to decode public key (%v): %v", accountAddr.Hex(), err) + } + + // Verify the signature + sigPublicKeyECDSA, err := crypto.SigToPub(message, sig) + if err != nil { + return fmt.Errorf("failed to recover public key from signature: %v", err) + } + + if !bytes.Equal(pubKey.X.Bytes(), sigPublicKeyECDSA.X.Bytes()) || !bytes.Equal(pubKey.Y.Bytes(), sigPublicKeyECDSA.Y.Bytes()) { + return errors.New("signature doesn't match with provided public key") + } + + return nil + +} diff --git a/core/auth/auth_test.go b/core/auth/auth_test.go index 55c405f552..293ba0a267 100644 --- a/core/auth/auth_test.go +++ b/core/auth/auth_test.go @@ -13,7 +13,7 @@ import ( func TestAuthentication(t *testing.T) { // Make the authenticator - authenticator := auth.NewAuthenticator(auth.AuthConfig{}) + authenticator := auth.NewAuthenticator() // Make the signer privateKeyHex := "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" @@ -43,7 +43,7 @@ func TestAuthentication(t *testing.T) { func TestAuthenticationFail(t *testing.T) { // Make the authenticator - authenticator := auth.NewAuthenticator(auth.AuthConfig{}) + authenticator := auth.NewAuthenticator() // Make the signer privateKeyHex := "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" diff --git a/core/auth/authenticator.go b/core/auth/authenticator.go index a3b29c07e0..74fe4bf50e 100644 --- a/core/auth/authenticator.go +++ b/core/auth/authenticator.go @@ -12,18 +12,12 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) -type AuthConfig struct { -} - -type authenticator struct { - config AuthConfig -} +type authenticator struct{} -func NewAuthenticator(config AuthConfig) core.BlobRequestAuthenticator { +var _ core.BlobRequestAuthenticator = &authenticator{} - return &authenticator{ - config: config, - } +func NewAuthenticator() core.BlobRequestAuthenticator { + return &authenticator{} } func (*authenticator) AuthenticateBlobRequest(header core.BlobAuthHeader) error { diff --git a/core/auth/signer.go b/core/auth/signer.go index 015db23fc4..d900a56bf1 100644 --- a/core/auth/signer.go +++ b/core/auth/signer.go @@ -56,6 +56,8 @@ func (s *LocalBlobRequestSigner) GetAccountID() (string, error) { type LocalNoopSigner struct{} +var _ core.BlobRequestSigner = &LocalNoopSigner{} + func NewLocalNoopSigner() *LocalNoopSigner { return &LocalNoopSigner{} } diff --git a/core/auth/v2/auth_test.go b/core/auth/v2/auth_test.go index 7877b62d49..cf5a474c8e 100644 --- a/core/auth/v2/auth_test.go +++ b/core/auth/v2/auth_test.go @@ -1,76 +1,60 @@ package v2_test import ( - "math/rand" + "math/big" "testing" "github.com/Layr-Labs/eigenda/core" - "github.com/Layr-Labs/eigenda/core/auth" + auth "github.com/Layr-Labs/eigenda/core/auth/v2" + corev2 "github.com/Layr-Labs/eigenda/core/v2" "github.com/Layr-Labs/eigenda/encoding" + "github.com/consensys/gnark-crypto/ecc/bn254/fp" "github.com/stretchr/testify/assert" ) -func TestAuthentication(t *testing.T) { - - // Make the authenticator - authenticator := auth.NewAuthenticator(auth.AuthConfig{}) +var ( + privateKeyHex = "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" +) - // Make the signer - privateKeyHex := "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" +func TestAuthentication(t *testing.T) { signer := auth.NewLocalBlobRequestSigner(privateKeyHex) + authenticator := auth.NewAuthenticator() accountId, err := signer.GetAccountID() assert.NoError(t, err) - - testHeader := core.BlobAuthHeader{ - BlobCommitments: encoding.BlobCommitments{}, - AccountID: accountId, - Nonce: rand.Uint32(), - AuthenticationData: []byte{}, - } + header := testHeader(t, accountId) // Sign the header - signature, err := signer.SignBlobRequest(testHeader) + signature, err := signer.SignBlobRequest(header) assert.NoError(t, err) - testHeader.AuthenticationData = signature + header.Signature = signature - err = authenticator.AuthenticateBlobRequest(testHeader) + err = authenticator.AuthenticateBlobRequest(header) assert.NoError(t, err) } func TestAuthenticationFail(t *testing.T) { - - // Make the authenticator - authenticator := auth.NewAuthenticator(auth.AuthConfig{}) - - // Make the signer - privateKeyHex := "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef" signer := auth.NewLocalBlobRequestSigner(privateKeyHex) + authenticator := auth.NewAuthenticator() accountId, err := signer.GetAccountID() assert.NoError(t, err) - testHeader := core.BlobAuthHeader{ - BlobCommitments: encoding.BlobCommitments{}, - AccountID: accountId, - Nonce: rand.Uint32(), - AuthenticationData: []byte{}, - } + header := testHeader(t, accountId) - privateKeyHex = "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcded" - signer = auth.NewLocalBlobRequestSigner(privateKeyHex) + wrongPrivateKeyHex := "0x0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcded" + signer = auth.NewLocalBlobRequestSigner(wrongPrivateKeyHex) // Sign the header - signature, err := signer.SignBlobRequest(testHeader) + signature, err := signer.SignBlobRequest(header) assert.NoError(t, err) - testHeader.AuthenticationData = signature + header.Signature = signature - err = authenticator.AuthenticateBlobRequest(testHeader) + err = authenticator.AuthenticateBlobRequest(header) assert.Error(t, err) - } func TestNoopSignerFail(t *testing.T) { @@ -78,12 +62,55 @@ func TestNoopSignerFail(t *testing.T) { accountId, err := signer.GetAccountID() assert.EqualError(t, err, "noop signer cannot get accountID") - testHeader := core.BlobAuthHeader{ - BlobCommitments: encoding.BlobCommitments{}, - AccountID: accountId, - Nonce: rand.Uint32(), - AuthenticationData: []byte{}, - } - _, err = signer.SignBlobRequest(testHeader) + header := testHeader(t, accountId) + + _, err = signer.SignBlobRequest(header) assert.EqualError(t, err, "noop signer cannot sign blob request") } + +func testHeader(t *testing.T, accountID string) *corev2.BlobHeader { + var commitX, commitY fp.Element + _, err := commitX.SetString("21661178944771197726808973281966770251114553549453983978976194544185382599016") + assert.NoError(t, err) + _, err = commitY.SetString("9207254729396071334325696286939045899948985698134704137261649190717970615186") + assert.NoError(t, err) + + commitment := &encoding.G1Commitment{ + X: commitX, + Y: commitY, + } + var lengthXA0, lengthXA1, lengthYA0, lengthYA1 fp.Element + _, err = lengthXA0.SetString("10857046999023057135944570762232829481370756359578518086990519993285655852781") + assert.NoError(t, err) + _, err = lengthXA1.SetString("11559732032986387107991004021392285783925812861821192530917403151452391805634") + assert.NoError(t, err) + _, err = lengthYA0.SetString("8495653923123431417604973247489272438418190587263600148770280649306958101930") + assert.NoError(t, err) + _, err = lengthYA1.SetString("4082367875863433681332203403145435568316851327593401208105741076214120093531") + assert.NoError(t, err) + + var lengthProof, lengthCommitment encoding.G2Commitment + lengthProof.X.A0 = lengthXA0 + lengthProof.X.A1 = lengthXA1 + lengthProof.Y.A0 = lengthYA0 + lengthProof.Y.A1 = lengthYA1 + + lengthCommitment = lengthProof + + return &corev2.BlobHeader{ + BlobVersion: 0, + BlobCommitments: encoding.BlobCommitments{ + Commitment: commitment, + LengthCommitment: &lengthCommitment, + LengthProof: &lengthProof, + Length: 50, + }, + QuorumNumbers: []core.QuorumID{0, 1}, + PaymentMetadata: core.PaymentMetadata{ + AccountID: accountID, + BinIndex: 5, + CumulativePayment: big.NewInt(100), + }, + Signature: []byte{}, + } +} diff --git a/core/auth/v2/authenticator.go b/core/auth/v2/authenticator.go index 5e9abcebbb..4d8c9615a1 100644 --- a/core/auth/v2/authenticator.go +++ b/core/auth/v2/authenticator.go @@ -2,55 +2,49 @@ package v2 import ( "bytes" - "encoding/binary" "errors" "fmt" - "github.com/Layr-Labs/eigenda/core" + core "github.com/Layr-Labs/eigenda/core/v2" "github.com/ethereum/go-ethereum/common/hexutil" "github.com/ethereum/go-ethereum/crypto" ) -type AuthConfig struct { -} +type authenticator struct{} -type authenticator struct { - config AuthConfig +func NewAuthenticator() *authenticator { + return &authenticator{} } -func NewAuthenticator(config AuthConfig) core.BlobRequestAuthenticator { - - return &authenticator{ - config: config, - } -} +var _ core.BlobRequestAuthenticator = &authenticator{} -func (*authenticator) AuthenticateBlobRequest(header core.BlobAuthHeader) error { - sig := header.AuthenticationData +func (*authenticator) AuthenticateBlobRequest(header *core.BlobHeader) error { + sig := header.Signature // Ensure the signature is 65 bytes (Recovery ID is the last byte) if len(sig) != 65 { return fmt.Errorf("signature length is unexpected: %d", len(sig)) } - buf := make([]byte, 4) - binary.BigEndian.PutUint32(buf, header.Nonce) - hash := crypto.Keccak256(buf) + blobKey, err := header.BlobKey() + if err != nil { + return fmt.Errorf("failed to get blob key: %v", err) + } - publicKeyBytes, err := hexutil.Decode(header.AccountID) + publicKeyBytes, err := hexutil.Decode(header.PaymentMetadata.AccountID) if err != nil { - return fmt.Errorf("failed to decode public key (%v): %v", header.AccountID, err) + return fmt.Errorf("failed to decode public key (%v): %v", header.PaymentMetadata.AccountID, err) } // Decode public key pubKey, err := crypto.UnmarshalPubkey(publicKeyBytes) if err != nil { - return fmt.Errorf("failed to decode public key (%v): %v", header.AccountID, err) + return fmt.Errorf("failed to decode public key (%v): %v", header.PaymentMetadata.AccountID, err) } // Verify the signature - sigPublicKeyECDSA, err := crypto.SigToPub(hash, sig) + sigPublicKeyECDSA, err := crypto.SigToPub(blobKey[:], sig) if err != nil { return fmt.Errorf("failed to recover public key from signature: %v", err) } @@ -60,5 +54,4 @@ func (*authenticator) AuthenticateBlobRequest(header core.BlobAuthHeader) error } return nil - } diff --git a/core/auth/v2/signer.go b/core/auth/v2/signer.go index 962c1ebd53..bac6f3684b 100644 --- a/core/auth/v2/signer.go +++ b/core/auth/v2/signer.go @@ -2,7 +2,6 @@ package v2 import ( "crypto/ecdsa" - "encoding/binary" "fmt" "log" @@ -30,13 +29,14 @@ func NewLocalBlobRequestSigner(privateKeyHex string) *LocalBlobRequestSigner { } } -func (s *LocalBlobRequestSigner) SignBlobRequest(header core.BlobHeader) ([]byte, error) { - // Message you want to sign - - hash := crypto.Keccak256(buf) +func (s *LocalBlobRequestSigner) SignBlobRequest(header *core.BlobHeader) ([]byte, error) { + blobKey, err := header.BlobKey() + if err != nil { + return nil, fmt.Errorf("failed to get blob key: %v", err) + } - // Sign the hash using the private key - sig, err := crypto.Sign(hash, s.PrivateKey) + // Sign the blob key using the private key + sig, err := crypto.Sign(blobKey[:], s.PrivateKey) if err != nil { return nil, fmt.Errorf("failed to sign hash: %v", err) } @@ -53,11 +53,13 @@ func (s *LocalBlobRequestSigner) GetAccountID() (string, error) { type LocalNoopSigner struct{} +var _ core.BlobRequestSigner = &LocalNoopSigner{} + func NewLocalNoopSigner() *LocalNoopSigner { return &LocalNoopSigner{} } -func (s *LocalNoopSigner) SignBlobRequest(header core.BlobHeader) ([]byte, error) { +func (s *LocalNoopSigner) SignBlobRequest(header *core.BlobHeader) ([]byte, error) { return nil, fmt.Errorf("noop signer cannot sign blob request") } diff --git a/core/v2/auth.go b/core/v2/auth.go index ac60632a19..7ad714bf80 100644 --- a/core/v2/auth.go +++ b/core/v2/auth.go @@ -1,10 +1,10 @@ package v2 type BlobRequestAuthenticator interface { - AuthenticateBlobRequest(header BlobHeader) error + AuthenticateBlobRequest(header *BlobHeader) error } type BlobRequestSigner interface { - SignBlobRequest(header BlobHeader) ([]byte, error) + SignBlobRequest(header *BlobHeader) ([]byte, error) GetAccountID() (string, error) } diff --git a/disperser/apiserver/server.go b/disperser/apiserver/server.go index e99a9ef535..dea50ee6db 100644 --- a/disperser/apiserver/server.go +++ b/disperser/apiserver/server.go @@ -81,7 +81,7 @@ func NewDispersalServer( } logger.Info("allowlist config", "file", rateConfig.AllowlistFile, "refreshInterval", rateConfig.AllowlistRefreshInterval.String()) - authenticator := auth.NewAuthenticator(auth.AuthConfig{}) + authenticator := auth.NewAuthenticator() return &DispersalServer{ serverConfig: serverConfig,