From fe0d29ff489a610e83a39c15e8cc60dc7c2900ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Bizjak?= Date: Mon, 2 May 2022 21:57:03 +0200 Subject: [PATCH 1/5] Towards the implementation of cryptographic primitives in the host. --- wasm-chain-integration/Cargo.lock | 42 +++++++++ wasm-chain-integration/Cargo.toml | 2 + wasm-chain-integration/src/v1/mod.rs | 117 +++++++++++++++++++++++++ wasm-chain-integration/src/v1/types.rs | 25 ++++++ 4 files changed, 186 insertions(+) diff --git a/wasm-chain-integration/Cargo.lock b/wasm-chain-integration/Cargo.lock index 9996fc84..2f3a0c06 100644 --- a/wasm-chain-integration/Cargo.lock +++ b/wasm-chain-integration/Cargo.lock @@ -149,6 +149,12 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "1.0.0" @@ -522,6 +528,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" + [[package]] name = "lazy_static" version = "0.2.11" @@ -894,6 +906,24 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "secp256k1" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26947345339603ae8395f68e2f3d85a6b0a8ddfe6315818e80b8504415099db0" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b5b9d7322572e1f3aeed208668ce87789b3645dbb73082c5ce99a004103a35" +dependencies = [ + "cc", +] + [[package]] name = "semver" version = "1.0.6" @@ -992,6 +1022,16 @@ dependencies = [ "digest 0.10.3", ] +[[package]] +name = "sha3" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86" +dependencies = [ + "digest 0.10.3", + "keccak", +] + [[package]] name = "slab" version = "0.4.5" @@ -1207,8 +1247,10 @@ dependencies = [ "num_enum", "ptree", "quickcheck", + "secp256k1", "serde 1.0.136", "sha2 0.10.2", + "sha3", "slab", "thiserror", "tinyvec", diff --git a/wasm-chain-integration/Cargo.toml b/wasm-chain-integration/Cargo.toml index 98cc838f..7bcb9267 100644 --- a/wasm-chain-integration/Cargo.toml +++ b/wasm-chain-integration/Cargo.toml @@ -22,6 +22,8 @@ serde = "1.0" num_enum = "0.5" derive_more = "0.99" sha2 = "0.10" +sha3 = "0.10" +secp256k1 = "0.22" thiserror = "1" byteorder = "1.4" tinyvec = {version = "1.5", features = ["alloc"]} diff --git a/wasm-chain-integration/src/v1/mod.rs b/wasm-chain-integration/src/v1/mod.rs index 5fca5a12..7a276e56 100644 --- a/wasm-chain-integration/src/v1/mod.rs +++ b/wasm-chain-integration/src/v1/mod.rs @@ -13,6 +13,7 @@ use concordium_contracts_common::{ OwnedEntrypointName, ReceiveName, }; use machine::Value; +use sha3::Digest; use std::{borrow::Borrow, io::Write, sync::Arc}; use trie::BackingStoreLoad; pub use types::*; @@ -621,6 +622,104 @@ mod host { memory[start as usize..end].copy_from_slice(entrypoint_str.as_bytes()); Ok(()) } + + #[cfg_attr(not(feature = "fuzz-coverage"), inline)] + pub fn verify_ed25519_signature( + memory: &mut Vec, + stack: &mut machine::RuntimeStack, + energy: &mut InterpreterEnergy, + ) -> machine::RunResult<()> { + todo!() + } + + #[cfg_attr(not(feature = "fuzz-coverage"), inline)] + pub fn verify_ecdsa_secp256k1_signature( + memory: &mut Vec, + stack: &mut machine::RuntimeStack, + energy: &mut InterpreterEnergy, + ) -> machine::RunResult<()> { + let message_start = unsafe { stack.pop_u32() }; + let signature_start = unsafe { stack.pop_u32() }; + let public_key_start = unsafe { stack.pop_u32() }; + let message_end = message_start as usize + 32; + ensure!(message_end <= memory.len(), "Illegal memory access."); + let public_key_end = public_key_start as usize + 33; + ensure!(public_key_end <= memory.len(), "Illegal memory access."); + let signature_end = signature_start as usize + 64; + ensure!(signature_end <= memory.len(), "Illegal memory access."); + let signature = secp256k1::ecdsa::Signature::from_compact( + &memory[signature_start as usize..signature_end], + ); + let message = secp256k1::Message::from_slice(&memory[message_start as usize..message_end]); + let public_key = + secp256k1::PublicKey::from_slice(&memory[public_key_start as usize..public_key_end]); + match (signature, message, public_key) { + (Ok(signature), Ok(message), Ok(public_key)) => { + let verifier = secp256k1::Secp256k1::verification_only(); + if verifier.verify_ecdsa(&message, &signature, &public_key).is_ok() { + stack.push_value(1u32); + } else { + stack.push_value(0u32); + } + } + _ => stack.push_value(0u32), + } + Ok(()) + } + + #[cfg_attr(not(feature = "fuzz-coverage"), inline)] + pub fn hash_sha2_256( + memory: &mut Vec, + stack: &mut machine::RuntimeStack, + energy: &mut InterpreterEnergy, + ) -> machine::RunResult<()> { + let output_start = unsafe { stack.pop_u32() }; + let data_len = unsafe { stack.pop_u32() }; + let data_start = unsafe { stack.pop_u32() }; + let data_end = data_start as usize + data_len as usize; + ensure!(data_end <= memory.len(), "Illegal memory access."); + let output_end = output_start as usize + 32; + ensure!(output_end <= memory.len(), "Illegal memory access."); + let hash = sha2::Sha256::digest(&memory[data_start as usize..data_end]); + memory[output_start as usize..output_end].copy_from_slice(&hash); + Ok(()) + } + + #[cfg_attr(not(feature = "fuzz-coverage"), inline)] + pub fn hash_sha3_256( + memory: &mut Vec, + stack: &mut machine::RuntimeStack, + energy: &mut InterpreterEnergy, + ) -> machine::RunResult<()> { + let output_start = unsafe { stack.pop_u32() }; + let data_len = unsafe { stack.pop_u32() }; + let data_start = unsafe { stack.pop_u32() }; + let data_end = data_start as usize + data_len as usize; + ensure!(data_end <= memory.len(), "Illegal memory access."); + let output_end = output_start as usize + 32; + ensure!(output_end <= memory.len(), "Illegal memory access."); + let hash = sha3::Sha3_256::digest(&memory[data_start as usize..data_end]); + memory[output_start as usize..output_end].copy_from_slice(&hash); + Ok(()) + } + + #[cfg_attr(not(feature = "fuzz-coverage"), inline)] + pub fn hash_keccak_256( + memory: &mut Vec, + stack: &mut machine::RuntimeStack, + energy: &mut InterpreterEnergy, + ) -> machine::RunResult<()> { + let output_start = unsafe { stack.pop_u32() }; + let data_len = unsafe { stack.pop_u32() }; + let data_start = unsafe { stack.pop_u32() }; + let data_end = data_start as usize + data_len as usize; + ensure!(data_end <= memory.len(), "Illegal memory access."); + let output_end = output_start as usize + 32; + ensure!(output_end <= memory.len(), "Illegal memory access."); + let hash = sha3::Keccak256::digest(&memory[data_start as usize..data_end]); + memory[output_start as usize..output_end].copy_from_slice(&hash); + Ok(()) + } } // The use of Vec is ugly, and we really should have [u8] there, but FFI @@ -709,6 +808,15 @@ impl<'a, BackingStore: BackingStoreLoad, ParamType: AsRef<[u8]>, Ctx: v0::HasIni CommonFunc::StateEntryResize => { host::state_entry_resize(stack, &mut self.energy, &mut self.state) } + CommonFunc::VerifyEd25519 => { + host::verify_ed25519_signature(memory, stack, &mut self.energy) + } + CommonFunc::VerifySecp256k1 => { + host::verify_ecdsa_secp256k1_signature(memory, stack, &mut self.energy) + } + CommonFunc::HashSHA2_256 => host::hash_sha2_256(memory, stack, &mut self.energy), + CommonFunc::HashSHA3_256 => host::hash_sha3_256(memory, stack, &mut self.energy), + CommonFunc::HashKeccak256 => host::hash_keccak_256(memory, stack, &mut self.energy), }?, ImportFunc::InitOnly(InitOnlyFunc::GetInitOrigin) => { v0::host::get_init_origin(memory, stack, self.init_ctx.init_origin())? @@ -850,6 +958,15 @@ impl<'a, BackingStore: BackingStoreLoad, ParamType: AsRef<[u8]>, Ctx: HasReceive CommonFunc::StateEntryResize => { host::state_entry_resize(stack, &mut self.energy, &mut self.state) } + CommonFunc::VerifyEd25519 => { + host::verify_ed25519_signature(memory, stack, &mut self.energy) + } + CommonFunc::VerifySecp256k1 => { + host::verify_ecdsa_secp256k1_signature(memory, stack, &mut self.energy) + } + CommonFunc::HashSHA2_256 => host::hash_sha2_256(memory, stack, &mut self.energy), + CommonFunc::HashSHA3_256 => host::hash_sha3_256(memory, stack, &mut self.energy), + CommonFunc::HashKeccak256 => host::hash_keccak_256(memory, stack, &mut self.energy), }?, ImportFunc::ReceiveOnly(rof) => match rof { ReceiveOnlyFunc::Invoke => { diff --git a/wasm-chain-integration/src/v1/types.rs b/wasm-chain-integration/src/v1/types.rs index 23c5e7e8..36116f93 100644 --- a/wasm-chain-integration/src/v1/types.rs +++ b/wasm-chain-integration/src/v1/types.rs @@ -303,6 +303,12 @@ pub enum CommonFunc { StateEntryWrite, StateEntrySize, StateEntryResize, + // Cryptographic functions + VerifyEd25519, + VerifySecp256k1, + HashSHA2_256, + HashSHA3_256, + HashKeccak256, } #[repr(u8)] @@ -416,6 +422,11 @@ impl Output for ImportFunc { CommonFunc::StateEntrySize => 20, CommonFunc::StateEntryResize => 21, CommonFunc::WriteOutput => 22, + CommonFunc::VerifyEd25519 => 32, + CommonFunc::VerifySecp256k1 => 33, + CommonFunc::HashSHA2_256 => 34, + CommonFunc::HashSHA3_256 => 35, + CommonFunc::HashKeccak256 => 36, }, ImportFunc::InitOnly(io) => match io { InitOnlyFunc::GetInitOrigin => 23, @@ -506,6 +517,13 @@ impl validate::ValidateImportExport for ConcordiumAllowedImports { "state_entry_write" => type_matches!(ty => [I64, I32, I32, I32]; I32), "state_entry_size" => type_matches!(ty => [I64]; I32), "state_entry_resize" => type_matches!(ty => [I64, I32]; I32), + "verify_ed25519_signature" => type_matches!(ty => [I32, I32, I32, I32]; I32), + "verify_ecdsa_secp256k1_signature" => { + type_matches!(ty => [I32, I32, I32]; I32) + } + "hash_sha2_256" => type_matches!(ty => [I32, I32, I32]), + "hash_sha3_256" => type_matches!(ty => [I32, I32, I32]), + "hash_keccak_256" => type_matches!(ty => [I32, I32, I32]), _ => false, } } else { @@ -600,6 +618,13 @@ impl TryFromImport for ProcessedImports { "state_entry_write" => ImportFunc::Common(CommonFunc::StateEntryWrite), "state_entry_size" => ImportFunc::Common(CommonFunc::StateEntrySize), "state_entry_resize" => ImportFunc::Common(CommonFunc::StateEntryResize), + "verify_ed25519_signature" => ImportFunc::Common(CommonFunc::VerifyEd25519), + "verify_ecdsa_secp256k1_signature" => { + ImportFunc::Common(CommonFunc::VerifySecp256k1) + } + "hash_sha2_256" => ImportFunc::Common(CommonFunc::HashSHA2_256), + "hash_sha3_256" => ImportFunc::Common(CommonFunc::HashSHA3_256), + "hash_keccak_256" => ImportFunc::Common(CommonFunc::HashKeccak256), name => bail!("Unsupported import {}.", name), } } else { From 1d8f14289102ec583585685a9e6e96428a485bf8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Bizjak?= Date: Tue, 3 May 2022 13:26:22 +0200 Subject: [PATCH 2/5] Benchmarks of cryptographic primitives. --- wasm-chain-integration/Cargo.lock | 320 ++++++++++++------ wasm-chain-integration/Cargo.toml | 1 + .../benches/code/v1/host-functions.wasm | Bin 1960 -> 2473 bytes .../benches/code/v1/host-functions.wat | 63 +++- .../benches/v1-host-functions.rs | 130 +++++++ wasm-chain-integration/src/constants.rs | 18 + wasm-chain-integration/src/v1/mod.rs | 40 ++- 7 files changed, 465 insertions(+), 107 deletions(-) diff --git a/wasm-chain-integration/Cargo.lock b/wasm-chain-integration/Cargo.lock index 2f3a0c06..105a39ff 100644 --- a/wasm-chain-integration/Cargo.lock +++ b/wasm-chain-integration/Cargo.lock @@ -22,9 +22,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.55" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "159bb86af3a200e19a068f4224eae4c8bb2d0fa054c7e5d1cacd5cef95e684cd" +checksum = "08f9b8508dccb7687a1d6c4ce66b2b0ecef467c94667de27d8d7fe1f8d2a9cdc" [[package]] name = "arbitrary" @@ -92,6 +92,15 @@ dependencies = [ "generic-array 0.12.4", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.5", +] + [[package]] name = "block-buffer" version = "0.10.2" @@ -119,7 +128,7 @@ dependencies = [ "lazy_static 1.4.0", "memchr", "regex-automata", - "serde 1.0.136", + "serde 1.0.137", ] [[package]] @@ -169,7 +178,7 @@ checksum = "670ad68c9088c2a963aaa298cb369688cf3f9465ce5e2d4ca10e6e0098a1ce73" dependencies = [ "libc", "num-integer", - "num-traits 0.2.14", + "num-traits 0.2.15", "time", "winapi", ] @@ -193,7 +202,7 @@ dependencies = [ "chrono", "fnv", "hashbrown", - "serde 1.0.136", + "serde 1.0.137", "serde_json", ] @@ -206,7 +215,7 @@ dependencies = [ "lazy_static 1.4.0", "nom", "rust-ini", - "serde 1.0.136", + "serde 1.0.137", "serde-hjson", "serde_json", "toml", @@ -221,9 +230,9 @@ checksum = "6245d59a3e82a7fc217c5828a6692dbc6dfb63a0c8c90495621f7b9d79704a0e" [[package]] name = "cpufeatures" -version = "0.2.1" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95059428f66df56b63431fdb4e1947ed2190586af5c5a8a8b71122bdf5a7f469" +checksum = "59a6001667ab124aebae2a495118e11d30984c3a653e99d86d58971708cf5e4b" dependencies = [ "libc", ] @@ -241,12 +250,12 @@ dependencies = [ "csv", "itertools", "lazy_static 1.4.0", - "num-traits 0.2.14", + "num-traits 0.2.15", "oorandom", "plotters", "rayon", "regex", - "serde 1.0.136", + "serde 1.0.137", "serde_cbor", "serde_derive", "serde_json", @@ -266,9 +275,9 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.5.2" +version = "0.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa" +checksum = "5aaa7bd5fb665c6864b5f963dd9097905c54125909c7aa94c9e18507cdbe6c53" dependencies = [ "cfg-if", "crossbeam-utils", @@ -287,10 +296,11 @@ dependencies = [ [[package]] name = "crossbeam-epoch" -version = "0.9.7" +version = "0.9.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9" +checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c" dependencies = [ + "autocfg", "cfg-if", "crossbeam-utils", "lazy_static 1.4.0", @@ -300,9 +310,9 @@ dependencies = [ [[package]] name = "crossbeam-utils" -version = "0.8.7" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6" +checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38" dependencies = [ "cfg-if", "lazy_static 1.4.0", @@ -328,7 +338,7 @@ dependencies = [ "csv-core", "itoa 0.4.8", "ryu", - "serde 1.0.136", + "serde 1.0.137", ] [[package]] @@ -340,6 +350,19 @@ dependencies = [ "memchr", ] +[[package]] +name = "curve25519-dalek" +version = "3.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b9fdf9972b2bd6af2d913799d9ebc165ea4d2e65878e329d9c6b372c4491b61" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core 0.5.1", + "subtle", + "zeroize", +] + [[package]] name = "derive_arbitrary" version = "0.4.7" @@ -373,6 +396,15 @@ dependencies = [ "generic-array 0.12.4", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.5", +] + [[package]] name = "digest" version = "0.10.3" @@ -394,15 +426,29 @@ dependencies = [ [[package]] name = "dirs-sys" -version = "0.3.6" +version = "0.3.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "03d86534ed367a67548dc68113a0f5db55432fdfbb6e6f9d77704397d95d5780" +checksum = "1b1d1d91c932ef41c0f2663aa8b0ca0342d444d842c06914aa0a7e352d0bada6" dependencies = [ "libc", "redox_users", "winapi", ] +[[package]] +name = "ed25519-zebra" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a128b76af6dd4b427e34a6fd43dc78dbfe73672ec41ff615a2414c1a0ad0409" +dependencies = [ + "curve25519-dalek", + "hex", + "rand_core 0.5.1", + "serde 1.0.137", + "sha2 0.9.9", + "thiserror", +] + [[package]] name = "either" version = "1.6.1" @@ -458,13 +504,24 @@ dependencies = [ [[package]] name = "getrandom" -version = "0.2.5" +version = "0.1.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.9.0+wasi-snapshot-preview1", +] + +[[package]] +name = "getrandom" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9be70c98951c83b8d2f8f60d7065fa6d5146873094452a1008da8c2f1e4205ad" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.10.0+wasi-snapshot-preview1", ] [[package]] @@ -488,11 +545,17 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "indexmap" -version = "1.8.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "282a6247722caba404c065016bbfa522806e51714c34f5dfc3e4a3a46fcb4223" +checksum = "0f647032dfaa1f8b6dc29bd3edb7bbef4861b8b8007ebb118d6db284fd59f6ee" dependencies = [ "autocfg", "hashbrown", @@ -521,9 +584,9 @@ checksum = "1aab8fc367588b89dcee83ab0fd66b72b50b72fa1904d7095045ace2b0c81c35" [[package]] name = "js-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a38fc24e30fd564ce974c02bf1d337caddff65be6cc4735a1f7eab22a7440f04" +checksum = "671a26f820db17c2a2750743f1dd03bafd15b98c9f30c7c2628c024c05d73397" dependencies = [ "wasm-bindgen", ] @@ -567,9 +630,9 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.119" +version = "0.2.125" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bf2e165bb3457c8e098ea76f3e3bc9db55f87aa90d52d0e6be741470916aaa4" +checksum = "5916d2ae698f6de9bfb891ad7a8d65c09d232dc58cc4ac433c7da3b2fd84bc2b" [[package]] name = "linked-hash-map" @@ -579,18 +642,18 @@ checksum = "7fb9b38af92608140b86b693604b9ffcc5824240a484d1ecd4795bacb2fe88f3" [[package]] name = "log" -version = "0.4.14" +version = "0.4.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "51b9bbe6c47d51fc3e1a9b945965946b4c44142ab8792c50835a980d362c2710" +checksum = "abb12e687cfb44aa40f41fc3978ef76448f9b6038cad6aef4259d3c095a2382e" dependencies = [ "cfg-if", ] [[package]] name = "memchr" -version = "2.4.1" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" [[package]] name = "memoffset" @@ -614,12 +677,12 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.44" +version = "0.1.45" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2cc698a63b549a70bc047073d2949cce27cd1c7b0a4a862d08a8031bc2801db" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" dependencies = [ "autocfg", - "num-traits 0.2.14", + "num-traits 0.2.15", ] [[package]] @@ -628,14 +691,14 @@ version = "0.1.43" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "92e5113e9fd4cc14ded8e499429f396a20f98c772a47cc8622a736e1ec843c31" dependencies = [ - "num-traits 0.2.14", + "num-traits 0.2.15", ] [[package]] name = "num-traits" -version = "0.2.14" +version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a64b1ec5cda2586e284722486d802acf1f7dbdc623e2bfc57e65ca1cd099290" +checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd" dependencies = [ "autocfg", ] @@ -652,18 +715,18 @@ dependencies = [ [[package]] name = "num_enum" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "720d3ea1055e4e4574c0c0b0f8c3fd4f24c4cdaf465948206dea090b57b526ad" +checksum = "cf5395665662ef45796a4ff5486c5d41d29e0c09640af4c5f17fd94ee2c119c9" dependencies = [ "num_enum_derive", ] [[package]] name = "num_enum_derive" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d992b768490d7fe0d8586d9b5745f6c49f557da6d81dc982b1d167ad4edbb21" +checksum = "3b0498641e53dd6ac1a4f22547548caa6864cc4933784319cd1775271c5a46ce" dependencies = [ "proc-macro-crate", "proc-macro2", @@ -683,13 +746,19 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "ordered-float" version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7940cf2ca942593318d07fcf2596cdca60a85c9e7fab408a5e21a4f9dcd40d87" dependencies = [ - "num-traits 0.2.14", + "num-traits 0.2.15", ] [[package]] @@ -708,7 +777,7 @@ version = "0.3.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a3fd9ec30b9749ce28cd91f255d569591cdf937fe280c312143e3c4bad6f2a" dependencies = [ - "num-traits 0.2.14", + "num-traits 0.2.15", "plotters-backend", "plotters-svg", "wasm-bindgen", @@ -742,9 +811,9 @@ dependencies = [ [[package]] name = "proc-macro2" -version = "1.0.36" +version = "1.0.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c7342d5883fbccae1cc37a2353b09c87c9b0f3afd73f5fb9bba687a1f733b029" +checksum = "ec757218438d5fda206afc041538b2f6d889286160d649a86a24d37e1235afd1" dependencies = [ "unicode-xid", ] @@ -760,7 +829,7 @@ dependencies = [ "config", "directories", "petgraph", - "serde 1.0.136", + "serde 1.0.137", "serde-value", "tint", ] @@ -778,9 +847,9 @@ dependencies = [ [[package]] name = "quote" -version = "1.0.15" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "864d3e96a899863136fc6e99f3d7cae289dafe43bf2c5ac19b70df7210c0a145" +checksum = "a1feb54ed693b93a84e14094943b84b7c4eae204c512b7ccb95ab0c66d278ad1" dependencies = [ "proc-macro2", ] @@ -791,7 +860,16 @@ version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" dependencies = [ - "rand_core", + "rand_core 0.6.3", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", ] [[package]] @@ -800,14 +878,14 @@ version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d34f1408f55294453790c48b2f1ebbb1c5b4b7563eb1f418bcfcfdbb06ebb4e7" dependencies = [ - "getrandom", + "getrandom 0.2.6", ] [[package]] name = "rayon" -version = "1.5.1" +version = "1.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06aca804d41dbc8ba42dfd964f0d01334eceb64314b9ecf7c5fad5188a06d90" +checksum = "fd249e82c21598a9a426a4e00dd7adc1d640b22445ec8545feef801d1a74c221" dependencies = [ "autocfg", "crossbeam-deque", @@ -817,41 +895,41 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.9.1" +version = "1.9.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d78120e2c850279833f1dd3582f730c4ab53ed95aeaaaa862a2a5c71b1656d8e" +checksum = "9f51245e1e62e1f1629cbfec37b5793bbabcaeb90f30e94d2ba03564687353e4" dependencies = [ "crossbeam-channel", "crossbeam-deque", "crossbeam-utils", - "lazy_static 1.4.0", "num_cpus", ] [[package]] name = "redox_syscall" -version = "0.2.10" +version = "0.2.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff" +checksum = "62f25bc4c7e55e0b0b7a1d43fb893f4fa1361d0abe38b9ce4f323c2adfe6ef42" dependencies = [ "bitflags", ] [[package]] name = "redox_users" -version = "0.4.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" dependencies = [ - "getrandom", + "getrandom 0.2.6", "redox_syscall", + "thiserror", ] [[package]] name = "regex" -version = "1.5.4" +version = "1.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461" +checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286" dependencies = [ "aho-corasick", "memchr", @@ -926,9 +1004,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.6" +version = "1.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d" +checksum = "8cb243bdfdb5936c8dc3c45762a19d12ab4550cdc753bc247637d4ec35a040fd" [[package]] name = "serde" @@ -938,9 +1016,9 @@ checksum = "9dad3f759919b92c3068c696c15c3d17238234498bbdcc80f2c469606f948ac8" [[package]] name = "serde" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce31e24b01e1e524df96f1c2fdd054405f8d7376249a5110886fb4b658484789" +checksum = "61ea8d54c77f8315140a05f4c7237403bf38b72704d031543aa1d16abbf517d1" dependencies = [ "serde_derive", ] @@ -964,7 +1042,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3a1a3341211875ef120e117ea7fd5228530ae7e7036a779fdc9117be6b3282c" dependencies = [ "ordered-float", - "serde 1.0.136", + "serde 1.0.137", ] [[package]] @@ -974,14 +1052,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2bef2ebfde456fb76bbcf9f59315333decc4fda0b2b44b420243c11e0f5ec1f5" dependencies = [ "half", - "serde 1.0.136", + "serde 1.0.137", ] [[package]] name = "serde_derive" -version = "1.0.136" +version = "1.0.137" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08597e7152fcd306f41838ed3e37be9eaeed2b61c42e2117266a554fab4662f9" +checksum = "1f26faba0c3959972377d3b2d306ee9f71faee9714294e41bb777f83f88578be" dependencies = [ "proc-macro2", "quote", @@ -990,13 +1068,13 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.79" +version = "1.0.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8e8d9fa5c3b304765ce1fd9c4c8a3de2c8db365a5b91be52f186efc675681d95" +checksum = "f972498cf015f7c0746cac89ebe1d6ef10c293b94175a243a2d9442c163d9944" dependencies = [ "itoa 1.0.1", "ryu", - "serde 1.0.136", + "serde 1.0.137", ] [[package]] @@ -1008,7 +1086,20 @@ dependencies = [ "block-buffer 0.7.3", "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] @@ -1034,9 +1125,9 @@ dependencies = [ [[package]] name = "slab" -version = "0.4.5" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9def91fd1e018fe007022791f865d0ccc9b3a0d5001e01aabb8b40e46000afb5" +checksum = "eb703cfe953bccee95685111adeedb76fabe4e97549a58d16f03ea7b9367bb32" [[package]] name = "static_assertions" @@ -1044,11 +1135,17 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" -version = "1.0.86" +version = "1.0.92" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b" +checksum = "7ff7c592601f11445996a06f8ad0c27f094a58857c2f89e97974ab9235b92c52" dependencies = [ "proc-macro2", "quote", @@ -1066,18 +1163,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "854babe52e4df1653706b98fcfc05843010039b406875930a70e4d9644e5c417" +checksum = "bd829fe32373d27f76265620b5309d0340cb8550f523c1dda251d6298069069a" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.30" +version = "1.0.31" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "aa32fd3f627f367fe16f893e2597ae3c05020f8bba2666a4e6ea73d377e5714b" +checksum = "0396bc89e626244658bef819e22d0cc459e795a5ebe878e6ec336d1674a8d79a" dependencies = [ "proc-macro2", "quote", @@ -1091,7 +1188,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", - "wasi", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] @@ -1110,15 +1207,15 @@ version = "1.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "be4d6b5f19ff7664e8c98d03e2139cb510db9b0a60b55f8e8709b689d939b6bc" dependencies = [ - "serde 1.0.136", + "serde 1.0.137", "serde_json", ] [[package]] name = "tinyvec" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2c1c1d5a42b6245520c249549ec267180beaffcc0615401ac8e31853d4b6d8d2" +checksum = "87cc5ceb3875bb20c2890005a4e226a4651264a5c75edb2421b52861a0a0cb50" dependencies = [ "tinyvec_macros", ] @@ -1131,11 +1228,11 @@ checksum = "cda74da7e1a664f795bb1f8a87ec406fb89a02522cf6e50620d016add6dbbf5c" [[package]] name = "toml" -version = "0.5.8" +version = "0.5.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a31142970826733df8241ef35dc040ef98c679ab14d7c3e54d827099b3acecaa" +checksum = "8d82e1a7758622a465f8cee077614c73484dac5b836c02ff6a40d5d1010324d7" dependencies = [ - "serde 1.0.136", + "serde 1.0.137", ] [[package]] @@ -1152,9 +1249,9 @@ checksum = "3ed742d4ea2bd1176e236172c8429aaf54486e7ac098db29ffe6529e0ce50973" [[package]] name = "unicode-xid" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +checksum = "957e51f3646910546462e67d5f7599b9e4fb8acdd304b087a6494730f9eebf04" [[package]] name = "version_check" @@ -1173,6 +1270,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" @@ -1181,9 +1284,9 @@ checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" [[package]] name = "wasm-bindgen" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "25f1af7423d8588a3d840681122e72e6a24ddbcb3f0ec385cac0d12d24256c06" +checksum = "27370197c907c55e3f1a9fbe26f44e937fe6451368324e009cba39e139dc08ad" dependencies = [ "cfg-if", "wasm-bindgen-macro", @@ -1191,9 +1294,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-backend" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b21c0df030f5a177f3cba22e9bc4322695ec43e7257d865302900290bcdedca" +checksum = "53e04185bfa3a779273da532f5025e33398409573f348985af9a1cbf3774d3f4" dependencies = [ "bumpalo", "lazy_static 1.4.0", @@ -1206,9 +1309,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2f4203d69e40a52ee523b2529a773d5ffc1dc0071801c87b3d270b471b80ed01" +checksum = "17cae7ff784d7e83a2fe7611cfe766ecf034111b49deb850a3dc7699c08251f5" dependencies = [ "quote", "wasm-bindgen-macro-support", @@ -1216,9 +1319,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bfa8a30d46208db204854cadbb5d4baf5fcf8071ba5bf48190c3e59937962ebc" +checksum = "99ec0dc7a4756fffc231aab1b9f2f578d23cd391390ab27f952ae0c9b3ece20b" dependencies = [ "proc-macro2", "quote", @@ -1229,9 +1332,9 @@ dependencies = [ [[package]] name = "wasm-bindgen-shared" -version = "0.2.79" +version = "0.2.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d958d035c4438e28c70e4321a2911302f10135ce78a9c7834c0cab4123d06a2" +checksum = "d554b7f530dee5964d9a9468d95c1f8b8acae4f282807e7d27d4b03099a46744" [[package]] name = "wasm-chain-integration" @@ -1243,12 +1346,13 @@ dependencies = [ "concordium-contracts-common", "criterion", "derive_more", + "ed25519-zebra", "libc", "num_enum", "ptree", "quickcheck", "secp256k1", - "serde 1.0.136", + "serde 1.0.137", "sha2 0.10.2", "sha3", "slab", @@ -1305,9 +1409,9 @@ dependencies = [ [[package]] name = "web-sys" -version = "0.3.56" +version = "0.3.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c060b319f29dd25724f09a2ba1418f142f539b2be99fbf4d2d5a8f7330afb8eb" +checksum = "7b17e741662c70c8bd24ac5c5b18de314a2c26c32bf8346ee1e6f53de919c283" dependencies = [ "js-sys", "wasm-bindgen", @@ -1352,3 +1456,9 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "zeroize" +version = "1.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94693807d016b2f2d2e14420eb3bfcca689311ff775dcf113d74ea624b7cdf07" diff --git a/wasm-chain-integration/Cargo.toml b/wasm-chain-integration/Cargo.toml index 7bcb9267..938b743b 100644 --- a/wasm-chain-integration/Cargo.toml +++ b/wasm-chain-integration/Cargo.toml @@ -24,6 +24,7 @@ derive_more = "0.99" sha2 = "0.10" sha3 = "0.10" secp256k1 = "0.22" +ed25519-zebra = "2.2" # TODO: After we only support Rust 1.54+ change to the latest version (3.*) thiserror = "1" byteorder = "1.4" tinyvec = {version = "1.5", features = ["alloc"]} diff --git a/wasm-chain-integration/benches/code/v1/host-functions.wasm b/wasm-chain-integration/benches/code/v1/host-functions.wasm index f3880387a4c5d8e5b8bf639df31cdd883b039e2d..bf4888a97b3613e5798da398ea4b78080ed10d01 100644 GIT binary patch literal 2473 zcmb7F%TC)s6uo07ggg-D>F_8R3WY*ji6AOJ=e8WAL0u^~ zfzGF(MV{5Cp6B)js5ec$_*K>kXqE3}bE6l=NjG?t^ExLsnf#$X#P%?5)=(x%4#CosTa1{zwLuRu1WdHN+Ml_lwOd%xsDQZT;BC7OzO`DyeTe{H@d6teU?EDwh>~p0a z+ZEzf#{V!zJJdceFhAk9hMIFwJh<5Sk{o0fiH~ADP7*6jNhiD)vRN_JpI@~L(vZ=>eYfoaWOV&S06oYsG delta 281 zcmZ1}yn>&bA+b1@k%57M(TRH^w<8PFX%?Z4VO~tk%)&yG{h7sB8QD8ngeGS(OEU^h zZex~{6_(7%FD^;T(?Bq7JMe9;i5l zL42|xixi{8WE~c1CP~%Fx-61>@p<`qsTG;UB|v2iQj-f, name_ext| { + let args = [machine::Value::I64(0)]; + let inputs: Vec<(Vec, [u8; 1])> = Vec::new(); + let artifact = &artifact; + let params = ¶ms; + let mk_data = || { + let (a, b) = mk_state(&inputs); + (a, b, vec![params.clone()]) + }; + let receive_ctx = &receive_ctx; + let args = &args[..]; + let bench_name = if let Some(n) = name_ext { + format!("{} n = {}", name, n) + } else { + name.to_string() + }; + group.bench_function(bench_name, move |b: &mut criterion::Bencher| { + b.iter_batched( + mk_data, + |(mut mutable_state, _, parameters)| { + let mut backing_store = Loader { + inner: Vec::new(), + }; + let inner = mutable_state.get_inner(&mut backing_store); + let state = InstanceState::new(0, backing_store, inner); + let mut host = ReceiveHost::<_, Vec, _> { + energy: start_energy, + stateless: StateLessReceiveHost { + activation_frames: MAX_ACTIVATION_FRAMES, + logs: v0::Logs::new(), + receive_ctx, + return_value: Vec::new(), + parameters, + }, + state, + }; + let r = artifact + .run(&mut host, name, args) + .expect_err("Execution should fail due to out of energy."); + // Should fail due to out of energy. + assert!( + r.downcast_ref::().is_some(), + "Execution did not fail due to out of energy: {}.", + r + ); + let params = std::mem::take(&mut host.stateless.parameters); + // it is not ideal to drop the host here since it could significantly affect the + // cost for small samples. + drop(host); + // return the state so that its drop is not counted in the benchmark. + (mutable_state, params) + }, + BatchSize::SmallInput, + ) + }); + }; + + { + // n is the length of the data to be hashed + for n in [0u32, 10, 20, 50, 100, 1000, 10_000, 100_000] { + let name = "hostfn.verify_ed25519_signature"; + let sk = ed25519_zebra::SigningKey::from([1u8; 32]); + let sig = sk.sign(&vec![0u8; n as usize]); // sign a zero message of a given length. + let pk = ed25519_zebra::VerificationKey::from(&sk); + let mut params = Vec::with_capacity(100); + params.extend_from_slice(pk.as_ref()); + params.extend_from_slice(&<[u8; 64]>::from(sig)[..]); + params.extend_from_slice(&n.to_le_bytes()); + add_crypto_primitive_benchmark(name, params, Some(n)); + } + } + + { + // ecdsa verification has a fixed message length + let name = "hostfn.verify_ecdsa_secp256k1_signature"; + let signer = secp256k1::Secp256k1::new(); + let sk = secp256k1::SecretKey::from_slice(&[ + 0xc9, 0xef, 0x15, 0x44, 0x4b, 0x1e, 0x88, 0x5f, 0x0e, 0xd0, 0x36, 0xaa, 0xc8, 0x64, + 0x6f, 0xb0, 0xc6, 0x11, 0x88, 0x6e, 0x8c, 0x40, 0x91, 0xa1, 0xb7, 0xb2, 0xb5, 0xa0, + 0x95, 0xd2, 0xd6, 0xba, + ]) + .expect("Key generated with openssl, so should be valid."); + let message = secp256k1::Message::from_slice(&sha2::Sha256::digest(&[])[..]) + .expect("Hashes are valid messages."); + let sig = signer.sign_ecdsa(&message, &sk); + let pk = secp256k1::PublicKey::from_slice(&[ + 0x04, 0xbb, 0xc0, 0xa1, 0xad, 0x6f, 0x0d, 0x2c, 0x1f, 0x32, 0x50, 0xd9, 0x08, 0x78, + 0x15, 0x37, 0xd6, 0x8c, 0xf4, 0xa6, 0x96, 0x41, 0x74, 0xb9, 0x70, 0x36, 0x2c, 0x66, + 0x47, 0x52, 0x11, 0xc6, 0xf8, 0x70, 0xd4, 0xc1, 0x99, 0xc7, 0x93, 0xbf, 0x3d, 0x6c, + 0x21, 0x55, 0x2d, 0xad, 0xee, 0xc5, 0x1b, 0x6a, 0x3f, 0xa6, 0x0a, 0x7c, 0x1a, 0x1f, + 0x63, 0xd5, 0x8f, 0xf5, 0x51, 0x7b, 0x74, 0xf8, 0x12, + ]) + .expect( + "Should be a valid public key matching the secret key above. Generated with openssl.", + ); + let mut params = Vec::with_capacity(100); + params.extend_from_slice(&pk.serialize()); + params.extend_from_slice(&sig.serialize_compact()); + params.extend_from_slice(message.as_ref()); + add_crypto_primitive_benchmark(name, params, None); + } + + { + // n is the length of the data to be hashed + for n in [0u32, 10, 20, 50, 100, 1000, 10_000, 100_000] { + let name = "hostfn.hash_sha2_256"; + let params = n.to_le_bytes().to_vec(); // length to hash + add_crypto_primitive_benchmark(name, params, Some(n)); + } + } + + { + // n is the length of the data to be hashed + for n in [0u32, 10, 20, 50, 100, 1000, 10_000, 100_000] { + let name = "hostfn.hash_sha3_256"; + let params = n.to_le_bytes().to_vec(); // length to hash + add_crypto_primitive_benchmark(name, params, Some(n)); + } + } + + { + // n is the length of the data to be hashed + for n in [0u32, 10, 20, 50, 100, 1000, 10_000, 100_000] { + let name = "hostfn.hash_keccak_256"; + let params = n.to_le_bytes().to_vec(); // length to hash + add_crypto_primitive_benchmark(name, params, Some(n)); + } + } + group.finish(); } diff --git a/wasm-chain-integration/src/constants.rs b/wasm-chain-integration/src/constants.rs index 603716e4..6275d9c3 100644 --- a/wasm-chain-integration/src/constants.rs +++ b/wasm-chain-integration/src/constants.rs @@ -218,3 +218,21 @@ pub fn write_output_cost(x: u32) -> u64 { 10 + u64::from(x) } /// and 3000000NRG there can be at most 100MB of output produced. #[inline(always)] pub fn additional_output_size_cost(x: u64) -> u64 { 30 * x } + +/// Cost of verification of an ed25519 with the Zebra implementation. +/// The cost depends on the size of the message and is based on benchmarking. +pub fn verify_ed25519_cost(message_len: u32) -> u64 { 100_000 + 100 * u64::from(message_len) } + +/// Cost of verification of an ecdsa over secp256k1 with the bitcoin-core +/// implementation. Since signature verification only works on 32 byte messages +/// (which are meant to be hashes) the cost is constant. +pub const VERIFY_ECDSA_SECP256K1_COST: u64 = 100_000; + +/// Cost of computing a SHA2-256 digest of the message of the given length. +pub fn hash_sha2_256_cost(data_len: u32) -> u64 { 500 + 7 * u64::from(data_len) } + +/// Cost of computing a SHA3-256 digest of the message of the given length. +pub fn hash_sha3_256_cost(data_len: u32) -> u64 { 600 + 5 * u64::from(data_len) } + +/// Cost of computing a Keccak-256 digest of the message of the given length. +pub fn hash_keccak_256_cost(data_len: u32) -> u64 { 600 + 5 * u64::from(data_len) } diff --git a/wasm-chain-integration/src/v1/mod.rs b/wasm-chain-integration/src/v1/mod.rs index 7a276e56..a2ab9262 100644 --- a/wasm-chain-integration/src/v1/mod.rs +++ b/wasm-chain-integration/src/v1/mod.rs @@ -175,6 +175,8 @@ mod host { //! These functions are safety-critical, and must withstand malicious use. //! Thus they are written in a very defensive way to make sure no out of //! bounds accesses occur. + use std::convert::TryFrom; + use super::*; use concordium_contracts_common::{ Cursor, EntrypointName, Get, ParseError, ParseResult, ACCOUNT_ADDRESS_SIZE, @@ -629,7 +631,35 @@ mod host { stack: &mut machine::RuntimeStack, energy: &mut InterpreterEnergy, ) -> machine::RunResult<()> { - todo!() + let message_len = unsafe { stack.pop_u32() }; + let message_start = unsafe { stack.pop_u32() }; + let signature_start = unsafe { stack.pop_u32() }; + let public_key_start = unsafe { stack.pop_u32() }; + let message_end = message_start as usize + message_len as usize; + ensure!(message_end <= memory.len(), "Illegal memory access."); + let public_key_end = public_key_start as usize + 32; + ensure!(public_key_end <= memory.len(), "Illegal memory access."); + let signature_end = signature_start as usize + 64; + ensure!(signature_end <= memory.len(), "Illegal memory access."); + // expensive operations start now. + energy.tick_energy(constants::verify_ed25519_cost(message_len))?; + let signature = + ed25519_zebra::Signature::try_from(&memory[signature_start as usize..signature_end]); + let message = &memory[message_start as usize..message_end]; + let public_key = ed25519_zebra::VerificationKey::try_from( + &memory[public_key_start as usize..public_key_end], + ); + match (signature, public_key) { + (Ok(ref signature), Ok(public_key)) => { + if public_key.verify(signature, message).is_ok() { + stack.push_value(1u32); + } else { + stack.push_value(0u32); + } + } + _ => stack.push_value(0u32), + } + Ok(()) } #[cfg_attr(not(feature = "fuzz-coverage"), inline)] @@ -647,6 +677,8 @@ mod host { ensure!(public_key_end <= memory.len(), "Illegal memory access."); let signature_end = signature_start as usize + 64; ensure!(signature_end <= memory.len(), "Illegal memory access."); + // expensive operations start now. + energy.tick_energy(constants::VERIFY_ECDSA_SECP256K1_COST)?; let signature = secp256k1::ecdsa::Signature::from_compact( &memory[signature_start as usize..signature_end], ); @@ -680,6 +712,8 @@ mod host { ensure!(data_end <= memory.len(), "Illegal memory access."); let output_end = output_start as usize + 32; ensure!(output_end <= memory.len(), "Illegal memory access."); + // expensive operations start here + energy.tick_energy(constants::hash_sha2_256_cost(data_len))?; let hash = sha2::Sha256::digest(&memory[data_start as usize..data_end]); memory[output_start as usize..output_end].copy_from_slice(&hash); Ok(()) @@ -698,6 +732,8 @@ mod host { ensure!(data_end <= memory.len(), "Illegal memory access."); let output_end = output_start as usize + 32; ensure!(output_end <= memory.len(), "Illegal memory access."); + // expensive operations start here + energy.tick_energy(constants::hash_sha3_256_cost(data_len))?; let hash = sha3::Sha3_256::digest(&memory[data_start as usize..data_end]); memory[output_start as usize..output_end].copy_from_slice(&hash); Ok(()) @@ -716,6 +752,8 @@ mod host { ensure!(data_end <= memory.len(), "Illegal memory access."); let output_end = output_start as usize + 32; ensure!(output_end <= memory.len(), "Illegal memory access."); + // expensive operations start here + energy.tick_energy(constants::hash_keccak_256_cost(data_len))?; let hash = sha3::Keccak256::digest(&memory[data_start as usize..data_end]); memory[output_start as usize..output_end].copy_from_slice(&hash); Ok(()) From d96ee0d538566ddeb9001644b394d2bc6c7de14d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Bizjak?= Date: Tue, 3 May 2022 19:13:52 +0200 Subject: [PATCH 3/5] Add deserialization of ImportFunc. --- cargo-concordium/Cargo.lock | 155 ++++++++++++++++++++++++- cargo-concordium/Cargo.toml | 2 +- wasm-chain-integration/src/v1/types.rs | 5 + 3 files changed, 156 insertions(+), 6 deletions(-) diff --git a/cargo-concordium/Cargo.lock b/cargo-concordium/Cargo.lock index dc928954..73ea8e1e 100644 --- a/cargo-concordium/Cargo.lock +++ b/cargo-concordium/Cargo.lock @@ -83,6 +83,15 @@ dependencies = [ "generic-array 0.12.4", ] +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.5", +] + [[package]] name = "block-buffer" version = "0.10.2" @@ -133,7 +142,7 @@ checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610" [[package]] name = "cargo-concordium" -version = "2.0.0" +version = "2.0.1" dependencies = [ "ansi_term", "anyhow", @@ -171,6 +180,12 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "cc" +version = "1.0.73" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11" + [[package]] name = "cfg-if" version = "1.0.0" @@ -360,6 +375,19 @@ dependencies = [ "memchr", ] +[[package]] +name = "curve25519-dalek" +version = "3.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f9d052967f590a76e62eb387bd0bbb1b000182c3cefe5364db6b7211651bc0" +dependencies = [ + "byteorder", + "digest 0.9.0", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "derive_more" version = "0.99.17" @@ -382,6 +410,15 @@ dependencies = [ "generic-array 0.12.4", ] +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.5", +] + [[package]] name = "digest" version = "0.10.3" @@ -412,6 +449,20 @@ dependencies = [ "winapi", ] +[[package]] +name = "ed25519-zebra" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a128b76af6dd4b427e34a6fd43dc78dbfe73672ec41ff615a2414c1a0ad0409" +dependencies = [ + "curve25519-dalek", + "hex", + "rand_core", + "serde 1.0.136", + "sha2 0.9.9", + "thiserror", +] + [[package]] name = "either" version = "1.6.1" @@ -455,6 +506,17 @@ dependencies = [ "version_check", ] +[[package]] +name = "getrandom" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fc3cb4d91f53b50155bdcfd23f6a4c39ae1969c2ae85982b135750cccaf5fce" +dependencies = [ + "cfg-if", + "libc", + "wasi 0.9.0+wasi-snapshot-preview1", +] + [[package]] name = "getrandom" version = "0.2.5" @@ -463,7 +525,7 @@ checksum = "d39cd93900197114fa1fcb7ae84ca742095eed9442088988ae74fa744e930e77" dependencies = [ "cfg-if", "libc", - "wasi", + "wasi 0.10.0+wasi-snapshot-preview1", ] [[package]] @@ -542,6 +604,12 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "keccak" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c21572b4949434e4fc1e1978b99c5f77064153c59d998bf13ecd96fb5ecba7" + [[package]] name = "lazy_static" version = "0.2.11" @@ -691,6 +759,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "ordered-float" version = "2.10.0" @@ -806,6 +880,15 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom 0.1.16", +] + [[package]] name = "rayon" version = "1.5.1" @@ -846,7 +929,7 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" dependencies = [ - "getrandom", + "getrandom 0.2.5", "redox_syscall", ] @@ -909,6 +992,24 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +[[package]] +name = "secp256k1" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26947345339603ae8395f68e2f3d85a6b0a8ddfe6315818e80b8504415099db0" +dependencies = [ + "secp256k1-sys", +] + +[[package]] +name = "secp256k1-sys" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07b5b9d7322572e1f3aeed208668ce87789b3645dbb73082c5ce99a004103a35" +dependencies = [ + "cc", +] + [[package]] name = "semver" version = "1.0.6" @@ -993,7 +1094,20 @@ dependencies = [ "block-buffer 0.7.3", "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d58a1e1bf39749807d89cf2d98ac2dfa0ff1cb3faa38fbb64dd88ac8013d800" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpufeatures", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] @@ -1007,6 +1121,16 @@ dependencies = [ "digest 0.10.3", ] +[[package]] +name = "sha3" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "881bf8156c87b6301fc5ca6b27f11eeb2761224c7081e69b409d5a1951a70c86" +dependencies = [ + "digest 0.10.3", + "keccak", +] + [[package]] name = "slab" version = "0.4.5" @@ -1055,6 +1179,12 @@ dependencies = [ "syn", ] +[[package]] +name = "subtle" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6bdef32e8150c2a081110b42772ffe7d7c9032b606bc226c8260fd97e0976601" + [[package]] name = "syn" version = "1.0.86" @@ -1102,7 +1232,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" dependencies = [ "libc", - "wasi", + "wasi 0.10.0+wasi-snapshot-preview1", "winapi", ] @@ -1196,6 +1326,12 @@ dependencies = [ "winapi-util", ] +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + [[package]] name = "wasi" version = "0.10.0+wasi-snapshot-preview1" @@ -1264,11 +1400,14 @@ dependencies = [ "byteorder", "concordium-contracts-common", "derive_more", + "ed25519-zebra", "libc", "num_enum", "ptree", + "secp256k1", "serde 1.0.136", "sha2 0.10.2", + "sha3", "slab", "thiserror", "tinyvec", @@ -1335,3 +1474,9 @@ checksum = "56c1936c4cc7a1c9ab21a1ebb602eb942ba868cbd44a99cb7cdc5892335e1c85" dependencies = [ "linked-hash-map", ] + +[[package]] +name = "zeroize" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4756f7db3f7b5574938c3eb1c117038b8e07f95ee6718c0efad4ac21508f1efd" diff --git a/cargo-concordium/Cargo.toml b/cargo-concordium/Cargo.toml index afeb49ff..0c7e3692 100644 --- a/cargo-concordium/Cargo.toml +++ b/cargo-concordium/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "cargo-concordium" -version = "2.0.0" +version = "2.0.1" authors = ["Concordium "] edition = "2018" license-file = "../LICENSE-APACHE" diff --git a/wasm-chain-integration/src/v1/types.rs b/wasm-chain-integration/src/v1/types.rs index 36116f93..2b258831 100644 --- a/wasm-chain-integration/src/v1/types.rs +++ b/wasm-chain-integration/src/v1/types.rs @@ -390,6 +390,11 @@ impl<'a, Ctx: Copy> Parseable<'a, Ctx> for ImportFunc { 29 => Ok(ImportFunc::ReceiveOnly(ReceiveOnlyFunc::GetReceiveEntrypointSize)), 30 => Ok(ImportFunc::ReceiveOnly(ReceiveOnlyFunc::GetReceiveEntryPoint)), 31 => Ok(ImportFunc::ReceiveOnly(ReceiveOnlyFunc::Invoke)), + 32 => Ok(ImportFunc::Common(CommonFunc::VerifyEd25519)), + 33 => Ok(ImportFunc::Common(CommonFunc::VerifySecp256k1)), + 34 => Ok(ImportFunc::Common(CommonFunc::HashSHA2_256)), + 35 => Ok(ImportFunc::Common(CommonFunc::HashSHA3_256)), + 36 => Ok(ImportFunc::Common(CommonFunc::HashKeccak256)), tag => bail!("Unexpected ImportFunc tag {}.", tag), } } From e7576f91652bedab5481399c59ca271ac96c995a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Bizjak?= Date: Tue, 3 May 2022 20:38:23 +0200 Subject: [PATCH 4/5] Add tests for the new host functions. --- .../src/v1/crypto_primitives_tests.rs | 350 ++++++++++++++++++ wasm-chain-integration/src/v1/mod.rs | 2 + .../code/v1/crypto-primitives-tests.wasm | Bin 0 -> 1220 bytes .../code/v1/crypto-primitives-tests.wat | 96 +++++ 4 files changed, 448 insertions(+) create mode 100644 wasm-chain-integration/src/v1/crypto_primitives_tests.rs create mode 100644 wasm-chain-integration/test-data/code/v1/crypto-primitives-tests.wasm create mode 100644 wasm-chain-integration/test-data/code/v1/crypto-primitives-tests.wat diff --git a/wasm-chain-integration/src/v1/crypto_primitives_tests.rs b/wasm-chain-integration/src/v1/crypto_primitives_tests.rs new file mode 100644 index 00000000..d74b180d --- /dev/null +++ b/wasm-chain-integration/src/v1/crypto_primitives_tests.rs @@ -0,0 +1,350 @@ +//! Basic integration tests for cryptographic primitives exposed to smart +//! contracts. +use crate::{ + constants::MAX_ACTIVATION_FRAMES, + v0, + v1::{ + trie::{ + self, low_level::MutableTrie, EmptyCollector, Loader, MutableState, PersistentState, + }, + ConcordiumAllowedImports, InstanceState, ProcessedImports, ReceiveContext, ReceiveHost, + StateLessReceiveHost, + }, + InterpreterEnergy, +}; +use concordium_contracts_common::{ + Address, Amount, ChainMetadata, ContractAddress, OwnedEntrypointName, Timestamp, +}; +use sha2::Digest; +use wasm_transform::{ + artifact::{Artifact, CompiledFunctionBytes}, + machine, + output::Output, + parse, utils, validate, +}; + +static CONTRACT_BYTES: &[u8] = + include_bytes!("../../test-data/code/v1/crypto-primitives-tests.wasm"); + +/// Construct the initial state for the benchmark from given key-value pairs. +fn mk_state, B: Copy>(inputs: &[(A, B)]) -> (MutableState, Loader>) +where + Vec: From, { + let mut node = MutableTrie::empty(); + let mut loader = Loader { + inner: Vec::new(), + }; + for (k, v) in inputs { + node.insert(&mut loader, k.as_ref(), trie::Value::from(*v)) + .expect("No locks, so cannot fail."); + } + if let Some(trie) = node.freeze(&mut loader, &mut EmptyCollector) { + (PersistentState::from(trie).thaw(), loader) + } else { + (PersistentState::Empty.thaw(), loader) + } +} + +#[test] +fn test_crypto_prims() -> anyhow::Result<()> { + let nrg = 1_000_000_000; + + let start_energy = InterpreterEnergy { + energy: nrg * 1000, + }; + + let skeleton = parse::parse_skeleton(CONTRACT_BYTES).unwrap(); + let module = { + let mut module = validate::validate_module(&ConcordiumAllowedImports, &skeleton).unwrap(); + module.inject_metering().expect("Metering injection should succeed."); + module + }; + + let artifact = module.compile::().unwrap(); + let mut out = Vec::new(); + // make sure serialization works for artifacts so do a needless serialization + + // deserialization + artifact.output(&mut out)?; + let artifact: Artifact = utils::parse_artifact(&out)?; + + let owner = concordium_contracts_common::AccountAddress([0u8; 32]); + + let receive_ctx: ReceiveContext<&[u8]> = ReceiveContext { + common: v0::ReceiveContext { + metadata: ChainMetadata { + slot_time: Timestamp::from_timestamp_millis(0), + }, + invoker: owner, + self_address: ContractAddress { + index: 0, + subindex: 0, + }, + self_balance: Amount::from_ccd(1000), + sender: Address::Account(owner), + owner, + sender_policies: &[], + }, + entrypoint: OwnedEntrypointName::new_unchecked("entrypoint".into()), + }; + + // Construct inputs, execute the named entrypoint, ensure it succeeds, and then + // return the return value from the contract. + let test_crypto_primitive = |name: &'static str, params: Vec| { + let args = [machine::Value::I64(0)]; + let inputs: Vec<(Vec, [u8; 1])> = Vec::new(); + let artifact = &artifact; + let params = ¶ms; + let (mut mutable_state, parameters) = { + let (a, _) = mk_state(&inputs); + (a, vec![params.clone()]) + }; + let receive_ctx = &receive_ctx; + let args = &args[..]; + let mut backing_store = Loader { + inner: Vec::new(), + }; + let inner = mutable_state.get_inner(&mut backing_store); + let state = InstanceState::new(0, backing_store, inner); + let mut host = ReceiveHost::<_, Vec, _> { + energy: start_energy, + stateless: StateLessReceiveHost { + activation_frames: MAX_ACTIVATION_FRAMES, + logs: v0::Logs::new(), + receive_ctx, + return_value: Vec::new(), + parameters, + }, + state, + }; + let r = artifact.run(&mut host, name, args); + match r { + Ok(res) => match res { + machine::ExecutionOutcome::Success { + .. + } => host.stateless.return_value, + machine::ExecutionOutcome::Interrupted { + .. + } => { + panic!( + "Execution terminated with an interruption, but was expected to succeed \ + for {}..", + name + ); + } + }, + Err(e) => panic!("Execution failed, but was expected to succeed for {}: {}.", name, e), + } + }; + + { + let name = "hostfn.verify_ed25519_signature"; + // expect verification to succeed. + let params1 = { + let sk = ed25519_zebra::SigningKey::from([1u8; 32]); + let sig = sk.sign(&[0u8; 17]); // sign a message of zeros + let pk = ed25519_zebra::VerificationKey::from(&sk); + let mut params = Vec::with_capacity(100); + params.extend_from_slice(pk.as_ref()); + params.extend_from_slice(&<[u8; 64]>::from(sig)[..]); + params.extend_from_slice(&17u32.to_le_bytes()); + params + }; + let rv1 = test_crypto_primitive(name, params1); + anyhow::ensure!( + rv1[..] == [1, 0, 0, 0], + "Incorrect verification result for {}, case 1, got {:?}.", + name, + rv1 + ); + + // incorrect message + let params2 = { + let sk = ed25519_zebra::SigningKey::from([1u8; 32]); + let sig = sk.sign(&[]); // sign an empty message + let pk = ed25519_zebra::VerificationKey::from(&sk); + let mut params = Vec::with_capacity(100); + params.extend_from_slice(pk.as_ref()); + params.extend_from_slice(&<[u8; 64]>::from(sig)[..]); + params.extend_from_slice(&17u32.to_le_bytes()); + params + }; + let rv2 = test_crypto_primitive(name, params2); + anyhow::ensure!( + rv2[..] == [0, 0, 0, 0], + "Incorrect verification result for {}, case 2, got {:?}.", + name, + rv2 + ); + + // incorrect public key + let params3 = { + let sk = ed25519_zebra::SigningKey::from([1u8; 32]); + let sig = sk.sign(&[0u8; 17]); // sign a message of zeros + let pk = + ed25519_zebra::VerificationKey::from(&ed25519_zebra::SigningKey::from([2u8; 32])); + let mut params = Vec::with_capacity(100); + params.extend_from_slice(pk.as_ref()); + params.extend_from_slice(&<[u8; 64]>::from(sig)[..]); + params.extend_from_slice(&17u32.to_le_bytes()); + params + }; + let rv3 = test_crypto_primitive(name, params3); + anyhow::ensure!( + rv3[..] == [0, 0, 0, 0], + "Incorrect verification result for {}, case 3, got {:?}.", + name, + rv3 + ); + } + + { + // ecdsa verification has a fixed message length + let name = "hostfn.verify_ecdsa_secp256k1_signature"; + let params1 = { + let signer = secp256k1::Secp256k1::new(); + let sk = secp256k1::SecretKey::from_slice(&[ + 0xc9, 0xef, 0x15, 0x44, 0x4b, 0x1e, 0x88, 0x5f, 0x0e, 0xd0, 0x36, 0xaa, 0xc8, 0x64, + 0x6f, 0xb0, 0xc6, 0x11, 0x88, 0x6e, 0x8c, 0x40, 0x91, 0xa1, 0xb7, 0xb2, 0xb5, 0xa0, + 0x95, 0xd2, 0xd6, 0xba, + ]) + .expect("Key generated with openssl, so should be valid."); + let message = secp256k1::Message::from_slice(&sha2::Sha256::digest(&[])[..]) + .expect("Hashes are valid messages."); + let sig = signer.sign_ecdsa(&message, &sk); + let pk = secp256k1::PublicKey::from_slice(&[ + 0x04, 0xbb, 0xc0, 0xa1, 0xad, 0x6f, 0x0d, 0x2c, 0x1f, 0x32, 0x50, 0xd9, 0x08, 0x78, + 0x15, 0x37, 0xd6, 0x8c, 0xf4, 0xa6, 0x96, 0x41, 0x74, 0xb9, 0x70, 0x36, 0x2c, 0x66, + 0x47, 0x52, 0x11, 0xc6, 0xf8, 0x70, 0xd4, 0xc1, 0x99, 0xc7, 0x93, 0xbf, 0x3d, 0x6c, + 0x21, 0x55, 0x2d, 0xad, 0xee, 0xc5, 0x1b, 0x6a, 0x3f, 0xa6, 0x0a, 0x7c, 0x1a, 0x1f, + 0x63, 0xd5, 0x8f, 0xf5, 0x51, 0x7b, 0x74, 0xf8, 0x12, + ]) + .expect( + "Should be a valid public key matching the secret key above. Generated with \ + openssl.", + ); + let mut params = Vec::with_capacity(100); + params.extend_from_slice(&pk.serialize()); + params.extend_from_slice(&sig.serialize_compact()); + params.extend_from_slice(message.as_ref()); + params + }; + let rv1 = test_crypto_primitive(name, params1); + anyhow::ensure!( + rv1[..] == [1, 0, 0, 0], + "Incorrect verification result for {}, case 1, got {:?}.", + name, + rv1 + ); + + // different message + let params2 = { + let signer = secp256k1::Secp256k1::new(); + let sk = secp256k1::SecretKey::from_slice(&[ + 0xc9, 0xef, 0x15, 0x44, 0x4b, 0x1e, 0x88, 0x5f, 0x0e, 0xd0, 0x36, 0xaa, 0xc8, 0x64, + 0x6f, 0xb0, 0xc6, 0x11, 0x88, 0x6e, 0x8c, 0x40, 0x91, 0xa1, 0xb7, 0xb2, 0xb5, 0xa0, + 0x95, 0xd2, 0xd6, 0xba, + ]) + .expect("Key generated with openssl, so should be valid."); + let message = secp256k1::Message::from_slice(&sha2::Sha256::digest(&[])[..]) + .expect("Hashes are valid messages."); + let sig = signer.sign_ecdsa(&message, &sk); + let pk = secp256k1::PublicKey::from_slice(&[ + 0x04, 0xbb, 0xc0, 0xa1, 0xad, 0x6f, 0x0d, 0x2c, 0x1f, 0x32, 0x50, 0xd9, 0x08, 0x78, + 0x15, 0x37, 0xd6, 0x8c, 0xf4, 0xa6, 0x96, 0x41, 0x74, 0xb9, 0x70, 0x36, 0x2c, 0x66, + 0x47, 0x52, 0x11, 0xc6, 0xf8, 0x70, 0xd4, 0xc1, 0x99, 0xc7, 0x93, 0xbf, 0x3d, 0x6c, + 0x21, 0x55, 0x2d, 0xad, 0xee, 0xc5, 0x1b, 0x6a, 0x3f, 0xa6, 0x0a, 0x7c, 0x1a, 0x1f, + 0x63, 0xd5, 0x8f, 0xf5, 0x51, 0x7b, 0x74, 0xf8, 0x12, + ]) + .expect( + "Should be a valid public key matching the secret key above. Generated with \ + openssl.", + ); + let mut params = Vec::with_capacity(100); + params.extend_from_slice(&pk.serialize()); + params.extend_from_slice(&sig.serialize_compact()); + let incorrect_message = secp256k1::Message::from_slice(&sha2::Sha256::digest(&[0])[..]) + .expect("Hashes are valid messages."); + params.extend_from_slice(incorrect_message.as_ref()); + params + }; + let rv2 = test_crypto_primitive(name, params2); + anyhow::ensure!( + rv2[..] == [0, 0, 0, 0], + "Incorrect verification result for {}, case 2, got {:?}.", + name, + rv2 + ); + + // non-matching public key + let params3 = { + let signer = secp256k1::Secp256k1::new(); + let sk = secp256k1::SecretKey::from_slice(&[ + 0xc9, 0xef, 0x15, 0x44, 0x4b, 0x1e, 0x88, 0x5f, 0x0e, 0xd0, 0x36, 0xaa, 0xc8, 0x64, + 0x6f, 0xb0, 0xc6, 0x11, 0x88, 0x6e, 0x8c, 0x40, 0x91, 0xa1, 0xb7, 0xb2, 0xb5, 0xa0, + 0x95, 0xd2, 0xd6, 0xba, + ]) + .expect("Key generated with openssl, so should be valid."); + let message = secp256k1::Message::from_slice(&sha2::Sha256::digest(&[])[..]) + .expect("Hashes are valid messages."); + let sig = signer.sign_ecdsa(&message, &sk); + let pk = secp256k1::PublicKey::from_slice(&[ + 0x04, 0xf2, 0x56, 0xc6, 0xe6, 0xc8, 0x0b, 0x21, 0x3f, 0x2a, 0xa0, 0xb0, 0x17, 0x44, + 0x23, 0x5d, 0x51, 0x5c, 0x59, 0x44, 0x35, 0xbe, 0x65, 0x1b, 0x15, 0x88, 0x3a, 0x10, + 0xdd, 0x47, 0x2f, 0xa6, 0x46, 0xce, 0x62, 0xea, 0xf3, 0x67, 0x0d, 0xc5, 0xcb, 0x91, + 0x00, 0xa0, 0xca, 0x2a, 0x55, 0xb2, 0xc1, 0x47, 0xc1, 0xe9, 0xa3, 0x8c, 0xe4, 0x28, + 0x87, 0x8e, 0x7d, 0x46, 0xe1, 0xfb, 0x71, 0x4a, 0x99, + ]) + .expect( + "Should be a valid public key matching the secret key above. Generated with \ + openssl.", + ); + let mut params = Vec::with_capacity(100); + params.extend_from_slice(&pk.serialize()); + params.extend_from_slice(&sig.serialize_compact()); + params.extend_from_slice(message.as_ref()); + params + }; + let rv3 = test_crypto_primitive(name, params3); + anyhow::ensure!( + rv3[..] == [0, 0, 0, 0], + "Incorrect verification result for {}, case 3, got {:?}.", + name, + rv3 + ); + } + + { + // n is the length of the data to be hashed + for n in [0u32, 10, 20, 50, 100, 1000, 10_000, 100_000] { + let name = "hostfn.hash_sha2_256"; + let params = n.to_le_bytes().to_vec(); // length to hash + let rv = test_crypto_primitive(name, params); + let hash = sha2::Sha256::digest(vec![0u8; n as usize]); + anyhow::ensure!(rv == hash[..], "Incorrect SHA2-256 digest for n = {}.", n); + } + } + + { + // n is the length of the data to be hashed + for n in [0u32, 10, 20, 50, 100, 1000, 10_000, 100_000] { + let name = "hostfn.hash_sha3_256"; + let params = n.to_le_bytes().to_vec(); // length to hash + let rv = test_crypto_primitive(name, params); + let hash = sha3::Sha3_256::digest(vec![0u8; n as usize]); + anyhow::ensure!(rv == hash[..], "Incorrect SHA3-256 digest for n = {}.", n); + } + } + + { + // n is the length of the data to be hashed + for n in [0u32, 10, 20, 50, 100, 1000, 10_000, 100_000] { + let name = "hostfn.hash_keccak_256"; + let params = n.to_le_bytes().to_vec(); // length to hash + let rv = test_crypto_primitive(name, params); + let hash = sha3::Keccak256::digest(vec![0u8; n as usize]); + anyhow::ensure!(rv == hash[..], "Incorrect Keccak-256 digest for n = {}.", n); + } + } + + Ok(()) +} diff --git a/wasm-chain-integration/src/v1/mod.rs b/wasm-chain-integration/src/v1/mod.rs index a2ab9262..5e3de70a 100644 --- a/wasm-chain-integration/src/v1/mod.rs +++ b/wasm-chain-integration/src/v1/mod.rs @@ -1,4 +1,6 @@ #[cfg(test)] +mod crypto_primitives_tests; +#[cfg(test)] mod tests; #[cfg(feature = "enable-ffi")] diff --git a/wasm-chain-integration/test-data/code/v1/crypto-primitives-tests.wasm b/wasm-chain-integration/test-data/code/v1/crypto-primitives-tests.wasm new file mode 100644 index 0000000000000000000000000000000000000000..4a8b8f4fe6fe782a37447158cc274a2d4dd21653 GIT binary patch literal 1220 zcma))&u*JQ5XNW0IIWW^j^jURb11pAIaP`)N9vJV-vSVfV?@lNWpU#kKz)ZkThFc3 zC+HJ&m&NS_J5@p2f%$&(&Flh%#hL*C`*;$tn$7c-Qs$+E0Z}eCD3ayY$9TS2+?v9G$BJ>N4^7-O6y&*L9e6b3Pm0zsFxvwxdChh)6@AstBrYglK3R5H6eaF_9 zV>7UhzB1?aiWhR3z1vN*H}mXmhj?<{i*ZXnp7munZRUJ6r8JrGa`25gbH-{9)csQ} zL*{*lYYVPelX6wkWy8^}rGcK(&pbFiexu*O`=TIKpdYWiA22-cVAnfmU8p$Y+jDi< SSQWV{Hh%vCC;tmhDfk<+2zt!` literal 0 HcmV?d00001 diff --git a/wasm-chain-integration/test-data/code/v1/crypto-primitives-tests.wat b/wasm-chain-integration/test-data/code/v1/crypto-primitives-tests.wat new file mode 100644 index 00000000..ba30ae37 --- /dev/null +++ b/wasm-chain-integration/test-data/code/v1/crypto-primitives-tests.wat @@ -0,0 +1,96 @@ +(module + + ;; Simple init and receive functions used for integration testing of cryptographic primitives. + ;; A general precondition is that at least one page of linear memory is allocated. + ;; Additional preconditions are listed above the relevant functions. + + ;; Function parameter + (import "concordium" "get_parameter_size" (func $get_parameter_size (param $index i32) (result i32))) + (import "concordium" "get_parameter_section" (func $get_parameter_section (param $index i32) (param $write_location i32) (param $length i32) (param $offset i32) (result i32))) + + ;; State functions + (import "concordium" "state_create_entry" (func $state_create_entry (param $key_start i32) (param $key_length i32) (result i64))) + (import "concordium" "state_entry_size" (func $state_entry_size (param $entry i64) (result i32))) + (import "concordium" "state_entry_read" (func $state_entry_read (param $entry i64) (param $write_location i32) (param $length i32) (param $offset i32) (result i32))) + (import "concordium" "state_lookup_entry" (func $state_lookup_entry (param $key_start i32) (param $key_length i32) (result i64))) + (import "concordium" "state_entry_write" (func $state_entry_write (param $entry i64) (param $read_location i32) (param $length i32) (param $offset i32) (result i32))) + (import "concordium" "state_delete_entry" (func $state_delete_entry (param $key_start i32) (param $key_length i32) (result i32))) + (import "concordium" "state_delete_prefix" (func $state_delete_prefix (param $key_start i32) (param $key_length i32) (result i32))) + + ;; Iterator functions + (import "concordium" "state_iterate_prefix" (func $state_iterate_prefix (param $key_start i32) (param $key_length i32) (result i64))) + (import "concordium" "state_iterator_next" (func $state_iterator_next (param $iter i64) (result i64))) + (import "concordium" "state_iterator_delete" (func $state_iterator_delete (param $iter i64) (result i32))) + (import "concordium" "state_iterator_key_size" (func $state_iterator_key_size (param $iter i64) (result i32))) + (import "concordium" "state_iterator_key_read" (func $state_iterator_key_read + (param $iter i64) + (param $write_location i32) + (param $length i32) + (param $offset i32) + (result i32))) + + ;; Fallback related functions. Only available in receive functions. + (import "concordium" "get_receive_entrypoint_size" (func $get_ep_size (result i32))) + (import "concordium" "get_receive_entrypoint" (func $get_ep (param $start i32))) + + ;; Invoke another contract or a transfer. + (import "concordium" "invoke" (func $invoke (param $tag i32) (param $start i32) (param $length i32) (result i64))) + + ;; return a value + (import "concordium" "write_output" (func $write_output (param $start i32) (param $length i32) (param $offset i32) (result i32))) + + ;; cryptographic primitives + (import "concordium" "verify_ed25519_signature" (func $verify_ed25519_signature (param $public_key i32) (param $signature i32) (param $message i32) (param $message_len i32) (result i32))) + (import "concordium" "verify_ecdsa_secp256k1_signature" (func $verify_ecdsa_secp256k1_signature (param $public_key i32) (param $signature i32) (param $message i32) (result i32))) + (import "concordium" "hash_sha2_256" (func $hash_sha2_256 (param $data i32) (param $data_len i32) (param $output i32))) + (import "concordium" "hash_sha3_256" (func $hash_sha3_256 (param $data i32) (param $data_len i32) (param $output i32))) + (import "concordium" "hash_keccak_256" (func $hash_keccak_256 (param $data i32) (param $data_len i32) (param $output i32))) + + (func (export "hostfn.verify_ed25519_signature") (param i64) (result i32) + (local $len i32) + (call $get_parameter_section (i32.const 0) (i32.const 0) (i32.const 100) (i32.const 0)) + (local.set $len (i32.load (i32.const 96))) + (i32.store (i32.const 0) (call $verify_ed25519_signature (i32.const 0) (i32.const 32) (i32.const 100) (local.get $len))) + (call $write_output (i32.const 0) (i32.const 4) (i32.const 0)) + (return (i32.const 0)) + ) + + (func (export "hostfn.verify_ecdsa_secp256k1_signature") (param i64) (result i32) + (call $get_parameter_section (i32.const 0) (i32.const 0) (i32.const 129) (i32.const 0)) + (i32.store (i32.const 0) (call $verify_ecdsa_secp256k1_signature (i32.const 0) (i32.const 33) (i32.const 97))) + (call $write_output (i32.const 0) (i32.const 4) (i32.const 0)) + (return (i32.const 0)) + ) + + (func (export "hostfn.hash_sha2_256") (param i64) (result i32) + (local $len i32) + (call $get_parameter_section (i32.const 0) (i32.const 0) (i32.const 4) (i32.const 0)) + (local.set $len (i32.load (i32.const 0))) + (call $hash_sha2_256 (i32.const 4) (local.get $len) (i32.const 0)) + (call $write_output (i32.const 0) (i32.const 32) (i32.const 0)) + (return (i32.const 0)) + ) + + (func (export "hostfn.hash_sha3_256") (param i64) (result i32) + (local $len i32) + (call $get_parameter_section (i32.const 0) (i32.const 0) (i32.const 4) (i32.const 0)) + (local.set $len (i32.load (i32.const 0))) + (call $hash_sha3_256 (i32.const 4) (local.get $len) (i32.const 0)) + (call $write_output (i32.const 0) (i32.const 32) (i32.const 0)) + (return (i32.const 0)) + ) + + (func (export "hostfn.hash_keccak_256") (param i64) (result i32) + (local $len i32) + (call $get_parameter_section (i32.const 0) (i32.const 0) (i32.const 4) (i32.const 0)) + (local.set $len (i32.load (i32.const 0))) + (call $hash_keccak_256 (i32.const 4) (local.get $len) (i32.const 0)) + (call $write_output (i32.const 0) (i32.const 32) (i32.const 0)) + (return (i32.const 0)) + ) + (memory 2) +) + +;; Local Variables: +;; compile-command: "wat2wasm crypto-primitives-tests.wat" +;; End: From a0c5498df937c4d5be09674cae1430aa1776bfed Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ale=C5=A1=20Bizjak?= Date: Wed, 4 May 2022 09:46:31 +0200 Subject: [PATCH 5/5] Revise costs for consistency. --- wasm-chain-integration/src/constants.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/wasm-chain-integration/src/constants.rs b/wasm-chain-integration/src/constants.rs index 6275d9c3..47339430 100644 --- a/wasm-chain-integration/src/constants.rs +++ b/wasm-chain-integration/src/constants.rs @@ -232,7 +232,7 @@ pub const VERIFY_ECDSA_SECP256K1_COST: u64 = 100_000; pub fn hash_sha2_256_cost(data_len: u32) -> u64 { 500 + 7 * u64::from(data_len) } /// Cost of computing a SHA3-256 digest of the message of the given length. -pub fn hash_sha3_256_cost(data_len: u32) -> u64 { 600 + 5 * u64::from(data_len) } +pub fn hash_sha3_256_cost(data_len: u32) -> u64 { 500 + 5 * u64::from(data_len) } /// Cost of computing a Keccak-256 digest of the message of the given length. -pub fn hash_keccak_256_cost(data_len: u32) -> u64 { 600 + 5 * u64::from(data_len) } +pub fn hash_keccak_256_cost(data_len: u32) -> u64 { 500 + 5 * u64::from(data_len) }