Hashing proc macro utils (#9875)

* hashing macro

* fmt

* use in easy place, and fix blake sizes

* fix

* Fixes, docs.
Allow ident as input.

* fix doc tests

* update error in test (nmapkey and key are same type).

* hashing crates under sp_core

* Doc updates and format.

* use all existing hashing functions.

* return array of u8

* Update primitives/core/hashing/proc-macro/src/impls.rs

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>

* ToTokeen for an array of u8

* fix

* re

* Improve impls

* complete doc tests

* fmt

* fix doctest format

* fix ui test (nmap key type alias)

Co-authored-by: Bastian Köcher <bkchr@users.noreply.github.com>
Co-authored-by: Bastian Köcher <info@kchr.de>
This commit is contained in:
cheme
2021-11-02 10:35:23 +01:00
committed by GitHub
parent 098815948a
commit 471e9cfbf1
14 changed files with 547 additions and 143 deletions
+26
View File
@@ -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"
+2
View File
@@ -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",
+1
View File
@@ -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"
@@ -344,7 +344,7 @@ fn decode_version(mut version: &[u8]) -> Result<RuntimeVersion, WasmError> {
})?
.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())
+1
View File
@@ -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"
+3 -3
View File
@@ -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.
@@ -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<frame_support::Twox64Concat, Bar>`
= note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo<T>, Key<frame_support::Twox64Concat, Bar>, u32>`
= note: required because of the requirements on the impl of `KeyGeneratorMaxEncodedLen` for `NMapKey<frame_support::Twox64Concat, Bar>`
= note: required because of the requirements on the impl of `StorageInfoTrait` for `frame_support::pallet_prelude::StorageNMap<_GeneratedPrefixForStorageFoo<T>, NMapKey<frame_support::Twox64Concat, Bar>, u32>`
note: required by `storage_info`
--> $DIR/storage.rs:71:2
|
+4
View File
@@ -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",
]
@@ -0,0 +1,31 @@
[package]
name = "sp-core-hashing"
version = "4.0.0-dev"
authors = ["Parity Technologies <admin@parity.io>"]
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",
]
@@ -0,0 +1,22 @@
[package]
name = "sp-core-hashing-proc-macro"
version = "4.0.0-dev"
authors = ["Parity Technologies <admin@parity.io>"]
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 }
@@ -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<u8>);
pub(super) struct MultipleInputBytes(pub Vec<Vec<u8>>);
impl MultipleInputBytes {
pub(super) fn concatenated(mut self) -> Vec<u8> {
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<Self> {
match syn::ExprArray::parse(input) {
Ok(array) => {
let mut bytes = Vec::<u8>::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<Self> {
let elts =
syn::punctuated::Punctuated::<InputBytes, syn::token::Comma>::parse_terminated(input)?;
Ok(MultipleInputBytes(elts.into_iter().map(|elt| elt.0).collect()))
}
}
pub(super) fn twox_64(bytes: Vec<u8>) -> TokenStream {
bytes_to_array(sp_core_hashing::twox_64(bytes.as_slice()))
}
pub(super) fn twox_128(bytes: Vec<u8>) -> TokenStream {
bytes_to_array(sp_core_hashing::twox_128(bytes.as_slice()))
}
pub(super) fn blake2b_512(bytes: Vec<u8>) -> TokenStream {
bytes_to_array(sp_core_hashing::blake2_512(bytes.as_slice()))
}
pub(super) fn blake2b_256(bytes: Vec<u8>) -> TokenStream {
bytes_to_array(sp_core_hashing::blake2_256(bytes.as_slice()))
}
pub(super) fn blake2b_64(bytes: Vec<u8>) -> TokenStream {
bytes_to_array(sp_core_hashing::blake2_64(bytes.as_slice()))
}
pub(super) fn keccak_256(bytes: Vec<u8>) -> TokenStream {
bytes_to_array(sp_core_hashing::keccak_256(bytes.as_slice()))
}
pub(super) fn keccak_512(bytes: Vec<u8>) -> TokenStream {
bytes_to_array(sp_core_hashing::keccak_512(bytes.as_slice()))
}
pub(super) fn sha2_256(bytes: Vec<u8>) -> TokenStream {
bytes_to_array(sp_core_hashing::sha2_256(bytes.as_slice()))
}
fn bytes_to_array(bytes: impl IntoIterator<Item = u8>) -> TokenStream {
let bytes = bytes.into_iter();
quote!(
[ #( #bytes ),* ]
)
.into()
}
@@ -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())
}
@@ -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
}
+35 -137
View File
@@ -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"[..]),
);
}
}