p3_commit/
mmcs.rs

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