hpl_interface/types/
merkle.rs1use cosmwasm_schema::cw_serde;
2use cosmwasm_std::{ensure, HexBinary, StdError, StdResult};
3
4use super::keccak256_hash;
5
6pub const HASH_LENGTH: usize = 32;
7pub const TREE_DEPTH: usize = 32;
8pub const MAX_LEAVES: u128 = (2_u128.pow(TREE_DEPTH as u32)) - 1;
9
10pub const ZERO_BYTES: &str = "0000000000000000000000000000000000000000000000000000000000000000";
11pub const ZERO_HASHES: [&str; TREE_DEPTH] = [
12 "0000000000000000000000000000000000000000000000000000000000000000",
13 "ad3228b676f7d3cd4284a5443f17f1962b36e491b30a40b2405849e597ba5fb5",
14 "b4c11951957c6f8f642c4af61cd6b24640fec6dc7fc607ee8206a99e92410d30",
15 "21ddb9a356815c3fac1026b6dec5df3124afbadb485c9ba5a3e3398a04b7ba85",
16 "e58769b32a1beaf1ea27375a44095a0d1fb664ce2dd358e7fcbfb78c26a19344",
17 "0eb01ebfc9ed27500cd4dfc979272d1f0913cc9f66540d7e8005811109e1cf2d",
18 "887c22bd8750d34016ac3c66b5ff102dacdd73f6b014e710b51e8022af9a1968",
19 "ffd70157e48063fc33c97a050f7f640233bf646cc98d9524c6b92bcf3ab56f83",
20 "9867cc5f7f196b93bae1e27e6320742445d290f2263827498b54fec539f756af",
21 "cefad4e508c098b9a7e1d8feb19955fb02ba9675585078710969d3440f5054e0",
22 "f9dc3e7fe016e050eff260334f18a5d4fe391d82092319f5964f2e2eb7c1c3a5",
23 "f8b13a49e282f609c317a833fb8d976d11517c571d1221a265d25af778ecf892",
24 "3490c6ceeb450aecdc82e28293031d10c7d73bf85e57bf041a97360aa2c5d99c",
25 "c1df82d9c4b87413eae2ef048f94b4d3554cea73d92b0f7af96e0271c691e2bb",
26 "5c67add7c6caf302256adedf7ab114da0acfe870d449a3a489f781d659e8becc",
27 "da7bce9f4e8618b6bd2f4132ce798cdc7a60e7e1460a7299e3c6342a579626d2",
28 "2733e50f526ec2fa19a22b31e8ed50f23cd1fdf94c9154ed3a7609a2f1ff981f",
29 "e1d3b5c807b281e4683cc6d6315cf95b9ade8641defcb32372f1c126e398ef7a",
30 "5a2dce0a8a7f68bb74560f8f71837c2c2ebbcbf7fffb42ae1896f13f7c7479a0",
31 "b46a28b6f55540f89444f63de0378e3d121be09e06cc9ded1c20e65876d36aa0",
32 "c65e9645644786b620e2dd2ad648ddfcbf4a7e5b1a3a4ecfe7f64667a3f0b7e2",
33 "f4418588ed35a2458cffeb39b93d26f18d2ab13bdce6aee58e7b99359ec2dfd9",
34 "5a9c16dc00d6ef18b7933a6f8dc65ccb55667138776f7dea101070dc8796e377",
35 "4df84f40ae0c8229d0d6069e5c8f39a7c299677a09d367fc7b05e3bc380ee652",
36 "cdc72595f74c7b1043d0e1ffbab734648c838dfb0527d971b602bc216c9619ef",
37 "0abf5ac974a1ed57f4050aa510dd9c74f508277b39d7973bb2dfccc5eeb0618d",
38 "b8cd74046ff337f0a7bf2c8e03e10f642c1886798d71806ab1e888d9e5ee87d0",
39 "838c5655cb21c6cb83313b5a631175dff4963772cce9108188b34ac87c81c41e",
40 "662ee4dd2dd7b2bc707961b1e646c4047669dcb6584f0d8d770daf5d7e7deb2e",
41 "388ab20e2573d171a88108e79d820e98f26c0b84aa8b2f4aa4968dbb818ea322",
42 "93237c50ba75ee485f4c22adf2f741400bdf8d6a9cc7df7ecae576221665d735",
43 "8448818bb4ae4562849e949e17ac16e0be16688e156b5cf15e098c627c0056a9",
44];
45
46#[cw_serde]
47pub struct MerkleTree {
48 pub branch: [HexBinary; TREE_DEPTH],
49 pub count: u128,
50}
51
52impl Default for MerkleTree {
53 fn default() -> Self {
54 Self {
55 branch: ZERO_HASHES
56 .into_iter()
57 .map(HexBinary::from_hex)
58 .collect::<StdResult<Vec<HexBinary>>>()
59 .unwrap()
60 .try_into()
61 .unwrap(),
62 count: Default::default(),
63 }
64 }
65}
66
67impl MerkleTree {
68 pub fn insert(&mut self, node: HexBinary) -> StdResult<()> {
69 ensure!(
70 self.count < MAX_LEAVES,
71 StdError::generic_err("tree is full")
72 );
73
74 self.count += 1;
75
76 let mut node = node;
77 let mut size = self.count;
78 for (i, next) in self.branch.iter().enumerate() {
79 if (size & 1) == 1 {
80 self.branch[i] = node;
81 return Ok(());
82 }
83 node = keccak256_hash(&[next.to_vec(), node.to_vec()].concat());
84 size /= 2;
85 }
86 panic!("unreachable code")
87 }
88
89 pub fn root_with_ctx(&self, zeroes: [[u8; HASH_LENGTH]; TREE_DEPTH]) -> StdResult<HexBinary> {
90 let idx = self.count;
91
92 Ok(zeroes
93 .iter()
94 .enumerate()
95 .fold(MerkleTree::zero()?.into(), |current, (i, zero)| {
96 let ith_bit = (idx >> i) & 1;
97 let next = self.branch[i].clone();
98 if ith_bit == 1 {
99 keccak256_hash(&[next.to_vec(), current.to_vec()].concat())
100 } else {
101 keccak256_hash(&[current.to_vec(), zero.to_vec()].concat())
102 }
103 }))
104 }
105
106 pub fn root(&self) -> StdResult<HexBinary> {
107 self.root_with_ctx(MerkleTree::zeroes()?)
108 }
109
110 pub fn branch_root(item: HexBinary, branch: [HexBinary; TREE_DEPTH], idx: u128) -> HexBinary {
111 branch
112 .into_iter()
113 .enumerate()
114 .fold(item, |current, (i, next)| match (idx >> i) & 1 {
115 1 => keccak256_hash(&[next.to_vec(), current.to_vec()].concat()),
116 _ => keccak256_hash(&[current.to_vec(), next.to_vec()].concat()),
117 })
118 }
119
120 pub fn zero() -> StdResult<[u8; HASH_LENGTH]> {
121 Ok(HexBinary::from_hex(ZERO_BYTES)?
122 .to_vec()
123 .try_into()
124 .expect("invalid length"))
125 }
126
127 pub fn zeroes() -> StdResult<[[u8; HASH_LENGTH]; TREE_DEPTH]> {
128 Ok(ZERO_HASHES
129 .into_iter()
130 .map(|v| {
131 Ok(HexBinary::from_hex(v)?
132 .to_vec()
133 .try_into()
134 .expect("invalid hash"))
135 })
136 .collect::<StdResult<Vec<_>>>()?
137 .try_into()
138 .expect("invalid depth"))
139 }
140}
141
142#[cfg(test)]
143mod tests {
144 use super::*;
145
146 #[test]
147 fn test_default_merkle_tree() {
148 for (i, branch) in MerkleTree::default().branch.into_iter().enumerate() {
149 assert_eq!(branch.to_hex(), super::ZERO_HASHES[i]);
150 }
151 }
152
153 #[test]
154 fn test_compatibility() {
155 let digest: HexBinary = [
156 keccak256_hash("hello_world".as_bytes()).to_vec(),
157 keccak256_hash("world_hello".as_bytes()).to_vec(),
158 ]
159 .concat()
160 .into();
161
162 assert_eq!(
163 format!("0x{}", digest.to_hex()),
164 "0x5b07e077a81ffc6b47435f65a8727bcc542bc6fc0f25a56210efb1a74b88a5ae5e3b3917b0a11fc9edfc594b3aabbc95167d176fcc17aa76c01d7bda956862cd",
166 );
167 }
168}