1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
mod helpers;
use helpers::{LeafHash, PathHash};
mod verify;
#[cfg(all(test, console))]
use snarkvm_circuit_types::environment::assert_scope;
use snarkvm_circuit_types::{environment::prelude::*, Boolean, Field, U64};
pub struct MerklePath<E: Environment, const DEPTH: u8> {
leaf_index: U64<E>,
siblings: Vec<Field<E>>,
}
#[cfg(console)]
impl<E: Environment, const DEPTH: u8> Inject for MerklePath<E, DEPTH> {
type Primitive = console::merkle_tree::MerklePath<E::Network, DEPTH>;
fn new(mode: Mode, merkle_path: Self::Primitive) -> Self {
let leaf_index = U64::new(mode, merkle_path.leaf_index());
let siblings: Vec<_> = merkle_path.siblings().iter().map(|node| Field::new(mode, *node)).collect();
match siblings.len() == DEPTH as usize {
true => Self { leaf_index, siblings },
false => E::halt("Merkle path is not the correct depth"),
}
}
}
#[cfg(console)]
impl<E: Environment, const DEPTH: u8> Eject for MerklePath<E, DEPTH> {
type Primitive = console::merkle_tree::MerklePath<E::Network, DEPTH>;
fn eject_mode(&self) -> Mode {
(&self.leaf_index, &self.siblings).eject_mode()
}
fn eject_value(&self) -> Self::Primitive {
match Self::Primitive::try_from((&self.leaf_index, &self.siblings).eject_value()) {
Ok(merkle_path) => merkle_path,
Err(error) => E::halt(format!("Failed to eject the Merkle path: {error}")),
}
}
}
#[cfg(all(test, console))]
mod tests {
use super::*;
use snarkvm_circuit_network::AleoV0 as Circuit;
use snarkvm_utilities::{TestRng, Uniform};
use anyhow::Result;
const ITERATIONS: u128 = 100;
fn check_new<const DEPTH: u8>(
mode: Mode,
num_constants: u64,
num_public: u64,
num_private: u64,
num_constraints: u64,
) -> Result<()> {
let mut rng = TestRng::default();
let mut create_leaves = |num_leaves| {
(0..num_leaves)
.map(|_| console::Field::<<Circuit as Environment>::Network>::rand(&mut rng).to_bits_le())
.collect::<Vec<_>>()
};
for i in 0..ITERATIONS {
let num_leaves = core::cmp::min(2u128.pow(DEPTH as u32), i);
let leaves = create_leaves(num_leaves);
let merkle_tree = <<Circuit as Environment>::Network as snarkvm_console_network::Network>::merkle_tree_bhp::<
DEPTH,
>(&leaves)?;
for (index, leaf) in leaves.iter().enumerate() {
let merkle_path = merkle_tree.prove(index, leaf)?;
Circuit::scope(format!("New {mode}"), || {
let candidate = MerklePath::<Circuit, DEPTH>::new(mode, merkle_path.clone());
assert_eq!(merkle_path, candidate.eject_value());
assert_scope!(num_constants, num_public, num_private, num_constraints);
});
Circuit::reset();
}
}
Ok(())
}
#[test]
fn test_new_constant() -> Result<()> {
check_new::<32>(Mode::Constant, 96, 0, 0, 0)
}
#[test]
fn test_new_public() -> Result<()> {
check_new::<32>(Mode::Public, 0, 96, 0, 64)
}
#[test]
fn test_new_private() -> Result<()> {
check_new::<32>(Mode::Private, 0, 0, 96, 64)
}
}