roshi_interface/
access.rs1use solana_pubkey::Pubkey;
4use solana_sha256_hasher::hashv;
5
6pub const ACCESS_LEAF_DOMAIN: &[u8] = b"roshi:vault-access:leaf:v1";
7pub const ACCESS_NODE_DOMAIN: &[u8] = b"roshi:vault-access:node:v1";
8pub const EMPTY_ACCESS_MERKLE_ROOT: [u8; 32] = [0; 32];
9pub const MAX_ACCESS_PROOF_LEN: usize = 32;
10
11pub fn access_merkle_leaf(owner: &Pubkey) -> [u8; 32] {
12 hashv(&[ACCESS_LEAF_DOMAIN, owner.as_ref()]).to_bytes()
13}
14
15pub fn access_merkle_node(left: &[u8; 32], right: &[u8; 32]) -> [u8; 32] {
16 let (first, second) = if left <= right {
17 (left.as_slice(), right.as_slice())
18 } else {
19 (right.as_slice(), left.as_slice())
20 };
21
22 hashv(&[ACCESS_NODE_DOMAIN, first, second]).to_bytes()
23}
24
25pub fn verify_access_merkle_proof(
26 owner: &Pubkey,
27 merkle_root: &[u8; 32],
28 proof: &[[u8; 32]],
29) -> bool {
30 if proof.len() > MAX_ACCESS_PROOF_LEN {
31 return false;
32 }
33
34 let mut node = access_merkle_leaf(owner);
35
36 for sibling in proof {
37 node = access_merkle_node(&node, sibling);
38 }
39
40 &node == merkle_root
41}
42
43#[cfg(test)]
44mod tests {
45 use super::*;
46
47 #[test]
48 fn verifies_single_leaf_root() {
49 let owner = Pubkey::new_unique();
50 let root = access_merkle_leaf(&owner);
51
52 assert!(verify_access_merkle_proof(&owner, &root, &[]));
53 }
54
55 #[test]
56 fn verifies_directionless_two_leaf_tree() {
57 let left = Pubkey::new_unique();
58 let right = Pubkey::new_unique();
59 let left_leaf = access_merkle_leaf(&left);
60 let right_leaf = access_merkle_leaf(&right);
61 let root = access_merkle_node(&left_leaf, &right_leaf);
62
63 assert!(verify_access_merkle_proof(&left, &root, &[right_leaf]));
64 assert!(verify_access_merkle_proof(&right, &root, &[left_leaf]));
65 }
66
67 #[test]
68 fn verifies_four_leaf_tree() {
69 let owners = [
70 Pubkey::new_unique(),
71 Pubkey::new_unique(),
72 Pubkey::new_unique(),
73 Pubkey::new_unique(),
74 ];
75 let leaves = owners.map(|owner| access_merkle_leaf(&owner));
76 let left_node = access_merkle_node(&leaves[0], &leaves[1]);
77 let right_node = access_merkle_node(&leaves[2], &leaves[3]);
78 let root = access_merkle_node(&left_node, &right_node);
79
80 assert!(verify_access_merkle_proof(
81 &owners[2],
82 &root,
83 &[leaves[3], left_node],
84 ));
85 assert!(verify_access_merkle_proof(
86 &owners[0],
87 &root,
88 &[leaves[1], right_node],
89 ));
90 }
91
92 #[test]
93 fn rejects_wrong_owner_or_proof() {
94 let owner = Pubkey::new_unique();
95 let other = Pubkey::new_unique();
96 let sibling = access_merkle_leaf(&Pubkey::new_unique());
97 let root = access_merkle_node(&access_merkle_leaf(&owner), &sibling);
98
99 assert!(!verify_access_merkle_proof(&other, &root, &[sibling]));
100 assert!(!verify_access_merkle_proof(&owner, &root, &[]));
101 }
102
103 #[test]
104 fn rejects_oversized_proof() {
105 let owner = Pubkey::new_unique();
106 let root = access_merkle_leaf(&owner);
107 let oversized_proof = vec![[0; 32]; MAX_ACCESS_PROOF_LEN + 1];
108
109 assert!(!verify_access_merkle_proof(&owner, &root, &oversized_proof));
110 }
111}