1use crate::{
2 arkworks::{CamlFq, CamlGPallas},
3 field_vector::fq::CamlFqVector,
4 pasta_fq_plonk_index::CamlPastaFqPlonkIndexPtr,
5 pasta_fq_plonk_verifier_index::CamlPastaFqPlonkVerifierIndex,
6};
7use ark_ec::AffineRepr;
8use ark_ff::One;
9use core::{array, convert::TryInto};
10use groupmap::GroupMap;
11use kimchi::{
12 circuits::{
13 lookup::runtime_tables::{caml::CamlRuntimeTable, RuntimeTable},
14 polynomial::COLUMNS,
15 },
16 proof::{
17 PointEvaluations, ProofEvaluations, ProverCommitments, ProverProof, RecursionChallenge,
18 },
19 prover::caml::CamlProofWithPublic,
20 prover_index::ProverIndex,
21 verifier::{batch_verify, Context},
22 verifier_index::VerifierIndex,
23};
24use mina_curves::pasta::{Fp, Fq, Pallas, PallasParameters};
25use mina_poseidon::{
26 constants::PlonkSpongeConstantsKimchi,
27 pasta::FULL_ROUNDS,
28 sponge::{DefaultFqSponge, DefaultFrSponge},
29};
30use poly_commitment::{
31 commitment::{CommitmentCurve, PolyComm},
32 ipa::OpeningProof,
33 lagrange_basis::WithLagrangeBasis,
34};
35
36type Srs =
37 <OpeningProof<Pallas, FULL_ROUNDS> as poly_commitment::OpenProof<Pallas, FULL_ROUNDS>>::SRS;
38
39#[ocaml_gen::func]
40#[ocaml::func]
41pub fn caml_pasta_fq_plonk_proof_create(
42 index: CamlPastaFqPlonkIndexPtr<'static>,
43 witness: Vec<CamlFqVector>,
44 runtime_tables: Vec<CamlRuntimeTable<CamlFq>>,
45 prev_challenges: Vec<CamlFq>,
46 prev_sgs: Vec<CamlGPallas>,
47) -> Result<CamlProofWithPublic<CamlGPallas, CamlFq>, ocaml::Error> {
48 {
49 index
50 .as_ref()
51 .0
52 .srs
53 .with_lagrange_basis(index.as_ref().0.cs.domain.d1);
54 }
55 let prev = if prev_challenges.is_empty() {
56 Vec::new()
57 } else {
58 let challenges_per_sg = prev_challenges.len() / prev_sgs.len();
59 prev_sgs
60 .into_iter()
61 .map(Into::<Pallas>::into)
62 .enumerate()
63 .map(|(i, sg)| {
64 let chals = prev_challenges[(i * challenges_per_sg)..(i + 1) * challenges_per_sg]
65 .iter()
66 .map(Into::<Fq>::into)
67 .collect();
68 let comm = PolyComm::<Pallas> { chunks: vec![sg] };
69 RecursionChallenge { chals, comm }
70 })
71 .collect()
72 };
73
74 let witness: Vec<Vec<_>> = witness.iter().map(|x| (**x).clone()).collect();
75 let witness: [Vec<_>; COLUMNS] = witness
76 .try_into()
77 .expect("the witness should be a column of 15 vectors");
78 let index: &ProverIndex<FULL_ROUNDS, Pallas, Srs> = &index.as_ref().0;
79
80 let runtime_tables: Vec<RuntimeTable<Fq>> =
81 runtime_tables.into_iter().map(Into::into).collect();
82
83 let public_input = witness[0][0..index.cs.public].to_vec();
85
86 if std::env::var("KIMCHI_PROVER_DUMP_ARGUMENTS").is_ok() {
87 kimchi::bench::bench_arguments_dump_into_file(&index.cs, &witness, &runtime_tables, &prev);
88 }
89
90 let runtime = unsafe { ocaml::Runtime::recover_handle() };
98
99 runtime.releasing_runtime(|| {
102 let group_map = GroupMap::<Fp>::setup();
103 let proof = ProverProof::create_recursive::<
104 DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
105 DefaultFrSponge<Fq, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
106 _,
107 >(
108 &group_map,
109 witness,
110 &runtime_tables,
111 index,
112 prev,
113 None,
114 &mut rand::rngs::OsRng,
115 )
116 .map_err(|e| ocaml::Error::Error(e.into()))?;
117 Ok((proof, public_input).into())
118 })
119}
120
121#[ocaml_gen::func]
122#[ocaml::func]
123pub fn caml_pasta_fq_plonk_proof_verify(
124 index: CamlPastaFqPlonkVerifierIndex,
125 proof: CamlProofWithPublic<CamlGPallas, CamlFq>,
126) -> bool {
127 let group_map = <Pallas as CommitmentCurve>::Map::setup();
128
129 let (proof, public_input) = proof.into();
130 let verifier_index = index.into();
131 let context = Context {
132 verifier_index: &verifier_index,
133 proof: &proof,
134 public_input: &public_input,
135 };
136
137 batch_verify::<
138 FULL_ROUNDS,
139 Pallas,
140 DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
141 DefaultFrSponge<Fq, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
142 OpeningProof<Pallas, FULL_ROUNDS>,
143 >(&group_map, &[context])
144 .is_ok()
145}
146
147#[ocaml_gen::func]
148#[ocaml::func]
149pub fn caml_pasta_fq_plonk_proof_batch_verify(
150 indexes: Vec<CamlPastaFqPlonkVerifierIndex>,
151 proofs: Vec<CamlProofWithPublic<CamlGPallas, CamlFq>>,
152) -> bool {
153 let ts: Vec<_> = indexes
154 .into_iter()
155 .zip(proofs.into_iter())
156 .map(|(caml_index, caml_proof)| {
157 let verifier_index: VerifierIndex<FULL_ROUNDS, Pallas, Srs> = caml_index.into();
158 let (proof, public_input): (
159 ProverProof<Pallas, OpeningProof<Pallas, FULL_ROUNDS>, FULL_ROUNDS>,
160 Vec<_>,
161 ) = caml_proof.into();
162 (verifier_index, proof, public_input)
163 })
164 .collect();
165 let ts_ref: Vec<Context<FULL_ROUNDS, Pallas, OpeningProof<Pallas, FULL_ROUNDS>, Srs>> = ts
166 .iter()
167 .map(|(verifier_index, proof, public_input)| Context {
168 verifier_index,
169 proof,
170 public_input,
171 })
172 .collect();
173 let group_map = GroupMap::<Fp>::setup();
174
175 batch_verify::<
176 55,
177 Pallas,
178 DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
179 DefaultFrSponge<Fq, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
180 OpeningProof<Pallas, FULL_ROUNDS>,
181 >(&group_map, &ts_ref)
182 .is_ok()
183}
184
185#[ocaml_gen::func]
186#[ocaml::func]
187pub fn caml_pasta_fq_plonk_proof_dummy() -> CamlProofWithPublic<CamlGPallas, CamlFq> {
188 fn comm() -> PolyComm<Pallas> {
189 let g = Pallas::generator();
190 PolyComm {
191 chunks: vec![g, g, g],
192 }
193 }
194
195 let prev = RecursionChallenge {
196 chals: vec![Fq::one(), Fq::one()],
197 comm: comm(),
198 };
199 let prev_challenges = vec![prev.clone(), prev.clone(), prev];
200
201 let g = Pallas::generator();
202 let proof: OpeningProof<_, FULL_ROUNDS> = OpeningProof {
203 lr: vec![(g, g), (g, g), (g, g)],
204 z1: Fq::one(),
205 z2: Fq::one(),
206 delta: g,
207 sg: g,
208 };
209 let eval = || PointEvaluations {
210 zeta: vec![Fq::one()],
211 zeta_omega: vec![Fq::one()],
212 };
213 let evals = ProofEvaluations {
214 public: Some(eval()),
215 w: core::array::from_fn(|_| eval()),
216 coefficients: core::array::from_fn(|_| eval()),
217 z: eval(),
218 s: core::array::from_fn(|_| eval()),
219 generic_selector: eval(),
220 poseidon_selector: eval(),
221 complete_add_selector: eval(),
222 mul_selector: eval(),
223 emul_selector: eval(),
224 endomul_scalar_selector: eval(),
225 range_check0_selector: None,
226 range_check1_selector: None,
227 foreign_field_add_selector: None,
228 foreign_field_mul_selector: None,
229 xor_selector: None,
230 rot_selector: None,
231 lookup_aggregation: None,
232 lookup_table: None,
233 lookup_sorted: array::from_fn(|_| None),
234 runtime_lookup_table: None,
235 runtime_lookup_table_selector: None,
236 xor_lookup_selector: None,
237 lookup_gate_lookup_selector: None,
238 range_check_lookup_selector: None,
239 foreign_field_mul_lookup_selector: None,
240 };
241
242 let public = vec![Fq::one(), Fq::one()];
243 let dlogproof = ProverProof {
244 commitments: ProverCommitments {
245 w_comm: core::array::from_fn(|_| comm()),
246 z_comm: comm(),
247 t_comm: comm(),
248 lookup: None,
249 },
250 proof,
251 evals,
252 ft_eval1: Fq::one(),
253 prev_challenges,
254 };
255
256 (dlogproof, public).into()
257}
258
259#[ocaml_gen::func]
260#[ocaml::func]
261pub fn caml_pasta_fq_plonk_proof_deep_copy(
262 x: CamlProofWithPublic<CamlGPallas, CamlFq>,
263) -> CamlProofWithPublic<CamlGPallas, CamlFq> {
264 x
265}