diff --git a/substrate/Cargo.lock b/substrate/Cargo.lock index 9686bf426f..20499facb5 100644 --- a/substrate/Cargo.lock +++ b/substrate/Cargo.lock @@ -2051,6 +2051,7 @@ dependencies = [ "smallvec 1.7.0", "sp-arithmetic", "sp-core", + "sp-core-hashing-proc-macro", "sp-inherents", "sp-io", "sp-runtime", @@ -7919,6 +7920,7 @@ dependencies = [ "sc-tracing", "sp-api", "sp-core", + "sp-core-hashing-proc-macro", "sp-externalities", "sp-io", "sp-maybe-compressed-blob", @@ -9303,6 +9305,8 @@ dependencies = [ "serde", "serde_json", "sha2 0.9.8", + "sp-core-hashing", + "sp-core-hashing-proc-macro", "sp-debug-derive", "sp-externalities", "sp-runtime-interface", @@ -9319,6 +9323,28 @@ dependencies = [ "zeroize", ] +[[package]] +name = "sp-core-hashing" +version = "4.0.0-dev" +dependencies = [ + "blake2-rfc", + "byteorder", + "sha2 0.9.8", + "sp-std", + "tiny-keccak", + "twox-hash", +] + +[[package]] +name = "sp-core-hashing-proc-macro" +version = "4.0.0-dev" +dependencies = [ + "proc-macro2", + "quote", + "sp-core-hashing", + "syn", +] + [[package]] name = "sp-database" version = "4.0.0-dev" diff --git a/substrate/Cargo.toml b/substrate/Cargo.toml index 197b156dea..32d10ca897 100644 --- a/substrate/Cargo.toml +++ b/substrate/Cargo.toml @@ -155,6 +155,8 @@ members = [ "primitives/consensus/pow", "primitives/consensus/vrf", "primitives/core", + "primitives/core/hashing", + "primitives/core/hashing/proc-macro", "primitives/database", "primitives/debug-derive", "primitives/externalities", diff --git a/substrate/client/executor/Cargo.toml b/substrate/client/executor/Cargo.toml index c8246d43a0..bc55172bc3 100644 --- a/substrate/client/executor/Cargo.toml +++ b/substrate/client/executor/Cargo.toml @@ -33,6 +33,7 @@ sc-executor-wasmtime = { version = "0.10.0-dev", path = "wasmtime", optional = t parking_lot = "0.11.1" log = "0.4.8" libsecp256k1 = "0.6" +sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } [dev-dependencies] wat = "1.0" diff --git a/substrate/client/executor/src/wasm_runtime.rs b/substrate/client/executor/src/wasm_runtime.rs index c7aa120071..204a095717 100644 --- a/substrate/client/executor/src/wasm_runtime.rs +++ b/substrate/client/executor/src/wasm_runtime.rs @@ -344,7 +344,7 @@ fn decode_version(mut version: &[u8]) -> Result { })? .into(); - let core_api_id = sp_core::hashing::blake2_64(b"Core"); + let core_api_id = sp_core_hashing_proc_macro::blake2b_64!(b"Core"); if v.has_api_with(&core_api_id, |v| v >= 3) { sp_api::RuntimeVersion::decode(&mut version).map_err(|_| { WasmError::Instantiation("failed to decode \"Core_version\" result".into()) diff --git a/substrate/frame/support/Cargo.toml b/substrate/frame/support/Cargo.toml index 4bc64d8b8e..b62ae3384f 100644 --- a/substrate/frame/support/Cargo.toml +++ b/substrate/frame/support/Cargo.toml @@ -34,6 +34,7 @@ bitflags = "1.3" impl-trait-for-tuples = "0.2.1" smallvec = "1.7.0" log = { version = "0.4.14", default-features = false } +sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "../../primitives/core/hashing/proc-macro" } [dev-dependencies] assert_matches = "1.3.0" diff --git a/substrate/frame/support/src/lib.rs b/substrate/frame/support/src/lib.rs index d81300a404..6e60988a4c 100644 --- a/substrate/frame/support/src/lib.rs +++ b/substrate/frame/support/src/lib.rs @@ -42,6 +42,8 @@ pub use scale_info; pub use serde; pub use sp_core::Void; #[doc(hidden)] +pub use sp_core_hashing_proc_macro; +#[doc(hidden)] pub use sp_io::{self, storage::root as storage_root}; #[doc(hidden)] pub use sp_runtime::RuntimeDebug; @@ -427,9 +429,7 @@ macro_rules! parameter_types { /// Returns the key for this parameter type. #[allow(unused)] pub fn key() -> [u8; 16] { - $crate::sp_io::hashing::twox_128( - concat!(":", stringify!($name), ":").as_bytes() - ) + $crate::sp_core_hashing_proc_macro::twox_128!(b":", $name, b":") } /// Set the value of this parameter type in the storage. diff --git a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr index 2b70102fda..ffbc5aeea6 100644 --- a/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr +++ b/substrate/frame/support/test/tests/pallet_ui/storage_info_unsatisfied_nmap.stderr @@ -4,8 +4,8 @@ error[E0277]: the trait bound `Bar: MaxEncodedLen` is not satisfied 10 | #[pallet::generate_storage_info] | ^^^^^^^^^^^^^^^^^^^^^ the trait `MaxEncodedLen` is not implemented for `Bar` | - = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `Key` - = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, Key, u32>` + = note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `NMapKey` + = note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo, NMapKey, u32>` note: required by `storage_info` --> $DIR/storage.rs:71:2 | diff --git a/substrate/primitives/core/Cargo.toml b/substrate/primitives/core/Cargo.toml index 14a76e2482..148f2343ee 100644 --- a/substrate/primitives/core/Cargo.toml +++ b/substrate/primitives/core/Cargo.toml @@ -66,6 +66,7 @@ sha2 = { version = "0.9.8", default-features = false, optional = true } hex = { version = "0.4", default-features = false, optional = true } twox-hash = { version = "1.6.1", default-features = false, optional = true } libsecp256k1 = { version = "0.6", default-features = false, features = ["hmac", "static-context"], optional = true } +sp-core-hashing = { version = "4.0.0-dev", path = "./hashing", default-features = false, optional = true } merlin = { version = "2.0", default-features = false, optional = true } ss58-registry = "1.0.0" sp-runtime-interface = { version = "4.0.0-dev", default-features = false, path = "../runtime-interface" } @@ -76,6 +77,7 @@ hex-literal = "0.3.3" rand = "0.7.2" criterion = "0.3.3" serde_json = "1.0" +sp-core-hashing-proc-macro = { version = "4.0.0-dev", path = "./hashing/proc-macro" } [[bench]] name = "bench" @@ -118,6 +120,7 @@ std = [ "regex", "num-traits/std", "tiny-keccak", + "sp-core-hashing/std", "sp-debug-derive/std", "sp-externalities", "sp-storage/std", @@ -142,6 +145,7 @@ full_crypto = [ "sha2", "twox-hash", "libsecp256k1", + "sp-core-hashing", "sp-runtime-interface/disable_target_static_assertions", "merlin", ] diff --git a/substrate/primitives/core/hashing/Cargo.toml b/substrate/primitives/core/hashing/Cargo.toml new file mode 100644 index 0000000000..43c670b59b --- /dev/null +++ b/substrate/primitives/core/hashing/Cargo.toml @@ -0,0 +1,31 @@ +[package] +name = "sp-core-hashing" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "Primitive core crate hashing implementation." +documentation = "https://docs.rs/sp-core-hashing" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[dependencies] +sp-std = { version = "4.0.0-dev", default-features = false, path = "../../std" } +byteorder = { version = "1.3.2", default-features = false } + +blake2-rfc = { version = "0.2.18", default-features = false } +tiny-keccak = { version = "2.0.1", features = ["keccak"] } +sha2 = { version = "0.9.2", default-features = false } +twox-hash = { version = "1.5.0", default-features = false } + +[features] +default = ["std"] +std = [ + "blake2-rfc/std", + "sha2/std", + "sp-std/std", + "twox-hash/std", +] diff --git a/substrate/primitives/core/hashing/proc-macro/Cargo.toml b/substrate/primitives/core/hashing/proc-macro/Cargo.toml new file mode 100644 index 0000000000..6d83b50b8a --- /dev/null +++ b/substrate/primitives/core/hashing/proc-macro/Cargo.toml @@ -0,0 +1,22 @@ +[package] +name = "sp-core-hashing-proc-macro" +version = "4.0.0-dev" +authors = ["Parity Technologies "] +edition = "2018" +license = "Apache-2.0" +homepage = "https://substrate.dev" +repository = "https://github.com/paritytech/substrate/" +description = "This crate provides procedural macros for calculating static hash." +documentation = "https://docs.rs/sp-core-hashing-proc-macro" + +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lib] +proc-macro = true + +[dependencies] +syn = { version = "1.0.77", features = ["full", "parsing"] } +quote = "1.0.6" +proc-macro2 = "1.0.29" +sp-core-hashing = { version = "4.0.0-dev", path = "../", default-features = false } diff --git a/substrate/primitives/core/hashing/proc-macro/src/impls.rs b/substrate/primitives/core/hashing/proc-macro/src/impls.rs new file mode 100644 index 0000000000..0ce388762a --- /dev/null +++ b/substrate/primitives/core/hashing/proc-macro/src/impls.rs @@ -0,0 +1,124 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// 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 quote::quote; +use syn::parse::{Parse, ParseStream}; + +use proc_macro::TokenStream; + +pub(super) struct InputBytes(pub Vec); + +pub(super) struct MultipleInputBytes(pub Vec>); + +impl MultipleInputBytes { + pub(super) fn concatenated(mut self) -> Vec { + if self.0.len() == 0 { + Vec::new() + } else { + let mut result = core::mem::take(&mut self.0[0]); + for other in self.0[1..].iter_mut() { + result.append(other); + } + result + } + } +} + +impl Parse for InputBytes { + fn parse(input: ParseStream) -> syn::Result { + match syn::ExprArray::parse(input) { + Ok(array) => { + let mut bytes = Vec::::new(); + for expr in array.elems.iter() { + match expr { + syn::Expr::Lit(lit) => match &lit.lit { + syn::Lit::Int(b) => bytes.push(b.base10_parse()?), + syn::Lit::Byte(b) => bytes.push(b.value()), + _ => + return Err(syn::Error::new( + input.span(), + "Expected array of u8 elements.".to_string(), + )), + }, + _ => + return Err(syn::Error::new( + input.span(), + "Expected array of u8 elements.".to_string(), + )), + } + } + return Ok(InputBytes(bytes)) + }, + Err(_e) => (), + } + // use rust names as a vec of their utf8 bytecode. + match syn::Ident::parse(input) { + Ok(ident) => return Ok(InputBytes(ident.to_string().as_bytes().to_vec())), + Err(_e) => (), + } + Ok(InputBytes(syn::LitByteStr::parse(input)?.value())) + } +} + +impl Parse for MultipleInputBytes { + fn parse(input: ParseStream) -> syn::Result { + let elts = + syn::punctuated::Punctuated::::parse_terminated(input)?; + Ok(MultipleInputBytes(elts.into_iter().map(|elt| elt.0).collect())) + } +} + +pub(super) fn twox_64(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::twox_64(bytes.as_slice())) +} + +pub(super) fn twox_128(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::twox_128(bytes.as_slice())) +} + +pub(super) fn blake2b_512(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::blake2_512(bytes.as_slice())) +} + +pub(super) fn blake2b_256(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::blake2_256(bytes.as_slice())) +} + +pub(super) fn blake2b_64(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::blake2_64(bytes.as_slice())) +} + +pub(super) fn keccak_256(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::keccak_256(bytes.as_slice())) +} + +pub(super) fn keccak_512(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::keccak_512(bytes.as_slice())) +} + +pub(super) fn sha2_256(bytes: Vec) -> TokenStream { + bytes_to_array(sp_core_hashing::sha2_256(bytes.as_slice())) +} + +fn bytes_to_array(bytes: impl IntoIterator) -> TokenStream { + let bytes = bytes.into_iter(); + + quote!( + [ #( #bytes ),* ] + ) + .into() +} diff --git a/substrate/primitives/core/hashing/proc-macro/src/lib.rs b/substrate/primitives/core/hashing/proc-macro/src/lib.rs new file mode 100644 index 0000000000..2af8554f4e --- /dev/null +++ b/substrate/primitives/core/hashing/proc-macro/src/lib.rs @@ -0,0 +1,129 @@ +// This file is part of Substrate. + +// Copyright (C) 2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// 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. + +//! Macros to calculate constant hash bytes result. +//! +//! Macros from this crate does apply a specific hash function on input. +//! Input can be literal byte array as `b"content"` or array of bytes +//! as `[1, 2, 3]`. +//! Rust identifier can also be use, in this case we use their utf8 string +//! byte representation, for instance if the ident is `MyStruct`, then +//! `b"MyStruct"` will be hashed. +//! If multiple arguments comma separated are passed, they are concatenated +//! then hashed. +//! +//! Examples: +//! +//! ```rust +//! assert_eq!( +//! sp_core_hashing_proc_macro::blake2b_256!(b"test"), +//! sp_core_hashing::blake2_256(b"test"), +//! ); +//! assert_eq!( +//! sp_core_hashing_proc_macro::blake2b_256!([1u8]), +//! sp_core_hashing::blake2_256(&[1u8]), +//! ); +//! assert_eq!( +//! sp_core_hashing_proc_macro::blake2b_256!([1, 2, 3]), +//! sp_core_hashing::blake2_256(&[1, 2, 3]), +//! ); +//! assert_eq!( +//! sp_core_hashing_proc_macro::blake2b_256!(identifier), +//! sp_core_hashing::blake2_256(b"identifier"), +//! ); +//! assert_eq!( +//! sp_core_hashing_proc_macro::blake2b_256!(identifier, b"/string"), +//! sp_core_hashing::blake2_256(b"identifier/string"), +//! ); +//! ``` + +mod impls; + +use impls::MultipleInputBytes; +use proc_macro::TokenStream; + +/// Process a Blake2 64-bit hash of bytes parameter outputs a `[u8; 8]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn blake2b_64(input: TokenStream) -> TokenStream { + impls::blake2b_64(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a Blake2 256-bit hash of bytes parameter, outputs a `[u8; 32]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn blake2b_256(input: TokenStream) -> TokenStream { + impls::blake2b_256(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a Blake2 512-bit hash of bytes parameter, outputs a `[u8; 64]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn blake2b_512(input: TokenStream) -> TokenStream { + impls::blake2b_512(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a XX 64-bit hash on its bytes parameter, outputs a `[u8; 8]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn twox_64(input: TokenStream) -> TokenStream { + impls::twox_64(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a XX 128-bit hash on its bytes parameter, outputs a `[u8; 16]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn twox_128(input: TokenStream) -> TokenStream { + impls::twox_128(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a keccak 256-bit hash on its bytes parameter, outputs a `[u8; 32]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn keccak_256(input: TokenStream) -> TokenStream { + impls::keccak_256(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a keccak 512-bit hash on its bytes parameter, outputs a `[u8; 64]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn keccak_512(input: TokenStream) -> TokenStream { + impls::keccak_512(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} + +/// Apply a sha2 256-bit hash on its bytes parameter, outputs a `[u8; 32]`. +/// Multiple inputs are concatenated before hashing. +/// Input can be identifier (name of identifier as bytes is used), byte string or +/// array of bytes. +#[proc_macro] +pub fn sha2_256(input: TokenStream) -> TokenStream { + impls::sha2_256(syn::parse_macro_input!(input as MultipleInputBytes).concatenated()) +} diff --git a/substrate/primitives/core/hashing/src/lib.rs b/substrate/primitives/core/hashing/src/lib.rs new file mode 100644 index 0000000000..f806613c5b --- /dev/null +++ b/substrate/primitives/core/hashing/src/lib.rs @@ -0,0 +1,166 @@ +// This file is part of Substrate. + +// Copyright (C) 2017-2021 Parity Technologies (UK) Ltd. +// SPDX-License-Identifier: Apache-2.0 + +// 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. + +//! Hashing Functions. + +#![warn(missing_docs)] +#![cfg_attr(not(feature = "std"), no_std)] + +use sha2::{Digest, Sha256}; +use tiny_keccak::{Hasher, Keccak}; + +/// Do a Blake2 512-bit hash and place result in `dest`. +pub fn blake2_512_into(data: &[u8], dest: &mut [u8; 64]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(64, &[], data).as_bytes()); +} + +/// Do a Blake2 512-bit hash and return result. +pub fn blake2_512(data: &[u8]) -> [u8; 64] { + let mut r = [0; 64]; + blake2_512_into(data, &mut r); + r +} + +/// Do a Blake2 256-bit hash and place result in `dest`. +pub fn blake2_256_into(data: &[u8], dest: &mut [u8; 32]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes()); +} + +/// Do a Blake2 256-bit hash and return result. +pub fn blake2_256(data: &[u8]) -> [u8; 32] { + let mut r = [0; 32]; + blake2_256_into(data, &mut r); + r +} + +/// Do a Blake2 128-bit hash and place result in `dest`. +pub fn blake2_128_into(data: &[u8], dest: &mut [u8; 16]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(16, &[], data).as_bytes()); +} + +/// Do a Blake2 128-bit hash and return result. +pub fn blake2_128(data: &[u8]) -> [u8; 16] { + let mut r = [0; 16]; + blake2_128_into(data, &mut r); + r +} + +/// Do a Blake2 64-bit hash and place result in `dest`. +pub fn blake2_64_into(data: &[u8], dest: &mut [u8; 8]) { + dest.copy_from_slice(blake2_rfc::blake2b::blake2b(8, &[], data).as_bytes()); +} + +/// Do a Blake2 64-bit hash and return result. +pub fn blake2_64(data: &[u8]) -> [u8; 8] { + let mut r = [0; 8]; + blake2_64_into(data, &mut r); + r +} + +/// Do a XX 64-bit hash and place result in `dest`. +pub fn twox_64_into(data: &[u8], dest: &mut [u8; 8]) { + use core::hash::Hasher; + let mut h0 = twox_hash::XxHash::with_seed(0); + h0.write(data); + let r0 = h0.finish(); + use byteorder::{ByteOrder, LittleEndian}; + LittleEndian::write_u64(&mut dest[0..8], r0); +} + +/// Do a XX 64-bit hash and return result. +pub fn twox_64(data: &[u8]) -> [u8; 8] { + let mut r: [u8; 8] = [0; 8]; + twox_64_into(data, &mut r); + r +} + +/// Do a XX 128-bit hash and place result in `dest`. +pub fn twox_128_into(data: &[u8], dest: &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(data); + h1.write(data); + let r0 = h0.finish(); + let r1 = h1.finish(); + use byteorder::{ByteOrder, LittleEndian}; + LittleEndian::write_u64(&mut dest[0..8], r0); + LittleEndian::write_u64(&mut dest[8..16], r1); +} + +/// Do a XX 128-bit hash and return result. +pub fn twox_128(data: &[u8]) -> [u8; 16] { + let mut r: [u8; 16] = [0; 16]; + twox_128_into(data, &mut r); + r +} + +/// Do a XX 256-bit hash and place result in `dest`. +pub fn twox_256_into(data: &[u8], dest: &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(data); + h1.write(data); + h2.write(data); + h3.write(data); + let r0 = h0.finish(); + let r1 = h1.finish(); + let r2 = h2.finish(); + let r3 = h3.finish(); + LittleEndian::write_u64(&mut dest[0..8], r0); + LittleEndian::write_u64(&mut dest[8..16], r1); + LittleEndian::write_u64(&mut dest[16..24], r2); + LittleEndian::write_u64(&mut dest[24..32], r3); +} + +/// Do a XX 256-bit hash and return result. +pub fn twox_256(data: &[u8]) -> [u8; 32] { + let mut r: [u8; 32] = [0; 32]; + twox_256_into(data, &mut r); + r +} + +/// Do a keccak 256-bit hash and return result. +pub fn keccak_256(data: &[u8]) -> [u8; 32] { + let mut keccak = Keccak::v256(); + keccak.update(data); + let mut output = [0u8; 32]; + keccak.finalize(&mut output); + output +} + +/// Do a keccak 512-bit hash and return result. +pub fn keccak_512(data: &[u8]) -> [u8; 64] { + let mut keccak = Keccak::v512(); + keccak.update(data); + let mut output = [0u8; 64]; + keccak.finalize(&mut output); + output +} + +/// Do a sha2 256-bit hash and return result. +pub fn sha2_256(data: &[u8]) -> [u8; 32] { + let mut hasher = Sha256::new(); + hasher.update(data); + let mut output = [0u8; 32]; + output.copy_from_slice(&hasher.finalize()); + output +} diff --git a/substrate/primitives/core/src/hashing.rs b/substrate/primitives/core/src/hashing.rs index 4c719f7c69..092cfc51b9 100644 --- a/substrate/primitives/core/src/hashing.rs +++ b/substrate/primitives/core/src/hashing.rs @@ -22,147 +22,45 @@ //! unless you know what you're doing. Using `sp_io` will be more performant, since instead of //! computing the hash in WASM it delegates that computation to the host client. -use sha2::{Digest, Sha256}; -use tiny_keccak::{Hasher, Keccak}; +pub use sp_core_hashing::*; -/// Do a Blake2 512-bit hash and place result in `dest`. -pub fn blake2_512_into(data: &[u8], dest: &mut [u8; 64]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(64, &[], data).as_bytes()); -} +#[cfg(test)] +mod test { + use super::*; -/// Do a Blake2 512-bit hash and return result. -pub fn blake2_512(data: &[u8]) -> [u8; 64] { - let mut r = [0; 64]; - blake2_512_into(data, &mut r); - r -} + #[test] + fn blake2b() { + assert_eq!(sp_core_hashing_proc_macro::blake2b_64!(b""), blake2_64(b"")[..]); + assert_eq!(sp_core_hashing_proc_macro::blake2b_256!(b"test"), blake2_256(b"test")[..]); + assert_eq!(sp_core_hashing_proc_macro::blake2b_512!(b""), blake2_512(b"")[..]); + } -/// Do a Blake2 256-bit hash and place result in `dest`. -pub fn blake2_256_into(data: &[u8], dest: &mut [u8; 32]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(32, &[], data).as_bytes()); -} + #[test] + fn keccak() { + assert_eq!(sp_core_hashing_proc_macro::keccak_256!(b"test"), keccak_256(b"test")[..]); + assert_eq!(sp_core_hashing_proc_macro::keccak_512!(b"test"), keccak_512(b"test")[..]); + } -/// Do a Blake2 256-bit hash and return result. -pub fn blake2_256(data: &[u8]) -> [u8; 32] { - let mut r = [0; 32]; - blake2_256_into(data, &mut r); - r -} + #[test] + fn sha2() { + assert_eq!(sp_core_hashing_proc_macro::sha2_256!(b"test"), sha2_256(b"test")[..]); + } -/// Do a Blake2 128-bit hash and place result in `dest`. -pub fn blake2_128_into(data: &[u8], dest: &mut [u8; 16]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(16, &[], data).as_bytes()); -} + #[test] + fn twox() { + assert_eq!(sp_core_hashing_proc_macro::twox_128!(b"test"), twox_128(b"test")[..]); + assert_eq!(sp_core_hashing_proc_macro::twox_64!(b""), twox_64(b"")[..]); + } -/// Do a Blake2 128-bit hash and return result. -pub fn blake2_128(data: &[u8]) -> [u8; 16] { - let mut r = [0; 16]; - blake2_128_into(data, &mut r); - r -} - -/// Do a Blake2 64-bit hash and place result in `dest`. -pub fn blake2_64_into(data: &[u8], dest: &mut [u8; 8]) { - dest.copy_from_slice(blake2_rfc::blake2b::blake2b(8, &[], data).as_bytes()); -} - -/// Do a Blake2 64-bit hash and return result. -pub fn blake2_64(data: &[u8]) -> [u8; 8] { - let mut r = [0; 8]; - blake2_64_into(data, &mut r); - r -} - -/// Do a XX 64-bit hash and place result in `dest`. -pub fn twox_64_into(data: &[u8], dest: &mut [u8; 8]) { - use core::hash::Hasher; - let mut h0 = twox_hash::XxHash::with_seed(0); - h0.write(data); - let r0 = h0.finish(); - use byteorder::{ByteOrder, LittleEndian}; - LittleEndian::write_u64(&mut dest[0..8], r0); -} - -/// Do a XX 64-bit hash and return result. -pub fn twox_64(data: &[u8]) -> [u8; 8] { - let mut r: [u8; 8] = [0; 8]; - twox_64_into(data, &mut r); - r -} - -/// Do a XX 128-bit hash and place result in `dest`. -pub fn twox_128_into(data: &[u8], dest: &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(data); - h1.write(data); - let r0 = h0.finish(); - let r1 = h1.finish(); - use byteorder::{ByteOrder, LittleEndian}; - LittleEndian::write_u64(&mut dest[0..8], r0); - LittleEndian::write_u64(&mut dest[8..16], r1); -} - -/// Do a XX 128-bit hash and return result. -pub fn twox_128(data: &[u8]) -> [u8; 16] { - let mut r: [u8; 16] = [0; 16]; - twox_128_into(data, &mut r); - r -} - -/// Do a XX 256-bit hash and place result in `dest`. -pub fn twox_256_into(data: &[u8], dest: &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(data); - h1.write(data); - h2.write(data); - h3.write(data); - let r0 = h0.finish(); - let r1 = h1.finish(); - let r2 = h2.finish(); - let r3 = h3.finish(); - LittleEndian::write_u64(&mut dest[0..8], r0); - LittleEndian::write_u64(&mut dest[8..16], r1); - LittleEndian::write_u64(&mut dest[16..24], r2); - LittleEndian::write_u64(&mut dest[24..32], r3); -} - -/// Do a XX 256-bit hash and return result. -pub fn twox_256(data: &[u8]) -> [u8; 32] { - let mut r: [u8; 32] = [0; 32]; - twox_256_into(data, &mut r); - r -} - -/// Do a keccak 256-bit hash and return result. -pub fn keccak_256(data: &[u8]) -> [u8; 32] { - let mut keccak = Keccak::v256(); - keccak.update(data); - let mut output = [0u8; 32]; - keccak.finalize(&mut output); - output -} - -/// Do a keccak 512-bit hash and return result. -pub fn keccak_512(data: &[u8]) -> [u8; 64] { - let mut keccak = Keccak::v512(); - keccak.update(data); - let mut output = [0u8; 64]; - keccak.finalize(&mut output); - output -} - -/// Do a sha2 256-bit hash and return result. -pub fn sha2_256(data: &[u8]) -> [u8; 32] { - let mut hasher = Sha256::new(); - hasher.update(data); - let mut output = [0u8; 32]; - output.copy_from_slice(&hasher.finalize()); - output + #[test] + fn twox_concats() { + assert_eq!( + sp_core_hashing_proc_macro::twox_128!(b"test", b"123", b"45", b"", b"67890"), + super::twox_128(&b"test1234567890"[..]), + ); + assert_eq!( + sp_core_hashing_proc_macro::twox_128!(b"test", test, b"45", b"", b"67890"), + super::twox_128(&b"testtest4567890"[..]), + ); + } }