keccak_hash/
lib.rs

1// Copyright 2020 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9#![cfg_attr(not(feature = "std"), no_std)]
10
11#[cfg(feature = "std")]
12use std::io;
13
14pub use primitive_types::H256;
15use tiny_keccak::{Hasher, Keccak};
16
17/// Get the KECCAK (i.e. Keccak) hash of the empty bytes string.
18pub const KECCAK_EMPTY: H256 = H256([
19	0xc5, 0xd2, 0x46, 0x01, 0x86, 0xf7, 0x23, 0x3c, 0x92, 0x7e, 0x7d, 0xb2, 0xdc, 0xc7, 0x03, 0xc0, 0xe5, 0x00, 0xb6,
20	0x53, 0xca, 0x82, 0x27, 0x3b, 0x7b, 0xfa, 0xd8, 0x04, 0x5d, 0x85, 0xa4, 0x70,
21]);
22
23/// The KECCAK of the RLP encoding of empty data.
24pub const KECCAK_NULL_RLP: H256 = H256([
25	0x56, 0xe8, 0x1f, 0x17, 0x1b, 0xcc, 0x55, 0xa6, 0xff, 0x83, 0x45, 0xe6, 0x92, 0xc0, 0xf8, 0x6e, 0x5b, 0x48, 0xe0,
26	0x1b, 0x99, 0x6c, 0xad, 0xc0, 0x01, 0x62, 0x2f, 0xb5, 0xe3, 0x63, 0xb4, 0x21,
27]);
28
29/// The KECCAK of the RLP encoding of empty list.
30pub const KECCAK_EMPTY_LIST_RLP: H256 = H256([
31	0x1d, 0xcc, 0x4d, 0xe8, 0xde, 0xc7, 0x5d, 0x7a, 0xab, 0x85, 0xb5, 0x67, 0xb6, 0xcc, 0xd4, 0x1a, 0xd3, 0x12, 0x45,
32	0x1b, 0x94, 0x8a, 0x74, 0x13, 0xf0, 0xa1, 0x42, 0xfd, 0x40, 0xd4, 0x93, 0x47,
33]);
34
35pub fn keccak<T: AsRef<[u8]>>(s: T) -> H256 {
36	let mut result = [0u8; 32];
37	write_keccak(s, &mut result);
38	H256(result)
39}
40
41/// Computes in-place keccak256 hash of `data`.
42pub fn keccak256(data: &mut [u8]) {
43	let mut keccak256 = Keccak::v256();
44	keccak256.update(data.as_ref());
45	keccak256.finalize(data);
46}
47
48/// Computes in-place keccak256 hash of `data[range]`.
49///
50/// The `range` argument specifies a subslice of `data` in bytes to be hashed.
51/// The resulting hash will be written back to `data`.
52/// # Panics
53///
54/// If `range` is out of bounds.
55///
56/// # Example
57///
58/// ```
59/// let mut data = [1u8; 32];
60/// // Hash the first 8 bytes of `data` and write the result, 32 bytes, to `data`.
61/// keccak_hash::keccak256_range(&mut data, 0..8);
62/// let expected = [
63///     0x54, 0x84, 0x4f, 0x69, 0xb4, 0xda, 0x4b, 0xb4, 0xa9, 0x9f, 0x24, 0x59, 0xb5, 0x11, 0xd4, 0x42,
64///     0xcc, 0x5b, 0xd2, 0xfd, 0xf4, 0xc3, 0x54, 0xd2, 0x07, 0xbb, 0x13, 0x08, 0x94, 0x43, 0xaf, 0x68,
65/// ];
66/// assert_eq!(&data, &expected);
67/// ```
68pub fn keccak256_range(data: &mut [u8], range: core::ops::Range<usize>) {
69	let mut keccak256 = Keccak::v256();
70	keccak256.update(&data[range]);
71	keccak256.finalize(data);
72}
73
74/// Computes in-place keccak512 hash of `data`.
75pub fn keccak512(data: &mut [u8]) {
76	let mut keccak512 = Keccak::v512();
77	keccak512.update(data.as_ref());
78	keccak512.finalize(data);
79}
80
81/// Computes in-place keccak512 hash of `data[range]`.
82///
83/// The `range` argument specifies a subslice of `data` in bytes to be hashed.
84/// The resulting hash will be written back to `data`.
85/// # Panics
86///
87/// If `range` is out of bounds.
88///
89/// # Example
90///
91/// ```
92/// let mut data = [1u8; 64];
93/// keccak_hash::keccak512_range(&mut data, 0..8);
94/// let expected = [
95///     0x90, 0x45, 0xc5, 0x9e, 0xd3, 0x0e, 0x1f, 0x42, 0xac, 0x35, 0xcc, 0xc9, 0x55, 0x7c, 0x77, 0x17,
96///     0xc8, 0x89, 0x3a, 0x77, 0x6c, 0xea, 0x2e, 0xf3, 0x88, 0xea, 0xe5, 0xc0, 0xea, 0x40, 0x26, 0x64,
97/// ];
98/// assert_eq!(&data[..32], &expected);
99/// ```
100pub fn keccak512_range(data: &mut [u8], range: core::ops::Range<usize>) {
101	let mut keccak512 = Keccak::v512();
102	keccak512.update(&data[range]);
103	keccak512.finalize(data);
104}
105
106pub fn keccak_256(input: &[u8], output: &mut [u8]) {
107	write_keccak(input, output);
108}
109
110pub fn keccak_512(input: &[u8], output: &mut [u8]) {
111	let mut keccak512 = Keccak::v512();
112	keccak512.update(input);
113	keccak512.finalize(output);
114}
115
116pub fn write_keccak<T: AsRef<[u8]>>(s: T, dest: &mut [u8]) {
117	let mut keccak256 = Keccak::v256();
118	keccak256.update(s.as_ref());
119	keccak256.finalize(dest);
120}
121
122#[cfg(feature = "std")]
123pub fn keccak_pipe(r: &mut dyn io::BufRead, w: &mut dyn io::Write) -> Result<H256, io::Error> {
124	let mut output = [0u8; 32];
125	let mut input = [0u8; 1024];
126	let mut keccak256 = Keccak::v256();
127
128	// read file
129	loop {
130		let some = r.read(&mut input)?;
131		if some == 0 {
132			break
133		}
134		keccak256.update(&input[0..some]);
135		w.write_all(&input[0..some])?;
136	}
137
138	keccak256.finalize(&mut output);
139	Ok(output.into())
140}
141
142#[cfg(feature = "std")]
143pub fn keccak_buffer(r: &mut dyn io::BufRead) -> Result<H256, io::Error> {
144	keccak_pipe(r, &mut io::sink())
145}
146
147#[cfg(test)]
148mod tests {
149	#[cfg(not(feature = "std"))]
150	extern crate alloc;
151	#[cfg(not(feature = "std"))]
152	use alloc::{vec, vec::Vec};
153
154	use super::*;
155
156	#[test]
157	fn keccak_empty() {
158		assert_eq!(keccak([0u8; 0]), KECCAK_EMPTY);
159	}
160
161	#[test]
162	fn keccak_as() {
163		assert_eq!(
164			keccak([0x41u8; 32]),
165			H256([
166				0x59, 0xca, 0xd5, 0x94, 0x86, 0x73, 0x62, 0x2c, 0x1d, 0x64, 0xe2, 0x32, 0x24, 0x88, 0xbf, 0x01, 0x61,
167				0x9f, 0x7f, 0xf4, 0x57, 0x89, 0x74, 0x1b, 0x15, 0xa9, 0xf7, 0x82, 0xce, 0x92, 0x90, 0xa8
168			]),
169		);
170	}
171
172	#[test]
173	fn write_keccak_with_content() {
174		let data: Vec<u8> = From::from("hello world");
175		let expected = vec![
176			0x47, 0x17, 0x32, 0x85, 0xa8, 0xd7, 0x34, 0x1e, 0x5e, 0x97, 0x2f, 0xc6, 0x77, 0x28, 0x63, 0x84, 0xf8, 0x02,
177			0xf8, 0xef, 0x42, 0xa5, 0xec, 0x5f, 0x03, 0xbb, 0xfa, 0x25, 0x4c, 0xb0, 0x1f, 0xad,
178		];
179		let mut dest = [0u8; 32];
180		write_keccak(data, &mut dest);
181
182		assert_eq!(dest, expected.as_ref());
183	}
184
185	#[cfg(feature = "std")]
186	#[test]
187	fn should_keccak_a_file() {
188		use std::{
189			fs,
190			io::{BufReader, Write},
191		};
192
193		// given
194		let tmpdir = tempfile::Builder::new().prefix("keccak").tempdir().unwrap();
195		let mut path = tmpdir.path().to_owned();
196		path.push("should_keccak_a_file");
197		// Prepare file
198		{
199			let mut file = fs::File::create(&path).unwrap();
200			file.write_all(b"something").unwrap();
201		}
202
203		let mut file = BufReader::new(fs::File::open(&path).unwrap());
204		// when
205		let hash = keccak_buffer(&mut file).unwrap();
206
207		// then
208		assert_eq!(format!("{:x}", hash), "68371d7e884c168ae2022c82bd837d51837718a7f7dfb7aa3f753074a35e1d87");
209	}
210}