1use crate::once::OnceTable;
2use bitvec::{order::Lsb0, view::AsBits};
3use group::{Curve, ff::PrimeField};
4use incrementalmerkletree::{Hashable, Level};
5use subtle::CtOption;
6
7use alloc::vec::Vec;
8use core::fmt;
9
10use super::{
11 note::ExtractedNoteCommitment,
12 pedersen_hash::{Personalization, pedersen_hash},
13};
14
15pub const NOTE_COMMITMENT_TREE_DEPTH: u8 = 32;
16pub type CommitmentTree =
17 incrementalmerkletree::frontier::CommitmentTree<Node, NOTE_COMMITMENT_TREE_DEPTH>;
18pub type IncrementalWitness =
19 incrementalmerkletree::witness::IncrementalWitness<Node, NOTE_COMMITMENT_TREE_DEPTH>;
20pub type MerklePath = incrementalmerkletree::MerklePath<Node, NOTE_COMMITMENT_TREE_DEPTH>;
21
22fn uncommitted_sapling() -> bls12_381::Scalar {
23 bls12_381::Scalar::one()
24}
25
26static EMPTY_ROOTS: OnceTable<Vec<Node>> = OnceTable::new();
27
28fn empty_roots() -> &'static [Node] {
29 EMPTY_ROOTS.get_or_init(|| {
30 let mut v = vec![Node::empty_leaf()];
31 for d in 0..NOTE_COMMITMENT_TREE_DEPTH {
32 let next = Node::combine(d.into(), &v[usize::from(d)], &v[usize::from(d)]);
33 v.push(next);
34 }
35 v
36 })
37}
38
39pub fn merkle_hash(depth: usize, lhs: &[u8; 32], rhs: &[u8; 32]) -> [u8; 32] {
41 merkle_hash_field(depth, lhs, rhs).to_repr()
42}
43
44fn merkle_hash_field(depth: usize, lhs: &[u8; 32], rhs: &[u8; 32]) -> jubjub::Base {
45 let lhs = {
46 let mut tmp = [false; 256];
47 for (a, b) in tmp.iter_mut().zip(lhs.as_bits::<Lsb0>()) {
48 *a = *b;
49 }
50 tmp
51 };
52
53 let rhs = {
54 let mut tmp = [false; 256];
55 for (a, b) in tmp.iter_mut().zip(rhs.as_bits::<Lsb0>()) {
56 *a = *b;
57 }
58 tmp
59 };
60
61 jubjub::ExtendedPoint::from(pedersen_hash(
62 Personalization::MerkleTree(depth),
63 lhs.iter()
64 .copied()
65 .take(bls12_381::Scalar::NUM_BITS as usize)
66 .chain(
67 rhs.iter()
68 .copied()
69 .take(bls12_381::Scalar::NUM_BITS as usize),
70 ),
71 ))
72 .to_affine()
73 .get_u()
74}
75
76#[derive(Eq, PartialEq, Clone, Copy, Debug)]
78pub struct Anchor(jubjub::Base);
79
80impl From<jubjub::Base> for Anchor {
81 fn from(anchor_field: jubjub::Base) -> Anchor {
82 Anchor(anchor_field)
83 }
84}
85
86impl From<Node> for Anchor {
87 fn from(anchor: Node) -> Anchor {
88 Anchor(anchor.0)
89 }
90}
91
92impl Anchor {
93 pub fn empty_tree() -> Anchor {
99 Anchor(Node::empty_root(NOTE_COMMITMENT_TREE_DEPTH.into()).0)
100 }
101
102 pub(crate) fn inner(&self) -> jubjub::Base {
103 self.0
104 }
105
106 pub fn from_bytes(bytes: [u8; 32]) -> CtOption<Anchor> {
108 jubjub::Base::from_repr(bytes).map(Self)
109 }
110
111 pub fn to_bytes(self) -> [u8; 32] {
113 self.0.to_repr()
114 }
115}
116
117#[derive(Clone, Copy, PartialEq, Eq)]
119pub struct Node(jubjub::Base);
120
121impl fmt::Debug for Node {
122 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
123 f.debug_struct("Node")
124 .field("repr", &hex::encode(self.0.to_bytes()))
125 .finish()
126 }
127}
128
129impl Node {
130 pub fn from_cmu(value: &ExtractedNoteCommitment) -> Self {
132 Node(value.inner())
133 }
134
135 pub fn from_scalar(cmu: bls12_381::Scalar) -> Self {
137 Self(cmu)
138 }
139
140 pub fn from_bytes(bytes: [u8; 32]) -> CtOption<Self> {
144 jubjub::Base::from_repr(bytes).map(Self)
145 }
146
147 pub fn to_bytes(&self) -> [u8; 32] {
149 self.0.to_repr()
150 }
151
152 #[cfg(feature = "circuit")]
154 pub(crate) fn inner(&self) -> &jubjub::Base {
155 &self.0
156 }
157}
158
159impl Hashable for Node {
160 fn empty_leaf() -> Self {
161 Node(uncommitted_sapling())
162 }
163
164 fn combine(level: Level, lhs: &Self, rhs: &Self) -> Self {
165 Node(merkle_hash_field(
166 level.into(),
167 &lhs.0.to_bytes(),
168 &rhs.0.to_bytes(),
169 ))
170 }
171
172 fn empty_root(level: Level) -> Self {
173 empty_roots()[<usize>::from(level)]
174 }
175}
176
177impl From<Node> for bls12_381::Scalar {
178 fn from(node: Node) -> Self {
179 node.0
180 }
181}
182
183#[cfg(any(test, feature = "test-dependencies"))]
184pub(super) mod testing {
185 use ff::Field;
186 use proptest::prelude::*;
187 use rand::{
188 Rng as RandRng,
189 distr::{Distribution, StandardUniform},
190 };
191
192 use super::Node;
193 use crate::note::testing::arb_cmu;
194
195 prop_compose! {
196 pub fn arb_node()(cmu in arb_cmu()) -> Node {
197 Node::from_cmu(&cmu)
198 }
199 }
200
201 impl Node {
202 pub fn random(rng: &mut impl RandRng) -> Self {
204 StandardUniform.sample(rng)
205 }
206 }
207
208 impl Distribution<Node> for StandardUniform {
209 fn sample<R: RandRng + ?Sized>(&self, rng: &mut R) -> Node {
210 Node::from_scalar(bls12_381::Scalar::random(rng))
211 }
212 }
213}