Skip to main content

p3_commit/adapters/
extension_mmcs.rs

1use alloc::vec::Vec;
2use core::marker::PhantomData;
3use core::ops::Deref;
4
5use p3_field::{ExtensionField, Field};
6use p3_matrix::extension::FlatMatrixView;
7use p3_matrix::{Dimensions, Matrix};
8
9use crate::{BatchOpening, BatchOpeningRef, Mmcs};
10
11/// A wrapper to lift an MMCS from a base field `F` to an extension field `EF`.
12///
13/// `ExtensionMmcs` allows committing to and opening matrices over an extension field by internally
14/// using an MMCS defined on the base field. It works by flattening each extension field element
15/// into its base field coordinates for commitment, and then reconstructing them on opening.
16#[derive(Clone, Debug)]
17pub struct ExtensionMmcs<F, EF, InnerMmcs> {
18    /// The inner MMCS instance used to handle commitments at the base field level.
19    pub(crate) inner: InnerMmcs,
20
21    pub(crate) _phantom: PhantomData<(F, EF)>,
22}
23
24impl<F, EF, InnerMmcs> ExtensionMmcs<F, EF, InnerMmcs> {
25    pub const fn new(inner: InnerMmcs) -> Self {
26        Self {
27            inner,
28            _phantom: PhantomData,
29        }
30    }
31}
32
33impl<F, EF, InnerMmcs> Mmcs<EF> for ExtensionMmcs<F, EF, InnerMmcs>
34where
35    F: Field,
36    EF: ExtensionField<F>,
37    InnerMmcs: Mmcs<F>,
38{
39    type ProverData<M> = InnerMmcs::ProverData<FlatMatrixView<F, EF, M>>;
40    type Commitment = InnerMmcs::Commitment;
41    type Proof = InnerMmcs::Proof;
42    type MultiProof = InnerMmcs::MultiProof;
43    type Error = InnerMmcs::Error;
44
45    fn commit<M: Matrix<EF>>(&self, inputs: Vec<M>) -> (Self::Commitment, Self::ProverData<M>) {
46        self.inner
47            .commit(inputs.into_iter().map(FlatMatrixView::new).collect())
48    }
49
50    fn open_batch<M: Matrix<EF>>(
51        &self,
52        index: usize,
53        prover_data: &Self::ProverData<M>,
54    ) -> BatchOpening<EF, Self> {
55        let (inner_opened_values, inner_proof) = self.inner.open_batch(index, prover_data).unpack();
56        let opened_ext_values = inner_opened_values
57            .into_iter()
58            .map(EF::reconstitute_from_base)
59            .collect();
60        BatchOpening::new(opened_ext_values, inner_proof)
61    }
62
63    fn get_matrices<'a, M: Matrix<EF>>(&self, prover_data: &'a Self::ProverData<M>) -> Vec<&'a M> {
64        self.inner
65            .get_matrices(prover_data)
66            .into_iter()
67            .map(|mat| mat.deref())
68            .collect()
69    }
70
71    fn verify_batch(
72        &self,
73        commit: &Self::Commitment,
74        dimensions: &[Dimensions],
75        index: usize,
76        batch_opening: BatchOpeningRef<'_, EF, Self>,
77    ) -> Result<(), Self::Error> {
78        let opened_base_values: Vec<Vec<F>> = batch_opening
79            .opened_values
80            .iter()
81            .cloned()
82            .map(EF::flatten_to_base)
83            .collect();
84        let base_dimensions = dimensions
85            .iter()
86            .map(|dim| Dimensions {
87                width: dim.width * EF::DIMENSION,
88                height: dim.height,
89            })
90            .collect::<Vec<_>>();
91        self.inner.verify_batch(
92            commit,
93            &base_dimensions,
94            index,
95            BatchOpeningRef::new(&opened_base_values, batch_opening.opening_proof),
96        )
97    }
98
99    fn open_multi_batch<M: Matrix<EF>>(
100        &self,
101        indices: &[usize],
102        prover_data: &Self::ProverData<M>,
103    ) -> (Vec<Vec<Vec<EF>>>, Self::MultiProof) {
104        let (base_values, proof) = self.inner.open_multi_batch(indices, prover_data);
105        let ext_values = base_values
106            .into_iter()
107            .map(|rows| rows.into_iter().map(EF::reconstitute_from_base).collect())
108            .collect();
109        (ext_values, proof)
110    }
111
112    fn verify_multi_batch<R: AsRef<[EF]> + PartialEq>(
113        &self,
114        commit: &Self::Commitment,
115        dimensions: &[Dimensions],
116        indices: &[usize],
117        opened_values: &[Vec<R>],
118        proof: &Self::MultiProof,
119    ) -> Result<(), Self::Error> {
120        // Each extension row reinterprets as `EF::DIMENSION` base elements.
121        // This layer always materializes owned base rows.
122        let opened_base_values: Vec<Vec<Vec<F>>> = opened_values
123            .iter()
124            .map(|rows| {
125                rows.iter()
126                    .map(|row| EF::flatten_to_base(row.as_ref().to_vec()))
127                    .collect()
128            })
129            .collect();
130        let base_dimensions = dimensions
131            .iter()
132            .map(|dim| Dimensions {
133                width: dim.width * EF::DIMENSION,
134                height: dim.height,
135            })
136            .collect::<Vec<_>>();
137        self.inner.verify_multi_batch(
138            commit,
139            &base_dimensions,
140            indices,
141            &opened_base_values,
142            proof,
143        )
144    }
145}