Unverified Commit e0204021 authored by Hero Bird's avatar Hero Bird Committed by GitHub

Implement crypto hash functions supported by contracts pallet (#360)

* [core] implement crypto hash functions supported by contracts pallet

* [core] fix clippy warnings

* [core] add unit tests for new crypto hashes

* [core] refactor unit tests for crypto hashes

* [core] make hash functions return their hash through output buffer

* [core] update docs of hash APIs

* [core] put hash API in its own sub-module of env

* [core] fix on-chain hash implementations

* [core] apply rustfmt
parent aaf42ed4
Pipeline #84018 passed with stages
in 7 minutes and 11 seconds
......@@ -26,6 +26,14 @@ derive_more = { version = "0.99", default-features = false, features = ["from",
smallvec = { version = "1.2", default-features = false, features = ["union"] }
cfg-if = "0.1"
num-traits = { version = "0.2", default-features = false, features = ["i128"] }
paste = "0.1"
# Hashes for the off-chain environment.
byteorder = { version = "1.3", optional = true }
blake2-rfc = { version = "0.2", optional = true }
sha2 = { version = "0.8", optional = true }
tiny-keccak = { version = "2.0", optional = true }
twox-hash = { version = "1.5", optional = true }
# Only used in the off-chain environment.
#
......@@ -55,6 +63,12 @@ std = [
"rand",
"rand/std",
"num-traits/std",
# Enables hashing crates for off-chain environment.
"byteorder",
"blake2-rfc",
"sha2",
"tiny-keccak",
"twox-hash",
]
ink-generate-abi = [
"ink_abi",
......
......@@ -506,3 +506,56 @@ where
Env::get_runtime_storage::<R>(instance, runtime_key)
})
}
/// Built-in efficient cryptographic hash functions.
pub mod hash {
use super::*;
macro_rules! impl_hash_fn {
( $(#[$doc:meta])* fn $name:ident($output_len:literal) ) => {
paste::item! {
$( #[$doc] )*
pub fn $name(input: &[u8], output: &mut [u8; $output_len]) {
// No need to actually access the environmental instance
// if we only call one of its inherent methods.
<EnvInstance as Env>::[<hash_ $name>](input, output)
}
}
};
}
impl_hash_fn!(
/// Conducts the SHA2 256-bit hash of the input and
/// puts the result into the output buffer.
fn sha2_256(32)
);
impl_hash_fn!(
/// Conducts the KECCAK 256-bit hash of the input and
/// puts the result into the output buffer.
fn keccak_256(32)
);
impl_hash_fn!(
/// Conducts the BLAKE2 256-bit hash of the input and
/// puts the result into the output buffer.
fn blake2_256(32)
);
impl_hash_fn!(
/// Conducts the BLAKE2 128-bit hash of the input and
/// puts the result into the output buffer.
fn blake2_128(16)
);
impl_hash_fn!(
/// Conducts the TWOX 256-bit hash of the input and
/// puts the result into the output buffer.
fn twox_256(32)
);
impl_hash_fn!(
/// Conducts the TWOX 128-bit hash of the input and
/// puts the result into the output buffer.
fn twox_128(16)
);
impl_hash_fn!(
/// Conducts the TWOX 64-bit hash of the input and
/// puts the result into the output buffer.
fn twox_64(8)
);
}
......@@ -77,6 +77,34 @@ pub trait Env {
/// Prints the given contents to the console log.
fn println(&mut self, content: &str);
/// Conducts the SHA2 256-bit hash of the input
/// puts the result into the output buffer.
fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]);
/// Conducts the KECCAK 256-bit hash of the input
/// puts the result into the output buffer.
fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]);
/// Conducts the BLAKE2 256-bit hash of the input
/// puts the result into the output buffer.
fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]);
/// Conducts the BLAKE2 128-bit hash of the input
/// puts the result into the output buffer.
fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]);
/// Conducts the TWOX 256-bit hash of the input
/// puts the result into the output buffer.
fn hash_twox_256(input: &[u8], output: &mut [u8; 32]);
/// Conducts the TWOX 128-bit hash of the input
/// puts the result into the output buffer.
fn hash_twox_128(input: &[u8], output: &mut [u8; 16]);
/// Conducts the TWOX 64-bit hash of the input
/// puts the result into the output buffer.
fn hash_twox_64(input: &[u8], output: &mut [u8; 8]);
}
/// Environmental contract functionality.
......
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Implementations of supported cryptographic hash functions.
/// Conduct the BLAKE2 256-bit hash and place the result into `output`.
pub fn blake2_256(input: &[u8], output: &mut [u8; 32]) {
output.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], input).as_bytes());
}
/// Conduct the BLAKE2 128-bit hash and place the result into `output`.
pub fn blake2_128(input: &[u8], output: &mut [u8; 16]) {
output.copy_from_slice(blake2_rfc::blake2b::blake2b(16, &[], input).as_bytes());
}
/// Conduct the TWOX (XX) 64-bit hash and place the result into `output`.
pub fn twox_64(input: &[u8], output: &mut [u8; 8]) {
use ::core::hash::Hasher;
let mut h0 = twox_hash::XxHash::with_seed(0);
h0.write(input);
let r0 = h0.finish();
use byteorder::{
ByteOrder,
LittleEndian,
};
LittleEndian::write_u64(&mut output[0..8], r0);
}
/// Conduct the TWOX (XX) 128-bit hash and place the result into `output`.
pub fn twox_128(input: &[u8], output: &mut [u8; 16]) {
use ::core::hash::Hasher;
let mut h0 = twox_hash::XxHash::with_seed(0);
let mut h1 = twox_hash::XxHash::with_seed(1);
h0.write(input);
h1.write(input);
let r0 = h0.finish();
let r1 = h1.finish();
use byteorder::{
ByteOrder,
LittleEndian,
};
LittleEndian::write_u64(&mut output[0..8], r0);
LittleEndian::write_u64(&mut output[8..16], r1);
}
/// Conduct the TWOX (XX) 256-bit hash and place the result into `output`.
pub fn twox_256(input: &[u8], output: &mut [u8; 32]) {
use ::core::hash::Hasher;
use byteorder::{
ByteOrder,
LittleEndian,
};
let mut h0 = twox_hash::XxHash::with_seed(0);
let mut h1 = twox_hash::XxHash::with_seed(1);
let mut h2 = twox_hash::XxHash::with_seed(2);
let mut h3 = twox_hash::XxHash::with_seed(3);
h0.write(input);
h1.write(input);
h2.write(input);
h3.write(input);
let r0 = h0.finish();
let r1 = h1.finish();
let r2 = h2.finish();
let r3 = h3.finish();
LittleEndian::write_u64(&mut output[0..8], r0);
LittleEndian::write_u64(&mut output[8..16], r1);
LittleEndian::write_u64(&mut output[16..24], r2);
LittleEndian::write_u64(&mut output[24..32], r3);
}
/// Conduct the KECCAK 256-bit hash and place the result into `output`.
pub fn keccak_256(input: &[u8], output: &mut [u8; 32]) {
use ::tiny_keccak::{
Hasher,
Keccak,
};
let mut keccak = Keccak::v256();
keccak.update(input);
keccak.finalize(output)
}
/// Conduct the SHA2 256-bit hash and place the result into `output`.
pub fn sha2_256(input: &[u8], output: &mut [u8; 32]) {
use ::sha2::{
Digest,
Sha256,
};
let mut hasher = Sha256::new();
hasher.input(input);
output.copy_from_slice(&hasher.result());
}
......@@ -13,6 +13,7 @@
// limitations under the License.
use super::{
hashing,
Account,
EnvInstance,
};
......@@ -111,6 +112,34 @@ impl Env for EnvInstance {
fn println(&mut self, content: &str) {
self.console.println(content)
}
fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]) {
hashing::keccak_256(input, output)
}
fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]) {
hashing::blake2_256(input, output)
}
fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]) {
hashing::blake2_128(input, output)
}
fn hash_twox_256(input: &[u8], output: &mut [u8; 32]) {
hashing::twox_256(input, output)
}
fn hash_twox_128(input: &[u8], output: &mut [u8; 16]) {
hashing::twox_128(input, output)
}
fn hash_twox_64(input: &[u8], output: &mut [u8; 8]) {
hashing::twox_64(input, output)
}
fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]) {
hashing::sha2_256(input, output)
}
}
impl TypedEnv for EnvInstance {
......
......@@ -13,6 +13,7 @@
// limitations under the License.
mod db;
mod hashing;
mod impls;
mod runtime_calls;
mod runtime_storage;
......
......@@ -101,6 +101,14 @@ mod sys {
pub fn ext_random_seed(subject_ptr: u32, subject_len: u32);
pub fn ext_println(str_ptr: u32, str_len: u32);
pub fn ext_hash_keccak_256(input_ptr: u32, input_len: u32, output_ptr: u32);
pub fn ext_hash_blake2_256(input_ptr: u32, input_len: u32, output_ptr: u32);
pub fn ext_hash_blake2_128(input_ptr: u32, input_len: u32, output_ptr: u32);
pub fn ext_hash_twox_256(input_ptr: u32, input_len: u32, output_ptr: u32);
pub fn ext_hash_twox_128(input_ptr: u32, input_len: u32, output_ptr: u32);
pub fn ext_hash_twox_64(input_ptr: u32, input_len: u32, output_ptr: u32);
pub fn ext_hash_sha2_256(input_ptr: u32, input_len: u32, output_ptr: u32);
}
}
......@@ -301,3 +309,26 @@ pub fn println(content: &str) {
let bytes = content.as_bytes();
unsafe { sys::ext_println(bytes.as_ptr() as u32, bytes.len() as u32) }
}
macro_rules! impl_hash_fn {
( $name:ident, $bytes_result:literal ) => {
paste::item! {
pub fn [<hash_ $name>](input: &[u8], output: &mut [u8; $bytes_result]) {
unsafe {
sys::[<ext_hash_ $name>](
input.as_ptr() as u32,
input.len() as u32,
output.as_ptr() as u32,
)
}
}
}
};
}
impl_hash_fn!(sha2_256, 32);
impl_hash_fn!(keccak_256, 32);
impl_hash_fn!(blake2_256, 32);
impl_hash_fn!(blake2_128, 16);
impl_hash_fn!(twox_256, 32);
impl_hash_fn!(twox_128, 16);
impl_hash_fn!(twox_64, 8);
......@@ -178,6 +178,34 @@ impl Env for EnvInstance {
fn println(&mut self, content: &str) {
ext::println(content)
}
fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]) {
ext::hash_keccak_256(input, output)
}
fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]) {
ext::hash_blake2_256(input, output)
}
fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]) {
ext::hash_blake2_128(input, output)
}
fn hash_twox_256(input: &[u8], output: &mut [u8; 32]) {
ext::hash_twox_256(input, output)
}
fn hash_twox_128(input: &[u8], output: &mut [u8; 16]) {
ext::hash_twox_128(input, output)
}
fn hash_twox_64(input: &[u8], output: &mut [u8; 8]) {
ext::hash_twox_64(input, output)
}
fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]) {
ext::hash_sha2_256(input, output)
}
}
impl TypedEnv for EnvInstance {
......
......@@ -24,6 +24,9 @@ mod engine;
mod error;
mod types;
#[cfg(test)]
mod tests;
#[cfg(any(feature = "std", test, doc))]
#[doc(inline)]
pub use self::engine::off_chain::test_api as test;
......
// Copyright 2019-2020 Parity Technologies (UK) Ltd.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
use crate::env;
static TEST_INPUT: &[u8] = b"DEAD_BEEF";
#[test]
fn test_hash_keccak_256() {
let mut output = [0x00_u8; 32];
env::hash::keccak_256(TEST_INPUT, &mut output);
assert_eq!(
output,
[
24, 230, 209, 59, 127, 30, 158, 244, 60, 177, 132, 150, 167, 244, 64, 69,
184, 123, 185, 44, 211, 199, 208, 179, 14, 64, 126, 140, 217, 69, 36, 216
]
);
}
#[test]
fn test_hash_sha2_256() {
let mut output = [0x00_u8; 32];
env::hash::sha2_256(TEST_INPUT, &mut output);
assert_eq!(
output,
[
136, 15, 25, 218, 88, 54, 49, 152, 115, 168, 147, 189, 207, 171, 243, 129,
161, 76, 15, 141, 197, 106, 111, 213, 19, 197, 133, 219, 181, 233, 195, 120
]
);
}
#[test]
fn test_hash_blake2_256() {
let mut output = [0x00_u8; 32];
env::hash::blake2_256(TEST_INPUT, &mut output);
assert_eq!(
output,
[
244, 247, 235, 182, 194, 161, 28, 69, 34, 106, 237, 7, 57, 87, 190, 12, 92,
171, 91, 176, 135, 52, 247, 94, 8, 112, 94, 183, 140, 101, 208, 120
]
);
}
#[test]
fn test_hash_blake2_128() {
let mut output = [0x00_u8; 16];
env::hash::blake2_128(TEST_INPUT, &mut output);
assert_eq!(
output,
[180, 158, 48, 21, 171, 163, 217, 175, 145, 160, 25, 159, 213, 142, 103, 242]
);
}
const EXPECTED_TWOX_256_HASH: [u8; 32] = [
184, 90, 166, 82, 206, 121, 53, 220, 214, 51, 21, 244, 158, 99, 210, 59, 173, 79,
253, 143, 224, 57, 69, 25, 254, 88, 31, 187, 27, 139, 238, 91,
];
#[test]
fn test_hash_twox_256() {
let mut output = [0x00_u8; 32];
env::hash::twox_256(TEST_INPUT, &mut output);
assert_eq!(&output, &EXPECTED_TWOX_256_HASH[..],);
}
#[test]
fn test_hash_twox_128() {
let mut output = [0x00_u8; 16];
env::hash::twox_128(TEST_INPUT, &mut output);
assert_eq!(&output, &EXPECTED_TWOX_256_HASH[..16],);
}
#[test]
fn test_hash_twox_64() {
let mut output = [0x00_u8; 8];
env::hash::twox_64(TEST_INPUT, &mut output);
assert_eq!(&output, &EXPECTED_TWOX_256_HASH[..8],);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment