Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 0.24.0 (TBD)

- Extracted `SmtStorageReader` trait from `SmtStorage`, allowing `LargeSmt<S>` to work with read-only storage backends ([#958](https://github.com/0xMiden/crypto/pull/958)).

## 0.23.0 (2026-03-11)

- Replaced `Subtree` internal storage with bitmask layout ([#784](https://github.com/0xMiden/crypto/pull/784)).
Expand Down
34 changes: 17 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ skip-tree = [
# miden-crypto uses rand 0.9 while Plonky3 0.5 uses rand 0.10,
# causing duplicate rand / rand_core / getrandom trees
{ name = "getrandom", version = "=0.2.17" },
{ name = "rand", version = "=0.9.2" },
{ name = "rand", version = "=0.9.3" },
{ name = "rand_core", version = "=0.6.4" },
{ name = "rand_core", version = "=0.9.5" },
]
wildcards = "allow"

Expand Down
64 changes: 33 additions & 31 deletions miden-crypto/src/merkle/smt/large/construction.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use p3_maybe_rayon::prelude::*;

use super::{
CONSTRUCTION_SUBTREE_BATCH_SIZE, IN_MEMORY_DEPTH, LargeSmt, LargeSmtError, NUM_IN_MEMORY_NODES,
ROOT_MEMORY_INDEX, SMT_DEPTH, SmtStorage, StorageError, Subtree,
ROOT_MEMORY_INDEX, SMT_DEPTH, SmtStorage, SmtStorageReader, StorageError, Subtree,
};
use crate::{
EMPTY_WORD, Word,
Expand All @@ -22,7 +22,7 @@ use crate::{
// CONSTRUCTION
// ================================================================================================

impl<S: SmtStorage> LargeSmt<S> {
impl<S: SmtStorageReader> LargeSmt<S> {
/// Creates a new empty [LargeSmt] backed by the provided storage.
///
/// This method is intended for creating a fresh tree with empty storage. If the storage
Expand Down Expand Up @@ -113,35 +113,6 @@ impl<S: SmtStorage> LargeSmt<S> {
Ok(smt)
}

/// Returns a new [Smt] instantiated with leaves set as specified by the provided entries.
///
/// If the `concurrent` feature is enabled, this function uses a parallel implementation to
/// process the entries efficiently, otherwise it defaults to the sequential implementation.
///
/// All leaves omitted from the entries list are set to [Self::EMPTY_VALUE].
///
/// # Errors
/// Returns an error if the provided entries contain multiple values for the same key.
pub fn with_entries(
storage: S,
entries: impl IntoIterator<Item = (Word, Word)>,
) -> Result<Self, LargeSmtError> {
let entries: Vec<(Word, Word)> = entries.into_iter().collect();

if storage.has_leaves()? {
return Err(StorageError::Unsupported(
"Cannot create SMT with non-empty storage".into(),
)
.into());
}
let mut tree = LargeSmt::new(storage)?;
if entries.is_empty() {
return Ok(tree);
}
tree.build_subtrees(entries)?;
Ok(tree)
}

/// Internal method that initializes the in-memory tree from storage.
///
/// For empty storage, returns an empty tree. For non-empty storage,
Expand Down Expand Up @@ -225,6 +196,37 @@ impl<S: SmtStorage> LargeSmt<S> {
entry_count,
})
}
}

impl<S: SmtStorage> LargeSmt<S> {
/// Returns a new [Smt] instantiated with leaves set as specified by the provided entries.
///
/// If the `concurrent` feature is enabled, this function uses a parallel implementation to
/// process the entries efficiently, otherwise it defaults to the sequential implementation.
///
/// All leaves omitted from the entries list are set to [Self::EMPTY_VALUE].
///
/// # Errors
/// Returns an error if the provided entries contain multiple values for the same key.
pub fn with_entries(
storage: S,
entries: impl IntoIterator<Item = (Word, Word)>,
) -> Result<Self, LargeSmtError> {
let entries: Vec<(Word, Word)> = entries.into_iter().collect();

if storage.has_leaves()? {
return Err(StorageError::Unsupported(
"Cannot create SMT with non-empty storage".into(),
)
.into());
}
let mut tree = LargeSmt::new(storage)?;
if entries.is_empty() {
return Ok(tree);
}
tree.build_subtrees(entries)?;
Ok(tree)
}

fn build_subtrees(&mut self, mut entries: Vec<(Word, Word)>) -> Result<(), MerkleError> {
entries.par_sort_unstable_by_key(|item| {
Expand Down
8 changes: 4 additions & 4 deletions miden-crypto/src/merkle/smt/large/iter.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use alloc::{boxed::Box, vec::Vec};

use super::{IN_MEMORY_DEPTH, LargeSmt, SmtStorage, is_empty_parent};
use super::{IN_MEMORY_DEPTH, LargeSmt, SmtStorageReader, is_empty_parent};
use crate::{
Word,
hash::poseidon2::Poseidon2,
Expand All @@ -22,12 +22,12 @@ enum InnerNodeIteratorState<'a> {
Done,
}

pub struct LargeSmtInnerNodeIterator<'a, S: SmtStorage> {
pub struct LargeSmtInnerNodeIterator<'a, S: SmtStorageReader> {
large_smt: &'a LargeSmt<S>,
state: InnerNodeIteratorState<'a>,
}

impl<'a, S: SmtStorage> LargeSmtInnerNodeIterator<'a, S> {
impl<'a, S: SmtStorageReader> LargeSmtInnerNodeIterator<'a, S> {
pub(super) fn new(large_smt: &'a LargeSmt<S>) -> Self {
// in-memory nodes should never be empty
Self {
Expand All @@ -40,7 +40,7 @@ impl<'a, S: SmtStorage> LargeSmtInnerNodeIterator<'a, S> {
}
}

impl<S: SmtStorage> Iterator for LargeSmtInnerNodeIterator<'_, S> {
impl<S: SmtStorageReader> Iterator for LargeSmtInnerNodeIterator<'_, S> {
type Item = InnerNodeInfo;

/// Returns the next inner node info in the tree.
Expand Down
Loading
Loading