From e827cc9eb433fb6b877af46999d2ca9b5e16fdad Mon Sep 17 00:00:00 2001
From: Ohad <137686240+ohad-starkware@users.noreply.github.com>
Date: Thu, 21 Mar 2024 14:09:26 +0200
Subject: [PATCH] changed interface to mixed merkle tree
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This change is [](https://reviewable.io/reviews/starkware-libs/stwo/456)
---
src/commitment_scheme/merkle_input.rs | 16 +-
.../mixed_degree_decommitment.rs | 60 ++--
.../mixed_degree_merkle_tree.rs | 262 ++++++++++--------
3 files changed, 175 insertions(+), 163 deletions(-)
diff --git a/src/commitment_scheme/merkle_input.rs b/src/commitment_scheme/merkle_input.rs
index a73a970c2..6053fce05 100644
--- a/src/commitment_scheme/merkle_input.rs
+++ b/src/commitment_scheme/merkle_input.rs
@@ -98,31 +98,31 @@ impl<'a, F: Field> MerkleTreeInput<'a, F> {
self.columns_to_inject.len()
}
- // Returns the structure of the merkle tree. i.e. for each depth, the length of the columns
+ // Returns the column layout of the merkle tree. i.e. for each depth, the length of the columns
// assigned to it.
// TODO(Ohad): implement this logic for the verifier.
- pub fn configuration(&self) -> MerkleTreeConfig {
+ pub fn column_layout(&self) -> MerkleTreeColumnLayout {
let column_sizes = self
.columns_to_inject
.iter()
.map(|col| col.len())
.collect::>();
- MerkleTreeConfig {
+ MerkleTreeColumnLayout {
column_sizes,
injected_depths_map: self.injected_depths_map.clone(),
}
}
}
-/// The structure of a mixed degree merkle tree.
+/// The column layout of a mixed degree merkle tree.
/// The sizes of columns assigned to every layer, ordered as they were inserted & injected into hash
/// blocks.
-pub struct MerkleTreeConfig {
+pub struct MerkleTreeColumnLayout {
column_sizes: Vec,
injected_depths_map: Vec>,
}
-impl MerkleTreeConfig {
+impl MerkleTreeColumnLayout {
pub fn sort_queries_by_layer(&self, queries: &[Vec]) -> Vec>> {
let mut queries_to_layers = vec![vec![]; self.height()];
(1..=self.height()).for_each(|i| {
@@ -261,7 +261,7 @@ mod tests {
merkle_input.insert_column(2, &column_length_4);
merkle_input.insert_column(3, &column_length_16);
- let merkle_config = merkle_input.configuration();
+ let merkle_config = merkle_input.column_layout();
assert_eq!(merkle_config.column_lengths_at_depth(3), vec![4, 16]);
assert_eq!(merkle_config.column_lengths_at_depth(2), vec![8, 4]);
@@ -280,7 +280,7 @@ mod tests {
let queries = vec![vec![0], vec![1], vec![2], vec![3], vec![4], vec![5]];
- let merkle_config = merkle_input.configuration();
+ let merkle_config = merkle_input.column_layout();
let sorted_queries = merkle_config.sort_queries_by_layer(&queries);
assert_eq!(
diff --git a/src/commitment_scheme/mixed_degree_decommitment.rs b/src/commitment_scheme/mixed_degree_decommitment.rs
index 96c9d6e33..dde6a4930 100644
--- a/src/commitment_scheme/mixed_degree_decommitment.rs
+++ b/src/commitment_scheme/mixed_degree_decommitment.rs
@@ -4,14 +4,14 @@ use itertools::Itertools;
use merging_iterator::MergeIter;
use super::hasher::Hasher;
-use super::merkle_input::MerkleTreeConfig;
+use super::merkle_input::MerkleTreeColumnLayout;
use super::mixed_degree_merkle_tree::queried_nodes_in_layer;
use crate::core::fields::{Field, IntoSlice};
/// A Merkle proof of queried indices.
/// Used for storing a all the paths from the query leaves to the root.
/// A correctly generated decommitment should hold all the information needed to generate the root
-/// of the tree, proving the queried values and the tree's structure.
+/// of the tree, proving the queried values and the tree's column layout.
// TODO(Ohad): write printing functions.
pub struct MixedDecommitment {
pub hashes: Vec,
@@ -34,7 +34,7 @@ impl MixedDecommitment {
pub fn verify(
&self,
root: H::Hash,
- structure: &MerkleTreeConfig,
+ column_layout: &MerkleTreeColumnLayout,
queries: &[Vec],
mut queried_values: impl Iterator- ,
) -> bool
@@ -42,16 +42,16 @@ impl MixedDecommitment {
F: IntoSlice,
{
let mut witness_hashes = self.hashes.iter();
- let sorted_queries_by_layer = structure.sort_queries_by_layer(queries);
+ let sorted_queries_by_layer = column_layout.sort_queries_by_layer(queries);
let mut next_layer_hashes = vec![];
let mut ancestor_indices = vec![];
let mut witness_elements = self.witness_elements.iter().copied();
- for i in (1..=structure.height()).rev() {
+ for i in (1..=column_layout.height()).rev() {
(next_layer_hashes, ancestor_indices) = Self::verify_single_layer(
i,
&sorted_queries_by_layer[i - 1],
- structure,
+ column_layout,
ancestor_indices.iter().copied().peekable(),
queried_values.by_ref(),
&mut witness_elements,
@@ -67,7 +67,7 @@ impl MixedDecommitment {
fn verify_single_layer<'a>(
layer_depth: usize,
queries_to_layer: &[Vec],
- structure: &MerkleTreeConfig,
+ column_layout: &MerkleTreeColumnLayout,
mut previous_layers_indices: Peekable + Clone>,
mut queried_values: impl Iterator
- ,
mut witness_elements: impl Iterator
- ,
@@ -78,7 +78,7 @@ impl MixedDecommitment {
F: IntoSlice,
{
let directly_queried_node_indices =
- queried_nodes_in_layer(queries_to_layer.iter(), structure, layer_depth);
+ queried_nodes_in_layer(queries_to_layer.iter(), column_layout, layer_depth);
let mut node_indices = MergeIter::new(
directly_queried_node_indices.iter().copied(),
previous_layers_indices.clone().map(|q| q / 2),
@@ -97,7 +97,7 @@ impl MixedDecommitment {
for &node_index in &node_indices {
// Push correct child hashes to the hasher.
match previous_layers_indices.next_if(|hash_index| *hash_index / 2 == node_index) {
- None if layer_depth < structure.height() => {
+ None if layer_depth < column_layout.height() => {
hasher.update(witness_hashes_iter.next().unwrap().as_ref());
hasher.update(witness_hashes_iter.next().unwrap().as_ref());
}
@@ -129,7 +129,7 @@ impl MixedDecommitment {
// Chunk size - according to the column's length and the current depth, we calculate the
// number of elements from that column 'injected' to the current node.
- for (chunk_size, column_queries) in structure
+ for (chunk_size, column_queries) in column_layout
.column_lengths_at_depth(layer_depth)
.iter()
.map(|&column_length| column_length >> (layer_depth - 1))
@@ -154,9 +154,7 @@ mod tests {
use crate::commitment_scheme::blake3_hash::Blake3Hasher;
use crate::commitment_scheme::hasher::Hasher;
use crate::commitment_scheme::merkle_input::MerkleTreeInput;
- use crate::commitment_scheme::mixed_degree_merkle_tree::{
- MixedDegreeMerkleTree, MixedDegreeMerkleTreeConfig,
- };
+ use crate::commitment_scheme::mixed_degree_merkle_tree::MixedDegreeMerkleTree;
use crate::core::fields::m31::M31;
#[test]
@@ -168,17 +166,11 @@ mod tests {
input.insert_column(TREE_HEIGHT, &column_length_8);
input.insert_column(TREE_HEIGHT - 1, &column_length_4);
input.insert_column(TREE_HEIGHT - 1, &column_length_8);
- let config = input.configuration();
- let mut tree = MixedDegreeMerkleTree::::new(
- input,
- MixedDegreeMerkleTreeConfig {
- multi_layer_sizes: [3, 1].to_vec(),
- },
- );
- let commitment = tree.commit();
+ let config = input.column_layout();
+ let (tree, commitment) = MixedDegreeMerkleTree::::commit_default(&input);
let queries: Vec> = vec![vec![2], vec![0_usize], vec![4, 7]];
- let decommitment = tree.decommit(&queries);
+ let decommitment = tree.decommit(&input, &queries);
assert!(decommitment.verify(
commitment,
&config,
@@ -197,18 +189,12 @@ mod tests {
input.insert_column(TREE_HEIGHT, &column_length_8);
input.insert_column(TREE_HEIGHT - 1, &column_length_4);
input.insert_column(TREE_HEIGHT - 1, &column_length_8);
- let config = input.configuration();
- let mut tree = MixedDegreeMerkleTree::::new(
- input,
- MixedDegreeMerkleTreeConfig {
- multi_layer_sizes: [3, 1].to_vec(),
- },
- );
- tree.commit();
+ let config = input.column_layout();
+ let (tree, _) = MixedDegreeMerkleTree::::commit_default(&input);
let false_commitment = Blake3Hasher::hash(b"false_commitment");
let queries: Vec> = vec![vec![2], vec![0_usize], vec![4, 7]];
- let decommitment = tree.decommit(&queries);
+ let decommitment = tree.decommit(&input, &queries);
assert!(decommitment.verify(
false_commitment,
@@ -228,17 +214,11 @@ mod tests {
input.insert_column(TREE_HEIGHT, &column_length_8);
input.insert_column(TREE_HEIGHT - 1, &column_length_4);
input.insert_column(TREE_HEIGHT - 1, &column_length_8);
- let config = input.configuration();
- let mut tree = MixedDegreeMerkleTree::::new(
- input,
- MixedDegreeMerkleTreeConfig {
- multi_layer_sizes: vec![3, 1],
- },
- );
- let commitment = tree.commit();
+ let config = input.column_layout();
+ let (tree, commitment) = MixedDegreeMerkleTree::::commit_default(&input);
let queries: Vec> = vec![vec![2], vec![0_usize], vec![4, 7]];
- let mut decommitment = tree.decommit(&queries);
+ let mut decommitment = tree.decommit(&input, &queries);
decommitment.hashes[0] = Blake3Hasher::hash(b"false_hash");
assert!(decommitment.verify(
diff --git a/src/commitment_scheme/mixed_degree_merkle_tree.rs b/src/commitment_scheme/mixed_degree_merkle_tree.rs
index 8e1c760dc..afbaf7204 100644
--- a/src/commitment_scheme/mixed_degree_merkle_tree.rs
+++ b/src/commitment_scheme/mixed_degree_merkle_tree.rs
@@ -4,7 +4,7 @@ use itertools::Itertools;
use merging_iterator::MergeIter;
use super::hasher::Hasher;
-use super::merkle_input::{MerkleTreeConfig, MerkleTreeInput};
+use super::merkle_input::{MerkleTreeColumnLayout, MerkleTreeInput};
use super::merkle_multilayer::MerkleMultiLayer;
use super::mixed_degree_decommitment::MixedDecommitment;
use crate::commitment_scheme::merkle_multilayer::MerkleMultiLayerConfig;
@@ -12,6 +12,8 @@ use crate::commitment_scheme::utils::get_column_chunk;
use crate::core::fields::{Field, IntoSlice};
/// A mixed degree merkle tree.
+/// Stored as a vector of ['MerkleMultiLayer']s, each with a configurable height.
+/// Only stores the generated hash values.
///
/// # Example
///
@@ -26,11 +28,11 @@ use crate::core::fields::{Field, IntoSlice};
/// input.insert_column(7, &column);
///
///
-/// let mut tree = MixedDegreeMerkleTree::::new(input,MixedDegreeMerkleTreeConfig {multi_layer_sizes: [5,2].to_vec(),});
-/// let root = tree.commit();
-pub struct MixedDegreeMerkleTree<'a, F: Field, H: Hasher> {
- input: MerkleTreeInput<'a, F>,
- pub multi_layers: Vec>,
+/// let (tree, commitment) = MixedDegreeMerkleTree::::commit_default(&input);
+pub struct MixedDegreeMerkleTree {
+ column_layout: MerkleTreeColumnLayout,
+ multi_layers: Vec>,
+ _field: std::marker::PhantomData,
}
/// Sets the heights of the multi layers in the tree in ascending order.
@@ -38,12 +40,53 @@ pub struct MixedDegreeMerkleTreeConfig {
pub multi_layer_sizes: Vec,
}
-impl<'a, F: Field, H: Hasher> MixedDegreeMerkleTree<'a, F, H>
+impl<'a, F: Field, H: Hasher> MixedDegreeMerkleTree
where
F: IntoSlice,
{
- pub fn new(input: MerkleTreeInput<'a, F>, config: MixedDegreeMerkleTreeConfig) -> Self {
- let tree_height = input.max_injected_depth();
+ pub fn commit_default(input: &MerkleTreeInput<'a, F>) -> (Self, H::Hash) {
+ // Default configuration is a single tree.
+ let config = MixedDegreeMerkleTreeConfig {
+ multi_layer_sizes: vec![input.max_injected_depth()],
+ };
+
+ Self::commit(input, config)
+ }
+
+ /// Generate a mixed degree merkle tree with configured ['MerkleMultiLayer'] sizes.
+ /// The sum of layer sizes must match the depth of the deepest column of the input.
+ ///
+ /// # Example
+ ///
+ /// ```rust
+ /// use stwo::commitment_scheme::merkle_input::MerkleTreeInput;
+ /// use stwo::commitment_scheme::mixed_degree_merkle_tree::*;
+ /// use stwo::commitment_scheme::blake3_hash::Blake3Hasher;
+ /// use stwo::core::fields::m31::M31;
+ ///
+ /// let mut input = MerkleTreeInput::::new();
+ /// let column = vec![M31::from_u32_unchecked(0); 1024];
+ /// input.insert_column(7, &column);
+ /// let config = MixedDegreeMerkleTreeConfig {multi_layer_sizes: vec![4,2,1]};
+ ///
+ ///
+ /// let (tree, commitment) = MixedDegreeMerkleTree::::commit(&input, config);
+ pub fn commit(
+ input: &MerkleTreeInput<'a, F>,
+ config: MixedDegreeMerkleTreeConfig,
+ ) -> (Self, H::Hash) {
+ let mut tree = Self {
+ column_layout: input.column_layout(),
+ multi_layers: vec![],
+ _field: std::marker::PhantomData,
+ };
+ tree.init_memory(config);
+ let root = tree.hash(input);
+ (tree, root)
+ }
+
+ fn init_memory(&mut self, config: MixedDegreeMerkleTreeConfig) {
+ let tree_height = self.height();
Self::validate_config(&config, tree_height);
let mut layers = Vec::>::new();
@@ -55,20 +98,13 @@ where
current_depth -= layer_height;
}
- MixedDegreeMerkleTree {
- input,
- multi_layers: layers,
- }
- }
-
- pub fn height(&self) -> usize {
- self.input.max_injected_depth()
+ self.multi_layers = layers;
}
- pub fn commit(&mut self) -> H::Hash {
+ fn hash(&mut self, input: &MerkleTreeInput<'a, F>) -> H::Hash {
let mut curr_layer = self.height() - self.multi_layer_height(0);
// Bottom layer.
- self.multi_layers[0].commit_layer::(&self.input, &[]);
+ self.multi_layers[0].commit_layer::(input, &[]);
// Rest of the tree.
for i in 1..self.multi_layers.len() {
// TODO(Ohad): implement Hash oracle and avoid these copies.
@@ -78,7 +114,7 @@ where
.collect::>();
debug_assert_eq!(prev_hashes.len(), 1 << (curr_layer));
curr_layer -= self.multi_layer_height(i);
- self.multi_layers[i].commit_layer::(&self.input, &prev_hashes);
+ self.multi_layers[i].commit_layer::(input, &prev_hashes);
}
let mut top_layer_roots = self.multi_layers.last().unwrap().get_roots();
let root = top_layer_roots
@@ -89,6 +125,10 @@ where
root
}
+ pub fn height(&self) -> usize {
+ self.column_layout.height()
+ }
+
/// Generates a mixed degree merkle decommitment.
///
/// # Arguments
@@ -101,9 +141,7 @@ where
/// ```rust
/// use stwo::commitment_scheme::blake3_hash::Blake3Hasher;
/// use stwo::commitment_scheme::merkle_input::MerkleTreeInput;
- /// use stwo::commitment_scheme::mixed_degree_merkle_tree::{
- /// MixedDegreeMerkleTree, MixedDegreeMerkleTreeConfig,
- /// };
+ /// use stwo::commitment_scheme::mixed_degree_merkle_tree::MixedDegreeMerkleTree;
/// use stwo::core::fields::m31::M31;
///
/// let mut input = MerkleTreeInput::::new();
@@ -111,31 +149,30 @@ where
/// let column_1 = vec![M31::from_u32_unchecked(0); 512];
/// input.insert_column(7, &column_0);
/// input.insert_column(6, &column_1);
- /// let mut tree = MixedDegreeMerkleTree::::new(
- /// input,
- /// MixedDegreeMerkleTreeConfig {
- /// multi_layer_sizes: [5, 2].to_vec(),
- /// },
- /// );
- /// let root = tree.commit();
+ /// let (tree, commitment) = MixedDegreeMerkleTree::::commit_default(&input);
///
/// let queries = vec![vec![0], vec![300, 511]];
- /// let decommitment = tree.decommit(queries.as_ref());
+ /// let decommitment = tree.decommit(&input, queries.as_ref());
/// ```
// TODO(Ohad): introduce a proper query struct, then deprecate 'drain' usage and accepting vecs.
- pub fn decommit(&self, queries: &[Vec]) -> MixedDecommitment {
+ pub fn decommit(
+ &self,
+ input: &MerkleTreeInput<'a, F>,
+ queries: &[Vec],
+ ) -> MixedDecommitment {
assert_eq!(
queries.len(),
- self.input.n_injected_columns(),
+ input.n_injected_columns(),
"Number of query vectors does not match number of injected columns."
);
let mut decommitment = MixedDecommitment::::new();
- let queries_to_layers = self.input.configuration().sort_queries_by_layer(queries);
+ let queries_to_layers = input.column_layout().sort_queries_by_layer(queries);
// Decommitment layers are built from the bottom up, excluding the root.
let mut ancestor_indices = vec![];
- (1..=self.input.max_injected_depth()).rev().for_each(|i| {
+ (1..=input.max_injected_depth()).rev().for_each(|i| {
ancestor_indices = self.decommit_single_layer(
+ input,
i,
&queries_to_layers[i - 1],
ancestor_indices.iter().copied().peekable(),
@@ -190,20 +227,19 @@ where
// 'queries_to_layer'- queries to columns at this layer.
fn decommit_single_layer(
&self,
+ input: &MerkleTreeInput<'a, F>,
layer_depth: usize,
queries_to_layer: &[Vec],
mut previous_layers_indices: Peekable + Clone>,
decommitment: &mut MixedDecommitment,
) -> Vec {
- let directly_queried_node_indices = queried_nodes_in_layer(
- queries_to_layer.iter(),
- &self.input.configuration(),
- layer_depth,
- );
+ let directly_queried_node_indices =
+ queried_nodes_in_layer(queries_to_layer.iter(), &self.column_layout, layer_depth);
let mut index_value_iterator = directly_queried_node_indices
.iter()
.copied()
- .zip(self.layer_felt_witnesses_and_queried_elements(
+ .zip(Self::layer_felt_witnesses_and_queried_elements(
+ input,
layer_depth,
queries_to_layer.iter(),
directly_queried_node_indices.iter().copied(),
@@ -240,7 +276,7 @@ where
decommitment.witness_elements.extend(witness);
decommitment.queried_values.extend(queried);
} else {
- let injected_elements = self.input.get_injected_elements(layer_depth, node_index);
+ let injected_elements = input.get_injected_elements(layer_depth, node_index);
decommitment.witness_elements.extend(injected_elements);
}
}
@@ -250,7 +286,7 @@ where
// Returns the felt witnesses and queried elements for the given node indices in the specified
// layer. Assumes that the queries & node indices are sorted in ascending order.
fn layer_felt_witnesses_and_queried_elements(
- &self,
+ input: &MerkleTreeInput<'a, F>,
layer_depth: usize,
queries: impl Iterator
- >,
node_indices: impl ExactSizeIterator
- ,
@@ -265,8 +301,7 @@ where
for (node_index, (witness_elements, queried_elements)) in
node_indices.zip(witnesses_and_queried_values_by_node.iter_mut())
{
- for (column, column_queries) in self
- .input
+ for (column, column_queries) in input
.get_columns(layer_depth)
.iter()
.zip(column_query_iterators.iter_mut())
@@ -302,10 +337,10 @@ where
/// was inserted to the tree's input in that layer.
pub fn queried_nodes_in_layer<'a>(
queries: impl Iterator
- >,
- config: &MerkleTreeConfig,
+ column_layout: &MerkleTreeColumnLayout,
layer_depth: usize,
) -> Vec {
- let columns_lengths = config.column_lengths_at_depth(layer_depth);
+ let columns_lengths = column_layout.column_lengths_at_depth(layer_depth);
let column_log_lengths = columns_lengths.iter().map(|c_len| c_len.ilog2() as usize);
let mut node_queries = queries
.into_iter()
@@ -329,24 +364,33 @@ mod tests {
use itertools::Itertools;
- use super::{queried_nodes_in_layer, MixedDegreeMerkleTree, MixedDegreeMerkleTreeConfig};
- use crate::commitment_scheme::blake2_hash::Blake2sHasher;
+ use super::{MixedDegreeMerkleTree, MixedDegreeMerkleTreeConfig};
use crate::commitment_scheme::blake3_hash::Blake3Hasher;
use crate::commitment_scheme::hasher::Hasher;
use crate::commitment_scheme::merkle_input::MerkleTreeInput;
+ use crate::commitment_scheme::mixed_degree_merkle_tree::queried_nodes_in_layer;
use crate::core::fields::m31::M31;
use crate::core::fields::Field;
use crate::m31;
+ fn hash_symmetric_path(
+ initial_value: &[H::NativeType],
+ path_length: usize,
+ ) -> H::Hash {
+ (1..path_length).fold(H::hash(initial_value), |curr_hash, _| {
+ H::concat_and_hash(&curr_hash, &curr_hash)
+ })
+ }
+
#[test]
- fn new_mixed_degree_merkle_tree_test() {
+ fn commit_configured_multi_layer_sizes_test() {
let mut input = super::MerkleTreeInput::::new();
let column = vec![M31::from_u32_unchecked(0); 1 << 12];
input.insert_column(12, &column);
let multi_layer_sizes = [5, 4, 3].to_vec();
- let tree = MixedDegreeMerkleTree::::new(
- input,
+ let (tree, _root) = MixedDegreeMerkleTree::::commit(
+ &input,
MixedDegreeMerkleTreeConfig {
multi_layer_sizes: multi_layer_sizes.clone(),
},
@@ -368,32 +412,23 @@ mod tests {
#[test]
#[should_panic]
- fn new_mixed_degree_merkle_tree_bad_config_test() {
+ fn mixed_degree_merkle_tree_bad_config_test() {
let mut input = super::MerkleTreeInput::::new();
let column = vec![M31::from_u32_unchecked(0); 4096];
input.insert_column(12, &column);
// This should panic because the sum of the layer heights is not equal to the tree height
// deferred by the input.
- MixedDegreeMerkleTree::::new(
- input,
+ MixedDegreeMerkleTree::::commit(
+ &input,
MixedDegreeMerkleTreeConfig {
multi_layer_sizes: [5, 4, 2].to_vec(),
},
);
}
- fn hash_symmetric_path(
- initial_value: &[H::NativeType],
- path_length: usize,
- ) -> H::Hash {
- (1..path_length).fold(H::hash(initial_value), |curr_hash, _| {
- H::concat_and_hash(&curr_hash, &curr_hash)
- })
- }
-
#[test]
- fn commit_test() {
+ fn commit_default_test() {
const TREE_HEIGHT: usize = 8;
const INJECT_DEPTH: usize = 3;
let mut input = super::MerkleTreeInput::::new();
@@ -401,12 +436,7 @@ mod tests {
let injected_column = vec![M31::from_u32_unchecked(1); 1 << (INJECT_DEPTH - 1)];
input.insert_column(TREE_HEIGHT + 1, &base_column);
input.insert_column(INJECT_DEPTH, &injected_column);
- let mut tree = MixedDegreeMerkleTree::::new(
- input,
- MixedDegreeMerkleTreeConfig {
- multi_layer_sizes: [5, 2, 2].to_vec(),
- },
- );
+
let expected_hash_at_injected_depth = hash_symmetric_path::(
0_u32.to_le_bytes().as_ref(),
TREE_HEIGHT + 1 - INJECT_DEPTH,
@@ -417,23 +447,38 @@ mod tests {
let expected_result =
hash_symmetric_path::(sack_at_injected_depth.as_ref(), INJECT_DEPTH);
- let root = tree.commit();
+ let (_, root) = MixedDegreeMerkleTree::::commit_default(&input);
assert_eq!(root, expected_result);
}
+ #[test]
+ fn commit_configured_test() {
+ const TREE_HEIGHT: usize = 8;
+ const INJECT_DEPTH: usize = 3;
+ let mut input = super::MerkleTreeInput::::new();
+ let base_column = vec![M31::from_u32_unchecked(0); 1 << (TREE_HEIGHT)];
+ let injected_column = vec![M31::from_u32_unchecked(1); 1 << (INJECT_DEPTH - 1)];
+ input.insert_column(TREE_HEIGHT + 1, &base_column);
+ input.insert_column(INJECT_DEPTH, &injected_column);
+
+ let config = super::MixedDegreeMerkleTreeConfig {
+ multi_layer_sizes: vec![5, 2, 2],
+ };
+ let (_, expected) = MixedDegreeMerkleTree::::commit_default(&input);
+
+ let (_, root) = MixedDegreeMerkleTree::::commit(&input, config);
+
+ assert_eq!(root, expected);
+ }
+
#[test]
fn get_hash_at_test() {
const TREE_HEIGHT: usize = 3;
let mut input = super::MerkleTreeInput::::new();
let base_column = (0..4).map(M31::from_u32_unchecked).collect::>();
input.insert_column(TREE_HEIGHT, &base_column);
- let mut tree = MixedDegreeMerkleTree::::new(
- input,
- MixedDegreeMerkleTreeConfig {
- multi_layer_sizes: [2, 1].to_vec(),
- },
- );
- let root = tree.commit();
+
+ let (tree, root) = MixedDegreeMerkleTree::::commit_default(&input);
assert_eq!(root, tree.get_hash_at(0, 0));
let mut hasher = Blake3Hasher::new();
@@ -465,12 +510,7 @@ mod tests {
let mut input = super::MerkleTreeInput::::new();
let base_column = (0..4).map(M31::from_u32_unchecked).collect::>();
input.insert_column(TREE_HEIGHT, &base_column);
- let tree = MixedDegreeMerkleTree::::new(
- input,
- MixedDegreeMerkleTreeConfig {
- multi_layer_sizes: [2, 1].to_vec(),
- },
- );
+ let (tree, _) = MixedDegreeMerkleTree::::commit_default(&input);
tree.get_hash_at(4, 0);
}
@@ -488,7 +528,7 @@ mod tests {
.collect::>();
super::queried_nodes_in_layer(
column_queries_at_depth.iter(),
- &input.configuration(),
+ &input.column_layout(),
i,
)
})
@@ -544,12 +584,8 @@ mod tests {
merkle_input.insert_column(4, &col_length_8);
merkle_input.insert_column(3, &col_length_8);
merkle_input.insert_column(3, &col_length_4);
- let tree = MixedDegreeMerkleTree::::new(
- merkle_input,
- MixedDegreeMerkleTreeConfig {
- multi_layer_sizes: [4].to_vec(),
- },
- );
+ let (tree, _root) =
+ MixedDegreeMerkleTree::::commit_default(&merkle_input);
let zero_column_queries = vec![0, 15];
let first_column_queries = vec![0, 7];
@@ -562,20 +598,22 @@ mod tests {
third_column_queries,
];
- let node_indices =
- queried_nodes_in_layer(queries.iter().take(2), &tree.input.configuration(), 4);
- let w4 = tree.layer_felt_witnesses_and_queried_elements(
- 4,
- queries[..2].iter(),
- node_indices.iter().copied(),
- );
- let node_indices =
- queried_nodes_in_layer(queries.iter().skip(2), &tree.input.configuration(), 3);
- let w3 = tree.layer_felt_witnesses_and_queried_elements(
- 4,
- queries[2..4].iter(),
- node_indices.iter().copied(),
- );
+ let node_indices = queried_nodes_in_layer(queries.iter().take(2), &tree.column_layout, 4);
+ let w4 =
+ MixedDegreeMerkleTree::::layer_felt_witnesses_and_queried_elements(
+ &merkle_input,
+ 4,
+ queries[..2].iter(),
+ node_indices.iter().copied(),
+ );
+ let node_indices = queried_nodes_in_layer(queries.iter().skip(2), &tree.column_layout, 3);
+ let w3 =
+ MixedDegreeMerkleTree::::layer_felt_witnesses_and_queried_elements(
+ &merkle_input,
+ 4,
+ queries[2..4].iter(),
+ node_indices.iter().copied(),
+ );
assert_eq!(
format!("{:?}", w4),
@@ -603,14 +641,8 @@ mod tests {
input.insert_column(TREE_HEIGHT - 6, &column_2);
input.insert_column(TREE_HEIGHT - 4, &column_1);
input.insert_column(TREE_HEIGHT, &column_3);
- let configuration = input.configuration();
- let mut tree = MixedDegreeMerkleTree::::new(
- input,
- MixedDegreeMerkleTreeConfig {
- multi_layer_sizes: vec![8],
- },
- );
- let commitment = tree.commit();
+ let configuration = input.column_layout();
+ let (tree, commitment) = MixedDegreeMerkleTree::::commit_default(&input);
let queries: Vec> = vec![
vec![2],
vec![0],
@@ -621,7 +653,7 @@ mod tests {
vec![0, 1, 1000, 4095],
];
- let test_decommitment = tree.decommit(&queries);
+ let test_decommitment = tree.decommit(&input, &queries);
assert!(test_decommitment.verify(
commitment,
&configuration,