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#[derive(Debug)]
19pub struct TrivialPcs<Val: TwoAdicField, Dft: TwoAdicSubgroupDft<Val>> {
20 pub dft: Dft,
21 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 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 assert!(log_domain_size >= self.log_n);
73 assert_eq!(domain.size(), evals.height());
74 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 rounds: Vec<(
142 &Self::ProverData,
143 Vec<
145 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 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 #[allow(clippy::panic_in_result_fn)]
175 fn verify(
176 &self,
177 rounds: Vec<(
179 Self::Commitment,
180 Vec<(
182 Self::Domain,
184 Vec<(
186 Challenge,
187 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}