Skip to content

Commit

Permalink
feat: add stdlib smt collection
Browse files Browse the repository at this point in the history
This commit introduces a `collections` module for the `stdlib`. It
contains, initially, functions to support Sparse Merkle Tree
functionality.

It also adds a `mtree_smt_index` operation that will fetch a depth/index
pair from the advice provider and push onto the operand stack.
  • Loading branch information
vlopes11 committed Mar 30, 2023
1 parent b7fabf9 commit 7e564e2
Show file tree
Hide file tree
Showing 18 changed files with 611 additions and 12 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,14 @@
# Changelog

## Next


#### Assembly
- Added new instructions: `mtree_smt_index`.

#### Stdlib
- Added new module: `collections::smt`.

## 0.5.0 (2023-03-29)

#### CLI
Expand Down
28 changes: 28 additions & 0 deletions assembly/src/assembler/instruction/crypto_ops.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,34 @@ pub(super) fn mtree_merge(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, A
hmerge(span)
}

/// Computes the index of a key/value pair of a Sparse Merkle tree and pushes it onto the advice
/// stack.
///
/// The operand stack is expected to be arranged as follows:
/// - key, 4 elements.
/// - value, 4 elements.
/// - root of the Sparse Merkle tree, 4 elements.
///
/// # Errors
/// Returns an error if a Merkle tree for the given root cannot be found in this advice
/// provider.
///
/// This operation takes 2 VM cycles.
pub(super) fn mtree_smt_index(span: &mut SpanBuilder) -> Result<Option<CodeBlock>, AssemblyError> {
// stack input: [K, V, R, ...]
// stack output: [d, i, K, V, R, ...]

// invoke the advice provider function to compute the target index for a SMT
span.push_decorator(Decorator::Advice(AdviceInjector::MerkleSmtIndex));

#[rustfmt::skip]
let ops = [
// fetch the computed items from the advice stack
AdvPop, AdvPop
];
span.add_ops(ops)
}

// MERKLE TREES - HELPERS
// ================================================================================================

Expand Down
1 change: 1 addition & 0 deletions assembly/src/assembler/instruction/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,7 @@ impl Assembler {
Instruction::MTreeGet => crypto_ops::mtree_get(span),
Instruction::MTreeSet => crypto_ops::mtree_set(span),
Instruction::MTreeMerge => crypto_ops::mtree_merge(span),
Instruction::MTreeSmtIndex => crypto_ops::mtree_smt_index(span),
Instruction::FriExt2Fold4 => span.add_op(FriE2F4),

// ----- exec/call instructions -------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions assembly/src/parsers/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -500,6 +500,7 @@ impl ParserContext {
"mtree_get" => simple_instruction(op, MTreeGet),
"mtree_set" => simple_instruction(op, MTreeSet),
"mtree_merge" => simple_instruction(op, MTreeMerge),
"mtree_smt_index" => simple_instruction(op, MTreeSmtIndex),

"fri_ext2fold4" => simple_instruction(op, FriExt2Fold4),

Expand Down
2 changes: 2 additions & 0 deletions assembly/src/parsers/nodes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,7 @@ pub enum Instruction {
MTreeGet,
MTreeSet,
MTreeMerge,
MTreeSmtIndex,
FriExt2Fold4,

// ----- exec / call --------------------------------------------------------------------------
Expand Down Expand Up @@ -544,6 +545,7 @@ impl fmt::Display for Instruction {
Self::MTreeGet => write!(f, "mtree_get"),
Self::MTreeSet => write!(f, "mtree_set"),
Self::MTreeMerge => write!(f, "mtree_merge"),
Self::MTreeSmtIndex => write!(f, "mtree_smt_index"),
Self::FriExt2Fold4 => write!(f, "fri_ext2fold4"),

// ----- exec / call ------------------------------------------------------------------
Expand Down
1 change: 1 addition & 0 deletions assembly/src/parsers/serde/deserialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -327,6 +327,7 @@ impl Deserializable for Instruction {
OpCode::MTreeGet => Ok(Instruction::MTreeGet),
OpCode::MTreeSet => Ok(Instruction::MTreeSet),
OpCode::MTreeMerge => Ok(Instruction::MTreeMerge),
OpCode::MTreeSmtIndex => Ok(Instruction::MTreeSmtIndex),
OpCode::FriExt2Fold4 => Ok(Instruction::FriExt2Fold4),

// ----- exec / call ------------------------------------------------------------------
Expand Down
13 changes: 7 additions & 6 deletions assembly/src/parsers/serde/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -265,14 +265,15 @@ pub enum OpCode {
MTreeGet = 233,
MTreeSet = 234,
MTreeMerge = 235,
FriExt2Fold4 = 236,
MTreeSmtIndex = 236,
FriExt2Fold4 = 237,

// ----- exec / call --------------------------------------------------------------------------
ExecLocal = 237,
ExecImported = 238,
CallLocal = 239,
CallImported = 240,
SysCall = 241,
ExecLocal = 238,
ExecImported = 239,
CallLocal = 240,
CallImported = 241,
SysCall = 242,

// ----- control flow -------------------------------------------------------------------------
IfElse = 253,
Expand Down
1 change: 1 addition & 0 deletions assembly/src/parsers/serde/serialization.rs
Original file line number Diff line number Diff line change
Expand Up @@ -444,6 +444,7 @@ impl Serializable for Instruction {
Self::MTreeGet => OpCode::MTreeGet.write_into(target)?,
Self::MTreeSet => OpCode::MTreeSet.write_into(target)?,
Self::MTreeMerge => OpCode::MTreeMerge.write_into(target)?,
Self::MTreeSmtIndex => OpCode::MTreeSmtIndex.write_into(target)?,
Self::FriExt2Fold4 => OpCode::FriExt2Fold4.write_into(target)?,

// ----- exec / call ------------------------------------------------------------------
Expand Down
3 changes: 2 additions & 1 deletion core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ std = ["math/std", "winter-utils/std"]

[dependencies]
math = { package = "winter-math", version = "0.6", default-features = false }
crypto = { package = "miden-crypto", version = "0.2", default-features = false }
#crypto = { package = "miden-crypto", version = "0.2", default-features = false }
crypto = { package = "miden-crypto", git = "https://github.com/0xPolygonMiden/crypto", branch = "next", default-features = false }
winter-crypto = { package = "winter-crypto", version = "0.6", default-features = false }
winter-utils = { package = "winter-utils", version = "0.6", default-features = false }

Expand Down
3 changes: 2 additions & 1 deletion core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ pub use ::crypto::{Word, ONE, WORD_SIZE, ZERO};
pub mod crypto {
pub mod merkle {
pub use ::crypto::merkle::{
MerkleError, MerklePath, MerklePathSet, MerkleStore, MerkleTree, NodeIndex, SimpleSmt,
EmptySubtreeRoots, MerkleError, MerklePath, MerklePathSet, MerkleStore, MerkleTree,
NodeIndex, SimpleSmt,
};
}

Expand Down
10 changes: 10 additions & 0 deletions core/src/operations/decorators/advice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,15 @@ pub enum AdviceInjector {
/// provider (i.e., the input trees are not removed).
MerkleMerge,

/// Computes the index of a key/value pair of a Sparse Merkle tree and pushes it onto
/// the operand stack.
///
/// The operand stack is expected to be arranged as follows:
/// - key, 4 elements.
/// - value, 4 elements.
/// - root of the Sparse Merkle tree, 4 elements.
MerkleSmtIndex,

/// Pushes the result of [u64] division (both the quotient and the remainder) onto the advice
/// stack. The operand stack is expected to be arranged as follows (from the top):
/// - divisor split into two 32-bit elements
Expand Down Expand Up @@ -58,6 +67,7 @@ impl fmt::Display for AdviceInjector {
match self {
Self::MerkleNode => write!(f, "merkle_node"),
Self::MerkleMerge => write!(f, "merkle_merge"),
Self::MerkleSmtIndex => write!(f, "merkle_smt_index"),
Self::DivResultU64 => write!(f, "div_result_u64"),
Self::MapValue => write!(f, "map_value"),
Self::Memory(start_addr, num_words) => write!(f, "mem({start_addr}, {num_words})"),
Expand Down
1 change: 1 addition & 0 deletions docs/src/user_docs/assembly/cryptographic_operations.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ Miden assembly provides a set of instructions for performing common cryptographi
| mtree_get <br> - *(9 cycles)* | [d, i, R, ...] | [V, R, ...] | Verifies that a Merkle tree with root $R$ opens to node $V$ at depth $d$ and index $i$. Merkle tree with root $R$ must be present in the advice provider, otherwise execution fails. |
| mtree_set <br> - *(29 cycles)* | [d, i, R, V', ...] | [V, R', ...] | Updates a node in the Merkle tree with root $R$ at depth $d$ and index $i$ to value $V'$. $R'$ is the Merkle root of the resulting tree and $V$ is old value of the node. Merkle tree with root $R$ must be present in the advice provider, otherwise execution fails. At the end of the operation the advice provider will contain both Merkle trees. |
| mtree_merge <br> - *(16 cycles)* | [R, L, ...] | [M, ...] | Merges two Merkle trees with the provided roots R (right), L (left) into a new Merkle tree with root M (merged). The input trees are retained in the advice provider. |
| mtree_smt_index <br> - *(?? cycles)* | [K, V, R, ...] | [d, i, K, V, R, ...] | Pushes the target depth $d$ and index $i$ of a key/value pair to the operand stack. The values are calculated for a Sparse Merkle tree with root $R$. A Merkle tree with root $R$ must be present in the advice provider, otherwise execution fails. |
6 changes: 3 additions & 3 deletions miden/src/cli/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ pub enum MerkleData {
/// vector of tuples where each tuple consists of a u64 node index and a 32 byte hex string
/// representing the value of the node.
#[serde(rename = "sparse_merkle_tree")]
SparseMerkleTree(Vec<(u64, String)>),
SparseMerkleTree(u8, Vec<(u64, String)>),
}

// INPUT FILE
Expand Down Expand Up @@ -195,9 +195,9 @@ impl InputFile {
.add_merkle_tree(leaves)
.map_err(|e| format!("failed to add merkle tree to merkle store - {e}"))?;
}
MerkleData::SparseMerkleTree(data) => {
MerkleData::SparseMerkleTree(depth, data) => {
let entries = Self::parse_sparse_merkle_tree(data)?;
merkle_store.add_sparse_merkle_tree(entries).map_err(|e| {
merkle_store.add_sparse_merkle_tree(*depth, entries).map_err(|e| {
format!("failed to add sparse merkle tree to merkle store - {e}")
})?;
}
Expand Down
3 changes: 3 additions & 0 deletions miden/tests/integration/stdlib/collections/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
use super::build_test;

mod smt;
Loading

0 comments on commit 7e564e2

Please sign in to comment.