Unverified Commit 3f36f02e authored by Hero Bird's avatar Hero Bird Committed by GitHub
Browse files

Implement new crypto hash API (#499)

* [core] add new crypto hash API

* [core] move new crypto hash definitions to dedicated module

* [core] integrate the new env::hash module into core::storage module

* [core] fix LayoutCryptoHasher impls

* [core] add doc test to hash_encoded

* [core] fix minor things in lazy hash map

* [core] apply rustfmt

* [core] remove old crypto hash module

* [core] base DynamicAllocation::key implementation on new hash API

* [core] remove old hash impls from on-chain env

* [core] make DynamicAllocation::key impl work on Wasm32 target

* [core] remove the entire deprecated ink_core::hash module
parent 7838c861
Pipeline #109181 passed with stages
in 8 minutes and 7 seconds
...@@ -28,6 +28,8 @@ cfg-if = "0.1" ...@@ -28,6 +28,8 @@ cfg-if = "0.1"
array-init = "0.1" array-init = "0.1"
generic-array = "0.14.1" generic-array = "0.14.1"
paste = "0.1" paste = "0.1"
arrayref = "0.3"
static_assertions = "1.1"
# Hashes for the off-chain environment. # Hashes for the off-chain environment.
sha2 = { version = "0.9", optional = true } sha2 = { version = "0.9", optional = true }
......
...@@ -240,34 +240,28 @@ macro_rules! gen_tests_for_backend { ...@@ -240,34 +240,28 @@ macro_rules! gen_tests_for_backend {
mod lazyhmap_backend { mod lazyhmap_backend {
use super::*; use super::*;
use ink_core::{ use ink_core::{
hash::hasher::Blake2x256Hasher, env::hash::Blake2x256,
storage::lazy::lazy_hmap::{ storage::lazy::lazy_hmap::{
Entry, Entry,
LazyHashMap, LazyHashMap,
}, },
}; };
gen_tests_for_backend!(LazyHashMap<i32, i32, Blake2x256Hasher>); gen_tests_for_backend!(LazyHashMap<i32, i32, Blake2x256>);
pub fn insert( pub fn insert(
hmap: &mut LazyHashMap<i32, i32, Blake2x256Hasher>, hmap: &mut LazyHashMap<i32, i32, Blake2x256>,
key: i32, key: i32,
value: i32, value: i32,
) -> Option<i32> { ) -> Option<i32> {
hmap.put_get(&key, Some(value)) hmap.put_get(&key, Some(value))
} }
pub fn take( pub fn take(hmap: &mut LazyHashMap<i32, i32, Blake2x256>, key: &i32) -> Option<i32> {
hmap: &mut LazyHashMap<i32, i32, Blake2x256Hasher>,
key: &i32,
) -> Option<i32> {
hmap.put_get(key, None) hmap.put_get(key, None)
} }
pub fn contains_key( pub fn contains_key(hmap: &LazyHashMap<i32, i32, Blake2x256>, key: &i32) -> bool {
hmap: &LazyHashMap<i32, i32, Blake2x256Hasher>,
key: &i32,
) -> bool {
hmap.get(key).is_some() hmap.get(key).is_some()
} }
......
...@@ -29,6 +29,10 @@ use crate::env::{ ...@@ -29,6 +29,10 @@ use crate::env::{
EnvInstance, EnvInstance,
OnInstance, OnInstance,
}, },
hash::{
CryptoHash,
HashOutput,
},
EnvTypes, EnvTypes,
Result, Result,
Topics, Topics,
...@@ -513,40 +517,37 @@ pub fn println(content: &str) { ...@@ -513,40 +517,37 @@ pub fn println(content: &str) {
<EnvInstance as OnInstance>::on_instance(|instance| Env::println(instance, content)) <EnvInstance as OnInstance>::on_instance(|instance| Env::println(instance, content))
} }
/// Built-in efficient cryptographic hash functions. /// Conducts the crypto hash of the given input and stores the result in `output`.
pub mod hash { pub fn hash_bytes<H>(input: &[u8], output: &mut <H as HashOutput>::Type)
use super::*; where
H: CryptoHash,
{
<EnvInstance as OnInstance>::on_instance(|instance| {
instance.hash_bytes::<H>(input, output)
})
}
macro_rules! impl_hash_fn { /// Conducts the crypto hash of the given encoded input and stores the result in `output`.
( $(#[$doc:meta])* fn $name:ident($output_len:literal) ) => { ///
paste::item! { /// # Example
$( #[$doc] )* ///
pub fn $name(input: &[u8], output: &mut [u8; $output_len]) { /// ```
// No need to actually access the environmental instance /// # use ink_core::env::hash::{Sha2x256, HashOutput};
// if we only call one of its inherent methods. /// const EXPECTED: [u8; 32] = [
<EnvInstance as Env>::[<hash_ $name>](input, output) /// 243, 242, 58, 110, 205, 68, 100, 244, 187, 55, 188, 248, 29, 136, 145, 115,
} /// 186, 134, 14, 175, 178, 99, 183, 21, 4, 94, 92, 69, 199, 207, 241, 179,
} /// ];
}; /// let encodable = (42, "foo", true); // Implements `scale::Encode`
} /// let mut output = <Sha2x256 as HashOutput>::Type::default(); // 256-bit buffer
impl_hash_fn!( /// ink_core::env::hash_encoded::<Sha2x256, _>(&encodable, &mut output);
/// Conducts the SHA2 256-bit hash of the given bytes and /// assert_eq!(output, EXPECTED);
/// puts the result into the output buffer. /// ```
fn sha2_256(32) pub fn hash_encoded<H, T>(input: &T, output: &mut <H as HashOutput>::Type)
); where
impl_hash_fn!( H: CryptoHash,
/// Conducts the KECCAK 256-bit hash of the given bytes and T: scale::Encode,
/// puts the result into the output buffer. {
fn keccak_256(32) <EnvInstance as OnInstance>::on_instance(|instance| {
); instance.hash_encoded::<H, T>(input, output)
impl_hash_fn!( })
/// Conducts the BLAKE2 256-bit hash of the given bytes and
/// puts the result into the output buffer.
fn blake2_256(32)
);
impl_hash_fn!(
/// Conducts the BLAKE2 128-bit hash of the given bytes and
/// puts the result into the output buffer.
fn blake2_128(16)
);
} }
...@@ -18,6 +18,10 @@ use crate::env::{ ...@@ -18,6 +18,10 @@ use crate::env::{
CallParams, CallParams,
CreateParams, CreateParams,
}, },
hash::{
CryptoHash,
HashOutput,
},
EnvTypes, EnvTypes,
Result, Result,
Topics, Topics,
...@@ -113,21 +117,16 @@ pub trait Env { ...@@ -113,21 +117,16 @@ pub trait Env {
/// Prints the given contents to the console log. /// Prints the given contents to the console log.
fn println(&mut self, content: &str); fn println(&mut self, content: &str);
/// Conducts the SHA2 256-bit hash of the input /// Conducts the crypto hash of the given input and stores the result in `output`.
/// puts the result into the output buffer. fn hash_bytes<H>(&mut self, input: &[u8], output: &mut <H as HashOutput>::Type)
fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]); where
H: CryptoHash;
/// 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 /// Conducts the crypto hash of the given encoded input and stores the result in `output`.
/// puts the result into the output buffer. fn hash_encoded<H, T>(&mut self, input: &T, output: &mut <H as HashOutput>::Type)
fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]); where
H: CryptoHash,
T: scale::Encode;
/// Calls the chain extension with the given ID and inputs. /// Calls the chain extension with the given ID and inputs.
/// ///
......
...@@ -222,7 +222,7 @@ mod tests { ...@@ -222,7 +222,7 @@ mod tests {
fn empty_args_works() { fn empty_args_works() {
let empty_list = ArgumentList::empty(); let empty_list = ArgumentList::empty();
let encoded = scale::Encode::encode(&empty_list); let encoded = scale::Encode::encode(&empty_list);
assert_eq!(encoded, Vec::new()); assert_eq!(encoded, <Vec<u8>>::new());
} }
#[test] #[test]
......
...@@ -19,15 +19,21 @@ use super::{ ...@@ -19,15 +19,21 @@ use super::{
}; };
use crate::env::{ use crate::env::{
call::{ call::{
utils::ReturnType,
CallParams, CallParams,
CreateParams, CreateParams,
utils::ReturnType,
}, },
Blake2x128,
Blake2x256,
CryptoHash,
Env, Env,
EnvError, EnvError,
EnvTypes, EnvTypes,
HashOutput,
Keccak256,
Result, Result,
ReturnFlags, ReturnFlags,
Sha2x256,
Topics, Topics,
TypedEnv, TypedEnv,
}; };
...@@ -61,6 +67,54 @@ impl EnvInstance { ...@@ -61,6 +67,54 @@ impl EnvInstance {
} }
} }
impl CryptoHash for Blake2x128 {
fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
type OutputType = [u8; 16];
static_assertions::assert_type_eq_all!(
<Blake2x128 as HashOutput>::Type,
OutputType
);
let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 16);
hashing::blake2b_128(input, output);
}
}
impl CryptoHash for Blake2x256 {
fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
type OutputType = [u8; 32];
static_assertions::assert_type_eq_all!(
<Blake2x256 as HashOutput>::Type,
OutputType
);
let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 32);
hashing::blake2b_256(input, output);
}
}
impl CryptoHash for Sha2x256 {
fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
type OutputType = [u8; 32];
static_assertions::assert_type_eq_all!(
<Sha2x256 as HashOutput>::Type,
OutputType
);
let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 32);
hashing::sha2_256(input, output);
}
}
impl CryptoHash for Keccak256 {
fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
type OutputType = [u8; 32];
static_assertions::assert_type_eq_all!(
<Keccak256 as HashOutput>::Type,
OutputType
);
let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 32);
hashing::keccak_256(input, output);
}
}
impl Env for EnvInstance { impl Env for EnvInstance {
fn set_contract_storage<V>(&mut self, key: &Key, value: &V) fn set_contract_storage<V>(&mut self, key: &Key, value: &V)
where where
...@@ -116,20 +170,20 @@ impl Env for EnvInstance { ...@@ -116,20 +170,20 @@ impl Env for EnvInstance {
self.console.println(content) self.console.println(content)
} }
fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]) { fn hash_bytes<H>(&mut self, input: &[u8], output: &mut <H as HashOutput>::Type)
hashing::keccak_256(input, output) where
} H: CryptoHash,
{
fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]) { <H as CryptoHash>::hash(input, output)
hashing::blake2b_256(input, output)
}
fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]) {
hashing::blake2b_128(input, output)
} }
fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]) { fn hash_encoded<H, T>(&mut self, input: &T, output: &mut <H as HashOutput>::Type)
hashing::sha2_256(input, output) where
H: CryptoHash,
T: scale::Encode,
{
let encoded = input.encode();
self.hash_bytes::<H>(&encoded[..], output)
} }
#[cfg(feature = "ink-unstable-chain-extensions")] #[cfg(feature = "ink-unstable-chain-extensions")]
...@@ -143,7 +197,11 @@ impl Env for EnvInstance { ...@@ -143,7 +197,11 @@ impl Env for EnvInstance {
} }
impl EnvInstance { impl EnvInstance {
fn transfer_impl<T>(&mut self, destination: T::AccountId, value: T::Balance) -> Result<()> fn transfer_impl<T>(
&mut self,
destination: T::AccountId,
value: T::Balance,
) -> Result<()>
where where
T: EnvTypes, T: EnvTypes,
{ {
......
...@@ -20,20 +20,62 @@ use super::{ ...@@ -20,20 +20,62 @@ use super::{
}; };
use crate::env::{ use crate::env::{
call::{ call::{
utils::ReturnType,
CallParams, CallParams,
CreateParams, CreateParams,
utils::ReturnType,
}, },
Blake2x128,
Blake2x256,
CryptoHash,
Env, Env,
EnvError, EnvError,
EnvTypes, EnvTypes,
Keccak256,
HashOutput,
Result, Result,
ReturnFlags, ReturnFlags,
Sha2x256,
Topics, Topics,
TypedEnv, TypedEnv,
}; };
use ink_primitives::Key; use ink_primitives::Key;
impl CryptoHash for Blake2x128 {
fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
type OutputType = [u8; 16];
static_assertions::assert_type_eq_all!(<Blake2x128 as HashOutput>::Type, OutputType);
let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 16);
ext::hash_blake2_128(input, output);
}
}
impl CryptoHash for Blake2x256 {
fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
type OutputType = [u8; 32];
static_assertions::assert_type_eq_all!(<Blake2x256 as HashOutput>::Type, OutputType);
let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 32);
ext::hash_blake2_256(input, output);
}
}
impl CryptoHash for Sha2x256 {
fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
type OutputType = [u8; 32];
static_assertions::assert_type_eq_all!(<Sha2x256 as HashOutput>::Type, OutputType);
let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 32);
ext::hash_sha2_256(input, output);
}
}
impl CryptoHash for Keccak256 {
fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type) {
type OutputType = [u8; 32];
static_assertions::assert_type_eq_all!(<Keccak256 as HashOutput>::Type, OutputType);
let output: &mut OutputType = arrayref::array_mut_ref!(output, 0, 32);
ext::hash_keccak_256(input, output);
}
}
impl From<ext::Error> for EnvError { impl From<ext::Error> for EnvError {
fn from(ext_error: ext::Error) -> Self { fn from(ext_error: ext::Error) -> Self {
match ext_error { match ext_error {
...@@ -141,28 +183,25 @@ impl Env for EnvInstance { ...@@ -141,28 +183,25 @@ impl Env for EnvInstance {
ext::println(content) ext::println(content)
} }
fn hash_keccak_256(input: &[u8], output: &mut [u8; 32]) { fn hash_bytes<H>(&mut self, input: &[u8], output: &mut <H as HashOutput>::Type)
ext::hash_keccak_256(input, output) where
} H: CryptoHash,
{
fn hash_blake2_256(input: &[u8], output: &mut [u8; 32]) { <H as CryptoHash>::hash(input, output)
ext::hash_blake2_256(input, output)
}
fn hash_blake2_128(input: &[u8], output: &mut [u8; 16]) {
ext::hash_blake2_128(input, output)
} }
fn hash_sha2_256(input: &[u8], output: &mut [u8; 32]) { fn hash_encoded<H, T>(&mut self, input: &T, output: &mut <H as HashOutput>::Type)
ext::hash_sha2_256(input, output) where
H: CryptoHash,
T: scale::Encode,
{
let mut scope = self.scoped_buffer();
let enc_input = scope.take_encoded(input);
<H as CryptoHash>::hash(enc_input, output)
} }
#[cfg(feature = "ink-unstable-chain-extensions")] #[cfg(feature = "ink-unstable-chain-extensions")]
fn call_chain_extension<I, O>( fn call_chain_extension<I, O>(&mut self, func_id: u32, input: &I) -> Result<O>
&mut self,
func_id: u32,
input: &I,
) -> Result<O>
where where
I: scale::Encode, I: scale::Encode,
O: scale::Decode, O: scale::Decode,
......
// Copyright 2018-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.
//! Provides type definitions and traits for the built-in cryptographic hashes.
/// The output type of a built-in cryptographic hash function.
pub trait HashOutput: private::Sealed {
/// The output type of the crypto hash.
///
/// This should be a byte array with some constant size such as `[u8; 32]`.
type Type: Default;
}
/// Types that are usable as built-in cryptographic hashes.
pub trait CryptoHash: HashOutput + private::Sealed {
/// Hashes the given raw byte input and copies the result into `output`.
fn hash(input: &[u8], output: &mut <Self as HashOutput>::Type);
}
/// The SHA2 crypto hash with 256-bit output.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Sha2x256 {}
/// The KECCAK crypto hash with 256-bit output.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Keccak256 {}
/// The BLAKE2 crypto hash with 256-bit output.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Blake2x256 {}
/// The BLAKE2 crypto hash with 128-bit output.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum Blake2x128 {}
mod private {
/// Seals the implementation of `CryptoHash` and `HashOutput`.
pub trait Sealed {}
}
impl private::Sealed for Sha2x256 {}
impl private::Sealed for Keccak256 {}
impl private::Sealed for Blake2x256 {}
impl private::Sealed for Blake2x128 {}
impl HashOutput for Sha2x256 {
type Type = [u8; 32];
}
impl HashOutput for Keccak256 {
type Type = [u8; 32];
}
impl HashOutput for Blake2x256 {
type Type = [u8; 32];
}
impl HashOutput for Blake2x128 {
type Type = [u8; 16];
}
...@@ -23,6 +23,7 @@ mod backend; ...@@ -23,6 +23,7 @@ mod backend;
pub mod call; pub mod call;
mod engine; mod engine;
mod error; mod error;
pub mod hash;
mod types; mod types;
#[cfg(test)] #[cfg(test)]
...@@ -43,6 +44,14 @@ pub use self::{ ...@@ -43,6 +44,14 @@ pub use self::{
EnvError, EnvError,
Result, Result,
}, },
hash::{
Blake2x128,
Blake2x256,
CryptoHash,
HashOutput,