asp_non_membership/lib.rs
1//! Sparse Merkle Tree implementation
2//!
3//! This is a Soroban-compatible port of the Sparse Merkle Tree implementation
4//! from:
5//! - circuits/src/test/utils/sparse_merkle_tree.rs (Rust reference
6//! implementation)
7//! - circomlibjs: <https://github.com/iden3/circomlibjs/blob/main/src/smt.js>
8//!
9//! This implementation uses Poseidon2 hash function for compatibility with the
10//! circomlib circuits
11//!
12//! # Design Considerations
13//!
14//! This is a full on-chain implementation where all tree nodes are stored in
15//! contract storage. While not the most cost-efficient approach, it provides:
16//! - Easy interaction and verification for users
17//! - Complete on-chain state for non-membership proofs
18//! - Flexibility to migrate to IPFS-based storage later if needed
19//!
20//! For scalability with large blocked key lists, consider the hybrid approach
21//! from: <https://www.newswise.com/pdf_docs/170903654855378_1-s2.0-S2096720923000519-main.pdf>
22//! We still present this implementation, as it allows making the decision to
23//! switch to IPFS-based storage later if needed.
24
25#![no_std]
26use soroban_sdk::{
27 Address, Env, U256, Vec, contract, contracterror, contractevent, contractimpl, contracttype,
28 vec,
29};
30use soroban_utils::{poseidon2_compress, poseidon2_hash2};
31#[contracttype]
32#[derive(Clone, Debug)]
33enum DataKey {
34 Admin,
35 Root,
36 Node(U256), // Node hash -> U256 (value)
37}
38
39/// Result of a find operation in the sparse Merkle tree
40#[contracttype]
41#[derive(Clone, Debug)]
42pub struct FindResult {
43 /// Whether the key was found in the tree
44 pub found: bool,
45 /// Sibling hashes along the path from root to leaf
46 pub siblings: Vec<U256>,
47 /// Value associated with the key (if found), zero otherwise
48 pub found_value: U256,
49 /// Key at the collision point
50 pub not_found_key: U256,
51 /// Value at the collision point
52 pub not_found_value: U256,
53 /// True if the path ended at an empty branch, false if collision with
54 /// existing leaf
55 pub is_old0: bool,
56}
57
58// Errors
59#[contracterror]
60#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord)]
61#[repr(u32)]
62pub enum Error {
63 NotAuthorized = 1,
64 KeyNotFound = 2,
65 KeyAlreadyExists = 3,
66 InvalidProof = 4,
67 NotInitialized = 5,
68}
69
70// Events
71#[contractevent(topics = ["LeafInserted"])]
72struct LeafInsertedEvent {
73 key: U256,
74 value: U256,
75 root: U256,
76}
77
78#[contractevent(topics = ["LeafUpdated"])]
79struct LeafUpdatedEvent {
80 key: U256,
81 old_value: U256,
82 new_value: U256,
83 root: U256,
84}
85
86#[contractevent(topics = ["LeafDeleted"])]
87struct LeafDeletedEvent {
88 key: U256,
89 root: U256,
90}
91
92#[contract]
93pub struct ASPNonMembership;
94
95#[contractimpl]
96impl ASPNonMembership {
97 /// Constructor: initialize the contract with an admin address and an empty
98 /// tree
99 ///
100 /// Sets up the contract with the specified admin and initializes an empty
101 /// Sparse Merkle Tree with root = 0. This function can only be called once.
102 ///
103 /// # Arguments
104 ///
105 /// * `env` - The Soroban environment
106 /// * `admin` - Address that will have permission to modify the tree
107 ///
108 /// # Returns
109 ///
110 /// Returns `Ok(())` on success
111 pub fn __constructor(env: Env, admin: Address) -> Result<(), Error> {
112 let store = env.storage().persistent();
113 store.set(&DataKey::Admin, &admin);
114 // Initialize with empty root (zero)
115 let zero = U256::from_u32(&env, 0u32);
116 store.set(&DataKey::Root, &zero);
117 Ok(())
118 }
119
120 /// Update the admin address
121 ///
122 /// Transfers administrative control to a new address. Requires
123 /// authorization from the current admin.
124 ///
125 /// # Arguments
126 ///
127 /// * `env` - The Soroban environment
128 /// * `new_admin` - New address that will have permission to modify the tree
129 pub fn update_admin(env: Env, new_admin: Address) {
130 soroban_utils::update_admin(&env, &DataKey::Admin, &new_admin);
131 }
132
133 /// Hash a leaf node using Poseidon2
134 ///
135 /// Computes the hash for leaf nodes using Poseidon2 with three inputs:
136 /// hash(key, value, 1). The domain separator of 1 distinguishes leaf nodes
137 /// from internal nodes. Mirrors circomlibjs "hash1" function so roots
138 /// generated here match the circuits.
139 ///
140 /// # Arguments
141 ///
142 /// * `env` - The Soroban environment
143 /// * `key` - Leaf key as U256
144 /// * `value` - Leaf value as U256
145 ///
146 /// # Returns
147 ///
148 /// Returns the leaf hash as a U256 value
149 fn hash_leaf(env: &Env, key: U256, value: U256) -> U256 {
150 let one = U256::from_u32(env, 1u32);
151 poseidon2_hash2(env, key, value, Some(one))
152 }
153
154 /// Hash an internal node using Poseidon2 compression
155 ///
156 /// Computes the hash for internal nodes using Poseidon2 compression mode
157 /// with two inputs: hash(left, right). This is the standard hash function
158 /// for inner nodes of the Sparse Merkle tree.
159 ///
160 /// # Arguments
161 ///
162 /// * `env` - The Soroban environment
163 /// * `left` - Left child hash as U256
164 /// * `right` - Right child hash as U256
165 ///
166 /// # Returns
167 ///
168 /// Returns the internal node hash as a U256 value
169 fn hash_internal(env: &Env, left: U256, right: U256) -> U256 {
170 poseidon2_compress(env, left, right)
171 }
172
173 /// Split a key into 256 bits from LSB to MSB
174 ///
175 /// Extracts the binary representation of a key for tree path traversal.
176 /// Bits are ordered from least significant (index 0) to most significant
177 /// (index 255) to match the circuits implementation.
178 ///
179 /// # Arguments
180 ///
181 /// * `env` - The Soroban environment
182 /// * `key` - Key to split into bits
183 ///
184 /// # Returns
185 ///
186 /// Returns a vector of 256 boolean values representing the key's bits
187 fn split_bits(env: &Env, key: &U256) -> Vec<bool> {
188 let mut bits = Vec::new(env);
189 let mut k = key.clone();
190 let two = U256::from_u32(env, 2u32);
191
192 for _ in 0..256 {
193 let rem = k.rem_euclid(&two);
194 bits.push_back(rem == U256::from_u32(env, 1u32));
195 k = k.div(&two);
196 }
197
198 bits
199 }
200
201 /// Internal recursive find method
202 ///
203 /// Traverses the tree from the given root to find a key, collecting sibling
204 /// hashes along the path. Returns detailed information about the search
205 /// result including whether the key was found, collision information
206 /// for non-membership proofs, and siblings required for witness
207 /// generation.
208 ///
209 /// # Arguments
210 ///
211 /// * `env` - The Soroban environment
212 /// * `store` - Persistent storage reference
213 /// * `key` - Key to search for
214 /// * `key_bits` - Pre-computed bits of the key
215 /// * `root` - Root hash to start search from
216 /// * `level` - Current tree level (0 = root)
217 ///
218 /// # Returns
219 ///
220 /// Returns `Ok(FindResult)` containing search results and path information,
221 /// or `Error::KeyNotFound` if database operations fail.
222 fn find_key_internal(
223 env: &Env,
224 store: &soroban_sdk::storage::Persistent,
225 key: &U256,
226 key_bits: &Vec<bool>,
227 root: &U256,
228 level: u32,
229 ) -> Result<FindResult, Error> {
230 let zero = U256::from_u32(env, 0u32);
231 // Empty tree
232 if *root == zero {
233 return Ok(FindResult {
234 found: false,
235 siblings: Vec::new(env),
236 found_value: zero.clone(),
237 not_found_key: key.clone(),
238 not_found_value: zero.clone(),
239 is_old0: true,
240 });
241 }
242
243 // Get node from storage
244 let node_key = DataKey::Node(root.clone());
245 let node_data: Vec<U256> = store.get(&node_key).ok_or(Error::KeyNotFound)?;
246
247 // Check if it's a leaf node (3 elements: [1, key, value])
248 if node_data.len() == 3 && node_data.get(0).unwrap() == U256::from_u32(env, 1u32) {
249 let stored_key = node_data.get(1).unwrap();
250 let stored_value = node_data.get(2).unwrap();
251 if stored_key == *key {
252 // Key found
253 return Ok(FindResult {
254 found: true,
255 siblings: Vec::new(env),
256 found_value: stored_value,
257 not_found_key: zero.clone(),
258 not_found_value: zero.clone(),
259 is_old0: false,
260 });
261 } else {
262 // Different key at leaf (collision)
263 return Ok(FindResult {
264 found: false,
265 siblings: Vec::new(env),
266 found_value: zero.clone(),
267 not_found_key: stored_key,
268 not_found_value: stored_value,
269 is_old0: false,
270 });
271 }
272 } else if node_data.len() == 2 {
273 // Internal node (2 elements: [left, right])
274 let left = node_data.get(0).unwrap();
275 let right = node_data.get(1).unwrap();
276
277 let level_idx = level;
278 let mut result = if !key_bits.get(level_idx).unwrap() {
279 // Go left
280 Self::find_key_internal(env, store, key, key_bits, &left, level + 1)?
281 } else {
282 // Go right
283 Self::find_key_internal(env, store, key, key_bits, &right, level + 1)?
284 };
285
286 // Add sibling to path
287 let sibling = if !key_bits.get(level_idx).unwrap() {
288 right.clone()
289 } else {
290 left.clone()
291 };
292 result.siblings.push_front(sibling);
293
294 return Ok(result);
295 }
296 Err(Error::KeyNotFound)
297 }
298
299 /// Find a key in the tree
300 ///
301 /// Public entry point for searching the tree. Returns comprehensive
302 /// information about the key including whether it exists, its value,
303 /// and the Merkle path siblings required for proof generation.
304 ///
305 /// # Arguments
306 ///
307 /// * `env` - The Soroban environment
308 /// * `key` - Key to search for in the tree
309 ///
310 /// # Returns
311 ///
312 /// Returns `Ok(FindResult)` containing whether the key was found, siblings
313 /// along the path, and collision information for non-membership proofs,
314 /// or an error if database operations fail.
315 ///
316 /// # Errors
317 ///
318 /// * `Error::KeyNotFound` - Database operations failed or invalid node
319 /// structure
320 pub fn find_key(env: Env, key: U256) -> Result<FindResult, Error> {
321 let store = env.storage().persistent();
322 let root: U256 = store
323 .get(&DataKey::Root)
324 .unwrap_or(U256::from_u32(&env, 0u32));
325 let key_bits = Self::split_bits(&env, &key);
326 Self::find_key_internal(&env, &store, &key, &key_bits, &root, 0u32)
327 }
328
329 /// Insert a new key-value pair into the tree
330 ///
331 /// Adds a new leaf to the Sparse Merkle tree, building any missing
332 /// intermediate nodes. Handles collision cases where a new key shares a
333 /// path prefix with an existing leaf by extending the tree depth.
334 /// Requires admin authorization.
335 ///
336 /// # Arguments
337 ///
338 /// * `env` - The Soroban environment
339 /// * `key` - Key to insert
340 /// * `value` - Value to associate with the key
341 ///
342 /// # Returns
343 ///
344 /// Returns `Ok(())` on success, emitting a `LeafInsertedEvent` with the new
345 /// root.
346 ///
347 /// # Errors
348 ///
349 /// * `Error::KeyAlreadyExists` - Key already exists in the tree
350 /// * `Error::KeyNotFound` - Database operations failed
351 pub fn insert_leaf(env: Env, key: U256, value: U256) -> Result<(), Error> {
352 let store = env.storage().persistent();
353 let admin: Address = store.get(&DataKey::Admin).unwrap();
354 admin.require_auth();
355
356 let root: U256 = store
357 .get(&DataKey::Root)
358 .unwrap_or(U256::from_u32(&env, 0u32));
359
360 // Compute key bits
361 let key_bits = Self::split_bits(&env, &key);
362
363 // Find the key
364 let find_result = Self::find_key_internal(&env, &store, &key, &key_bits, &root, 0u32)?;
365
366 if find_result.found {
367 return Err(Error::KeyAlreadyExists);
368 }
369
370 let zero = U256::from_u32(&env, 0u32);
371 let mut siblings = find_result.siblings.clone();
372 let mut mixed = false;
373 let mut rt_old = zero.clone();
374 let mut added_one = false;
375
376 // Handle collision case: extend siblings for a common prefix and add old leaf
377 if !find_result.is_old0 {
378 let old_key_bits = Self::split_bits(&env, &find_result.not_found_key);
379 let mut i = siblings.len();
380 // Extend siblings with zeros for common prefix bits
381 while i < old_key_bits.len()
382 && i < key_bits.len()
383 && old_key_bits.get(i).unwrap() == key_bits.get(i).unwrap()
384 {
385 siblings.push_back(zero.clone());
386 i += 1;
387 }
388 rt_old = Self::hash_leaf(
389 &env,
390 find_result.not_found_key.clone(),
391 find_result.not_found_value.clone(),
392 );
393 siblings.push_back(rt_old.clone());
394 added_one = true;
395 mixed = false;
396 } else if !siblings.is_empty() {
397 mixed = true;
398 rt_old = zero.clone();
399 }
400
401 // Insert the new leaf
402 let mut rt = Self::hash_leaf(&env, key.clone(), value.clone());
403 let leaf_node = vec![&env, U256::from_u32(&env, 1u32), key.clone(), value.clone()];
404 store.set(&DataKey::Node(rt.clone()), &leaf_node);
405
406 // Build up the tree from leaf to root (process siblings in reverse)
407 // Siblings are stored from root level (index 0) to leaf level (last index)
408 let siblings_len = siblings.len();
409 for (i, sibling) in siblings.iter().enumerate().rev() {
410 // Check if we need to delete old nodes (mixed case)
411 // Skip the last index if added_one=true (it's the old leaf, not an internal
412 // node)
413 let is_last_added_leaf = added_one && (i == (siblings_len - 1) as usize);
414 if !is_last_added_leaf
415 && (i as u32) < siblings_len.saturating_sub(1)
416 && sibling.clone() != zero
417 {
418 mixed = true;
419 }
420
421 if mixed && !is_last_added_leaf {
422 let old_sibling = if (i as u32) < find_result.siblings.len() {
423 find_result.siblings.get(i as u32).unwrap().clone()
424 } else {
425 zero.clone()
426 };
427 let bit = key_bits.get(i as u32).unwrap();
428 rt_old = if bit {
429 Self::hash_internal(&env, old_sibling.clone(), rt_old.clone())
430 } else {
431 Self::hash_internal(&env, rt_old.clone(), old_sibling.clone())
432 };
433 store.remove(&DataKey::Node(rt_old.clone()));
434 }
435
436 // Build a new internal node
437 let bit = key_bits.get(i as u32).unwrap();
438 let (left_hash, right_hash) = if bit {
439 (sibling.clone(), rt.clone())
440 } else {
441 (rt.clone(), sibling.clone())
442 };
443
444 rt = Self::hash_internal(&env, left_hash.clone(), right_hash.clone());
445
446 // Store internal node
447 let internal_node = vec![&env, left_hash, right_hash];
448 store.set(&DataKey::Node(rt.clone()), &internal_node);
449 }
450
451 // Remove the temporary sibling if we added one for collision
452 if added_one {
453 siblings.pop_back();
454 }
455 // Remove trailing zeros from siblings
456 while !siblings.is_empty() {
457 let last_idx = siblings.len() - 1;
458 if siblings.get(last_idx).unwrap() == zero {
459 siblings.pop_back();
460 } else {
461 break;
462 }
463 }
464
465 // Update root
466 store.set(&DataKey::Root, &rt);
467
468 // Emit event
469 LeafInsertedEvent {
470 key: key.clone(),
471 value: value.clone(),
472 root: rt,
473 }
474 .publish(&env);
475
476 Ok(())
477 }
478
479 /// Delete a key from the tree
480 ///
481 /// Removes a leaf from the Sparse Merkle tree, handling both sparse
482 /// branches (single child) and mixed branches (two populated children).
483 /// When a leaf is deleted, its sibling may be promoted to replace the
484 /// parent node, collapsing the tree structure. Requires admin
485 /// authorization.
486 ///
487 /// # Arguments
488 ///
489 /// * `env` - The Soroban environment
490 /// * `key` - Key to delete from the tree
491 ///
492 /// # Returns
493 ///
494 /// Returns `Ok(())` on success, emitting a `LeafDeletedEvent` with the new
495 /// root.
496 ///
497 /// # Errors
498 ///
499 /// * `Error::KeyNotFound` - Key does not exist in the tree or database
500 /// operations failed
501 pub fn delete_leaf(env: Env, key: U256) -> Result<(), Error> {
502 let store = env.storage().persistent();
503 let admin: Address = store.get(&DataKey::Admin).unwrap();
504 admin.require_auth();
505 let root: U256 = store.get(&DataKey::Root).unwrap();
506
507 // Compute key bits once for both find and delete operations
508 let key_bits = Self::split_bits(&env, &key);
509
510 // Find the key
511 let find_result = Self::find_key_internal(&env, &store, &key, &key_bits, &root, 0u32)?;
512
513 if !find_result.found {
514 return Err(Error::KeyNotFound);
515 }
516
517 let zero = U256::from_u32(&env, 0u32);
518 let one = U256::from_u32(&env, 1u32);
519
520 // Track nodes to delete (old path if any)
521 let mut rt_old = Self::hash_leaf(&env, key.clone(), find_result.found_value.clone());
522 store.remove(&DataKey::Node(rt_old.clone()));
523
524 let mut rt_new: U256;
525 let mut siblings_to_use = find_result.siblings.clone();
526
527 // Check if the last sibling is a leaf that should be promoted
528 if let Some(last_sibling) = find_result.siblings.last() {
529 let node_key = DataKey::Node(last_sibling.clone());
530 if let Some(node_data) = store.get::<DataKey, Vec<U256>>(&node_key) {
531 // Check if it's a leaf node (3 elements: [1, key, value])
532 if node_data.len() == 3 && node_data.get(0).unwrap() == one {
533 // Last sibling is a leaf - promote it
534 rt_new = last_sibling.clone();
535 // Remove the last sibling from the list since we're promoting it
536 siblings_to_use.pop_back();
537 } else if node_data.len() == 2 {
538 // Last sibling is an internal node - replace with zero
539 rt_new = zero.clone();
540 } else {
541 return Err(Error::KeyNotFound); // Invalid node
542 }
543 } else {
544 return Err(Error::KeyNotFound); // Sibling not found
545 }
546 } else {
547 // No siblings - The tree becomes empty
548 rt_new = zero.clone();
549 }
550
551 // Rebuild the tree from the deletion point upwards
552 let mut mixed = false;
553 let siblings_len = siblings_to_use.len();
554
555 for level_idx in 0..siblings_len {
556 let level = siblings_len - 1 - level_idx; // Process from leaf to root
557 let sibling = siblings_to_use.get(level).unwrap();
558
559 // Use actual sibling value
560 let new_sibling = sibling.clone();
561
562 // Delete old internal node along the old path
563 let bit = key_bits.get(level).unwrap();
564 rt_old = if bit {
565 Self::hash_internal(&env, sibling.clone(), rt_old)
566 } else {
567 Self::hash_internal(&env, rt_old, sibling.clone())
568 };
569 store.remove(&DataKey::Node(rt_old.clone()));
570
571 // Check if we need to continue rebuilding
572 if new_sibling != zero {
573 mixed = true;
574 }
575
576 if mixed {
577 // Build new internal node
578 let (left_hash, right_hash) = if bit {
579 (new_sibling, rt_new.clone())
580 } else {
581 (rt_new.clone(), new_sibling)
582 };
583
584 // Create and store new internal node
585 rt_new = Self::hash_internal(&env, left_hash.clone(), right_hash.clone());
586 let internal_node = vec![&env, left_hash, right_hash];
587 store.set(&DataKey::Node(rt_new.clone()), &internal_node);
588 }
589 }
590
591 // Update root
592 store.set(&DataKey::Root, &rt_new);
593
594 // Emit event
595 LeafDeletedEvent {
596 key: key.clone(),
597 root: rt_new,
598 }
599 .publish(&env);
600
601 Ok(())
602 }
603
604 /// Update a key-value pair in the tree
605 ///
606 /// Changes the value associated with an existing key. Recomputes all nodes
607 /// along the path from the leaf to the root, removing old nodes and
608 /// creating new ones. Requires admin authorization.
609 ///
610 /// # Arguments
611 ///
612 /// * `env` - The Soroban environment
613 /// * `key` - Key to update
614 /// * `new_value` - New value to associate with the key
615 ///
616 /// # Returns
617 ///
618 /// Returns `Ok(())` on success, emitting a `LeafUpdatedEvent` with the new
619 /// root.
620 ///
621 /// # Errors
622 ///
623 /// * `Error::KeyNotFound` - Key does not exist in the tree or database
624 /// operations failed
625 pub fn update_leaf(env: Env, key: U256, new_value: U256) -> Result<(), Error> {
626 let store = env.storage().persistent();
627 let admin: Address = store.get(&DataKey::Admin).unwrap();
628 admin.require_auth();
629 let root: U256 = store
630 .get(&DataKey::Root)
631 .unwrap_or(U256::from_u32(&env, 0u32));
632
633 // Compute key bits once
634 let key_bits = Self::split_bits(&env, &key);
635
636 // Find the key
637 let find_result = Self::find_key_internal(&env, &store, &key, &key_bits, &root, 0u32)?;
638
639 if !find_result.found {
640 return Err(Error::KeyNotFound);
641 }
642 // Update the leaf
643 let old_leaf_hash = Self::hash_leaf(&env, key.clone(), find_result.found_value.clone());
644 let new_leaf_hash = Self::hash_leaf(&env, key.clone(), new_value.clone());
645 // Update leaf node
646 let leaf_node = vec![
647 &env,
648 U256::from_u32(&env, 1u32),
649 key.clone(),
650 new_value.clone(),
651 ];
652 store.set(&DataKey::Node(new_leaf_hash.clone()), &leaf_node);
653
654 // Remove old leaf
655 store.remove(&DataKey::Node(old_leaf_hash.clone()));
656
657 // Rebuild path from leaf to root (process siblings in reverse)
658 let mut current_hash = new_leaf_hash;
659 let mut old_current_hash = old_leaf_hash;
660
661 let siblings_len = find_result.siblings.len();
662 for level_idx in 0..siblings_len {
663 let level = siblings_len - 1 - level_idx; // Reverse: process from leaf to root
664 let sibling = find_result.siblings.get(level).unwrap();
665 let bit = key_bits.get(level).unwrap();
666
667 let (left_hash, right_hash) = if bit {
668 (sibling.clone(), current_hash)
669 } else {
670 (current_hash, sibling.clone())
671 };
672
673 let (old_left_hash, old_right_hash) = if bit {
674 (sibling.clone(), old_current_hash)
675 } else {
676 (old_current_hash, sibling.clone())
677 };
678
679 current_hash = Self::hash_internal(&env, left_hash.clone(), right_hash.clone());
680 old_current_hash = Self::hash_internal(&env, old_left_hash, old_right_hash);
681
682 // Update internal node
683 let internal_node = vec![&env, left_hash, right_hash];
684 store.set(&DataKey::Node(current_hash.clone()), &internal_node);
685
686 // Remove old internal node
687 store.remove(&DataKey::Node(old_current_hash.clone()));
688 }
689
690 // Update root
691 store.set(&DataKey::Root, ¤t_hash);
692
693 // Emit event
694 LeafUpdatedEvent {
695 key: key.clone(),
696 old_value: find_result.found_value,
697 new_value: new_value.clone(),
698 root: current_hash,
699 }
700 .publish(&env);
701
702 Ok(())
703 }
704
705 /// Verify non-membership proof for a key
706 ///
707 /// Verifies that a key is NOT in the tree by checking the provided Merkle
708 /// proof. The proof includes siblings along the path and collision
709 /// information (not_found_key/value at the leaf). Reconstructs the root
710 /// from the proof and compares it with the stored root.
711 ///
712 /// # Arguments
713 ///
714 /// * `env` - The Soroban environment
715 /// * `key` - Key to verify is not in the tree
716 /// * `siblings` - Sibling hashes along the path from root to leaf
717 /// * `not_found_key` - Key at the collision point (or queried key if empty
718 /// path)
719 /// * `not_found_value` - Value at the collision point (or zero if empty
720 /// path)
721 ///
722 /// # Returns
723 ///
724 /// Returns `Ok(true)` if non-membership is verified, `Ok(false)` if the key
725 /// actually exists in the tree.
726 pub fn verify_non_membership(
727 env: Env,
728 key: U256,
729 siblings: Vec<U256>,
730 not_found_key: U256,
731 not_found_value: U256,
732 ) -> Result<bool, Error> {
733 let store = env.storage().persistent();
734 let root: U256 = store
735 .get(&DataKey::Root)
736 .unwrap_or(U256::from_u32(&env, 0u32));
737
738 // Compute key bits once
739 let key_bits = Self::split_bits(&env, &key);
740
741 // Find the key
742 let find_result = Self::find_key_internal(&env, &store, &key, &key_bits, &root, 0u32)?;
743
744 if find_result.found {
745 return Ok(false); // Key exists, so non-membership is false
746 }
747
748 // Verify the proof: check that siblings match and not_found_key/value match
749 if find_result.siblings.len() != siblings.len() {
750 return Err(Error::InvalidProof);
751 }
752
753 for (i, sibling) in siblings.iter().enumerate() {
754 let expected = find_result.siblings.get(i as u32).unwrap();
755 if sibling != expected {
756 return Err(Error::InvalidProof);
757 }
758 }
759
760 if find_result.not_found_key != not_found_key
761 || find_result.not_found_value != not_found_value
762 {
763 return Err(Error::InvalidProof);
764 }
765
766 // Reconstruct root from proof (process siblings in reverse: leaf to root)
767 let mut computed_root =
768 if not_found_key != key && not_found_value != U256::from_u32(&env, 0u32) {
769 Self::hash_leaf(&env, not_found_key, not_found_value)
770 } else {
771 U256::from_u32(&env, 0u32)
772 };
773
774 let siblings_len = siblings.len();
775 for level_idx in 0..siblings_len {
776 let level = siblings_len - 1 - level_idx; // Reverse: process from leaf to root
777 let sibling = siblings.get(level).unwrap();
778 let bit = key_bits.get(level).unwrap();
779
780 computed_root = if bit {
781 Self::hash_internal(&env, sibling.clone(), computed_root)
782 } else {
783 Self::hash_internal(&env, computed_root, sibling.clone())
784 };
785 }
786
787 if computed_root != root {
788 return Err(Error::InvalidProof);
789 }
790
791 Ok(true) // Non-membership verified
792 }
793
794 /// Get the current root of the tree
795 ///
796 /// Returns the root hash of the Sparse Merkle tree. Returns zero if the
797 /// tree is empty or hasn't been initialized yet.
798 ///
799 /// # Arguments
800 ///
801 /// * `env` - The Soroban environment
802 ///
803 /// # Returns
804 ///
805 /// Returns the current root hash as a U256 value, or zero if empty
806 pub fn get_root(env: Env) -> Result<U256, Error> {
807 env.storage()
808 .persistent()
809 .get(&DataKey::Root)
810 .ok_or(Error::NotInitialized)
811 }
812}
813
814mod test;