Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(wasmer/crypto): move sig verifier to crypto pkg #2057

Merged
Merged
Show file tree
Hide file tree
Changes from 25 commits
Commits
Show all changes
43 commits
Select commit Hold shift + click to select a range
db85f05
chore: delete sig verifier from runtime pkg
1garo Nov 20, 2021
eda4236
feat: implement SignVerify for sr25519
1garo Nov 20, 2021
ed89c50
feat: implement SignVerify for ed25519
1garo Nov 20, 2021
6f41dfc
feat: implement SignVerify for srcp256k1
1garo Nov 20, 2021
73e8d87
fix: move sig_verifier to crypto pkg
1garo Nov 20, 2021
11b6016
chore: update usages for crypto pkg
1garo Nov 20, 2021
63a3442
fix: resolve lint problem
1garo Nov 20, 2021
969efc2
chore: add comment on exported type
1garo Nov 20, 2021
9146c37
remove spaces between imports
1garo Nov 23, 2021
a839018
rename function to improve readability
1garo Nov 23, 2021
43ad637
add err signature err msg and add return for docs purpose
1garo Nov 23, 2021
9531a54
improve naming and error handling
1garo Nov 23, 2021
7a9560e
implement tests for new function
1garo Nov 23, 2021
9c31504
gen by mockery
1garo Nov 23, 2021
fd188fc
create tests for sig verifier
1garo Nov 24, 2021
53ca92b
Merge branch 'development' into 1garo/move-sig-verifier-to-crypto
1garo Nov 24, 2021
610e4cd
rename type and refactor VerifyFunc call
1garo Nov 24, 2021
5c45a1f
remove ok bool as return value
1garo Nov 24, 2021
5c15e6f
update tests and add one for sig_verifier
1garo Nov 24, 2021
fbe70d8
add signature name when error occurs
1garo Nov 26, 2021
c164f4d
parallel tests and rename test case
1garo Nov 26, 2021
e1717bc
parallel tests and add log level
1garo Nov 26, 2021
f009530
gofmt
1garo Nov 26, 2021
b83cc03
Merge branch 'development' into 1garo/move-sig-verifier-to-crypto
1garo Nov 26, 2021
9534e7e
resolve make build erroring
1garo Nov 26, 2021
634ea82
rename type
1garo Nov 26, 2021
973ce6b
remove space between imports
1garo Nov 26, 2021
ddba19f
remove useless alias
1garo Nov 26, 2021
da14c99
check ok, if false errors
1garo Nov 26, 2021
664aa50
rename typ
1garo Nov 26, 2021
625ca02
solve tests failing
1garo Nov 26, 2021
975b406
use test cases to remove useless code
1garo Nov 26, 2021
75f6080
send empty bytes on error test case
1garo Nov 26, 2021
7a62d06
improve tests cases
1garo Nov 27, 2021
7da55ab
use constants instead of just []byte
1garo Nov 30, 2021
2fdabf8
switch validation order
1garo Nov 30, 2021
ae14785
use new err approach validation and add tests
1garo Nov 30, 2021
f223d65
make use of constants
1garo Nov 30, 2021
1ee5e82
fix error validation on ed25519
1garo Dec 1, 2021
4012a66
fix error validation on sr25519
1garo Dec 1, 2021
f7b81b1
put publicKey in var to avoid golangci-lint error
1garo Dec 1, 2021
52bc4c3
use a new err variable for each parallel test run
kishansagathiya Dec 6, 2021
698d36e
Merge branch 'development' into 1garo/move-sig-verifier-to-crypto
kishansagathiya Dec 6, 2021
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions lib/crypto/ed25519/ed25519.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,22 @@ type PublicKey ed25519.PublicKey
// PublicKeyBytes is an encoded ed25519 public key
type PublicKeyBytes [PublicKeyLength]byte

// VerifySignature verifies a signature given a public key and a message
func VerifySignature(publicKey, signature, message []byte) error {
pubKey, err := NewPublicKey(publicKey)
if err != nil {
return fmt.Errorf("ed25519: %w", err)
}

_, err = pubKey.Verify(message, signature)
qdm12 marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return fmt.Errorf("ed25519: %w: for message 0x%x, signature 0x%x and public key 0x%x",
qdm12 marked this conversation as resolved.
Show resolved Hide resolved
crypto.ErrSignatureVerificationFailed, message, signature, publicKey)
}

return nil
}

// String returns the PublicKeyBytes formatted as a hex string
func (b PublicKeyBytes) String() string {
pk := [PublicKeyLength]byte(b)
Expand Down
54 changes: 54 additions & 0 deletions lib/crypto/ed25519/ed25519_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,13 @@ package ed25519

import (
ed25519 "crypto/ed25519"
1garo marked this conversation as resolved.
Show resolved Hide resolved
"errors"
"fmt"
"reflect"
"testing"

"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/crypto"

bip39 "github.com/cosmos/go-bip39"
"github.com/stretchr/testify/require"
Expand Down Expand Up @@ -99,3 +102,54 @@ func TestNewKeypairFromMnenomic_Again(t *testing.T) {
expectedPubkey := common.MustHexToBytes("0xf56d9231e7b7badd3f1e10ad15ef8aa08b70839723d0a2d10d7329f0ea2b8c61")
require.Equal(t, expectedPubkey, kp.Public().Encode())
}

func TestVerifySignature(t *testing.T) {
1garo marked this conversation as resolved.
Show resolved Hide resolved
t.Parallel()
keypair, err := GenerateKeypair()
require.NoError(t, err)

message := []byte("Hello world!")

signature, err := keypair.Sign(message)
require.NoError(t, err)

testCase := map[string]struct {
publicKey, signature, message []byte
err error
}{
"success": {
publicKey: keypair.public.Encode(),
signature: signature,
message: message,
},
"bad public key input": {
publicKey: []byte{},
signature: signature,
message: message,
err: errors.New("cannot create public key: input is not 32 bytes"),
},
"verification failed": {
publicKey: keypair.public.Encode(),
signature: []byte{},
message: message,
err: fmt.Errorf("ed25519: %w: for message 0x%x, signature 0x and public key 0x%x",
crypto.ErrSignatureVerificationFailed, message, keypair.public.Encode()),
},
}

for name, value := range testCase {
testCase := value
t.Run(name, func(t *testing.T) {
t.Parallel()

err = VerifySignature(testCase.publicKey, testCase.signature, testCase.message)
kishansagathiya marked this conversation as resolved.
Show resolved Hide resolved

if testCase.err != nil {
require.EqualError(t, err, testCase.err.Error())
return
}
require.NoError(t, err)
})
}

}
12 changes: 12 additions & 0 deletions lib/crypto/secp256k1/secp256k1.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"crypto/ecdsa"
"encoding/hex"
"errors"
"fmt"

"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/crypto"
Expand Down Expand Up @@ -36,6 +37,17 @@ type PublicKey struct {
key ecdsa.PublicKey
}

// VerifySignature verifies a signature given a public key and a message
func VerifySignature(publicKey, signature, message []byte) error {
ok := secp256k1.VerifySignature(publicKey, message, signature)
if !ok {
return fmt.Errorf("secp256k1: %w: for message 0x%x, signature 0x%x and public key 0x%x",
crypto.ErrSignatureVerificationFailed, message, signature, publicKey)
}

return nil
qdm12 marked this conversation as resolved.
Show resolved Hide resolved
}

// RecoverPublicKey returns the 64-byte uncompressed public key that created the given signature.
func RecoverPublicKey(msg, sig []byte) ([]byte, error) {
// update recovery bit
Expand Down
47 changes: 47 additions & 0 deletions lib/crypto/secp256k1/secp256k1_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,12 @@
package secp256k1

import (
"fmt"
"reflect"
"testing"

"github.com/ChainSafe/gossamer/lib/common"
"github.com/ChainSafe/gossamer/lib/crypto"

"github.com/stretchr/testify/require"
)
Expand Down Expand Up @@ -154,3 +156,48 @@ func TestRecoverPublicKeyCompressed(t *testing.T) {
require.NoError(t, err)
require.Equal(t, kp.Public(), r)
}

func TestVerifySignature(t *testing.T) {
1garo marked this conversation as resolved.
Show resolved Hide resolved
t.Parallel()
keypair, err := GenerateKeypair()
require.NoError(t, err)

message := []byte("a225e8c75da7da319af6335e7642d473")

signature, err := keypair.Sign(message)
require.NoError(t, err)

testCase := map[string]struct {
publicKey, signature, message []byte
err error
}{
"success": {
publicKey: keypair.public.Encode(),
signature: signature[:64],
message: message,
},
"verification failed": {
publicKey: keypair.public.Encode(),
signature: []byte{},
message: message,
err: fmt.Errorf("secp256k1: %w: for message 0x%x, signature 0x and public key 0x%x",
crypto.ErrSignatureVerificationFailed, message, keypair.public.Encode()),
},
}

for name, value := range testCase {
testCase := value
t.Run(name, func(t *testing.T) {
t.Parallel()

err = VerifySignature(testCase.publicKey, testCase.signature, testCase.message)
kishansagathiya marked this conversation as resolved.
Show resolved Hide resolved

if testCase.err != nil {
require.EqualError(t, err, testCase.err.Error())
return
}
require.NoError(t, err)
})
}

}
70 changes: 21 additions & 49 deletions lib/runtime/sig_verifier.go → lib/crypto/sig_verifier.go
Original file line number Diff line number Diff line change
@@ -1,31 +1,32 @@
// Copyright 2021 ChainSafe Systems (ON)
// SPDX-License-Identifier: LGPL-3.0-only

package runtime
package crypto

import (
"fmt"
"errors"
"sync"
"time"

"github.com/ChainSafe/gossamer/internal/log"
"github.com/ChainSafe/gossamer/lib/crypto"
"github.com/ChainSafe/gossamer/lib/crypto/ed25519"
"github.com/ChainSafe/gossamer/lib/crypto/sr25519"
"github.com/ethereum/go-ethereum/crypto/secp256k1"
)

// Signature ...
type Signature struct {
PubKey []byte
Sign []byte
Msg []byte
KeyTypeID crypto.KeyType
var ErrSignatureVerificationFailed = errors.New("failed to verify signature")

// SigVerifyFunc verifies a signature given a public key and a message
type SigVerifyFunc func(pubkey, sig, msg []byte) (err error)

// Signing ...
type Signing struct {
qdm12 marked this conversation as resolved.
Show resolved Hide resolved
PubKey []byte
Sign []byte
Msg []byte
VerifyFunc SigVerifyFunc
}

// SignatureVerifier ...
type SignatureVerifier struct {
batch []*Signature
batch []*Signing
init bool // Indicates whether the batch processing is started.
invalid bool // Set to true if any signature verification fails.
logger log.LeveledLogger
Expand All @@ -41,7 +42,7 @@ type SignatureVerifier struct {
// Signatures can be added to the batch using Add().
func NewSignatureVerifier(logger log.LeveledLogger) *SignatureVerifier {
return &SignatureVerifier{
batch: make([]*Signature, 0),
batch: make([]*Signing, 0),
init: false,
invalid: false,
logger: logger,
Expand All @@ -66,11 +67,11 @@ func (sv *SignatureVerifier) Start() {
case <-sv.closeCh:
return
default:
sign := sv.Remove()
if sign == nil {
signature := sv.Remove()
if signature == nil {
continue
}
err := sign.verify()
err := signature.VerifyFunc(signature.PubKey, signature.Sign, signature.Msg)
if err != nil {
sv.logger.Errorf("[ext_crypto_start_batch_verify_version_1]: %s", err)
sv.Invalid()
Expand Down Expand Up @@ -103,7 +104,7 @@ func (sv *SignatureVerifier) Invalid() {
}

// Add ...
func (sv *SignatureVerifier) Add(s *Signature) {
func (sv *SignatureVerifier) Add(s *Signing) {
if sv.IsInvalid() {
return
}
Expand All @@ -114,7 +115,7 @@ func (sv *SignatureVerifier) Add(s *Signature) {
}

// Remove returns the first signature from the batch. Returns nil if batch is empty.
func (sv *SignatureVerifier) Remove() *Signature {
func (sv *SignatureVerifier) Remove() *Signing {
sv.Lock()
defer sv.Unlock()
if len(sv.batch) == 0 {
Expand All @@ -130,7 +131,7 @@ func (sv *SignatureVerifier) Reset() {
sv.Lock()
defer sv.Unlock()
sv.init = false
sv.batch = make([]*Signature, 0)
sv.batch = make([]*Signing, 0)
sv.invalid = false
sv.closeCh = make(chan struct{})
}
Expand All @@ -153,32 +154,3 @@ func (sv *SignatureVerifier) Finish() bool {
sv.Reset()
return !isInvalid
}

func (sig *Signature) verify() error {
switch sig.KeyTypeID {
case crypto.Ed25519Type:
pubKey, err := ed25519.NewPublicKey(sig.PubKey)
if err != nil {
return fmt.Errorf("failed to fetch ed25519 public key: %s", err)
}
ok, err := pubKey.Verify(sig.Msg, sig.Sign)
if err != nil || !ok {
return fmt.Errorf("failed to verify ed25519 signature: %s", err)
}
case crypto.Sr25519Type:
pubKey, err := sr25519.NewPublicKey(sig.PubKey)
if err != nil {
return fmt.Errorf("failed to fetch sr25519 public key: %s", err)
}
ok, err := pubKey.Verify(sig.Msg, sig.Sign)
if err != nil || !ok {
return fmt.Errorf("failed to verify sr25519 signature: %s", err)
}
case crypto.Secp256k1Type:
ok := secp256k1.VerifySignature(sig.PubKey, sig.Msg, sig.Sign)
if !ok {
return fmt.Errorf("failed to verify secp256k1 signature")
}
}
return nil
}
Loading