Skip to content

Commit

Permalink
feat(grpc): support Ed25519 message signing and verification (#1667)
Browse files Browse the repository at this point in the history
Co-authored-by: Shivam Mantri <[email protected]>
  • Loading branch information
BuidlWithShivam and Shivam Mantri authored Jan 15, 2025
1 parent 0b9353e commit d0e66e5
Show file tree
Hide file tree
Showing 2 changed files with 124 additions and 14 deletions.
62 changes: 48 additions & 14 deletions www/grpc/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@ package grpc

import (
"context"
"errors"
"fmt"

"github.com/pactus-project/pactus/crypto"
"github.com/pactus-project/pactus/crypto/bls"
"github.com/pactus-project/pactus/crypto/ed25519"
pactus "github.com/pactus-project/pactus/www/grpc/gen/go"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
Expand All @@ -20,35 +23,28 @@ func newUtilsServer(server *Server) *utilServer {
}
}

func (*utilServer) SignMessageWithPrivateKey(_ context.Context,
func (u *utilServer) SignMessageWithPrivateKey(_ context.Context,
req *pactus.SignMessageWithPrivateKeyRequest,
) (*pactus.SignMessageWithPrivateKeyResponse, error) {
prvKey, err := bls.PrivateKeyFromString(req.PrivateKey)
prvKey, err := u.privateKeyFromString(req.PrivateKey)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "invalid private key")
return nil, status.Error(codes.InvalidArgument, err.Error())
}

sig := prvKey.Sign([]byte(req.Message)).String()

return &pactus.SignMessageWithPrivateKeyResponse{
Signature: sig,
}, nil
}

func (*utilServer) VerifyMessage(_ context.Context,
func (u *utilServer) VerifyMessage(_ context.Context,
req *pactus.VerifyMessageRequest,
) (*pactus.VerifyMessageResponse, error) {
sig, err := bls.SignatureFromString(req.Signature)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "signature is invalid")
}

pub, err := bls.PublicKeyFromString(req.PublicKey)
pubKey, sig, err := u.publicKeyAndSigFromString(req.PublicKey, req.Signature)
if err != nil {
return nil, status.Error(codes.InvalidArgument, "public key is invalid")
return nil, status.Error(codes.InvalidArgument, err.Error())
}

if err := pub.Verify([]byte(req.Message), sig); err == nil {
if err = pubKey.Verify([]byte(req.Message), sig); err == nil {
return &pactus.VerifyMessageResponse{
IsValid: true,
}, nil
Expand Down Expand Up @@ -101,3 +97,41 @@ func (*utilServer) BLSSignatureAggregation(_ context.Context,
Signature: bls.SignatureAggregate(sigs...).String(),
}, nil
}

func (*utilServer) privateKeyFromString(prvStr string) (crypto.PrivateKey, error) {
blsPrv, err := bls.PrivateKeyFromString(prvStr)
if err == nil {
return blsPrv, nil
}

ed25519Prv, err := ed25519.PrivateKeyFromString(prvStr)
if err == nil {
return ed25519Prv, nil
}

return nil, errors.New("invalid Private Key")
}

func (*utilServer) publicKeyAndSigFromString(pubStr, sigStr string) (crypto.PublicKey, crypto.Signature, error) {
blsPub, err := bls.PublicKeyFromString(pubStr)
if err == nil {
blsSig, err := bls.SignatureFromString(sigStr)
if err != nil {
return nil, nil, errors.New("invalid BLS signature")
}

return blsPub, blsSig, nil
}

ed25519Pub, err := ed25519.PublicKeyFromString(pubStr)
if err == nil {
ed25519Sig, err := ed25519.SignatureFromString(sigStr)
if err != nil {
return nil, nil, errors.New("invalid Ed25519 signature")
}

return ed25519Pub, ed25519Sig, nil
}

return nil, nil, errors.New("invalid Public Key")
}
76 changes: 76 additions & 0 deletions www/grpc/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,43 @@ func TestSignMessageWithPrivateKey(t *testing.T) {
td.StopServer()
}

func TestSignMessageWithED25519PrivateKey(t *testing.T) {
conf := testConfig()
td := setup(t, conf)
conn, client := td.utilClient(t)

msg := "pactus"
prvStr := "SECRET1RYY62A96X25ZAL4DPL5Z63G83GCSFCCQ7K0CMQD3MFNLYK3A6R26QUUK3Y0"
invalidPrvStr := "INVSECRET1RYY62A96X25ZAL4DPL5Z63G83GCSFCCQ7K0CMQD3MFNLYK3A6R26QUUK3Y0"
expectedSig := "361aaa09c408bfcf7e79dd90c583eeeaefe7c732ca5643cfb2ea7a6d22105b874a412080" +
"525a855bbd5df94110a7d0083d6e386e016ecf8b7f522c339f79d305"

t.Run("", func(t *testing.T) {
res, err := client.SignMessageWithPrivateKey(context.Background(),
&pactus.SignMessageWithPrivateKeyRequest{
Message: msg,
PrivateKey: prvStr,
})

assert.Nil(t, err)
assert.Equal(t, expectedSig, res.Signature)
})

t.Run("", func(t *testing.T) {
res, err := client.SignMessageWithPrivateKey(context.Background(),
&pactus.SignMessageWithPrivateKeyRequest{
Message: msg,
PrivateKey: invalidPrvStr,
})

assert.NotNil(t, err)
assert.Nil(t, res)
})

assert.Nil(t, conn.Close(), "Error closing connection")
td.StopServer()
}

func TestVerifyMessage(t *testing.T) {
conf := testConfig()
td := setup(t, conf)
Expand Down Expand Up @@ -84,6 +121,45 @@ func TestVerifyMessage(t *testing.T) {
td.StopServer()
}

func TestVerifyED25519Message(t *testing.T) {
conf := testConfig()
td := setup(t, conf)
conn, client := td.utilClient(t)

msg := "pactus"
pubStr := "public1rvqxnpfph8tnc3ck55z85w285t5jetylmmktr9wlzs0zvx7kx500szxfudh"
sigStr := "361aaa09c408bfcf7e79dd90c583eeeaefe7c732ca5643cfb2ea7a6d22105b874a41" +
"2080525a855bbd5df94110a7d0083d6e386e016ecf8b7f522c339f79d305"
invalidSigStr := "001aaa09c408bfcf7e79dd90c583eeeaefe7c732ca5643cfb2ea7a6d22105b" +
"874a412080525a855bbd5df94110a7d0083d6e386e016ecf8b7f522c339f79d305"

t.Run("valid message", func(t *testing.T) {
res, err := client.VerifyMessage(context.Background(),
&pactus.VerifyMessageRequest{
Message: msg,
Signature: sigStr,
PublicKey: pubStr,
})
assert.Nil(t, err)
assert.True(t, res.IsValid)
})

t.Run("invalid message", func(t *testing.T) {
res, err := client.VerifyMessage(context.Background(),
&pactus.VerifyMessageRequest{
Message: msg,
Signature: invalidSigStr,
PublicKey: pubStr,
})

assert.Nil(t, err)
assert.False(t, res.IsValid)
})

assert.Nil(t, conn.Close(), "Error closing connection")
td.StopServer()
}

func TestBLSPublicKeyAggregation(t *testing.T) {
ts := testsuite.NewTestSuite(t)
conf := testConfig()
Expand Down

0 comments on commit d0e66e5

Please sign in to comment.