tetsy_trie_root/
lib.rs

1// Copyright 2017, 2020 Parity Technologies
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! Generates trie root.
16//!
17//! This module should be used to generate trie root hash.
18
19#![cfg_attr(not(feature = "std"), no_std)]
20
21#[cfg(not(feature = "std"))]
22extern crate alloc;
23
24
25#[cfg(feature = "std")]
26mod rstd {
27	pub use std::vec::Vec;
28	pub use std::cmp;
29	pub use std::collections::{BTreeMap, VecDeque};
30}
31
32#[cfg(not(feature = "std"))]
33mod rstd {
34	pub use core::cmp;
35	pub use alloc::collections::{BTreeMap, VecDeque};
36	pub use alloc::vec::Vec;
37}
38
39use self::rstd::*;
40
41pub use tetsy_hash_db::Hasher;
42
43/// Byte-stream oriented trait for constructing closed-form tries.
44pub trait TrieStream {
45	/// Construct a new `TrieStream`
46	fn new() -> Self;
47	/// Append an Empty node
48	fn append_empty_data(&mut self);
49	/// Start a new Branch node, possibly with a value; takes a list indicating
50	/// which slots in the Branch node has further child nodes.
51	fn begin_branch(
52		&mut self,
53		maybe_key: Option<&[u8]>,
54		maybe_value: Option<&[u8]>,
55		has_children: impl Iterator<Item = bool>,
56	);
57	/// Append an empty child node. Optional.
58	fn append_empty_child(&mut self) {}
59	/// Wrap up a Branch node portion of a `TrieStream` and append the value
60	/// stored on the Branch (if any).
61	fn end_branch(&mut self, _value: Option<&[u8]>) {}
62	/// Append a Leaf node
63	fn append_leaf(&mut self, key: &[u8], value: &[u8]);
64	/// Append an Extension node
65	fn append_extension(&mut self, key: &[u8]);
66	/// Append a Branch of Extension substream
67	fn append_substream<H: Hasher>(&mut self, other: Self);
68	/// Return the finished `TrieStream` as a vector of bytes.
69	fn out(self) -> Vec<u8>;
70}
71
72fn shared_prefix_length<T: Eq>(first: &[T], second: &[T]) -> usize {
73	first.iter()
74		.zip(second.iter())
75		.position(|(f, s)| f != s)
76		.unwrap_or_else(|| cmp::min(first.len(), second.len()))
77}
78
79/// Generates a trie root hash for a vector of key-value tuples
80///
81/// ```ignore
82/// use hex_literal::hex;
83/// use tetsy_trie_root::tetsy_trie_root;
84/// use tetsy_reference_trie::ReferenceTrieStream;
85/// use tetsy_keccak_hasher::KeccakHasher;
86///
87/// let v = vec![
88///     ("doe", "reindeer"),
89///     ("dog", "puppy"),
90///     ("dogglesworth", "cat"),
91/// ];
92///
93/// let root = hex!["0807d5393ae7f349481063ebb5dbaf6bda58db282a385ca97f37dccba717cb79"];
94/// assert_eq!(tetsy_trie_root::<KeccakHasher, ReferenceTrieStream, _, _, _>(v), root);
95/// ```
96pub fn tetsy_trie_root<H, S, I, A, B>(input: I) -> H::Out where
97	I: IntoIterator<Item = (A, B)>,
98	A: AsRef<[u8]> + Ord,
99	B: AsRef<[u8]>,
100	H: Hasher,
101	S: TrieStream,
102{
103	tetsy_trie_root_inner::<H, S, I, A, B>(input, false)
104}
105
106fn tetsy_trie_root_inner<H, S, I, A, B>(input: I, no_extension: bool) -> H::Out where
107	I: IntoIterator<Item = (A, B)>,
108	A: AsRef<[u8]> + Ord,
109	B: AsRef<[u8]>,
110	H: Hasher,
111	S: TrieStream,
112{
113	// first put elements into btree to sort them and to remove duplicates
114	let input = input
115		.into_iter()
116		.collect::<BTreeMap<_, _>>();
117
118	// convert to nibbles
119	let mut nibbles = Vec::with_capacity(input.keys().map(|k| k.as_ref().len()).sum::<usize>() * 2);
120	let mut lens = Vec::with_capacity(input.len() + 1);
121	lens.push(0);
122	for k in input.keys() {
123		for &b in k.as_ref() {
124			nibbles.push(b >> 4);
125			nibbles.push(b & 0x0F);
126		}
127		lens.push(nibbles.len());
128	}
129
130	// then move them to a vector
131	let input = input.into_iter().zip(lens.windows(2))
132		.map(|((_, v), w)| (&nibbles[w[0]..w[1]], v))
133		.collect::<Vec<_>>();
134
135	let mut stream = S::new();
136	build_trie::<H, S, _, _>(&input, 0, &mut stream, no_extension);
137	H::hash(&stream.out())
138}
139
140/// Variant of `tetsy_trie_root` for patricia trie without extension node.
141/// See [`tetsy_trie_root`].
142pub fn tetsy_trie_root_no_extension<H, S, I, A, B>(input: I) -> H::Out where
143	I: IntoIterator<Item = (A, B)>,
144	A: AsRef<[u8]> + Ord,
145	B: AsRef<[u8]>,
146	H: Hasher,
147	S: TrieStream,
148{
149	tetsy_trie_root_inner::<H, S, I, A, B>(input, true)
150}
151
152//#[cfg(test)]	// consider feature="std"
153/// Method similar to `tetsy_trie_root` but returning the root encoded
154/// node instead of its hash.
155/// Mainly use for testing or debugging.
156pub fn unhashed_trie<H, S, I, A, B>(input: I) -> Vec<u8> where
157	I: IntoIterator<Item = (A, B)>,
158	A: AsRef<[u8]> + Ord,
159	B: AsRef<[u8]>,
160	H: Hasher,
161	S: TrieStream,
162{
163	unhashed_trie_inner::<H, S, I, A, B>(input, false)
164}
165
166fn unhashed_trie_inner<H, S, I, A, B>(input: I, no_extension: bool) -> Vec<u8> where
167	I: IntoIterator<Item = (A, B)>,
168	A: AsRef<[u8]> + Ord,
169	B: AsRef<[u8]>,
170	H: Hasher,
171	S: TrieStream,
172{
173	// first put elements into btree to sort them and to remove duplicates
174	let input = input
175		.into_iter()
176		.collect::<BTreeMap<_, _>>();
177
178	let mut nibbles = Vec::with_capacity(input.keys().map(|k| k.as_ref().len()).sum::<usize>() * 2);
179	let mut lens = Vec::with_capacity(input.len() + 1);
180	lens.push(0);
181	for k in input.keys() {
182		for &b in k.as_ref() {
183			nibbles.push(b >> 4);
184			nibbles.push(b & 0x0F);
185		}
186		lens.push(nibbles.len());
187	}
188
189	// then move them to a vector
190	let input = input.into_iter().zip(lens.windows(2))
191		.map(|((_, v), w)| (&nibbles[w[0]..w[1]], v))
192		.collect::<Vec<_>>();
193
194	let mut stream = S::new();
195	build_trie::<H, S, _, _>(&input, 0, &mut stream, no_extension);
196	stream.out()
197}
198
199/// Variant of `unhashed_trie` for patricia trie without extension node.
200/// See [`unhashed_trie`].
201pub fn unhashed_trie_no_extension<H, S, I, A, B>(input: I) -> Vec<u8> where
202	I: IntoIterator<Item = (A, B)>,
203	A: AsRef<[u8]> + Ord,
204	B: AsRef<[u8]>,
205	H: Hasher,
206	S: TrieStream,
207{
208	unhashed_trie_inner::<H, S, I, A, B>(input, true)
209}
210
211/// Generates a key-hashed (secure) trie root hash for a vector of key-value tuples.
212///
213/// ```ignore
214/// use hex_literal::hex;
215/// use tetsy_trie_root::sec_tetsy_trie_root;
216/// use tetsy_keccak_hasher::KeccakHasher;
217/// use tetsy_reference_trie::ReferenceTrieStream;
218///
219/// let v = vec![
220/// 	("doe", "reindeer"),
221/// 	("dog", "puppy"),
222/// 	("dogglesworth", "cat"),
223/// ];
224///
225/// let root = hex!["d6e02b2bd48aa04fd2ad87cfac1144a29ca7f7dc60f4526c7b7040763abe3d43"];
226/// assert_eq!(sec_tetsy_trie_root::<KeccakHasher, ReferenceTrieStream, _, _, _>(v), root);
227/// ```
228pub fn sec_tetsy_trie_root<H, S, I, A, B>(input: I) -> H::Out where
229	I: IntoIterator<Item = (A, B)>,
230	A: AsRef<[u8]>,
231	B: AsRef<[u8]>,
232	H: Hasher,
233	H::Out: Ord,
234	S: TrieStream,
235{
236	tetsy_trie_root::<H, S, _, _, _>(input.into_iter().map(|(k, v)| (H::hash(k.as_ref()), v)))
237}
238
239/// Takes a slice of key/value tuples where the key is a slice of nibbles
240/// and encodes it into the provided `Stream`.
241fn build_trie<H, S, A, B>(input: &[(A, B)], cursor: usize, stream: &mut S, no_extension: bool) where
242	A: AsRef<[u8]>,
243	B: AsRef<[u8]>,
244	H: Hasher,
245	S: TrieStream,
246{
247	match input.len() {
248		// No input, just append empty data.
249		0 => stream.append_empty_data(),
250		// Leaf node; append the remainder of the key and the value. Done.
251		1 => stream.append_leaf(&input[0].0.as_ref()[cursor..], &input[0].1.as_ref() ),
252		// We have multiple items in the input. Figure out if we should add an
253		// extension node or a branch node.
254		_ => {
255			let (key, value) = (&input[0].0.as_ref(), input[0].1.as_ref());
256			// Count the number of nibbles in the other elements that are
257			// shared with the first key.
258			// e.g. input = [ [1'7'3'10'12'13], [1'7'3'], [1'7'7'8'9'] ] => [1'7'] is common => 2
259			let shared_nibble_count = input.iter().skip(1).fold(key.len(), |acc, &(ref k, _)| {
260				cmp::min( shared_prefix_length(key, k.as_ref()), acc )
261			});
262			// Add an extension node if the number of shared nibbles is greater
263			// than what we saw on the last call (`cursor`): append the new part
264			// of the path then recursively append the remainder of all items
265			// who had this partial key.
266			let (cursor, o_branch_slice) = if no_extension {
267				if shared_nibble_count > cursor {
268					(shared_nibble_count, Some(&key[cursor..shared_nibble_count]))
269				} else {
270					(cursor, Some(&key[0..0]))
271				}
272			} else if shared_nibble_count > cursor {
273				stream.append_extension(&key[cursor..shared_nibble_count]);
274				build_trie_trampoline::<H, _, _, _>(
275					input,
276					shared_nibble_count,
277					stream,
278					no_extension,
279				);
280				return;
281			} else { (cursor, None) };
282
283			// We'll be adding a branch node because the path is as long as it gets.
284			// First we need to figure out what entries this branch node will have...
285
286			// We have a a value for exactly this key. Branch node will have a value
287			// attached to it.
288			let value = if cursor == key.len() { Some(value) } else { None };
289
290			// We need to know how many key nibbles each of the children account for.
291			let mut shared_nibble_counts = [0usize; 16];
292			{
293				// If the Branch node has a value then the first of the input keys
294				// is exactly the key for that value and we don't care about it
295				// when finding shared nibbles for our child nodes. (We know it's
296				// the first of the input keys, because the input is sorted)
297				let mut begin = match value { None => 0, _ => 1 };
298				for i in 0..16 {
299					shared_nibble_counts[i] = input[begin..].iter()
300						.take_while(|(k, _)| k.as_ref()[cursor] == i as u8)
301						.count();
302					begin += shared_nibble_counts[i];
303				}
304			}
305
306			// Put out the node header:
307			stream.begin_branch(o_branch_slice, value, shared_nibble_counts.iter().map(|&n| n > 0));
308
309			// Fill in each slot in the branch node. We don't need to bother with empty slots
310			// since they were registered in the header.
311			let mut begin = match value { None => 0, _ => 1 };
312			for &count in &shared_nibble_counts {
313				if count > 0 {
314					build_trie_trampoline::<H, S, _, _>(
315						&input[begin..(begin + count)],
316						cursor + 1,
317						stream,
318						no_extension,
319					);
320					begin += count;
321				} else {
322					stream.append_empty_child();
323				}
324			}
325
326			stream.end_branch(value);
327		}
328	}
329}
330
331fn build_trie_trampoline<H, S, A, B>(
332	input: &[(A, B)],
333	cursor: usize,
334	stream: &mut S,
335	no_extension: bool,
336) where
337	A: AsRef<[u8]>,
338	B: AsRef<[u8]>,
339	H: Hasher,
340	S: TrieStream,
341{
342	let mut substream = S::new();
343	build_trie::<H, _, _, _>(input, cursor, &mut substream, no_extension);
344	stream.append_substream::<H>(substream);
345}