lib_q_stark_commit/mmcs.rs
1use alloc::vec;
2use alloc::vec::Vec;
3use core::fmt::Debug;
4
5use lib_q_stark_matrix::dense::RowMajorMatrix;
6use lib_q_stark_matrix::{
7 Dimensions,
8 Matrix,
9};
10use serde::de::DeserializeOwned;
11use serde::{
12 Deserialize,
13 Serialize,
14};
15
16/// A "Mixed Matrix Commitment Scheme" (MMCS) is a generalization of a vector commitment scheme.
17///
18/// It supports committing to matrices and then opening rows. It is also batch-oriented; one can commit
19/// to a batch of matrices at once even if their widths and heights differ.
20///
21/// When a particular row index is opened, it is interpreted directly as a row index for matrices
22/// with the largest height. For matrices with smaller heights, some bits of the row index are
23/// removed (from the least-significant side) to get the effective row index. These semantics are
24/// useful in the FRI protocol. See the documentation for `open_batch` for more details.
25pub trait Mmcs<T: Send + Sync + Clone>: Clone {
26 type ProverData<M>;
27 type Commitment: Clone + Serialize + DeserializeOwned;
28 type Proof: Clone + Serialize + DeserializeOwned;
29 type Error: Debug;
30
31 /// Commits to a batch of matrices at once and returns both the commitment and associated prover data.
32 ///
33 /// Each matrix in the batch may have different dimensions.
34 ///
35 /// # Parameters
36 /// - `inputs`: A vector of matrices to commit to.
37 ///
38 /// # Returns
39 /// A tuple `(commitment, prover_data)` where:
40 /// - `commitment` is a compact representation of all matrix elements and will be sent to the verifier.
41 /// - `prover_data` is auxiliary data used by the prover open the commitment.
42 fn commit<M: Matrix<T>>(&self, inputs: Vec<M>) -> (Self::Commitment, Self::ProverData<M>);
43
44 /// Convenience method to commit to a single matrix.
45 ///
46 /// Internally wraps the matrix in a singleton vector and delegates to [`Mmcs::commit`].
47 ///
48 /// # Parameters
49 /// - `input`: The matrix to commit to.
50 ///
51 /// # Returns
52 /// A tuple `(commitment, prover_data)` as in [`Mmcs::commit`].
53 fn commit_matrix<M: Matrix<T>>(&self, input: M) -> (Self::Commitment, Self::ProverData<M>) {
54 self.commit(vec![input])
55 }
56
57 /// Convenience method to commit to a single column vector, treated as a column matrix.
58 ///
59 /// Automatically wraps the vector into a column matrix using [`RowMajorMatrix::new_col`].
60 ///
61 /// # Parameters
62 /// - `input`: A vector of field elements representing a single column.
63 ///
64 /// # Returns
65 /// A tuple `(commitment, prover_data)` for the resulting 1-column matrix.
66 fn commit_vec(&self, input: Vec<T>) -> (Self::Commitment, Self::ProverData<RowMajorMatrix<T>>)
67 where
68 T: Clone + Send + Sync,
69 {
70 self.commit_matrix(RowMajorMatrix::new_col(input))
71 }
72
73 /// Opens a specific row (identified by `index`) from each matrix in the batch.
74 ///
75 /// This function is designed to support batch opening semantics where matrices may have different heights.
76 /// The given index is interpreted relative to the maximum matrix height; smaller matrices apply a
77 /// bit-shift to extract the corresponding row.
78 ///
79 /// # Parameters
80 /// - `index`: The global row index (relative to max height).
81 /// - `prover_data`: Prover data returned from [`Mmcs::commit`] or related methods.
82 ///
83 /// # Returns
84 /// A [`BatchOpening`] containing the opened rows and the proof of their correctness.
85 ///
86 /// # Opening Index Semantics
87 /// For each matrix `M[i]`, the row index used is:
88 /// ```text
89 /// j = index >> (log2_ceil(max_height) - log2_ceil(M[i].height))
90 /// ```
91 fn open_batch<M: Matrix<T>>(
92 &self,
93 index: usize,
94 prover_data: &Self::ProverData<M>,
95 ) -> BatchOpening<T, Self>;
96
97 /// Returns references to all matrices originally committed to in the batch.
98 ///
99 /// This allows access to the underlying data for inspection or additional logic.
100 ///
101 /// # Parameters
102 /// - `prover_data`: The prover data returned by [`Mmcs::commit`].
103 ///
104 /// # Returns
105 /// A vector of references to the committed matrices.
106 fn get_matrices<'a, M: Matrix<T>>(&self, prover_data: &'a Self::ProverData<M>) -> Vec<&'a M>;
107
108 /// Returns the height (number of rows) of each matrix in the batch.
109 ///
110 /// This is a utility method derived from [`Mmcs::get_matrices`].
111 ///
112 /// # Parameters
113 /// - `prover_data`: The prover data returned by [`Mmcs::commit`].
114 ///
115 /// # Returns
116 /// A vector containing the height of each committed matrix.
117 fn get_matrix_heights<M: Matrix<T>>(&self, prover_data: &Self::ProverData<M>) -> Vec<usize> {
118 self.get_matrices(prover_data)
119 .iter()
120 .map(|matrix| matrix.height())
121 .collect()
122 }
123
124 /// Get the largest height of any committed matrix.
125 ///
126 /// # Panics
127 /// This may panic if there are no committed matrices.
128 fn get_max_height<M: Matrix<T>>(&self, prover_data: &Self::ProverData<M>) -> usize {
129 self.get_matrix_heights(prover_data)
130 .into_iter()
131 .max()
132 .unwrap_or_else(|| panic!("No committed matrices?"))
133 }
134
135 /// Verifies a batch opening at a specific row index against the original commitment.
136 ///
137 /// This is the verifier-side analogue of [`Mmcs::open_batch`]. The verifier receives:
138 /// - The original commitment.
139 /// - Dimensions of each matrix being opened (in the same order as originally committed).
140 /// - The global index used for opening (interpreted as in [`Mmcs::open_batch`]).
141 /// - A [`BatchOpeningRef`] containing the claimed opened values and the proof.
142 ///
143 /// # Parameters
144 /// - `commit`: The original commitment.
145 /// - `dimensions`: Dimensions of the committed matrices, in order.
146 /// - `index`: The global row index that was opened.
147 /// - `batch_opening`: A reference to the values and proof to verify.
148 ///
149 /// # Returns
150 /// `Ok(())` if the opening is valid; otherwise returns a verification error.
151 fn verify_batch(
152 &self,
153 commit: &Self::Commitment,
154 dimensions: &[Dimensions],
155 index: usize,
156 batch_opening: BatchOpeningRef<'_, T, Self>,
157 ) -> Result<(), Self::Error>;
158}
159
160/// A Batched opening proof.
161///
162/// Contains a collection of opened values at a Merkle proof for those openings.
163///
164/// Primarily used by the prover.
165#[derive(Serialize, Deserialize, Clone)]
166// Enable Serialize/Deserialize whenever T supports it.
167#[serde(bound(serialize = "T: Serialize"))]
168#[serde(bound(deserialize = "T: DeserializeOwned"))]
169pub struct BatchOpening<T: Send + Sync + Clone, InputMmcs: Mmcs<T>> {
170 /// The opened row values from each matrix in the batch.
171 /// Each inner vector corresponds to one matrix.
172 pub opened_values: Vec<Vec<T>>,
173 /// The proof showing the values are valid openings.
174 pub opening_proof: InputMmcs::Proof,
175}
176
177impl<T: Send + Sync + Clone, InputMmcs: Mmcs<T>> BatchOpening<T, InputMmcs> {
178 /// Creates a new batch opening proof.
179 #[inline]
180 pub const fn new(opened_values: Vec<Vec<T>>, opening_proof: InputMmcs::Proof) -> Self {
181 Self {
182 opened_values,
183 opening_proof,
184 }
185 }
186
187 /// Unpacks the batch opening proof into its components.
188 #[inline]
189 pub fn unpack(self) -> (Vec<Vec<T>>, InputMmcs::Proof) {
190 (self.opened_values, self.opening_proof)
191 }
192}
193
194/// A reference to a batched opening proof.
195///
196/// Contains references to a collection of claimed opening values and a Merkle proof for those values.
197///
198/// Primarily used by the verifier.
199#[derive(Copy, Clone)]
200pub struct BatchOpeningRef<'a, T: Send + Sync + Clone, InputMmcs: Mmcs<T>> {
201 /// Reference to the opened row values, as slices of base elements.
202 pub opened_values: &'a [Vec<T>],
203 /// Reference to the proof object used for verification.
204 pub opening_proof: &'a InputMmcs::Proof,
205}
206
207impl<'a, T: Send + Sync + Clone, InputMmcs: Mmcs<T>> BatchOpeningRef<'a, T, InputMmcs> {
208 /// Creates a new batch opening proof.
209 #[inline]
210 pub const fn new(opened_values: &'a [Vec<T>], opening_proof: &'a InputMmcs::Proof) -> Self {
211 Self {
212 opened_values,
213 opening_proof,
214 }
215 }
216
217 /// Unpacks the batch opening proof into its components.
218 #[inline]
219 pub const fn unpack(&self) -> (&'a [Vec<T>], &'a InputMmcs::Proof) {
220 (self.opened_values, self.opening_proof)
221 }
222}
223
224impl<'a, T: Send + Sync + Clone, InputMmcs: Mmcs<T>> From<&'a BatchOpening<T, InputMmcs>>
225 for BatchOpeningRef<'a, T, InputMmcs>
226{
227 #[inline]
228 fn from(batch_opening: &'a BatchOpening<T, InputMmcs>) -> Self {
229 Self::new(&batch_opening.opened_values, &batch_opening.opening_proof)
230 }
231}