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(lib/runtime/wasmer) implement ext_crypto_ecdsa_verify_version_2 #1912

Merged
merged 9 commits into from
Oct 25, 2021
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]
qdm12 marked this conversation as resolved.
Show resolved Hide resolved

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)
qdm12 marked this conversation as resolved.
Show resolved Hide resolved
}

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 @@ -2054,6 +2105,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
100 changes: 100 additions & 0 deletions lib/runtime/wasmer/imports_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -629,6 +629,106 @@ 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 := []struct {
name string
sig []byte
msg []byte
key []byte
expected []byte
errMsg string
}{
{
name: "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},
},
{
name: "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},
},
{
name: "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},
},
{
name: "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},
expected: nil,
errMsg: "Failed to call the `rtm_ext_crypto_ecdsa_verify_version_2` exported function.",
},
{
name: "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},
errMsg: "Failed to call the `rtm_ext_crypto_ecdsa_verify_version_2` exported function.",
},
}
for _, tc := range testCases {
tc := tc
qdm12 marked this conversation as resolved.
Show resolved Hide resolved
t.Run(tc.name, func(t *testing.T) {
qdm12 marked this conversation as resolved.
Show resolved Hide resolved
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...))
require.Equal(t, tc.expected, ret)
if tc.errMsg != "" {
require.EqualError(t, err, tc.errMsg)
return
}
require.NoError(t, err)
qdm12 marked this conversation as resolved.
Show resolved Hide resolved
})
}
}

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

Expand Down