p3_commit/
testing.rs

1use alloc::vec;
2use alloc::vec::Vec;
3use core::marker::PhantomData;
4
5use p3_challenger::CanSample;
6use p3_dft::TwoAdicSubgroupDft;
7use p3_field::coset::TwoAdicMultiplicativeCoset;
8use p3_field::{ExtensionField, Field, TwoAdicField};
9use p3_matrix::Matrix;
10use p3_matrix::dense::RowMajorMatrix;
11use p3_util::log2_strict_usize;
12use p3_util::zip_eq::zip_eq;
13use serde::{Deserialize, Serialize};
14
15use crate::{OpenedValues, Pcs, PolynomialSpace};
16
17/// A trivial PCS: its commitment is simply the coefficients of each poly.
18#[derive(Debug)]
19pub struct TrivialPcs<Val: TwoAdicField, Dft: TwoAdicSubgroupDft<Val>> {
20    pub dft: Dft,
21    // degree bound
22    pub log_n: usize,
23    pub _phantom: PhantomData<Val>,
24}
25
26pub fn eval_coeffs_at_pt<F: Field, EF: ExtensionField<F>>(
27    coeffs: &RowMajorMatrix<F>,
28    x: EF,
29) -> Vec<EF> {
30    let mut acc = vec![EF::ZERO; coeffs.width()];
31    for r in (0..coeffs.height()).rev() {
32        let row = coeffs.row_slice(r).unwrap();
33        for (acc_c, row_c) in acc.iter_mut().zip(row.iter()) {
34            *acc_c *= x;
35            *acc_c += *row_c;
36        }
37    }
38    acc
39}
40
41impl<Val, Dft, Challenge, Challenger> Pcs<Challenge, Challenger> for TrivialPcs<Val, Dft>
42where
43    Val: TwoAdicField,
44    Challenge: ExtensionField<Val>,
45    Challenger: CanSample<Challenge>,
46    Dft: TwoAdicSubgroupDft<Val>,
47    Vec<Vec<Val>>: Serialize + for<'de> Deserialize<'de>,
48{
49    type Domain = TwoAdicMultiplicativeCoset<Val>;
50    type Commitment = Vec<Vec<Val>>;
51    type ProverData = Vec<RowMajorMatrix<Val>>;
52    type EvaluationsOnDomain<'a> = Dft::Evaluations;
53    type Proof = ();
54    type Error = ();
55    const ZK: bool = false;
56
57    fn natural_domain_for_degree(&self, degree: usize) -> Self::Domain {
58        // This panics if (and only if) `degree` is not a power of 2 or `degree`
59        // > `1 << Val::TWO_ADICITY`.
60        TwoAdicMultiplicativeCoset::new(Val::ONE, log2_strict_usize(degree)).unwrap()
61    }
62
63    fn commit(
64        &self,
65        evaluations: impl IntoIterator<Item = (Self::Domain, RowMajorMatrix<Val>)>,
66    ) -> (Self::Commitment, Self::ProverData) {
67        let coeffs: Vec<_> = evaluations
68            .into_iter()
69            .map(|(domain, evals)| {
70                let log_domain_size = log2_strict_usize(domain.size());
71                // for now, only commit on larger domain than natural
72                assert!(log_domain_size >= self.log_n);
73                assert_eq!(domain.size(), evals.height());
74                // coset_idft_batch
75                let mut coeffs = self.dft.idft_batch(evals);
76                coeffs
77                    .rows_mut()
78                    .zip(domain.shift_inverse().powers())
79                    .for_each(|(row, weight)| {
80                        row.iter_mut().for_each(|coeff| {
81                            *coeff *= weight;
82                        });
83                    });
84                coeffs
85            })
86            .collect();
87        (
88            coeffs.clone().into_iter().map(|m| m.values).collect(),
89            coeffs,
90        )
91    }
92
93    fn commit_quotient(
94        &self,
95        quotient_domain: Self::Domain,
96        quotient_evaluations: RowMajorMatrix<crate::Val<Self::Domain>>,
97        num_chunks: usize,
98    ) -> (Self::Commitment, Self::ProverData) {
99        let quotient_sub_evaluations =
100            quotient_domain.split_evals(num_chunks, quotient_evaluations);
101        let quotient_sub_domains = quotient_domain.split_domains(num_chunks);
102
103        Pcs::<Challenge, Challenger>::commit(
104            self,
105            quotient_sub_domains
106                .into_iter()
107                .zip(quotient_sub_evaluations),
108        )
109    }
110
111    fn get_quotient_ldes(
112        &self,
113        _evaluations: impl IntoIterator<Item = (Self::Domain, RowMajorMatrix<Val>)>,
114        _num_chunks: usize,
115    ) -> Vec<RowMajorMatrix<crate::Val<Self::Domain>>> {
116        unimplemented!("This PCS does not support computing of LDEs");
117    }
118
119    fn commit_ldes(&self, _ldes: Vec<RowMajorMatrix<Val>>) -> (Self::Commitment, Self::ProverData) {
120        unimplemented!("This PCS does not support computing of LDEs");
121    }
122
123    fn get_evaluations_on_domain<'a>(
124        &self,
125        prover_data: &'a Self::ProverData,
126        idx: usize,
127        domain: Self::Domain,
128    ) -> Self::EvaluationsOnDomain<'a> {
129        let mut coeffs = prover_data[idx].clone();
130        assert!(domain.log_size() >= self.log_n);
131        coeffs.values.resize(
132            coeffs.values.len() << (domain.log_size() - self.log_n),
133            Val::ZERO,
134        );
135        self.dft.coset_dft_batch(coeffs, domain.shift())
136    }
137
138    fn open(
139        &self,
140        // For each round,
141        rounds: Vec<(
142            &Self::ProverData,
143            // for each matrix,
144            Vec<
145                // points to open
146                Vec<Challenge>,
147            >,
148        )>,
149        _challenger: &mut Challenger,
150    ) -> (OpenedValues<Challenge>, Self::Proof) {
151        (
152            rounds
153                .into_iter()
154                .map(|(coeffs_for_round, points_for_round)| {
155                    // ensure that each matrix corresponds to a set of opening points
156                    debug_assert_eq!(coeffs_for_round.len(), points_for_round.len());
157                    coeffs_for_round
158                        .iter()
159                        .zip(points_for_round)
160                        .map(|(coeffs_for_mat, points_for_mat)| {
161                            points_for_mat
162                                .into_iter()
163                                .map(|pt| eval_coeffs_at_pt(coeffs_for_mat, pt))
164                                .collect()
165                        })
166                        .collect()
167                })
168                .collect(),
169            (),
170        )
171    }
172
173    // This is a testing function, so we allow panics for convenience.
174    #[allow(clippy::panic_in_result_fn)]
175    fn verify(
176        &self,
177        // For each round:
178        rounds: Vec<(
179            Self::Commitment,
180            // for each matrix:
181            Vec<(
182                // its domain,
183                Self::Domain,
184                // for each point:
185                Vec<(
186                    Challenge,
187                    // values at this point
188                    Vec<Challenge>,
189                )>,
190            )>,
191        )>,
192        _proof: &Self::Proof,
193        _challenger: &mut Challenger,
194    ) -> Result<(), Self::Error> {
195        for (comm, round_opening) in rounds {
196            for (coeff_vec, (domain, points_and_values)) in zip_eq(comm, round_opening, ())? {
197                let width = coeff_vec.len() / domain.size();
198                assert_eq!(width * domain.size(), coeff_vec.len());
199                let coeffs = RowMajorMatrix::new(coeff_vec, width);
200                for (pt, values) in points_and_values {
201                    assert_eq!(eval_coeffs_at_pt(&coeffs, pt), values);
202                }
203            }
204        }
205        Ok(())
206    }
207}