darkfi_sdk/monotree/node.rs
1/* This file is part of DarkFi (https://dark.fi)
2 *
3 * Copyright (C) 2020-2025 Dyne.org foundation
4 * Copyright (C) 2021 MONOLOG (Taeho Francis Lim and Jongwhan Lee) MIT License
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU Affero General Public License as
8 * published by the Free Software Foundation, either version 3 of the
9 * License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU Affero General Public License for more details.
15 *
16 * You should have received a copy of the GNU Affero General Public License
17 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 */
19
20use super::{
21 bits::Bits,
22 utils::{bytes_to_int, nbytes_across},
23 BitsLen, HASH_LEN,
24};
25use crate::GenericResult;
26
27/// A type for describing components of `Node`: a real element of `Unit`
28/// or a virtual element `None`.
29pub type Cell<'a> = Option<Unit<'a>>;
30
31/// A component of `Node` consisting of `Hash` and `Bits`, which represents
32/// a joint of subtrees it has.
33#[derive(Clone, Debug, PartialEq)]
34pub struct Unit<'a> {
35 pub hash: &'a [u8],
36 pub bits: Bits<'a>,
37}
38
39/// The only component of `monotree`. In a big picture, `monotree` simply
40/// consists of structured `Node`s.
41///
42/// # Schematic
43/// There are two types of `Node` -- ___Soft node___ and ___Hard node___.
44/// * ___Hard___: A node that has two real cells as components. Two links to child nodes.
45/// * ___Soft___: A node that has only one real cell and it has only one link going out to child node.
46/// ```text
47/// Root
48/// / \
49/// NodeA NodeB
50/// / \ \
51/// NodeC LeafB LeafC
52/// /
53/// LeafA
54/// ```
55/// Where NodeA is a _Hard node_, NodeB and NodeC are _Soft nodes_.
56///
57/// # Byte-Serialized View
58/// Numbers in parentheses refer to byte length.
59/// By default `HashLen = 32`, `BitsLen = 2`.
60///
61/// _SoftNode_ = `Cell` + `0x00`(1), where
62/// `Cell` = `hash`(`HASH_LEN`) + `path`(`< HASH_LEN`) + `range_start`(`BitsLen`) + `range_end`(`BitsLen`).
63/// `0x00` is an indicator for soft node.
64///
65/// _HardNode_ = `Cell_L` + `Cell_R` + `0x01`(1), where
66/// `Cell_L` = `hash_L`(`HASH_LEN`) + `path_L`(`< HASH_LEN`) + `range_L_start`(`BitsLen`) + `range_L_end`(`BitsLen`
67/// `Cell_R` = `path_R`(`< HASH_LEN`) _ `range_R_start`(`BitsLen`) + `range_R_end`(`BitsLen`) + `hash_R`(`HASH_LEN`).
68/// `0x01` is an indicator for hard node.
69///
70/// To make ***Merkle proof*** easier, we purposely placed the _hashes_ on outskirts of the serialized form.
71/// With only 1-bit information of left or right, provers can easily guess
72/// which side of the hash they hold should be appended for the next step.
73/// Refer to `verify_proof()` implementation regarding on this discussion.
74pub enum Node<'a> {
75 Soft(Cell<'a>),
76 Hard(Cell<'a>, Cell<'a>),
77}
78
79impl<'a> Node<'a> {
80 pub fn new(lc: Cell<'a>, rc: Cell<'a>) -> Self {
81 match (&lc, &rc) {
82 (&Some(_), &None) => Node::Soft(lc),
83 (&None, &Some(_)) => Node::Soft(rc),
84 (&Some(_), &Some(_)) => Node::Hard(lc, rc),
85 _ => unreachable!("Node::new()"),
86 }
87 }
88
89 /// Construct `Cell`s by deserializing bytes slice.
90 pub fn cells_from_bytes(bytes: &'a [u8], right: bool) -> GenericResult<(Cell<'a>, Cell<'a>)> {
91 match Node::from_bytes(bytes)? {
92 Node::Soft(cell) => Ok((cell, None)),
93 Node::Hard(lc, rc) => {
94 if right {
95 Ok((rc, lc))
96 } else {
97 Ok((lc, rc))
98 }
99 }
100 }
101 }
102
103 fn parse_bytes(bytes: &'a [u8], right: bool) -> GenericResult<(Cell<'a>, usize)> {
104 let len_bytes = bytes.len();
105 let len_bits = std::mem::size_of::<BitsLen>();
106 let offset_hash = if right { 0_usize } else { HASH_LEN };
107 let range_hash = if right { len_bytes - HASH_LEN..len_bytes } else { 0..HASH_LEN };
108 let start: BitsLen = bytes_to_int(&bytes[offset_hash..offset_hash + len_bits]);
109 let end: BitsLen = bytes_to_int(&bytes[offset_hash + len_bits..offset_hash + 2 * len_bits]);
110 let offset_bits = nbytes_across(start, end) as usize;
111
112 Ok((
113 Some(Unit {
114 hash: &bytes[range_hash],
115 bits: Bits {
116 path: &bytes
117 [offset_hash + 2 * len_bits..offset_hash + 2 * len_bits + offset_bits],
118 range: start..end,
119 },
120 }),
121 offset_hash + 2 * len_bits + offset_bits,
122 ))
123 }
124
125 /// Construct `Node` by deserializing bytes slice.
126 pub fn from_bytes(bytes: &'a [u8]) -> GenericResult<Self> {
127 match bytes.last() {
128 Some(&0x00) => {
129 let (cell, _) = Node::parse_bytes(&bytes[..bytes.len() - 1], false)?;
130 Ok(Node::Soft(cell))
131 }
132 Some(&0x01) => {
133 let (lc, size) = Node::parse_bytes(bytes, false)?;
134 let (rc, _) = Node::parse_bytes(&bytes[size..bytes.len() - 1], true)?;
135 Ok(Node::Hard(lc, rc))
136 }
137 _ => unreachable!("Node::from_bytes()"),
138 }
139 }
140
141 /// Serialize `Node` into bytes.
142 pub fn to_bytes(&self) -> GenericResult<Vec<u8>> {
143 match self {
144 Node::Soft(Some(unit)) => Ok([unit.hash, &unit.bits.to_bytes()?, &[0x00]].concat()),
145 Node::Hard(Some(lu), Some(ru)) => {
146 let (lu, ru) = if ru.bits.first() { (lu, ru) } else { (ru, lu) };
147 Ok([lu.hash, &lu.bits.to_bytes()?, &ru.bits.to_bytes()?, ru.hash, &[0x01]].concat())
148 }
149 _ => unreachable!("node.to_bytes()"),
150 }
151 }
152}