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