vote_commitment_tree/
path.rs1use incrementalmerkletree::Hashable;
4use pasta_curves::Fp;
5
6use crate::anchor::Anchor;
7use crate::hash::{MerkleHashVote, TREE_DEPTH};
8
9pub const MERKLE_PATH_BYTES: usize = 4 + 32 * TREE_DEPTH;
11
12#[derive(Clone, Debug, PartialEq, Eq)]
20pub struct MerklePath {
21 position: u32,
22 auth_path: [MerkleHashVote; TREE_DEPTH],
23}
24
25impl From<incrementalmerkletree::MerklePath<MerkleHashVote, { TREE_DEPTH as u8 }>> for MerklePath {
26 fn from(path: incrementalmerkletree::MerklePath<MerkleHashVote, { TREE_DEPTH as u8 }>) -> Self {
27 let position: u64 = path.position().into();
28 Self {
29 position: position as u32,
30 auth_path: path.path_elems().try_into().unwrap(),
31 }
32 }
33}
34
35impl MerklePath {
36 pub fn from_parts(position: u32, auth_path: [MerkleHashVote; TREE_DEPTH]) -> Self {
38 Self {
39 position,
40 auth_path,
41 }
42 }
43
44 pub fn root(&self, leaf: MerkleHashVote) -> Anchor {
46 self.auth_path
47 .iter()
48 .enumerate()
49 .fold(leaf, |node, (l, sibling)| {
50 let l = l as u8;
51 if self.position & (1 << l) == 0 {
52 MerkleHashVote::combine(l.into(), &node, sibling)
53 } else {
54 MerkleHashVote::combine(l.into(), sibling, &node)
55 }
56 })
57 .into()
58 }
59
60 pub fn verify(&self, leaf: Fp, root: Fp) -> bool {
62 let computed = self.root(MerkleHashVote::from_fp(leaf));
63 computed.inner() == root
64 }
65
66 pub fn position(&self) -> u32 {
68 self.position
69 }
70
71 pub fn auth_path(&self) -> &[MerkleHashVote; TREE_DEPTH] {
73 &self.auth_path
74 }
75
76 pub fn to_bytes(&self) -> Vec<u8> {
83 let mut buf = Vec::with_capacity(MERKLE_PATH_BYTES);
84 buf.extend_from_slice(&self.position.to_le_bytes());
85 for hash in &self.auth_path {
86 buf.extend_from_slice(&hash.to_bytes());
87 }
88 buf
89 }
90
91 pub fn from_bytes(bytes: &[u8]) -> Option<Self> {
96 if bytes.len() < MERKLE_PATH_BYTES {
97 return None;
98 }
99
100 let position = u32::from_le_bytes(bytes[0..4].try_into().ok()?);
101
102 let mut auth_path = [MerkleHashVote::from_fp(Fp::zero()); TREE_DEPTH];
103 for (i, hash) in auth_path.iter_mut().enumerate() {
104 let start = 4 + i * 32;
105 let chunk: [u8; 32] = bytes[start..start + 32].try_into().ok()?;
106 *hash = MerkleHashVote::from_bytes(&chunk)?;
107 }
108
109 Some(Self {
110 position,
111 auth_path,
112 })
113 }
114}