Skip to content

Commit dc8bbef

Browse files
1garotimwu20
authored andcommitted
feat(wasmer/crypto): move sig verifier to crypto pkg (#2057)
1 parent 3f46262 commit dc8bbef

File tree

15 files changed

+432
-110
lines changed

15 files changed

+432
-110
lines changed

lib/crypto/ed25519/ed25519.go

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,24 @@ type PublicKey ed25519.PublicKey
4444
// PublicKeyBytes is an encoded ed25519 public key
4545
type PublicKeyBytes [PublicKeyLength]byte
4646

47+
// VerifySignature verifies a signature given a public key and a message
48+
func VerifySignature(publicKey, signature, message []byte) error {
49+
pubKey, err := NewPublicKey(publicKey)
50+
if err != nil {
51+
return fmt.Errorf("ed25519: %w", err)
52+
}
53+
54+
ok, err := pubKey.Verify(message, signature)
55+
if err != nil {
56+
return fmt.Errorf("ed25519: %w", err)
57+
} else if !ok {
58+
return fmt.Errorf("ed25519: %w: for message 0x%x, signature 0x%x and public key 0x%x",
59+
crypto.ErrSignatureVerificationFailed, message, signature, publicKey)
60+
}
61+
62+
return nil
63+
}
64+
4765
// String returns the PublicKeyBytes formatted as a hex string
4866
func (b PublicKeyBytes) String() string {
4967
pk := [PublicKeyLength]byte(b)

lib/crypto/ed25519/ed25519_test.go

Lines changed: 62 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,13 @@
44
package ed25519
55

66
import (
7-
ed25519 "crypto/ed25519"
7+
"crypto/ed25519"
8+
"fmt"
89
"reflect"
910
"testing"
1011

1112
"github.com/ChainSafe/gossamer/lib/common"
13+
"github.com/ChainSafe/gossamer/lib/crypto"
1214

1315
bip39 "github.com/cosmos/go-bip39"
1416
"github.com/stretchr/testify/require"
@@ -99,3 +101,62 @@ func TestNewKeypairFromMnenomic_Again(t *testing.T) {
99101
expectedPubkey := common.MustHexToBytes("0xf56d9231e7b7badd3f1e10ad15ef8aa08b70839723d0a2d10d7329f0ea2b8c61")
100102
require.Equal(t, expectedPubkey, kp.Public().Encode())
101103
}
104+
105+
func TestVerifySignature(t *testing.T) {
106+
t.Parallel()
107+
keypair, err := GenerateKeypair()
108+
require.NoError(t, err)
109+
110+
publicKey := keypair.public.Encode()
111+
112+
message := []byte("Hello world!")
113+
114+
signature, err := keypair.Sign(message)
115+
require.NoError(t, err)
116+
117+
testCase := map[string]struct {
118+
publicKey, signature, message []byte
119+
err error
120+
}{
121+
"success": {
122+
publicKey: publicKey,
123+
signature: signature,
124+
message: message,
125+
},
126+
"bad public key input": {
127+
publicKey: []byte{},
128+
signature: signature,
129+
message: message,
130+
err: fmt.Errorf("ed25519: cannot create public key: input is not 32 bytes"),
131+
},
132+
"invalid signature length": {
133+
publicKey: publicKey,
134+
signature: []byte{},
135+
message: message,
136+
err: fmt.Errorf("ed25519: invalid signature length"),
137+
},
138+
"verification failed": {
139+
publicKey: publicKey,
140+
signature: signature,
141+
message: []byte("a225e8c75da7da319af6335e7642d473"),
142+
err: fmt.Errorf("ed25519: %w: for message 0x%x, signature 0x%x and public key 0x%x",
143+
crypto.ErrSignatureVerificationFailed, []byte("a225e8c75da7da319af6335e7642d473"), signature, publicKey),
144+
},
145+
}
146+
147+
for name, value := range testCase {
148+
testCase := value
149+
t.Run(name, func(t *testing.T) {
150+
t.Parallel()
151+
152+
err := VerifySignature(testCase.publicKey, testCase.signature, testCase.message)
153+
154+
if testCase.err != nil {
155+
require.EqualError(t, err, testCase.err.Error())
156+
return
157+
}
158+
require.NoError(t, err)
159+
})
160+
}
161+
162+
}

lib/crypto/secp256k1/secp256k1.go

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"crypto/ecdsa"
88
"encoding/hex"
99
"errors"
10+
"fmt"
1011

1112
"github.com/ChainSafe/gossamer/lib/common"
1213
"github.com/ChainSafe/gossamer/lib/crypto"
@@ -36,6 +37,17 @@ type PublicKey struct {
3637
key ecdsa.PublicKey
3738
}
3839

40+
// VerifySignature verifies a signature given a public key and a message
41+
func VerifySignature(publicKey, signature, message []byte) error {
42+
ok := secp256k1.VerifySignature(publicKey, message, signature)
43+
if ok {
44+
return nil
45+
}
46+
47+
return fmt.Errorf("secp256k1: %w: for message 0x%x, signature 0x%x and public key 0x%x",
48+
crypto.ErrSignatureVerificationFailed, message, signature, publicKey)
49+
}
50+
3951
// RecoverPublicKey returns the 64-byte uncompressed public key that created the given signature.
4052
func RecoverPublicKey(msg, sig []byte) ([]byte, error) {
4153
// update recovery bit

lib/crypto/secp256k1/secp256k1_test.go

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,12 @@
44
package secp256k1
55

66
import (
7+
"fmt"
78
"reflect"
89
"testing"
910

1011
"github.com/ChainSafe/gossamer/lib/common"
12+
"github.com/ChainSafe/gossamer/lib/crypto"
1113

1214
"github.com/stretchr/testify/require"
1315
)
@@ -154,3 +156,48 @@ func TestRecoverPublicKeyCompressed(t *testing.T) {
154156
require.NoError(t, err)
155157
require.Equal(t, kp.Public(), r)
156158
}
159+
160+
func TestVerifySignature(t *testing.T) {
161+
t.Parallel()
162+
keypair, err := GenerateKeypair()
163+
require.NoError(t, err)
164+
165+
message := []byte("a225e8c75da7da319af6335e7642d473")
166+
167+
signature, err := keypair.Sign(message)
168+
require.NoError(t, err)
169+
170+
testCase := map[string]struct {
171+
publicKey, signature, message []byte
172+
err error
173+
}{
174+
"success": {
175+
publicKey: keypair.public.Encode(),
176+
signature: signature[:64],
177+
message: message,
178+
},
179+
"verification failed": {
180+
publicKey: keypair.public.Encode(),
181+
signature: []byte{},
182+
message: message,
183+
err: fmt.Errorf("secp256k1: %w: for message 0x%x, signature 0x and public key 0x%x",
184+
crypto.ErrSignatureVerificationFailed, message, keypair.public.Encode()),
185+
},
186+
}
187+
188+
for name, value := range testCase {
189+
testCase := value
190+
t.Run(name, func(t *testing.T) {
191+
t.Parallel()
192+
193+
err := VerifySignature(testCase.publicKey, testCase.signature, testCase.message)
194+
195+
if testCase.err != nil {
196+
require.EqualError(t, err, testCase.err.Error())
197+
return
198+
}
199+
require.NoError(t, err)
200+
})
201+
}
202+
203+
}

lib/runtime/sig_verifier.go renamed to lib/crypto/sig_verifier.go

Lines changed: 21 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,32 @@
11
// Copyright 2021 ChainSafe Systems (ON)
22
// SPDX-License-Identifier: LGPL-3.0-only
33

4-
package runtime
4+
package crypto
55

66
import (
7-
"fmt"
7+
"errors"
88
"sync"
99
"time"
1010

1111
"github.com/ChainSafe/gossamer/internal/log"
12-
"github.com/ChainSafe/gossamer/lib/crypto"
13-
"github.com/ChainSafe/gossamer/lib/crypto/ed25519"
14-
"github.com/ChainSafe/gossamer/lib/crypto/sr25519"
15-
"github.com/ethereum/go-ethereum/crypto/secp256k1"
1612
)
1713

18-
// Signature ...
19-
type Signature struct {
20-
PubKey []byte
21-
Sign []byte
22-
Msg []byte
23-
KeyTypeID crypto.KeyType
14+
var ErrSignatureVerificationFailed = errors.New("failed to verify signature")
15+
16+
// SigVerifyFunc verifies a signature given a public key and a message
17+
type SigVerifyFunc func(pubkey, sig, msg []byte) (err error)
18+
19+
// SignatureInfo ...
20+
type SignatureInfo struct {
21+
PubKey []byte
22+
Sign []byte
23+
Msg []byte
24+
VerifyFunc SigVerifyFunc
2425
}
2526

2627
// SignatureVerifier ...
2728
type SignatureVerifier struct {
28-
batch []*Signature
29+
batch []*SignatureInfo
2930
init bool // Indicates whether the batch processing is started.
3031
invalid bool // Set to true if any signature verification fails.
3132
logger log.LeveledLogger
@@ -41,7 +42,7 @@ type SignatureVerifier struct {
4142
// Signatures can be added to the batch using Add().
4243
func NewSignatureVerifier(logger log.LeveledLogger) *SignatureVerifier {
4344
return &SignatureVerifier{
44-
batch: make([]*Signature, 0),
45+
batch: make([]*SignatureInfo, 0),
4546
init: false,
4647
invalid: false,
4748
logger: logger,
@@ -66,11 +67,11 @@ func (sv *SignatureVerifier) Start() {
6667
case <-sv.closeCh:
6768
return
6869
default:
69-
sign := sv.Remove()
70-
if sign == nil {
70+
signature := sv.Remove()
71+
if signature == nil {
7172
continue
7273
}
73-
err := sign.verify()
74+
err := signature.VerifyFunc(signature.PubKey, signature.Sign, signature.Msg)
7475
if err != nil {
7576
sv.logger.Errorf("[ext_crypto_start_batch_verify_version_1]: %s", err)
7677
sv.Invalid()
@@ -103,7 +104,7 @@ func (sv *SignatureVerifier) Invalid() {
103104
}
104105

105106
// Add ...
106-
func (sv *SignatureVerifier) Add(s *Signature) {
107+
func (sv *SignatureVerifier) Add(s *SignatureInfo) {
107108
if sv.IsInvalid() {
108109
return
109110
}
@@ -114,7 +115,7 @@ func (sv *SignatureVerifier) Add(s *Signature) {
114115
}
115116

116117
// Remove returns the first signature from the batch. Returns nil if batch is empty.
117-
func (sv *SignatureVerifier) Remove() *Signature {
118+
func (sv *SignatureVerifier) Remove() *SignatureInfo {
118119
sv.Lock()
119120
defer sv.Unlock()
120121
if len(sv.batch) == 0 {
@@ -130,7 +131,7 @@ func (sv *SignatureVerifier) Reset() {
130131
sv.Lock()
131132
defer sv.Unlock()
132133
sv.init = false
133-
sv.batch = make([]*Signature, 0)
134+
sv.batch = make([]*SignatureInfo, 0)
134135
sv.invalid = false
135136
sv.closeCh = make(chan struct{})
136137
}
@@ -153,32 +154,3 @@ func (sv *SignatureVerifier) Finish() bool {
153154
sv.Reset()
154155
return !isInvalid
155156
}
156-
157-
func (sig *Signature) verify() error {
158-
switch sig.KeyTypeID {
159-
case crypto.Ed25519Type:
160-
pubKey, err := ed25519.NewPublicKey(sig.PubKey)
161-
if err != nil {
162-
return fmt.Errorf("failed to fetch ed25519 public key: %s", err)
163-
}
164-
ok, err := pubKey.Verify(sig.Msg, sig.Sign)
165-
if err != nil || !ok {
166-
return fmt.Errorf("failed to verify ed25519 signature: %s", err)
167-
}
168-
case crypto.Sr25519Type:
169-
pubKey, err := sr25519.NewPublicKey(sig.PubKey)
170-
if err != nil {
171-
return fmt.Errorf("failed to fetch sr25519 public key: %s", err)
172-
}
173-
ok, err := pubKey.Verify(sig.Msg, sig.Sign)
174-
if err != nil || !ok {
175-
return fmt.Errorf("failed to verify sr25519 signature: %s", err)
176-
}
177-
case crypto.Secp256k1Type:
178-
ok := secp256k1.VerifySignature(sig.PubKey, sig.Msg, sig.Sign)
179-
if !ok {
180-
return fmt.Errorf("failed to verify secp256k1 signature")
181-
}
182-
}
183-
return nil
184-
}

0 commit comments

Comments
 (0)