Skip to content

Commit

Permalink
feat(lib/runtime/wasmer) implement ext_crypto_ecdsa_verify_version_2 (#…
Browse files Browse the repository at this point in the history
…1912)

* implement ext_crypto_ecdsa_verify_version_2

* remove comment

* cleanup tests

* add to tests

* update test to use map and assert

Co-authored-by: noot <36753753+noot@users.noreply.github.com>
  • Loading branch information
edwardmack and noot authored Oct 25, 2021
1 parent 579a791 commit 2a418f0
Show file tree
Hide file tree
Showing 3 changed files with 151 additions and 1 deletion.
2 changes: 1 addition & 1 deletion lib/runtime/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ const (
// v0.8 test API wasm
HOST_API_TEST_RUNTIME = "hostapi_runtime"
HOST_API_TEST_RUNTIME_FP = "hostapi_runtime.compact.wasm"
HOST_API_TEST_RUNTIME_URL = "https://github.com/ChainSafe/polkadot-spec/blob/f9f8c94397d155c4f2edc9c59828dc4ef2c62dd3/test/hostapi_runtime.compact.wasm?raw=true"
HOST_API_TEST_RUNTIME_URL = "https://github.com/ChainSafe/polkadot-spec/blob/80fa2be272820731b5159e9dc2a3eec3cca02b4d/test/hostapi_runtime.compact.wasm?raw=true"

// v0.8 substrate runtime with modified name and babe C=(1, 1)
DEV_RUNTIME = "dev_runtime"
Expand Down
55 changes: 55 additions & 0 deletions lib/runtime/wasmer/imports.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ package wasmer
// extern int64_t ext_crypto_secp256k1_ecdsa_recover_version_2(void *context, int32_t a, int32_t b);
// extern int64_t ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(void *context, int32_t a, int32_t b);
// extern int64_t ext_crypto_secp256k1_ecdsa_recover_compressed_version_2(void *context, int32_t a, int32_t b);
// extern int32_t ext_crypto_ecdsa_verify_version_2(void *context, int32_t a, int64_t b, int32_t c);
// extern int32_t ext_crypto_sr25519_generate_version_1(void *context, int32_t a, int64_t b);
// extern int64_t ext_crypto_sr25519_public_keys_version_1(void *context, int32_t a);
// extern int64_t ext_crypto_sr25519_sign_version_1(void *context, int32_t a, int32_t b, int64_t c);
Expand Down Expand Up @@ -449,6 +450,56 @@ func ext_crypto_secp256k1_ecdsa_recover_version_2(context unsafe.Pointer, sig, m
return ext_crypto_secp256k1_ecdsa_recover_version_1(context, sig, msg)
}

//export ext_crypto_ecdsa_verify_version_2
func ext_crypto_ecdsa_verify_version_2(context unsafe.Pointer, sig C.int32_t, msg C.int64_t, key C.int32_t) C.int32_t {
logger.Trace("executing...")

instanceContext := wasm.IntoInstanceContext(context)
memory := instanceContext.Memory().Data()
sigVerifier := instanceContext.Data().(*runtime.Context).SigVerifier

message := asMemorySlice(instanceContext, msg)
signature := memory[sig : sig+64]
pubKey := memory[key : key+33]

pub := new(secp256k1.PublicKey)
err := pub.Decode(pubKey)
if err != nil {
logger.Error("failed to decode public key", "error", err)
return C.int32_t(0)
}

logger.Debug("", "pub", pub.Hex(),
"message", fmt.Sprintf("0x%x", message),
"signature", fmt.Sprintf("0x%x", signature),
)

hash, err := common.Blake2bHash(message)
if err != nil {
logger.Error("failed to hash message", "error", err)
return C.int32_t(0)
}

if sigVerifier.IsStarted() {
signature := runtime.Signature{
PubKey: pub.Encode(),
Sign: signature,
Msg: hash[:],
KeyTypeID: crypto.Secp256k1Type,
}
sigVerifier.Add(&signature)
return C.int32_t(1)
}

if ok, err := pub.Verify(hash[:], signature); err != nil || !ok {
logger.Error("failed to validate signature", "error", err)
return C.int32_t(0)
}

logger.Debug("validated signature")
return C.int32_t(1)
}

//export ext_crypto_secp256k1_ecdsa_recover_compressed_version_1
func ext_crypto_secp256k1_ecdsa_recover_compressed_version_1(context unsafe.Pointer, sig, msg C.int32_t) C.int64_t {
logger.Trace("[ext_crypto_secp256k1_ecdsa_recover_compressed_version_1] executing...")
Expand Down Expand Up @@ -2102,6 +2153,10 @@ func ImportsNodeRuntime() (*wasm.Imports, error) { //nolint
if err != nil {
return nil, err
}
_, err = imports.Append("ext_crypto_ecdsa_verify_version_2", ext_crypto_ecdsa_verify_version_2, C.ext_crypto_ecdsa_verify_version_2)
if err != nil {
return nil, err
}
_, err = imports.Append("ext_crypto_start_batch_verify_version_1", ext_crypto_start_batch_verify_version_1, C.ext_crypto_start_batch_verify_version_1)
if err != nil {
return nil, err
Expand Down
95 changes: 95 additions & 0 deletions lib/runtime/wasmer/imports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,9 @@ import (
"github.com/ChainSafe/gossamer/lib/trie"
"github.com/ChainSafe/gossamer/pkg/scale"
log "github.com/ChainSafe/log15"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"github.com/wasmerio/go-ext-wasm/wasmer"
)

var testChildKey = []byte("childKey")
Expand Down Expand Up @@ -629,6 +631,99 @@ func Test_ext_crypto_ed25519_verify_version_1(t *testing.T) {
require.True(t, read.Exists())
}

func Test_ext_crypto_ecdsa_verify_version_2(t *testing.T) {
t.Parallel()

inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME)

kp, err := secp256k1.GenerateKeypair()
require.NoError(t, err)

pubKeyData := kp.Public().Encode()
encPubKey, err := scale.Marshal(pubKeyData)
require.NoError(t, err)

msgData := []byte("Hello world!")
encMsg, err := scale.Marshal(msgData)
require.NoError(t, err)

msgHash, err := common.Blake2bHash(msgData)
require.NoError(t, err)

sig, err := kp.Private().Sign(msgHash[:])
require.NoError(t, err)

encSig, err := scale.Marshal(sig)
require.NoError(t, err)

ret, err := inst.Exec("rtm_ext_crypto_ecdsa_verify_version_2", append(append(encSig, encMsg...), encPubKey...))
require.NoError(t, err)

buf := bytes.NewBuffer(ret)

read, err := new(optional.Bytes).Decode(buf)
require.NoError(t, err)

require.True(t, read.Exists())
}

func Test_ext_crypto_ecdsa_verify_version_2_Table(t *testing.T) {
testCases := map[string]struct {
sig []byte
msg []byte
key []byte
expected []byte
err error
}{
"valid signature": {
sig: []byte{5, 1, 187, 179, 88, 183, 46, 115, 242, 32, 9, 54, 141, 207, 44, 15, 238, 42, 217, 196, 111, 173, 239, 204, 128, 93, 49, 179, 137, 150, 162, 125, 226, 225, 28, 145, 122, 127, 15, 154, 185, 11, 3, 66, 27, 187, 204, 242, 107, 68, 26, 111, 245, 30, 115, 141, 85, 74, 158, 211, 161, 217, 43, 151, 120, 125, 1},
msg: []byte{48, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33},
key: []byte{132, 2, 39, 206, 55, 134, 131, 142, 43, 100, 63, 134, 96, 14, 253, 15, 222, 119, 154, 110, 188, 20, 159, 62, 125, 42, 59, 127, 19, 16, 0, 161, 236, 109},
expected: []byte{1, 0, 0, 0},
},
"invalid signature": {
sig: []byte{5, 1, 187, 0, 0, 183, 46, 115, 242, 32, 9, 54, 141, 207, 44, 15, 238, 42, 217, 196, 111, 173, 239, 204, 128, 93, 49, 179, 137, 150, 162, 125, 226, 225, 28, 145, 122, 127, 15, 154, 185, 11, 3, 66, 27, 187, 204, 242, 107, 68, 26, 111, 245, 30, 115, 141, 85, 74, 158, 211, 161, 217, 43, 151, 120, 125, 1},
msg: []byte{48, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33},
key: []byte{132, 2, 39, 206, 55, 134, 131, 142, 43, 100, 63, 134, 96, 14, 253, 15, 222, 119, 154, 110, 188, 20, 159, 62, 125, 42, 59, 127, 19, 16, 0, 161, 236, 109},
expected: []byte{0, 0, 0, 0},
},
"wrong key": {
sig: []byte{5, 1, 187, 0, 0, 183, 46, 115, 242, 32, 9, 54, 141, 207, 44, 15, 238, 42, 217, 196, 111, 173, 239, 204, 128, 93, 49, 179, 137, 150, 162, 125, 226, 225, 28, 145, 122, 127, 15, 154, 185, 11, 3, 66, 27, 187, 204, 242, 107, 68, 26, 111, 245, 30, 115, 141, 85, 74, 158, 211, 161, 217, 43, 151, 120, 125, 1},
msg: []byte{48, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33},
key: []byte{132, 2, 39, 0, 55, 134, 131, 142, 43, 100, 63, 134, 96, 14, 253, 15, 222, 119, 154, 110, 188, 20, 159, 62, 125, 42, 59, 127, 19, 16, 0, 161, 236, 109},
expected: []byte{0, 0, 0, 0},
},
"invalid key": {
sig: []byte{5, 1, 187, 0, 0, 183, 46, 115, 242, 32, 9, 54, 141, 207, 44, 15, 238, 42, 217, 196, 111, 173, 239, 204, 128, 93, 49, 179, 137, 150, 162, 125, 226, 225, 28, 145, 122, 127, 15, 154, 185, 11, 3, 66, 27, 187, 204, 242, 107, 68, 26, 111, 245, 30, 115, 141, 85, 74, 158, 211, 161, 217, 43, 151, 120, 125, 1},
msg: []byte{48, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 33},
key: []byte{132, 2, 39, 55, 134, 131, 142, 43, 100, 63, 134, 96, 14, 253, 15, 222, 119, 154, 110, 188, 20, 159, 62, 125, 42, 59, 127, 19, 16, 0, 161, 236, 109},
err: wasmer.NewExportedFunctionError("rtm_ext_crypto_ecdsa_verify_version_2", "Failed to call the `%s` exported function."),
},
"invalid message": {
sig: []byte{5, 1, 187, 179, 88, 183, 46, 115, 242, 32, 9, 54, 141, 207, 44, 15, 238, 42, 217, 196, 111, 173, 239, 204, 128, 93, 49, 179, 137, 150, 162, 125, 226, 225, 28, 145, 122, 127, 15, 154, 185, 11, 3, 66, 27, 187, 204, 242, 107, 68, 26, 111, 245, 30, 115, 141, 85, 74, 158, 211, 161, 217, 43, 151, 120, 125, 1},
msg: []byte{48, 72, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100},
key: []byte{132, 2, 39, 206, 55, 134, 131, 142, 43, 100, 63, 134, 96, 14, 253, 15, 222, 119, 154, 110, 188, 20, 159, 62, 125, 42, 59, 127, 19, 16, 0, 161, 236, 109},
err: wasmer.NewExportedFunctionError("rtm_ext_crypto_ecdsa_verify_version_2", "Failed to call the `%s` exported function."),
},
}
for name, tc := range testCases {
tc := tc
t.Run(name, func(t *testing.T) {
t.Parallel()

inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME)

ret, err := inst.Exec("rtm_ext_crypto_ecdsa_verify_version_2", append(append(tc.sig, tc.msg...), tc.key...))
assert.Equal(t, tc.expected, ret)
if tc.err != nil {
assert.EqualError(t, err, tc.err.Error())
return
}
assert.NoError(t, err)
})
}
}

func Test_ext_crypto_sr25519_generate_version_1(t *testing.T) {
inst := NewTestInstance(t, runtime.HOST_API_TEST_RUNTIME)

Expand Down

0 comments on commit 2a418f0

Please sign in to comment.