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, &current_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;