nomt_core/
trie.rs

1//! This module defines the types of a binary merkle trie, generalized over a 256 bit hash function.
2//! All lookup paths in the trie are 256 bits.
3//!
4//! All nodes are 256 bits. There are three kinds of nodes.
5//!   1. Internal nodes, which each have two children. The value of an internal node is
6//!       given by hashing the concatenation of the two child nodes and setting the MSB to 0.
7//!   2. Leaf nodes, which have zero children. The value of a leaf node is given by hashing
8//!       the concatenation of the 256-bit lookup path and the hash of the value stored at the leaf,
9//!       and setting the MSB to 1.
10//!   3. [`TERMINATOR`] nodes, which have the special value of all 0s. These nodes have no children
11//!      and serve as a stand-in for an empty sub-trie at any height. Terminator nodes enable the
12//!      trie to be tractably represented.
13//!
14//! All node preimages are 512 bits.
15
16use crate::hasher::NodeHasher;
17
18/// A node in the binary trie. In this schema, it is always 256 bits and is the hash of either
19/// an [`LeafData`] or [`InternalData`], or zeroed if it's a [`TERMINATOR`].
20///
21/// [`Node`]s are labeled by the [`NodeHasher`] used to indicate whether they are leaves or internal
22/// nodes. Typically, this is done by setting the MSB.
23pub type Node = [u8; 32];
24
25/// The path to a key. All paths have a 256 bit fixed length.
26pub type KeyPath = [u8; 32];
27
28/// The hash of a value. In this schema, it is always 256 bits.
29pub type ValueHash = [u8; 32];
30
31/// The terminator hash is a special node hash value denoting an empty sub-tree.
32/// Concretely, when this appears at a given location in the trie,
33/// it implies that no key with a path beginning with the location has a value.
34///
35/// This value may appear at any height.
36pub const TERMINATOR: Node = [0u8; 32];
37
38/// Whether the node hash indicates the node is a leaf.
39pub fn is_leaf<H: NodeHasher>(hash: &Node) -> bool {
40    H::node_kind(hash) == NodeKind::Leaf
41}
42
43/// Whether the node hash indicates the node is an internal node.
44pub fn is_internal<H: NodeHasher>(hash: &Node) -> bool {
45    H::node_kind(hash) == NodeKind::Internal
46}
47
48/// Whether the node holds the special `EMPTY_SUBTREE` value.
49pub fn is_terminator<H: NodeHasher>(hash: &Node) -> bool {
50    H::node_kind(hash) == NodeKind::Terminator
51}
52
53/// The kind of a node.
54#[derive(Debug, Clone, Copy, PartialEq, Eq)]
55pub enum NodeKind {
56    /// A terminator node indicates an empty sub-trie.
57    Terminator,
58    /// A leaf node indicates a sub-trie with a single leaf.
59    Leaf,
60    /// An internal node indicates at least two values.
61    Internal,
62}
63
64impl NodeKind {
65    /// Get the kind of the provided node.
66    pub fn of<H: NodeHasher>(node: &Node) -> Self {
67        H::node_kind(node)
68    }
69}
70
71/// The data of an internal (branch) node.
72#[derive(Debug, Clone, PartialEq, Eq)]
73pub struct InternalData {
74    /// The hash of the left child of this node.
75    pub left: Node,
76    /// The hash of the right child of this node.
77    pub right: Node,
78}
79
80/// The data of a leaf node.
81#[derive(Debug, Default, Clone, PartialEq, Eq)]
82#[cfg_attr(
83    feature = "borsh",
84    derive(borsh::BorshDeserialize, borsh::BorshSerialize)
85)]
86#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
87pub struct LeafData {
88    /// The total path to this value within the trie.
89    ///
90    /// The actual location of this node may be anywhere along this path, depending on the other
91    /// data within the trie.
92    pub key_path: KeyPath,
93    /// The hash of the value carried in this leaf.
94    pub value_hash: ValueHash,
95}