Skip to content

Commit

Permalink
implement ecdsa sign, verify, sign_prehashed and verify_prehashed (#2120
Browse files Browse the repository at this point in the history
)

* implement ecdsa sign, sign_prehashed and verify_prehashed

Closes #1968

* fix compilation errors and return an error

if we fail to parse secret key

* implement ecdsa verify

* remove outdated comment

#2120 (comment)

* avoid extra copy

* improve comments

Co-authored-by: mergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
  • Loading branch information
melekes and mergify[bot] authored Mar 7, 2022
1 parent 71128fa commit 00ba3c8
Show file tree
Hide file tree
Showing 3 changed files with 153 additions and 5 deletions.
36 changes: 35 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,7 @@ hashbrown = { version = "0.12.0", default-features = false, features = ["serde"]
hex = { version = "0.4.3", default-features = false }
hmac = { version = "0.12.1", default-features = false }
itertools = { version = "0.10.3", default-features = false }
# TODO: don't activate `static-context` by default; see https://github.com/paritytech/libsecp256k1/issues/77
libsecp256k1 = { version = "0.7.0", default-features = false, features = ["static-context"] }
libsecp256k1 = { version = "0.7.0", default-features = false, features = ["static-context", "hmac"] }
# Reminder: `log` is forbidden
merlin = { version = "3.0", default-features = false }
nom = { version = "7.1.0", default-features = false, features = ["alloc"] }
Expand Down
119 changes: 117 additions & 2 deletions src/executor/host.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1113,8 +1113,117 @@ impl ReadyToRun {
})
}
HostFunction::ext_crypto_ecdsa_generate_version_1 => host_fn_not_implemented!(),
HostFunction::ext_crypto_ecdsa_sign_version_1 => host_fn_not_implemented!(),
HostFunction::ext_crypto_ecdsa_sign_version_1 => {
// NOTE: safe to unwrap here because we supply the nn to blake2b fn
let data = <[u8; 32]>::try_from(
blake2_rfc::blake2b::blake2b(32, &[], expect_pointer_size!(0).as_ref())
.as_bytes(),
)
.unwrap();
let message = libsecp256k1::Message::parse(&data);

if let Ok(sc) =
libsecp256k1::SecretKey::parse(&expect_pointer_constant_size!(1, 32))
{
let (sig, ri) = libsecp256k1::sign(&message, &sc);

// NOTE: the function returns 2 slices: signature (64 bytes) and recovery ID (1 byte; AS A SLICE)
self.inner.alloc_write_and_return_pointer(
host_fn.name(),
[&sig.serialize()[..], &[ri.serialize()]].into_iter(),
)
} else {
HostVm::Error {
error: Error::ParamDecodeError,
prototype: self.inner.into_prototype(),
}
}
}
HostFunction::ext_crypto_ecdsa_public_keys_version_1 => host_fn_not_implemented!(),
HostFunction::ext_crypto_ecdsa_verify_version_1 => {
let success = {
// NOTE: safe to unwrap here because we supply the nn to blake2b fn
let data = <[u8; 32]>::try_from(
blake2_rfc::blake2b::blake2b(32, &[], expect_pointer_size!(0).as_ref())
.as_bytes(),
)
.unwrap();
let message = libsecp256k1::Message::parse(&data);

// signature (64 bytes) + recovery ID (1 byte)
let sig_bytes = expect_pointer_constant_size!(0, 65);
if let Ok(sig) = libsecp256k1::Signature::parse_standard_slice(&sig_bytes[..64])
{
if let Ok(ri) = libsecp256k1::RecoveryId::parse(sig_bytes[64]) {
if let Ok(actual) = libsecp256k1::recover(&message, &sig, &ri) {
expect_pointer_constant_size!(2, 33)[..]
== actual.serialize_compressed()[..]
} else {
false
}
} else {
false
}
} else {
false
}
};

HostVm::ReadyToRun(ReadyToRun {
resume_value: Some(vm::WasmValue::I32(if success { 1 } else { 0 })),
inner: self.inner,
})
}
HostFunction::ext_crypto_ecdsa_sign_prehashed_version_1 => {
let message = libsecp256k1::Message::parse(&expect_pointer_constant_size!(0, 32));

if let Ok(sc) =
libsecp256k1::SecretKey::parse(&expect_pointer_constant_size!(1, 32))
{
let (sig, ri) = libsecp256k1::sign(&message, &sc);

// NOTE: the function returns 2 slices: signature (64 bytes) and recovery ID (1 byte; AS A SLICE)
self.inner.alloc_write_and_return_pointer(
host_fn.name(),
[&sig.serialize()[..], &[ri.serialize()]].into_iter(),
)
} else {
HostVm::Error {
error: Error::ParamDecodeError,
prototype: self.inner.into_prototype(),
}
}
}
HostFunction::ext_crypto_ecdsa_verify_prehashed_version_1 => {
let success = {
let message =
libsecp256k1::Message::parse(&expect_pointer_constant_size!(0, 32));

// signature (64 bytes) + recovery ID (1 byte)
let sig_bytes = expect_pointer_constant_size!(0, 65);
if let Ok(sig) = libsecp256k1::Signature::parse_standard_slice(&sig_bytes[..64])
{
if let Ok(ri) = libsecp256k1::RecoveryId::parse(sig_bytes[64]) {
if let Ok(actual) = libsecp256k1::recover(&message, &sig, &ri) {
expect_pointer_constant_size!(2, 33)[..]
== actual.serialize_compressed()[..]
} else {
false
}
} else {
false
}
} else {
false
}
};

HostVm::ReadyToRun(ReadyToRun {
resume_value: Some(vm::WasmValue::I32(if success { 1 } else { 0 })),
inner: self.inner,
})
}

HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_1
| HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_2 => {
let sig = expect_pointer_constant_size!(0, 65);
Expand Down Expand Up @@ -2702,6 +2811,9 @@ externalities! {
ext_crypto_ecdsa_generate_version_1,
ext_crypto_ecdsa_sign_version_1,
ext_crypto_ecdsa_public_keys_version_1,
ext_crypto_ecdsa_verify_version_1,
ext_crypto_ecdsa_sign_prehashed_version_1,
ext_crypto_ecdsa_verify_prehashed_version_1,
ext_crypto_secp256k1_ecdsa_recover_version_1,
ext_crypto_secp256k1_ecdsa_recover_version_2,
ext_crypto_secp256k1_ecdsa_recover_compressed_version_1,
Expand Down Expand Up @@ -2807,8 +2919,11 @@ impl HostFunction {
HostFunction::ext_crypto_sr25519_verify_version_1 => 3,
HostFunction::ext_crypto_sr25519_verify_version_2 => 3,
HostFunction::ext_crypto_ecdsa_generate_version_1 => todo!(),
HostFunction::ext_crypto_ecdsa_sign_version_1 => todo!(),
HostFunction::ext_crypto_ecdsa_sign_version_1 => 2,
HostFunction::ext_crypto_ecdsa_public_keys_version_1 => todo!(),
HostFunction::ext_crypto_ecdsa_verify_version_1 => 3,
HostFunction::ext_crypto_ecdsa_sign_prehashed_version_1 => 2,
HostFunction::ext_crypto_ecdsa_verify_prehashed_version_1 => 3,
HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_1 => 2,
HostFunction::ext_crypto_secp256k1_ecdsa_recover_version_2 => 2,
HostFunction::ext_crypto_secp256k1_ecdsa_recover_compressed_version_1 => 2,
Expand Down

0 comments on commit 00ba3c8

Please sign in to comment.