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]
}
}
This diff is collapsed.
// 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.
//
// 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.
//! High-level, built-in and efficient cryptographic hashing routines.
mod accumulator;
mod builder;
pub mod hasher;
pub use self::{
accumulator::{
Accumulator,
Wrap,
},
builder::HashBuilder,
};
/// SHA2 256-bit hash builder.
pub type Sha2x256<S> = HashBuilder<hasher::Sha2x256Hasher, S>;
/// KECCAK 256-bit hash builder.
pub type Keccak256<S> = HashBuilder<hasher::Keccak256Hasher, S>;
/// BLAKE2 256-bit hash builder.
pub type Blake2x256<S> = HashBuilder<hasher::Blake2x256Hasher, S>;
/// BLAKE2 128-bit hash builder.
pub type Blake2x128<S> = HashBuilder<hasher::Blake2x128Hasher, S>;
......@@ -47,6 +47,7 @@
extern crate ink_alloc;
pub mod env;
pub mod hash;
pub mod storage;
// Needed for derive macros of `core/derive` sub crate.
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment