From b90736d2ea72e742cc985e26031448fdddf57e31 Mon Sep 17 00:00:00 2001 From: Ian Shim Date: Wed, 30 Oct 2024 09:58:54 -0700 Subject: [PATCH] unexport payment signer --- core/auth/payment_signer.go | 43 ++++++++++++++++++-------------- core/auth/payment_signer_test.go | 15 +++++------ disperser/apiserver/server.go | 11 ++++---- 3 files changed, 38 insertions(+), 31 deletions(-) diff --git a/core/auth/payment_signer.go b/core/auth/payment_signer.go index 0d873e75fe..2afd16ea6e 100644 --- a/core/auth/payment_signer.go +++ b/core/auth/payment_signer.go @@ -3,7 +3,6 @@ package auth import ( "crypto/ecdsa" "fmt" - "log" commonpb "github.com/Layr-Labs/eigenda/api/grpc/common" "github.com/Layr-Labs/eigenda/core" @@ -11,37 +10,39 @@ import ( "github.com/ethereum/go-ethereum/crypto" ) -type PaymentSigner struct { +type paymentSigner struct { PrivateKey *ecdsa.PrivateKey } -var _ core.PaymentSigner = &PaymentSigner{} - -func NewPaymentSigner(privateKeyHex string) *PaymentSigner { +var _ core.PaymentSigner = &paymentSigner{} +func NewPaymentSigner(privateKeyHex string) (*paymentSigner, error) { + if len(privateKeyHex) == 0 { + return nil, fmt.Errorf("private key cannot be empty") + } privateKeyBytes := common.FromHex(privateKeyHex) privateKey, err := crypto.ToECDSA(privateKeyBytes) if err != nil { - log.Fatalf("Failed to parse private key: %v", err) + return nil, fmt.Errorf("failed to convert hex to ECDSA private key: %w", err) } - return &PaymentSigner{ + return &paymentSigner{ PrivateKey: privateKey, - } + }, nil } // SignBlobPayment signs the payment header and returns the signature -func (s *PaymentSigner) SignBlobPayment(header *commonpb.PaymentHeader) ([]byte, error) { +func (s *paymentSigner) SignBlobPayment(header *commonpb.PaymentHeader) ([]byte, error) { header.AccountId = s.GetAccountID() pm := core.ConvertPaymentHeader(header) hash, err := pm.Hash() if err != nil { - return nil, fmt.Errorf("failed to hash payment header: %v", err) + return nil, fmt.Errorf("failed to hash payment header: %w", err) } sig, err := crypto.Sign(hash[:], s.PrivateKey) if err != nil { - return nil, fmt.Errorf("failed to sign hash: %v", err) + return nil, fmt.Errorf("failed to sign hash: %w", err) } return sig, nil @@ -62,35 +63,39 @@ func (s *NoopPaymentSigner) GetAccountID() string { } // VerifyPaymentSignature verifies the signature against the payment metadata -func VerifyPaymentSignature(paymentHeader *commonpb.PaymentHeader, paymentSignature []byte) bool { +func VerifyPaymentSignature(paymentHeader *commonpb.PaymentHeader, paymentSignature []byte) error { pm := core.ConvertPaymentHeader(paymentHeader) hash, err := pm.Hash() if err != nil { - return false + return fmt.Errorf("failed to hash payment header: %w", err) } recoveredPubKey, err := crypto.SigToPub(hash[:], paymentSignature) if err != nil { - log.Printf("Failed to recover public key from signature: %v\n", err) - return false + return fmt.Errorf("failed to recover public key from signature: %w", err) } recoveredAddress := crypto.PubkeyToAddress(*recoveredPubKey) accountId := common.HexToAddress(paymentHeader.AccountId) if recoveredAddress != accountId { - log.Printf("Signature address %s does not match account id %s\n", recoveredAddress.Hex(), accountId.Hex()) - return false + return fmt.Errorf("signature address %s does not match account id %s", recoveredAddress.Hex(), accountId.Hex()) } - return crypto.VerifySignature( + ok := crypto.VerifySignature( crypto.FromECDSAPub(recoveredPubKey), hash[:], paymentSignature[:len(paymentSignature)-1], // Remove recovery ID ) + + if !ok { + return fmt.Errorf("invalid signature") + } + + return nil } // GetAccountID returns the Ethereum address of the signer -func (s *PaymentSigner) GetAccountID() string { +func (s *paymentSigner) GetAccountID() string { publicKey := crypto.FromECDSAPub(&s.PrivateKey.PublicKey) hash := crypto.Keccak256(publicKey[1:]) diff --git a/core/auth/payment_signer_test.go b/core/auth/payment_signer_test.go index 4ba7c872a4..ecd9ec692d 100644 --- a/core/auth/payment_signer_test.go +++ b/core/auth/payment_signer_test.go @@ -16,7 +16,8 @@ func TestPaymentSigner(t *testing.T) { require.NoError(t, err) privateKeyHex := hex.EncodeToString(crypto.FromECDSA(privateKey)) - signer := auth.NewPaymentSigner(privateKeyHex) + signer, err := auth.NewPaymentSigner(privateKeyHex) + require.NoError(t, err) t.Run("SignBlobPayment", func(t *testing.T) { header := &commonpb.PaymentHeader{ @@ -30,8 +31,8 @@ func TestPaymentSigner(t *testing.T) { assert.NotEmpty(t, signature) // Verify the signature - isValid := auth.VerifyPaymentSignature(header, signature) - assert.True(t, isValid) + err = auth.VerifyPaymentSignature(header, signature) + assert.NoError(t, err) }) t.Run("VerifyPaymentSignature_InvalidSignature", func(t *testing.T) { @@ -43,8 +44,8 @@ func TestPaymentSigner(t *testing.T) { // Create an invalid signature invalidSignature := make([]byte, 65) - isValid := auth.VerifyPaymentSignature(header, invalidSignature) - assert.False(t, isValid) + err = auth.VerifyPaymentSignature(header, invalidSignature) + assert.Error(t, err) }) t.Run("VerifyPaymentSignature_ModifiedHeader", func(t *testing.T) { @@ -60,8 +61,8 @@ func TestPaymentSigner(t *testing.T) { // Modify the header after signing header.BinIndex = 2 - isValid := auth.VerifyPaymentSignature(header, signature) - assert.False(t, isValid) + err = auth.VerifyPaymentSignature(header, signature) + assert.Error(t, err) }) } diff --git a/disperser/apiserver/server.go b/disperser/apiserver/server.go index 83dbdb9bed..cf9b1e8538 100644 --- a/disperser/apiserver/server.go +++ b/disperser/apiserver/server.go @@ -329,9 +329,6 @@ func (s *DispersalServer) DispersePaidBlob(ctx context.Context, req *pb.Disperse cumulativePayment := new(big.Int).SetBytes(req.PaymentHeader.CumulativePayment) //todo: before disperse blob, validate the signature signature := req.PaymentSignature - if !auth.VerifyPaymentSignature(req.GetPaymentHeader(), signature) { - return nil, api.NewErrorInvalidArg("payment signature is invalid") - } if err != nil { for _, quorumID := range req.QuorumNumbers { s.metrics.HandleFailedRequest(codes.InvalidArgument.String(), fmt.Sprint(quorumID), len(req.GetData()), "DispersePaidBlob") @@ -340,6 +337,10 @@ func (s *DispersalServer) DispersePaidBlob(ctx context.Context, req *pb.Disperse return nil, api.NewErrorInvalidArg(err.Error()) } + if err = auth.VerifyPaymentSignature(req.GetPaymentHeader(), signature); err != nil { + return nil, api.NewErrorInvalidArg("payment signature is invalid") + } + paymentHeader := core.PaymentMetadata{ AccountID: blob.RequestHeader.AccountID, BinIndex: binIndex, @@ -1114,8 +1115,8 @@ func (s *DispersalServer) validatePaidRequestAndGetBlob(ctx context.Context, req seenQuorums := make(map[uint8]struct{}) // TODO: validate payment signature against payment metadata - if !auth.VerifyPaymentSignature(req.GetPaymentHeader(), req.GetPaymentSignature()) { - return nil, fmt.Errorf("payment signature is invalid") + if err = auth.VerifyPaymentSignature(req.GetPaymentHeader(), req.GetPaymentSignature()); err != nil { + return nil, fmt.Errorf("payment signature is invalid: %w", err) } // Unlike regular blob dispersal request validation, there's no check with required quorums // Because Reservation has their specific quorum requirements, and on-demand is only allowed and paid to the required quorums.