Skip to main content

triehash/
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//! Generetes trie root.
10//!
11//! This module should be used to generate trie root hash.
12
13#![cfg_attr(not(feature = "std"), no_std)]
14
15#[cfg(not(feature = "std"))]
16extern crate alloc;
17
18#[cfg(feature = "std")]
19mod rstd {
20	pub use std::collections::BTreeMap;
21}
22
23#[cfg(not(feature = "std"))]
24mod rstd {
25	pub use alloc::collections::BTreeMap;
26	pub use alloc::vec::Vec;
27}
28
29use core::cmp;
30use core::iter::once;
31use rstd::*;
32
33use hash_db::Hasher;
34use rlp::RlpStream;
35
36fn shared_prefix_len<T: Eq>(first: &[T], second: &[T]) -> usize {
37	first.iter().zip(second.iter()).position(|(f, s)| f != s).unwrap_or_else(|| cmp::min(first.len(), second.len()))
38}
39
40/// Generates a trie root hash for a vector of values
41///
42/// ```
43/// use hex_literal::hex;
44/// use ethereum_types::H256;
45/// use triehash::ordered_trie_root;
46/// use keccak_hasher::KeccakHasher;
47///
48/// let v = &["doe", "reindeer"];
49/// let root = H256::from(hex!("e766d5d51b89dc39d981b41bda63248d7abce4f0225eefd023792a540bcffee3"));
50/// assert_eq!(ordered_trie_root::<KeccakHasher, _>(v), root.as_ref());
51/// ```
52pub fn ordered_trie_root<H, I>(input: I) -> H::Out
53where
54	I: IntoIterator,
55	I::Item: AsRef<[u8]>,
56	H: Hasher,
57	<H as hash_db::Hasher>::Out: cmp::Ord,
58{
59	trie_root::<H, _, _, _>(input.into_iter().enumerate().map(|(i, v)| (rlp::encode(&i), v)))
60}
61
62/// Generates a trie root hash for a vector of key-value tuples
63///
64/// ```
65/// use hex_literal::hex;
66/// use triehash::trie_root;
67/// use ethereum_types::H256;
68/// use keccak_hasher::KeccakHasher;
69///
70/// let v = vec![
71/// 	("doe", "reindeer"),
72/// 	("dog", "puppy"),
73/// 	("dogglesworth", "cat"),
74/// ];
75///
76/// let root = H256::from(hex!("8aad789dff2f538bca5d8ea56e8abe10f4c7ba3a5dea95fea4cd6e7c3a1168d3"));
77/// assert_eq!(trie_root::<KeccakHasher, _, _, _>(v), root.as_ref());
78/// ```
79pub fn trie_root<H, I, A, B>(input: I) -> H::Out
80where
81	I: IntoIterator<Item = (A, B)>,
82	A: AsRef<[u8]> + Ord,
83	B: AsRef<[u8]>,
84	H: Hasher,
85	<H as hash_db::Hasher>::Out: cmp::Ord,
86{
87	// first put elements into btree to sort them and to remove duplicates
88	let input = input.into_iter().collect::<BTreeMap<_, _>>();
89
90	let mut nibbles = Vec::with_capacity(input.keys().map(|k| k.as_ref().len()).sum::<usize>() * 2);
91	let mut lens = Vec::with_capacity(input.len() + 1);
92	lens.push(0);
93	for k in input.keys() {
94		for &b in k.as_ref() {
95			nibbles.push(b >> 4);
96			nibbles.push(b & 0x0F);
97		}
98		lens.push(nibbles.len());
99	}
100
101	// then move them to a vector
102	let input = input.into_iter().zip(lens.windows(2)).map(|((_, v), w)| (&nibbles[w[0]..w[1]], v)).collect::<Vec<_>>();
103
104	let mut stream = RlpStream::new();
105	hash256rlp::<H, _, _>(&input, 0, &mut stream);
106	H::hash(&stream.out())
107}
108
109/// Generates a key-hashed (secure) trie root hash for a vector of key-value tuples.
110///
111/// ```
112/// use hex_literal::hex;
113/// use ethereum_types::H256;
114/// use triehash::sec_trie_root;
115/// use keccak_hasher::KeccakHasher;
116///
117/// let v = vec![
118/// 	("doe", "reindeer"),
119/// 	("dog", "puppy"),
120/// 	("dogglesworth", "cat"),
121/// ];
122///
123/// let root = H256::from(hex!("d4cd937e4a4368d7931a9cf51686b7e10abb3dce38a39000fd7902a092b64585"));
124/// assert_eq!(sec_trie_root::<KeccakHasher, _, _, _>(v), root.as_ref());
125/// ```
126pub fn sec_trie_root<H, I, A, B>(input: I) -> H::Out
127where
128	I: IntoIterator<Item = (A, B)>,
129	A: AsRef<[u8]>,
130	B: AsRef<[u8]>,
131	H: Hasher,
132	<H as hash_db::Hasher>::Out: cmp::Ord,
133{
134	trie_root::<H, _, _, _>(input.into_iter().map(|(k, v)| (H::hash(k.as_ref()), v)))
135}
136
137/// Hex-prefix Notation. First nibble has flags: oddness = 2^0 & termination = 2^1.
138///
139/// The "termination marker" and "leaf-node" specifier are completely equivalent.
140///
141/// Input values are in range `[0, 0xf]`.
142///
143/// ```markdown
144///  [0,0,1,2,3,4,5]   0x10012345 // 7 > 4
145///  [0,1,2,3,4,5]     0x00012345 // 6 > 4
146///  [1,2,3,4,5]       0x112345   // 5 > 3
147///  [0,0,1,2,3,4]     0x00001234 // 6 > 3
148///  [0,1,2,3,4]       0x101234   // 5 > 3
149///  [1,2,3,4]         0x001234   // 4 > 3
150///  [0,0,1,2,3,4,5,T] 0x30012345 // 7 > 4
151///  [0,0,1,2,3,4,T]   0x20001234 // 6 > 4
152///  [0,1,2,3,4,5,T]   0x20012345 // 6 > 4
153///  [1,2,3,4,5,T]     0x312345   // 5 > 3
154///  [1,2,3,4,T]       0x201234   // 4 > 3
155/// ```
156fn hex_prefix_encode<'a>(nibbles: &'a [u8], leaf: bool) -> impl Iterator<Item = u8> + 'a {
157	let inlen = nibbles.len();
158	let oddness_factor = inlen % 2;
159
160	let first_byte = {
161		let mut bits = ((inlen as u8 & 1) + (2 * leaf as u8)) << 4;
162		if oddness_factor == 1 {
163			bits += nibbles[0];
164		}
165		bits
166	};
167	once(first_byte).chain(nibbles[oddness_factor..].chunks(2).map(|ch| ch[0] << 4 | ch[1]))
168}
169
170fn hash256rlp<H, A, B>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream)
171where
172	A: AsRef<[u8]>,
173	B: AsRef<[u8]>,
174	H: Hasher,
175{
176	let inlen = input.len();
177
178	// in case of empty slice, just append empty data
179	if inlen == 0 {
180		stream.append_empty_data();
181		return;
182	}
183
184	// take slices
185	let key: &[u8] = &input[0].0.as_ref();
186	let value: &[u8] = &input[0].1.as_ref();
187
188	// if the slice contains just one item, append the suffix of the key
189	// and then append value
190	if inlen == 1 {
191		stream.begin_list(2);
192		stream.append_iter(hex_prefix_encode(&key[pre_len..], true));
193		stream.append(&value);
194		return;
195	}
196
197	// get length of the longest shared prefix in slice keys
198	let shared_prefix = input
199		.iter()
200		// skip first tuple
201		.skip(1)
202		// get minimum number of shared nibbles between first and each successive
203		.fold(key.len(), |acc, &(ref k, _)| cmp::min(shared_prefix_len(key, k.as_ref()), acc));
204
205	// if shared prefix is higher than current prefix append its
206	// new part of the key to the stream
207	// then recursively append suffixes of all items who had this key
208	if shared_prefix > pre_len {
209		stream.begin_list(2);
210		stream.append_iter(hex_prefix_encode(&key[pre_len..shared_prefix], false));
211		hash256aux::<H, _, _>(input, shared_prefix, stream);
212		return;
213	}
214
215	// an item for every possible nibble/suffix
216	// + 1 for data
217	stream.begin_list(17);
218
219	// if first key len is equal to prefix_len, move to next element
220	let mut begin = if pre_len == key.len() { 1 } else { 0 };
221
222	// iterate over all possible nibbles
223	for i in 0..16 {
224		// count how many successive elements have same next nibble
225		let len = input.iter().skip(begin).take_while(|pair| pair.0.as_ref()[pre_len] == i).count();
226
227		// if at least 1 successive element has the same nibble
228		// append their suffixes
229		match len {
230			0 => {
231				stream.append_empty_data();
232			}
233			_ => hash256aux::<H, _, _>(&input[begin..(begin + len)], pre_len + 1, stream),
234		}
235		begin += len;
236	}
237
238	// if fist key len is equal prefix, append its value
239	if pre_len == key.len() {
240		stream.append(&value);
241	} else {
242		stream.append_empty_data();
243	}
244}
245
246fn hash256aux<H, A, B>(input: &[(A, B)], pre_len: usize, stream: &mut RlpStream)
247where
248	A: AsRef<[u8]>,
249	B: AsRef<[u8]>,
250	H: Hasher,
251{
252	let mut s = RlpStream::new();
253	hash256rlp::<H, _, _>(input, pre_len, &mut s);
254	let out = s.out();
255	match out.len() {
256		0..=31 => stream.append_raw(&out, 1),
257		_ => stream.append(&H::hash(&out).as_ref()),
258	};
259}
260
261#[cfg(test)]
262mod tests {
263	use super::{hex_prefix_encode, shared_prefix_len, trie_root};
264	use ethereum_types::H256;
265	use hex_literal::hex;
266	use keccak_hasher::KeccakHasher;
267
268	#[test]
269	fn test_hex_prefix_encode() {
270		let v = vec![0, 0, 1, 2, 3, 4, 5];
271		let e = vec![0x10, 0x01, 0x23, 0x45];
272		let h = hex_prefix_encode(&v, false).collect::<Vec<_>>();
273		assert_eq!(h, e);
274
275		let v = vec![0, 1, 2, 3, 4, 5];
276		let e = vec![0x00, 0x01, 0x23, 0x45];
277		let h = hex_prefix_encode(&v, false).collect::<Vec<_>>();
278		assert_eq!(h, e);
279
280		let v = vec![0, 1, 2, 3, 4, 5];
281		let e = vec![0x20, 0x01, 0x23, 0x45];
282		let h = hex_prefix_encode(&v, true).collect::<Vec<_>>();
283		assert_eq!(h, e);
284
285		let v = vec![1, 2, 3, 4, 5];
286		let e = vec![0x31, 0x23, 0x45];
287		let h = hex_prefix_encode(&v, true).collect::<Vec<_>>();
288		assert_eq!(h, e);
289
290		let v = vec![1, 2, 3, 4];
291		let e = vec![0x00, 0x12, 0x34];
292		let h = hex_prefix_encode(&v, false).collect::<Vec<_>>();
293		assert_eq!(h, e);
294
295		let v = vec![4, 1];
296		let e = vec![0x20, 0x41];
297		let h = hex_prefix_encode(&v, true).collect::<Vec<_>>();
298		assert_eq!(h, e);
299	}
300
301	#[test]
302	fn simple_test() {
303		assert_eq!(
304			trie_root::<KeccakHasher, _, _, _>(vec![(
305				b"A",
306				b"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" as &[u8]
307			)]),
308			H256::from(hex!("d23786fb4a010da3ce639d66d5e904a11dbc02746d1ce25029e53290cabf28ab")).as_ref(),
309		);
310	}
311
312	#[test]
313	fn test_triehash_out_of_order() {
314		assert_eq!(
315			trie_root::<KeccakHasher, _, _, _>(vec![
316				(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
317				(vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
318				(vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]),
319			]),
320			trie_root::<KeccakHasher, _, _, _>(vec![
321				(vec![0x01u8, 0x23], vec![0x01u8, 0x23]),
322				(vec![0xf1u8, 0x23], vec![0xf1u8, 0x23]), // last two tuples are swapped
323				(vec![0x81u8, 0x23], vec![0x81u8, 0x23]),
324			]),
325		);
326	}
327
328	#[test]
329	fn test_shared_prefix() {
330		let a = vec![1, 2, 3, 4, 5, 6];
331		let b = vec![4, 2, 3, 4, 5, 6];
332		assert_eq!(shared_prefix_len(&a, &b), 0);
333	}
334
335	#[test]
336	fn test_shared_prefix2() {
337		let a = vec![1, 2, 3, 3, 5];
338		let b = vec![1, 2, 3];
339		assert_eq!(shared_prefix_len(&a, &b), 3);
340	}
341
342	#[test]
343	fn test_shared_prefix3() {
344		let a = vec![1, 2, 3, 4, 5, 6];
345		let b = vec![1, 2, 3, 4, 5, 6];
346		assert_eq!(shared_prefix_len(&a, &b), 6);
347	}
348}