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

Initial implementation of high-level hashing infrastructure (#363)

* [core] initial implementation of high-level hashing infrastructure

* [core] apply rustfmt

* [core] add doc-comment to state some potential optimization

* [core] add Wrap as another built-in way of creating an InputBuffer instance

* [core] make &mut T implement InputBuffer if T: InputBuffer

* [core] publicly export Wrap

* [core] remove the two simple forms of all hash functions

* [core] add extensive docs with examples to all hash functions

* [core] fix doc tests

* [core] fix bug in InputBuffer impl of Wrap

* [core] add asserts to hash doc tests

* [core] apply rustfmt

* [core] simplify doc tests

* [core] adjust doc comments for raw hashes

* [core] improve docs

* [core] add missing internal docs

* [core] rename InputBuffer -> Accumulator

* [core] apply rustfmt

* [core] make Accumulator impl more explicit
Co-Authored-By: Nikolay Volf's avatarNikolay Volf <nikvolf@gmail.com>

* [core] make Accumulator impl less explicit
Co-Authored-By: Nikolay Volf's avatarNikolay Volf <nikvolf@gmail.com>

* [core] make Accumulator impl less explicit
Co-Authored-By: Nikolay Volf's avatarNikolay Volf <nikvolf@gmail.com>

* [core] make Accumulator impl less explicit
Co-Authored-By: Nikolay Volf's avatarNikolay Volf <nikvolf@gmail.com>

* [core] remove minor code dupe

* [core] completely refactor hash module

* [core] remove XX hash from low-level and high-level API

* [core] fix typo in docs

* [core] fix macro generated docs
Co-authored-by: Nikolay Volf's avatarNikolay Volf <nikvolf@gmail.com>
parent e0204021
Pipeline #84610 passed with stages
in 7 minutes and 36 seconds
......@@ -33,7 +33,6 @@ 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.
#
......@@ -68,7 +67,6 @@ std = [
"blake2-rfc",
"sha2",
"tiny-keccak",
"twox-hash",
]
ink-generate-abi = [
"ink_abi",
......
......@@ -524,38 +524,23 @@ pub mod hash {
};
}
impl_hash_fn!(
/// Conducts the SHA2 256-bit hash of the input and
/// Conducts the SHA2 256-bit hash of the given bytes 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
/// Conducts the KECCAK 256-bit hash of the given bytes 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
/// 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 input and
/// Conducts the BLAKE2 128-bit hash of the given bytes 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)
);
}
......@@ -93,18 +93,6 @@ pub trait Env {
/// 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.
......
......@@ -24,61 +24,6 @@ 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::{
......
......@@ -125,18 +125,6 @@ impl Env for EnvInstance {
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)
}
......
......@@ -105,9 +105,6 @@ mod sys {
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);
}
}
......@@ -329,6 +326,3 @@ 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);
......@@ -191,18 +191,6 @@ impl Env for EnvInstance {
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)
}
......
......@@ -69,24 +69,3 @@ 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],);
}
// 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.
use ink_prelude::vec::Vec;
/// Hash builder that accumulates a buffer on the contract side.
pub trait Accumulator {
/// Resets the buffer which cleans all state from it.
///
/// # Note
///
/// Useful when using `Vec` or similar as accumulator.
fn reset(&mut self);
/// Writes the given bytes into the buffer.
fn write(&mut self, bytes: &[u8]);
/// Returns a shared reference to the slice of the current state of the buffer.
fn as_slice(&self) -> &[u8];
}
impl Accumulator for Vec<u8> {
fn reset(&mut self) {
self.clear()
}
fn write(&mut self, bytes: &[u8]) {
// This could theoretically be speed-up by using `unsafe` `set_len`
// and `[u8]` `copy_from_slice` methods.
self.extend_from_slice(bytes)
}
fn as_slice(&self) -> &[u8] {
self.as_slice()
}
}
impl<'a, T> Accumulator for &'a mut T
where
T: Accumulator,
{
fn reset(&mut self) {
<T as Accumulator>::reset(self)
}
fn write(&mut self, bytes: &[u8]) {
<T as Accumulator>::write(self, bytes)
}
fn as_slice(&self) -> &[u8] {
<T as Accumulator>::as_slice(self)
}
}
/// Wraps a bytes buffer and turns it into an accumulator.
///
/// # Panics
///
/// Upon hash calculation if the underlying buffer length does not suffice the
/// needs of the accumulated hash buffer.
pub struct Wrap<'a> {
/// The underlying wrapped buffer.
buffer: &'a mut [u8],
/// The current length of the filled area.
len: usize,
}
impl<'a> From<&'a mut [u8]> for Wrap<'a> {
fn from(buffer: &'a mut [u8]) -> Self {
Self { buffer, len: 0 }
}
}
impl<'a> Accumulator for Wrap<'a> {
fn reset(&mut self) {
self.len = 0;
}
fn write(&mut self, bytes: &[u8]) {
let len = self.len;
let bytes_len = bytes.len();
self.buffer[len..(len + bytes_len)].copy_from_slice(bytes);
self.len += bytes_len;
}
fn as_slice(&self) -> &[u8] {
&self.buffer[..self.len]
}
}
// 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.
use super::{
hasher::Hasher,
Accumulator,
};
use core::marker::PhantomData;
/// Generic hash builder to construct hashes given a builder strategy.
///
/// - `H` defines the crytographic hash to be conducted.
/// - `S` defines the strategy.
/// Currently only accumulating strategy is supported but in the future there
/// might be support for incremental hash builders.
///
/// # Note
///
/// This is just a base type and should not be used directly.
/// Use one of the following concrete hash builders instead:
///
/// - [`Sha2x256`](`crate::hash::Sha2x256`)
/// - [`Keccak256`](`crate::hash::Keccak256`)
/// - [`Blake2x256`](`crate::hash::Blake2x256`)
/// - [`Blake2x128`](`crate::hash::Blake2x128`)
pub struct HashBuilder<H, S> {
/// The strategy used to build up the hash.
strategy: S,
/// The underlying cryptographic hasher.
hasher: PhantomData<fn() -> H>,
}
impl<H, S> scale::Output for HashBuilder<H, S>
where
S: Accumulator,
{
fn write(&mut self, bytes: &[u8]) {
<S as Accumulator>::write(&mut self.strategy, bytes)
}
}
impl<H, S> From<S> for HashBuilder<H, S>
where
S: Accumulator,
{
fn from(accumulator: S) -> Self {
Self {
hasher: Default::default(),
strategy: accumulator,
}
}
}
pub trait Finalize<H>
where
H: Hasher,
{
fn finalize_using(&self, output: &mut <H as Hasher>::Output);
fn finalize(&self) -> <H as Hasher>::Output;
}
impl<H, S> Finalize<H> for HashBuilder<H, S>
where
H: Hasher,
S: Accumulator,
{
fn finalize_using(&self, output: &mut <H as Hasher>::Output) {
<H as Hasher>::finalize_immediate(self.strategy.as_slice(), output)
}
fn finalize(&self) -> <H as Hasher>::Output {
let mut output = <<H as Hasher>::Output as Default>::default();
Self::finalize_using(self, &mut output);
output
}
}
impl<H, S> HashBuilder<H, S>
where
Self: Finalize<H> + scale::Output,
H: Hasher,
{
/// Conducts the hash for the given bytes.
///
/// Puts the resulting hash into the provided output buffer.
///
/// # Note
///
/// Prefer the simpler [`hash_raw`](`HashBuilder::hash_raw`)
/// if you do _not_ need full control over the `output` buffer.
pub fn hash_raw_using(&mut self, input: &[u8], output: &mut <H as Hasher>::Output)
where
H: Hasher,
{
<Self as scale::Output>::write(self, input);
self.finalize_using(output)
}
/// Returns the hash for the given bytes.
///
/// # Note
///
/// Use [`hash_raw_using`](`HashBuilder::hash_raw_using`)
/// if you need full control over the `output` buffer.
pub fn hash_raw(&mut self, input: &[u8]) -> <H as Hasher>::Output
where
H: Hasher,
{
<Self as scale::Output>::write(self, input);
self.finalize()
}
/// Conducts the hash for the encoded input.
///
/// Puts the resulting hash into the provided output buffer.
///
/// # Note
///
/// Prefer the simpler [`hash_encoded`](`HashBuilder::hash_encoded`)
/// if you do _not_ need full control over the `output` buffer.
///
/// # Examples
///
/// In the following examples the `EXPECTED` buffer is defined as:
///
/// ```
/// const EXPECTED: [u8; 32] = [
/// 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,
/// ];
/// ```
///
/// ## 1. Using a new `Vec` as accumulating buffer.
///
/// This is the simplest way to call this API but does not avoid heap
/// allocations.
///
/// ```
/// # use ink_core::hash::Sha2x256;
/// # use ink_prelude::vec::Vec;
/// # const EXPECTED: [u8; 32] = [
/// # 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 hashable = (42, "foo", true); // Implements `core::hash::Hash`
/// let mut output = [0x00_u8; 32]; // 256-bit buffer
/// let mut hasher = Sha2x256::from(Vec::new());
/// hasher.hash_encoded_using(&hashable, &mut output);
/// assert_eq!(output, EXPECTED);
/// ```
///
/// ## 2. Using an existing `Vec` as accumulating buffer.
///
/// This API is preferred if the call site already has an allocated buffer
/// that it can reuse. This will reset the existing buffer and might grow it.
///
/// ```
/// # use ink_core::hash::Sha2x256;
/// # use ink_prelude::vec::Vec;
/// # const EXPECTED: [u8; 32] = [
/// # 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 hashable = (42, "foo", true); // Implements `core::hash::Hash`
/// let mut output = [0x00_u8; 32]; // 256-bit buffer
/// let mut accumulator = Vec::with_capacity(32);
/// let mut hasher = Sha2x256::from(&mut accumulator);
/// hasher.hash_encoded_using(&hashable, &mut output);
/// assert_eq!(output, EXPECTED);
/// ```
///
/// ## 3. Using a wrapped static buffer as accumulating buffer.
///
/// This API avoids heap allocation completely but might panic in cases
/// where the static buffer is too small.
///
/// ```
/// # use ink_core::hash::{Sha2x256, Wrap};
/// # use ink_prelude::vec::Vec;
/// # const EXPECTED: [u8; 32] = [
/// # 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 hashable = (42, "foo", true); // Implements `core::hash::Hash`
/// let mut output = [0x00_u8; 32]; // 256-bit buffer
/// let mut accumulator = [0x00_u8; 64];
/// let mut hasher = Sha2x256::from(Wrap::from(accumulator.as_mut()));
/// hasher.hash_encoded_using(&hashable, &mut output);
/// assert_eq!(output, EXPECTED);
/// ```
pub fn hash_encoded_using<T>(&mut self, input: &T, output: &mut <H as Hasher>::Output)
where
H: Hasher,
T: scale::Encode,
{
<T as scale::Encode>::encode_to(&input, self);
self.finalize_using(output)
}
/// Returns the hash for the encoded input.
///
/// # Note
///
/// Use [`hash_encoded_using`](`HashBuilder::hash_encoded_using`)
/// if you need full control over the `output` buffer.
///
/// # Examples
///
/// In the following examples the `EXPECTED` buffer is defined as:
///
/// ```
/// const EXPECTED: [u8; 32] = [
/// 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,
/// ];
/// ```
///
/// ## 1. Using a new `Vec` as accumulating buffer.
///
/// This is the simplest way to call this API but does not avoid heap
/// allocations.
///
/// ```
/// # use ink_core::hash::Sha2x256;
/// # use ink_prelude::vec::Vec;
/// # const EXPECTED: [u8; 32] = [
/// # 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 hashable = (42, "foo", true); // Implements `core::hash::Hash`
/// let mut hasher = Sha2x256::from(Vec::new());
/// assert_eq!(hasher.hash_encoded(&hashable), EXPECTED);
/// ```
///
/// ## 2. Using an existing `Vec` as accumulating buffer.
///
/// This API is preferred if the call site already has an allocated buffer
/// that it can reuse. This will reset the existing buffer and might grow it.
///
/// ```
/// # use ink_core::hash::Sha2x256;
/// # use ink_prelude::vec::Vec;
/// # const EXPECTED: [u8; 32] = [
/// # 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 hashable = (42, "foo", true); // Implements `core::hash::Hash`
/// let mut accumulator = Vec::with_capacity(32);
/// let mut hasher = Sha2x256::from(&mut accumulator);
/// assert_eq!(hasher.hash_encoded(&hashable), EXPECTED);
/// ```
///
/// ## 3. Using a wrapped static buffer as accumulating buffer.
///
/// This API avoids heap allocation completely but might panic in cases
/// where the static buffer is too small.
///
/// ```
/// # use ink_core::hash::{Sha2x256, Wrap};
/// # use ink_prelude::vec::Vec;
/// # const EXPECTED: [u8; 32] = [
/// # 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 hashable = (42, "foo", true); // Implements `core::hash::Hash`
/// let mut accumulator = [0x00_u8; 64];
/// let mut hasher = Sha2x256::from(Wrap::from(accumulator.as_mut()));
/// assert_eq!(hasher.hash_encoded(&hashable), EXPECTED);
/// ```
pub fn hash_encoded<T>(&mut self, input: &T) -> <H as Hasher>::Output
where
H: Hasher,
T: scale::Encode,
{
<T as scale::Encode>::encode_to(&input, self);
self.finalize()
}
}
// 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.
//! Supported cryptographic hashing algorithms.
/// Types that implement this trait are marker types that identify a supported
/// cryptographic hash function.
pub trait Hasher {
/// The output of the hash function.
///
/// # Note
///
/// This is a byte slice with varying lengths, e.g. `[u8; 32]`, [`u8; 16]`, etc.
type Output: Default;
/// Finalizes the hash using the underlying procedure.
fn finalize_immediate(input: &[u8], output: &mut Self::Output);
}
macro_rules! impl_hasher_for {
(
$( #[$doc:meta] )*
struct $ty_name:ident($fn_name:ident, $output_len:literal);
) => {
$( #[$doc] )*
pub enum $ty_name {}
impl Hasher for $ty_name {
type Output = [u8; $output_len];
fn finalize_immediate(input: &[u8], output: &mut Self::Output) {
crate::env::hash::$fn_name(input, output)
}
}
};
}
impl_hasher_for! {
/// SHA2 256-bit hasher.
struct Sha2x256Hasher(sha2_256, 32);
}
impl_hasher_for! {
/// KECCAK 256-bit hasher.
struct Keccak256Hasher(keccak_256, 32);
}
impl_hasher_for! {
/// BLAKE2 256-bit hasher.
struct Blake2x256Hasher(blake2_256, 32);
}
impl_hasher_for! {
/// BLAKE2 128-bit hasher.
struct Blake2x128Hasher(blake2_128, 16);
}
// Copyright 2018-2020 Parity Technologies (UK) Ltd.
//