Skip to main content

binius_iop_prover/merkle_tree/
mod.rs

1// Copyright 2025 Irreducible Inc.
2// Copyright 2026 The Binius Developers
3
4use binius_field::PackedField;
5use binius_iop::merkle_tree::{Commitment, MerkleTreeScheme};
6use binius_math::FieldSlice;
7use binius_transcript::{BufMut, TranscriptWriter};
8use binius_utils::{FixedSizeSerializeBytes, rayon::prelude::*};
9
10pub mod prover;
11#[cfg(test)]
12mod tests;
13
14/// The digest type produced by a Merkle tree prover's scheme.
15pub type ProverDigest<T, M> = <<M as MerkleTreeProver<T>>::Scheme as MerkleTreeScheme<T>>::Digest;
16
17/// A Merkle tree prover for a particular scheme.
18///
19/// This is separate from [`MerkleTreeScheme`] so that it may be implemented using a
20/// hardware-accelerated backend.
21pub trait MerkleTreeProver<T: FixedSizeSerializeBytes> {
22	type Scheme: MerkleTreeScheme<T>;
23	/// Data generated during commitment required to generate opening proofs.
24	type Committed;
25
26	/// Returns the Merkle tree scheme used by the prover.
27	fn scheme(&self) -> &Self::Scheme;
28
29	/// Commit a vector of values.
30	///
31	/// ## Preconditions
32	///
33	/// * `data.len()` must be a multiple of `batch_size`, and the resulting leaf count (`data.len()
34	///   / batch_size`) must be a power of two.
35	fn commit(
36		&self,
37		data: &[T],
38		batch_size: usize,
39	) -> (Commitment<ProverDigest<T, Self>>, Self::Committed)
40	where
41		T: Clone + Sync,
42	{
43		self.commit_iterated(
44			data.par_chunks_exact(batch_size)
45				.map(|chunk| chunk.iter().cloned()),
46			batch_size,
47		)
48	}
49
50	/// Commits a field buffer, packing `2^log_leaf_len` scalars into each leaf.
51	///
52	/// Scalars fill leaves in order:
53	///
54	/// ```text
55	/// leaf i  <-  buffer[i * 2^log_leaf_len .. (i+1) * 2^log_leaf_len]
56	/// ```
57	///
58	/// The leaf count is `2^(log_len - log_leaf_len)`, hence a power of two by construction.
59	/// That is what [`commit_iterated`](Self::commit_iterated) requires of it.
60	///
61	/// ## Preconditions
62	///
63	/// * `log_leaf_len` must be at most the buffer's log length.
64	fn commit_field_buffer<P>(
65		&self,
66		buffer: FieldSlice<'_, P>,
67		log_leaf_len: usize,
68	) -> (Commitment<ProverDigest<T, Self>>, Self::Committed)
69	where
70		P: PackedField<Scalar = T>,
71	{
72		// Invariant: leaves are counted in scalar space, never in backing words.
73		// A buffer narrower than one packed word therefore commits no dead lanes.
74		self.commit_iterated(buffer.par_chunk_scalars(log_leaf_len), 1 << log_leaf_len)
75	}
76
77	/// Commit interleaved elements from iterator by val
78	///
79	/// Each leaf is built from exactly `n_items_per_input` elements, which lets the leaf hasher
80	/// specialize for short, constant-length leaves.
81	///
82	/// ## Preconditions
83	///
84	/// * The number of leaves must be a power of two.
85	/// * Each iterator in `leaves` yields exactly `n_items_per_input` elements.
86	fn commit_iterated<ParIter>(
87		&self,
88		leaves: ParIter,
89		n_items_per_input: usize,
90	) -> (Commitment<ProverDigest<T, Self>>, Self::Committed)
91	where
92		ParIter: IndexedParallelIterator<Item: IntoIterator<Item = T, IntoIter: Send>>;
93
94	/// Returns the internal digest layer at the given depth.
95	///
96	/// ## Preconditions
97	///
98	/// * `layer_depth` must be at most the committed tree's depth.
99	fn layer<'a>(
100		&self,
101		committed: &'a Self::Committed,
102		layer_depth: usize,
103	) -> &'a [<Self::Scheme as MerkleTreeScheme<T>>::Digest];
104
105	/// Generate an opening proof for an entry in a committed vector at the given index.
106	///
107	/// ## Arguments
108	///
109	/// * `committed` - helper data generated during commitment
110	/// * `layer_depth` - depth of the layer to prove inclusion in
111	/// * `index` - the entry index
112	///
113	/// ## Preconditions
114	///
115	/// * `index` must be within the committed tree and `layer_depth` at most its depth.
116	fn prove_opening<B: BufMut>(
117		&self,
118		committed: &Self::Committed,
119		layer_depth: usize,
120		index: usize,
121		proof: &mut TranscriptWriter<'_, B>,
122	);
123}