Skip to main content

miden_stdlib_sys/stdlib/collections/
smt.rs

1//! Bindings for the `std::collections::smt` module, which exposes sparse Merkle tree
2//! functionality from the Miden standard library.
3
4use crate::intrinsics::{Felt, Word, WordAligned};
5
6/// Result of [`smt_get`], containing the retrieved `value` and the (unchanged) `root`.
7#[derive(Debug, Clone, PartialEq, Eq)]
8pub struct SmtGetResponse {
9    pub value: Word,
10    pub root: Word,
11}
12
13/// Result of [`smt_set`], containing the `old_value` and the updated `new_root`.
14#[derive(Debug, Clone, PartialEq, Eq)]
15pub struct SmtSetResponse {
16    pub old_value: Word,
17    pub new_root: Word,
18}
19
20#[allow(improper_ctypes)]
21unsafe extern "C" {
22    /// Returns the value located under the specified `key` in the sparse Merkle tree defined by
23    /// the specified `root`.
24    ///
25    /// This maps to the `std::collections::smt::get` procedure.
26    ///
27    /// Inputs: `[key, root, ...]`
28    /// Outputs: `[value, root, ...]`
29    ///
30    /// Fails if the tree with the specified `root` does not exist in the VM's advice provider. When
31    /// no value has previously been inserted under `key`, the procedure returns the empty word.
32    #[cfg_attr(all(target_family = "wasm", miden), linkage = "extern_weak")]
33    #[link_name = "miden::core::collections::smt::get"]
34    fn extern_smt_get(
35        k0: Felt,
36        k1: Felt,
37        k2: Felt,
38        k3: Felt,
39        r0: Felt,
40        r1: Felt,
41        r2: Felt,
42        r3: Felt,
43        ptr: *mut (Word, Word),
44    );
45
46    /// Inserts `value` under `key` in the sparse Merkle tree defined by `root`.
47    ///
48    /// This maps to the `std::collections::smt::set` procedure.
49    ///
50    /// Inputs: `[value, key, root, ...]`
51    /// Outputs: `[old_value, new_root, ...]`
52    ///
53    /// On success, the prior value stored under `key` is returned along with the updated root. If
54    /// `value` is the empty word, the new tree state is equivalent to omitting the update.
55    ///
56    /// Fails if the tree with the specified `root` does not exist in the VM's advice provider.
57    #[cfg_attr(all(target_family = "wasm", miden), linkage = "extern_weak")]
58    #[link_name = "miden::core::collections::smt::set"]
59    fn extern_smt_set(
60        v0: Felt,
61        v1: Felt,
62        v2: Felt,
63        v3: Felt,
64        k0: Felt,
65        k1: Felt,
66        k2: Felt,
67        k3: Felt,
68        r0: Felt,
69        r1: Felt,
70        r2: Felt,
71        r3: Felt,
72        ptr: *mut (Word, Word),
73    );
74}
75
76/// Returns the value associated with `key` in the sparse Merkle tree rooted at `root` as tracked by
77/// the VM's advice provider. The returned [`SmtGetResponse`] contains the retrieved value and the
78/// (unchanged) root returned by the ABI.
79/// Fails if the tree with the specified `root` does not exist in the VM's advice provider. When
80/// no value has previously been inserted under `key`, the procedure returns the empty word.
81#[inline]
82pub fn smt_get(key: Word, root: Word) -> SmtGetResponse {
83    unsafe {
84        let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<(Word, Word)>>::uninit();
85        let ptr = ret_area.as_mut_ptr() as *mut (Word, Word);
86        extern_smt_get(key[0], key[1], key[2], key[3], root[0], root[1], root[2], root[3], ptr);
87        let (value, returned_root) = ret_area.assume_init().into_inner();
88        SmtGetResponse {
89            value,
90            root: returned_root,
91        }
92    }
93}
94
95/// Inserts `value` at `key` in the sparse Merkle tree rooted at `root`, returning the prior value
96/// stored at `key` along with the new root. The returned [`SmtSetResponse`] contains
97/// the previous value stored under `key` and the updated root.
98/// Fails if the tree with the specified `root` does not exist in the VM's advice provider.
99#[inline]
100pub fn smt_set(value: Word, key: Word, root: Word) -> SmtSetResponse {
101    unsafe {
102        let mut ret_area = ::core::mem::MaybeUninit::<WordAligned<(Word, Word)>>::uninit();
103        let ptr = ret_area.as_mut_ptr() as *mut (Word, Word);
104        extern_smt_set(
105            value[0], value[1], value[2], value[3], key[0], key[1], key[2], key[3], root[0],
106            root[1], root[2], root[3], ptr,
107        );
108        let (old_value, new_root) = ret_area.assume_init().into_inner();
109        SmtSetResponse {
110            old_value,
111            new_root,
112        }
113    }
114}