1use crate::prelude::*;
13
14pub type AuthPath<Tree> = <<Tree as Height>::Height as Path>::Path;
18
19pub trait Path: IsHeight + Sized {
21 type Path;
23
24 fn root(path: &Self::Path, index: u64, leaf: Hash) -> Hash;
26}
27
28#[derive(Debug, Clone, Copy, Eq, PartialEq, Default)]
30pub struct Leaf;
31
32impl Path for Zero {
33 type Path = Leaf;
34
35 #[inline]
36 fn root(Leaf: &Leaf, _index: u64, leaf: Hash) -> Hash {
37 leaf
38 }
39}
40
41#[derive(Debug, Clone, Copy, Eq, PartialEq)]
43pub struct Node<Child> {
44 pub siblings: [Hash; 3],
49
50 pub child: Child,
52}
53
54impl<Child, N: Path<Path = Child>> Path for Succ<N> {
55 type Path = Node<Child>;
56
57 #[inline]
58 fn root(Node { siblings, child }: &Node<Child>, index: u64, leaf: Hash) -> Hash {
59 let which_way = WhichWay::at(Self::HEIGHT, index).0;
62 let [leftmost, left, right, rightmost] =
63 which_way.insert(N::root(child, index, leaf), *siblings);
64
65 Hash::node(Self::HEIGHT, leftmost, left, right, rightmost)
67 }
68}
69
70#[derive(Debug, Clone, Copy, Eq, PartialEq)]
72pub enum WhichWay {
73 Leftmost,
75 Left,
77 Right,
79 Rightmost,
81}
82
83impl WhichWay {
84 #[inline]
87 pub fn at(height: u8, index: u64) -> (WhichWay, u64) {
88 let which_way = match (index >> (2 * (height - 1))) & 0b11 {
91 0 => WhichWay::Leftmost,
92 1 => WhichWay::Left,
93 2 => WhichWay::Right,
94 3 => WhichWay::Rightmost,
95 _ => unreachable!(),
96 };
97
98 let index = index & !(0b11 << ((height - 1) * 2));
100
101 (which_way, index)
102 }
103
104 #[inline]
108 pub fn insert<T>(&self, item: T, siblings: [T; 3]) -> [T; 4] {
109 use WhichWay::*;
110
111 let (
112 (Leftmost, leftmost, [left, right, rightmost ]) |
113 (Left, left, [ leftmost, right, rightmost ]) |
114 (Right, right, [ leftmost, left, rightmost ]) |
115 (Rightmost, rightmost, [ leftmost, left, right, ])
116 ) = (self, item, siblings);
117
118 [leftmost, left, right, rightmost]
119 }
120
121 #[inline]
126 pub fn pick<T>(&self, siblings: [T; 4]) -> (T, [T; 3]) {
127 use WhichWay::*;
128
129 let ((Leftmost, [picked, a, b, c])
130 | (Left, [a, picked, b, c])
131 | (Right, [a, b, picked, c])
132 | (Rightmost, [a, b, c, picked])) = (self, siblings);
133
134 (picked, [a, b, c])
135 }
136}
137
138impl<T> Index<WhichWay> for [T; 4] {
139 type Output = T;
140
141 fn index(&self, index: WhichWay) -> &T {
142 match index {
143 WhichWay::Leftmost => &self[0],
144 WhichWay::Left => &self[1],
145 WhichWay::Right => &self[2],
146 WhichWay::Rightmost => &self[3],
147 }
148 }
149}
150
151impl<T> IndexMut<WhichWay> for [T; 4] {
152 fn index_mut(&mut self, index: WhichWay) -> &mut T {
153 match index {
154 WhichWay::Leftmost => &mut self[0],
155 WhichWay::Left => &mut self[1],
156 WhichWay::Right => &mut self[2],
157 WhichWay::Rightmost => &mut self[3],
158 }
159 }
160}
161
162#[cfg(test)]
163mod test {
164 use super::*;
165 use proptest::prelude::*;
166
167 fn directions_of_index(height: u8, index: u64) -> Vec<WhichWay> {
169 (1..=height)
170 .rev() .map(|height| WhichWay::at(height, index).0)
172 .collect()
173 }
174
175 fn directions_via_indices(height: u8, index: u64) -> Vec<WhichWay> {
178 (1..=height)
179 .rev() .scan(index, |index, height| {
181 let (which_way, next_index) = WhichWay::at(height, *index);
182 *index = next_index;
183 Some(which_way)
184 })
185 .collect()
186 }
187
188 #[test]
189 fn directions_of_index_check() {
190 assert_eq!(directions_of_index(1, 0), &[WhichWay::Leftmost]);
191 assert_eq!(directions_of_index(1, 1), &[WhichWay::Left]);
192 assert_eq!(directions_of_index(1, 2), &[WhichWay::Right]);
193 assert_eq!(directions_of_index(1, 3), &[WhichWay::Rightmost]);
194 }
195
196 fn index_of_directions(directions: &[WhichWay]) -> u64 {
198 directions
199 .iter()
200 .rev() .zip(1..) .fold(0, |index, (&direction, height)| {
203 index | (direction as u64) << (2 * (height - 1)) })
206 }
207
208 proptest! {
209 #[test]
210 fn which_way_indices_correct(
211 (height, index) in (
212 (0u8..(3 * 8)), 0u64..u64::MAX).prop_map(|(height, index)| (height, (index % (4u64.pow(height as u32))))
214 )
215 ) {
216 assert_eq!(directions_of_index(height, index), directions_via_indices(height, index));
217 }
218
219 #[test]
220 fn which_way_direction_correct(
221 (height, index) in (
222 (0u8..(3 * 8)), 0u64..u64::MAX).prop_map(|(height, index)| (height, (index % (4u64.pow(height as u32)))))
224 ) {
225 assert_eq!(index, index_of_directions(&directions_of_index(height, index)));
226 }
227 }
228}
229
230#[derive(Debug, Clone, Copy, Eq, PartialEq, Error)]
234#[error("could not decode authentication path")]
235pub struct PathDecodeError;
236
237use decaf377::Fq;
238use penumbra_sdk_proto::penumbra::crypto::tct::v1 as pb;
239use std::{
240 collections::VecDeque,
241 ops::{Index, IndexMut},
242};
243
244impl From<Leaf> for VecDeque<pb::MerklePathChunk> {
245 fn from(Leaf: Leaf) -> VecDeque<pb::MerklePathChunk> {
246 VecDeque::new()
247 }
248}
249
250impl From<Leaf> for Vec<pb::MerklePathChunk> {
251 fn from(Leaf: Leaf) -> Vec<pb::MerklePathChunk> {
252 Vec::new()
253 }
254}
255
256impl TryFrom<VecDeque<pb::MerklePathChunk>> for Leaf {
257 type Error = PathDecodeError;
258
259 fn try_from(queue: VecDeque<pb::MerklePathChunk>) -> Result<Leaf, Self::Error> {
260 if queue.is_empty() {
261 Ok(Leaf)
262 } else {
263 Err(PathDecodeError)
264 }
265 }
266}
267
268impl TryFrom<Vec<pb::MerklePathChunk>> for Leaf {
269 type Error = PathDecodeError;
270
271 fn try_from(vec: Vec<pb::MerklePathChunk>) -> Result<Leaf, Self::Error> {
272 if vec.is_empty() {
273 Ok(Leaf)
274 } else {
275 Err(PathDecodeError)
276 }
277 }
278}
279
280impl<Child> From<Node<Child>> for VecDeque<pb::MerklePathChunk>
283where
284 VecDeque<pb::MerklePathChunk>: From<Child>,
285{
286 fn from(node: Node<Child>) -> VecDeque<pb::MerklePathChunk> {
287 let [sibling_1, sibling_2, sibling_3] =
288 node.siblings.map(|hash| Fq::from(hash).to_bytes().to_vec());
289 let mut path: VecDeque<pb::MerklePathChunk> = node.child.into();
290 path.push_front(pb::MerklePathChunk {
291 sibling_1,
292 sibling_2,
293 sibling_3,
294 });
295 path
296 }
297}
298
299impl<Child> From<Node<Child>> for Vec<pb::MerklePathChunk>
300where
301 VecDeque<pb::MerklePathChunk>: From<Child>,
302{
303 fn from(node: Node<Child>) -> Vec<pb::MerklePathChunk> {
304 let [sibling_1, sibling_2, sibling_3] =
305 node.siblings.map(|hash| Fq::from(hash).to_bytes().to_vec());
306 let mut path = VecDeque::from(node.child);
307 path.push_front(pb::MerklePathChunk {
308 sibling_1,
309 sibling_2,
310 sibling_3,
311 });
312 path.into()
313 }
314}
315
316impl<Child> TryFrom<VecDeque<pb::MerklePathChunk>> for Node<Child>
319where
320 Child: TryFrom<VecDeque<pb::MerklePathChunk>, Error = PathDecodeError>,
321{
322 type Error = PathDecodeError;
323
324 fn try_from(mut queue: VecDeque<pb::MerklePathChunk>) -> Result<Node<Child>, Self::Error> {
325 if let Some(pb::MerklePathChunk {
326 sibling_1,
327 sibling_2,
328 sibling_3,
329 }) = queue.pop_front()
330 {
331 let child = Child::try_from(queue)?;
332 Ok(Node {
333 siblings: [
334 Hash::new(
335 Fq::from_bytes_checked(&sibling_1.try_into().map_err(|_| PathDecodeError)?)
336 .map_err(|_| PathDecodeError)?,
337 ),
338 Hash::new(
339 Fq::from_bytes_checked(&sibling_2.try_into().map_err(|_| PathDecodeError)?)
340 .map_err(|_| PathDecodeError)?,
341 ),
342 Hash::new(
343 Fq::from_bytes_checked(&sibling_3.try_into().map_err(|_| PathDecodeError)?)
344 .map_err(|_| PathDecodeError)?,
345 ),
346 ],
347 child,
348 })
349 } else {
350 Err(PathDecodeError)
351 }
352 }
353}
354
355impl<Child> TryFrom<Vec<pb::MerklePathChunk>> for Node<Child>
356where
357 Node<Child>: TryFrom<VecDeque<pb::MerklePathChunk>>,
358{
359 type Error = <Node<Child> as TryFrom<VecDeque<pb::MerklePathChunk>>>::Error;
360
361 fn try_from(queue: Vec<pb::MerklePathChunk>) -> Result<Node<Child>, Self::Error> {
362 <Node<Child>>::try_from(VecDeque::from(queue))
363 }
364}