1use crate::{
4 alphas::Alphas,
5 circuits::{
6 berkeley_columns::{BerkeleyChallengeTerm, Column},
7 constraints::{ColumnEvaluations, ConstraintSystem},
8 expr::{Linearization, PolishToken},
9 },
10 curve::KimchiCurve,
11 linearization::expr_linearization,
12 o1_utils::lazy_cache::LazyCache,
13 verifier_index::VerifierIndex,
14};
15use ark_ff::PrimeField;
16use mina_poseidon::FqSponge;
17use poly_commitment::SRS;
18use serde::{de::DeserializeOwned, Deserialize, Serialize};
19use serde_with::serde_as;
20use std::sync::Arc;
21
22#[serde_as]
24#[derive(Serialize, Deserialize, Clone, Debug)]
25pub struct ProverIndex<const FULL_ROUNDS: usize, G: KimchiCurve<FULL_ROUNDS>, Srs> {
27 #[serde(bound = "ConstraintSystem<G::ScalarField>: Serialize + DeserializeOwned")]
29 pub cs: Arc<ConstraintSystem<G::ScalarField>>,
30
31 #[serde(skip)]
33 pub linearization:
34 Linearization<Vec<PolishToken<G::ScalarField, Column, BerkeleyChallengeTerm>>, Column>,
35
36 #[serde(skip)]
38 pub powers_of_alpha: Alphas<G::ScalarField>,
39
40 #[serde(skip)]
42 pub srs: Arc<Srs>,
43
44 pub max_poly_size: usize,
46
47 #[serde(bound = "ColumnEvaluations<G::ScalarField>: Serialize + DeserializeOwned")]
48 pub column_evaluations: Arc<LazyCache<ColumnEvaluations<G::ScalarField>>>,
49
50 #[serde(skip)]
52 pub verifier_index: Option<VerifierIndex<FULL_ROUNDS, G, Srs>>,
53
54 #[serde_as(as = "Option<o1_utils::serialization::SerdeAs>")]
56 pub verifier_index_digest: Option<G::BaseField>,
57}
58impl<const FULL_ROUNDS: usize, G: KimchiCurve<FULL_ROUNDS>, Srs: SRS<G>>
61 ProverIndex<FULL_ROUNDS, G, Srs>
62where
63 G::BaseField: PrimeField,
64{
65 pub fn create(
67 mut cs: ConstraintSystem<G::ScalarField>,
68 endo_q: G::ScalarField,
69 srs: Arc<Srs>,
70 lazy_mode: bool,
71 ) -> Self {
72 let max_poly_size = srs.max_poly_size();
73 cs.endo = endo_q;
74
75 let (linearization, powers_of_alpha) = expr_linearization(Some(&cs.feature_flags), true);
77
78 let evaluated_column_coefficients = cs.evaluated_column_coefficients();
79
80 let cs = Arc::new(cs);
81 let cs_clone = Arc::clone(&cs);
82 let column_evaluations =
83 LazyCache::new(move || cs_clone.column_evaluations(&evaluated_column_coefficients));
84 if !lazy_mode {
85 column_evaluations.get();
87 };
88
89 ProverIndex {
90 cs,
91 linearization,
92 powers_of_alpha,
93 srs,
94 max_poly_size,
95 column_evaluations: Arc::new(column_evaluations),
96 verifier_index: None,
97 verifier_index_digest: None,
98 }
99 }
100
101 pub fn compute_verifier_index_digest<
104 EFqSponge: Clone + FqSponge<G::BaseField, G, G::ScalarField, FULL_ROUNDS>,
105 >(
106 &mut self,
107 ) -> G::BaseField
108 where
109 VerifierIndex<FULL_ROUNDS, G, Srs>: Clone,
110 {
111 if let Some(verifier_index_digest) = self.verifier_index_digest {
112 return verifier_index_digest;
113 }
114
115 if self.verifier_index.is_none() {
116 self.verifier_index = Some(self.verifier_index());
117 }
118
119 let verifier_index_digest = self.verifier_index_digest::<EFqSponge>();
120 self.verifier_index_digest = Some(verifier_index_digest);
121 verifier_index_digest
122 }
123
124 pub fn verifier_index_digest<
126 EFqSponge: Clone + FqSponge<G::BaseField, G, G::ScalarField, FULL_ROUNDS>,
127 >(
128 &self,
129 ) -> G::BaseField
130 where
131 VerifierIndex<FULL_ROUNDS, G, Srs>: Clone,
132 {
133 if let Some(verifier_index_digest) = self.verifier_index_digest {
134 return verifier_index_digest;
135 }
136
137 match &self.verifier_index {
138 None => {
139 let verifier_index = self.verifier_index();
140 verifier_index.digest::<EFqSponge>()
141 }
142 Some(verifier_index) => verifier_index.digest::<EFqSponge>(),
143 }
144 }
145}
146
147pub mod testing {
148 use super::*;
149 use crate::circuits::{
150 gate::CircuitGate,
151 lookup::{runtime_tables::RuntimeTableCfg, tables::LookupTable},
152 };
153 use ark_ff::PrimeField;
154 use ark_poly::{EvaluationDomain, Radix2EvaluationDomain as D};
155 use poly_commitment::{ipa::OpeningProof, precomputed_srs, OpenProof, SRS};
156
157 #[allow(clippy::too_many_arguments)]
158 pub fn new_index_for_test_with_lookups_and_custom_srs<const FULL_ROUNDS: usize, G, Srs, F>(
159 gates: Vec<CircuitGate<G::ScalarField>>,
160 public: usize,
161 prev_challenges: usize,
162 lookup_tables: Vec<LookupTable<G::ScalarField>>,
163 runtime_tables: Option<Vec<RuntimeTableCfg<G::ScalarField>>>,
164 disable_gates_checks: bool,
165 override_srs_size: Option<usize>,
166 mut get_srs: F,
167 lazy_mode: bool,
168 ) -> ProverIndex<FULL_ROUNDS, G, Srs>
169 where
170 G: KimchiCurve<FULL_ROUNDS>,
171 Srs: SRS<G>,
172 F: FnMut(D<G::ScalarField>, usize) -> Srs,
173 G::BaseField: PrimeField,
174 G::ScalarField: PrimeField,
175 {
176 let cs = ConstraintSystem::<G::ScalarField>::create(gates)
178 .lookup(lookup_tables)
179 .runtime(runtime_tables)
180 .public(public)
181 .prev_challenges(prev_challenges)
182 .disable_gates_checks(disable_gates_checks)
183 .max_poly_size(override_srs_size)
184 .lazy_mode(lazy_mode)
185 .build()
186 .unwrap();
187
188 let srs_size = override_srs_size.unwrap_or_else(|| cs.domain.d1.size());
189 let srs = get_srs(cs.domain.d1, srs_size);
190 let srs = Arc::new(srs);
191
192 let &endo_q = G::other_curve_endo();
193 ProverIndex::create(cs, endo_q, srs, lazy_mode)
194 }
195
196 pub fn new_index_for_test_with_lookups<const FULL_ROUNDS: usize, G: KimchiCurve<FULL_ROUNDS>>(
202 gates: Vec<CircuitGate<G::ScalarField>>,
203 public: usize,
204 prev_challenges: usize,
205 lookup_tables: Vec<LookupTable<G::ScalarField>>,
206 runtime_tables: Option<Vec<RuntimeTableCfg<G::ScalarField>>>,
207 disable_gates_checks: bool,
208 override_srs_size: Option<usize>,
209 lazy_mode: bool,
210 ) -> ProverIndex<FULL_ROUNDS, G, <OpeningProof<G, FULL_ROUNDS> as OpenProof<G, FULL_ROUNDS>>::SRS>
211 where
212 G::BaseField: PrimeField,
213 G::ScalarField: PrimeField,
214 {
215 new_index_for_test_with_lookups_and_custom_srs::<FULL_ROUNDS, _, _, _>(
216 gates,
217 public,
218 prev_challenges,
219 lookup_tables,
220 runtime_tables,
221 disable_gates_checks,
222 override_srs_size,
223 |d1: D<G::ScalarField>, size: usize| {
224 let log2_size = size.ilog2();
225 let srs = if log2_size <= precomputed_srs::SERIALIZED_SRS_SIZE {
226 precomputed_srs::get_srs_test()
228 } else {
229 SRS::<G>::create(size)
231 };
232
233 srs.get_lagrange_basis(d1);
234 srs
235 },
236 lazy_mode,
237 )
238 }
239
240 pub fn new_index_for_test<const FULL_ROUNDS: usize, G: KimchiCurve<FULL_ROUNDS>>(
241 gates: Vec<CircuitGate<G::ScalarField>>,
242 public: usize,
243 ) -> ProverIndex<FULL_ROUNDS, G, poly_commitment::ipa::SRS<G>>
244 where
245 G::BaseField: PrimeField,
246 G::ScalarField: PrimeField,
247 {
248 new_index_for_test_with_lookups::<FULL_ROUNDS, G>(
249 gates,
250 public,
251 0,
252 vec![],
253 None,
254 false,
255 None,
256 false,
257 )
258 }
259}