1use crate::{
2 arkworks::{CamlFp, CamlGVesta},
3 field_vector::fp::CamlFpVector,
4 pasta_fp_plonk_index::{CamlPastaFpPlonkIndex, CamlPastaFpPlonkIndexPtr},
5 pasta_fp_plonk_verifier_index::CamlPastaFpPlonkVerifierIndex,
6 srs::fp::CamlFpSrs,
7 WithLagrangeBasis,
8};
9use ark_ec::AffineRepr;
10use ark_ff::One;
11use core::array;
12use groupmap::GroupMap;
13use kimchi::{
14 circuits::{
15 lookup::runtime_tables::{caml::CamlRuntimeTable, RuntimeTable},
16 polynomial::COLUMNS,
17 },
18 proof::{
19 PointEvaluations, ProofEvaluations, ProverCommitments, ProverProof, RecursionChallenge,
20 },
21 prover::caml::CamlProofWithPublic,
22 prover_index::ProverIndex,
23 verifier::{batch_verify, verify, Context},
24 verifier_index::VerifierIndex,
25};
26use mina_curves::pasta::{Fp, Fq, Pallas, Vesta, VestaParameters};
27use mina_poseidon::{
28 constants::PlonkSpongeConstantsKimchi,
29 sponge::{DefaultFqSponge, DefaultFrSponge},
30};
31use poly_commitment::{
32 commitment::{CommitmentCurve, PolyComm},
33 ipa::OpeningProof,
34};
35use std::convert::TryInto;
36
37type EFqSponge = DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>;
38type EFrSponge = DefaultFrSponge<Fp, PlonkSpongeConstantsKimchi>;
39
40#[ocaml_gen::func]
41#[ocaml::func]
42pub fn caml_pasta_fp_plonk_proof_create(
43 index: CamlPastaFpPlonkIndexPtr<'static>,
44 witness: Vec<CamlFpVector>,
45 runtime_tables: Vec<CamlRuntimeTable<CamlFp>>,
46 prev_challenges: Vec<CamlFp>,
47 prev_sgs: Vec<CamlGVesta>,
48) -> Result<CamlProofWithPublic<CamlGVesta, CamlFp>, ocaml::Error> {
49 {
50 index
51 .as_ref()
52 .0
53 .srs
54 .with_lagrange_basis(index.as_ref().0.cs.domain.d1);
55 }
56
57 let prev = if prev_challenges.is_empty() {
58 Vec::new()
59 } else {
60 let challenges_per_sg = prev_challenges.len() / prev_sgs.len();
61 prev_sgs
62 .into_iter()
63 .map(Into::<Vesta>::into)
64 .enumerate()
65 .map(|(i, sg)| {
66 let chals = prev_challenges[(i * challenges_per_sg)..(i + 1) * challenges_per_sg]
67 .iter()
68 .map(Into::<Fp>::into)
69 .collect();
70 let comm = PolyComm::<Vesta> { chunks: vec![sg] };
71 RecursionChallenge { chals, comm }
72 })
73 .collect()
74 };
75
76 let witness: Vec<Vec<_>> = witness.iter().map(|x| (**x).clone()).collect();
77 let witness: [Vec<_>; COLUMNS] = witness
78 .try_into()
79 .map_err(|_| ocaml::Error::Message("the witness should be a column of 15 vectors"))?;
80 let index: &ProverIndex<Vesta, OpeningProof<Vesta>> = &index.as_ref().0;
81 let runtime_tables: Vec<RuntimeTable<Fp>> =
82 runtime_tables.into_iter().map(Into::into).collect();
83
84 let public_input = witness[0][0..index.cs.public].to_vec();
86
87 let runtime = unsafe { ocaml::Runtime::recover_handle() };
91
92 runtime.releasing_runtime(|| {
94 let group_map = GroupMap::<Fq>::setup();
95 let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
96 &group_map,
97 witness,
98 &runtime_tables,
99 index,
100 prev,
101 None,
102 &mut rand::rngs::OsRng,
103 )
104 .map_err(|e| ocaml::Error::Error(e.into()))?;
105 Ok((proof, public_input).into())
106 })
107}
108
109#[ocaml_gen::func]
110#[ocaml::func]
111pub fn caml_pasta_fp_plonk_proof_create_and_verify(
112 index: CamlPastaFpPlonkIndexPtr<'static>,
113 witness: Vec<CamlFpVector>,
114 runtime_tables: Vec<CamlRuntimeTable<CamlFp>>,
115 prev_challenges: Vec<CamlFp>,
116 prev_sgs: Vec<CamlGVesta>,
117) -> Result<CamlProofWithPublic<CamlGVesta, CamlFp>, ocaml::Error> {
118 {
119 index
120 .as_ref()
121 .0
122 .srs
123 .with_lagrange_basis(index.as_ref().0.cs.domain.d1);
124 }
125 let prev = if prev_challenges.is_empty() {
126 Vec::new()
127 } else {
128 let challenges_per_sg = prev_challenges.len() / prev_sgs.len();
129 prev_sgs
130 .into_iter()
131 .map(Into::<Vesta>::into)
132 .enumerate()
133 .map(|(i, sg)| {
134 let chals = prev_challenges[(i * challenges_per_sg)..(i + 1) * challenges_per_sg]
135 .iter()
136 .map(Into::<Fp>::into)
137 .collect();
138 let comm = PolyComm::<Vesta> { chunks: vec![sg] };
139 RecursionChallenge { chals, comm }
140 })
141 .collect()
142 };
143
144 let witness: Vec<Vec<_>> = witness.iter().map(|x| (**x).clone()).collect();
145 let witness: [Vec<_>; COLUMNS] = witness
146 .try_into()
147 .map_err(|_| ocaml::Error::Message("the witness should be a column of 15 vectors"))?;
148 let index: &ProverIndex<Vesta, OpeningProof<Vesta>> = &index.as_ref().0;
149 let runtime_tables: Vec<RuntimeTable<Fp>> =
150 runtime_tables.into_iter().map(Into::into).collect();
151
152 let public_input = witness[0][0..index.cs.public].to_vec();
154
155 let runtime = unsafe { ocaml::Runtime::recover_handle() };
159
160 runtime.releasing_runtime(|| {
162 let group_map = GroupMap::<Fq>::setup();
163 let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
164 &group_map,
165 witness,
166 &runtime_tables,
167 index,
168 prev,
169 None,
170 &mut rand::rngs::OsRng,
171 )
172 .map_err(|e| ocaml::Error::Error(e.into()))?;
173
174 let verifier_index = index.verifier_index();
175
176 verify::<Vesta, EFqSponge, EFrSponge, OpeningProof<Vesta>>(
178 &group_map,
179 &verifier_index,
180 &proof,
181 &public_input,
182 )?;
183
184 Ok((proof, public_input).into())
185 })
186}
187
188#[ocaml_gen::func]
189#[ocaml::func]
190pub fn caml_pasta_fp_plonk_proof_example_with_lookup(
191 srs: CamlFpSrs,
192) -> (
193 CamlPastaFpPlonkIndex,
194 CamlFp,
195 CamlProofWithPublic<CamlGVesta, CamlFp>,
196) {
197 use ark_ff::Zero;
198 use kimchi::circuits::{
199 constraints::ConstraintSystem,
200 gate::{CircuitGate, GateType},
201 lookup::{
202 runtime_tables::{RuntimeTable, RuntimeTableCfg},
203 tables::LookupTable,
204 },
205 polynomial::COLUMNS,
206 wires::Wire,
207 };
208 use poly_commitment::ipa::endos;
209
210 let num_gates = 1000;
211 let num_tables: usize = 5;
212
213 let fixed_tables = vec![LookupTable {
215 id: 0,
216 data: vec![vec![0, 0, 0, 0, 0].into_iter().map(Into::into).collect()],
217 }];
218
219 let mut runtime_tables_setup = vec![];
220 let first_column: Vec<_> = [8u32, 9, 8, 7, 1].into_iter().map(Into::into).collect();
221 for table_id in 0..num_tables {
222 let cfg = RuntimeTableCfg {
223 id: table_id as i32,
224 first_column: first_column.clone(),
225 };
226 runtime_tables_setup.push(cfg);
227 }
228
229 let data: Vec<Fp> = [0u32, 2, 3, 4, 5].into_iter().map(Into::into).collect();
230 let runtime_tables: Vec<RuntimeTable<Fp>> = runtime_tables_setup
231 .iter()
232 .map(|cfg| RuntimeTable {
233 id: cfg.id(),
234 data: data.clone(),
235 })
236 .collect();
237
238 let mut gates = vec![];
240 for row in 0..num_gates {
241 gates.push(CircuitGate {
242 typ: GateType::Lookup,
243 wires: Wire::for_row(row),
244 coeffs: vec![],
245 });
246 }
247
248 let witness = {
250 let mut cols: [_; COLUMNS] = core::array::from_fn(|_col| vec![Fp::zero(); gates.len()]);
251
252 let (lookup_cols, _rest) = cols.split_at_mut(7);
254
255 for row in 0..num_gates {
256 lookup_cols[0][row] = ((row % num_tables) as u64).into();
258
259 let lookup_cols = &mut lookup_cols[1..];
261 for (chunk_id, chunk) in lookup_cols.chunks_mut(2).enumerate() {
262 if (row + chunk_id) % 2 == 0 {
264 chunk[0][row] = 9u32.into(); chunk[1][row] = 2u32.into(); } else {
267 chunk[0][row] = 8u32.into(); chunk[1][row] = 3u32.into(); }
270 }
271 }
272 cols
273 };
274
275 let num_public_inputs = 1;
276
277 let cs = ConstraintSystem::<Fp>::create(gates)
279 .runtime(Some(runtime_tables_setup))
280 .lookup(fixed_tables)
281 .public(num_public_inputs)
282 .build()
283 .unwrap();
284
285 srs.0.with_lagrange_basis(cs.domain.d1);
286
287 let (endo_q, _endo_r) = endos::<Pallas>();
288 let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
289 let group_map = <Vesta as CommitmentCurve>::Map::setup();
290 let public_input = witness[0][0];
291 let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
292 &group_map,
293 witness,
294 &runtime_tables,
295 &index,
296 vec![],
297 None,
298 &mut rand::rngs::OsRng,
299 )
300 .unwrap();
301
302 let caml_prover_proof = (proof, vec![public_input]).into();
303
304 (
305 CamlPastaFpPlonkIndex(Box::new(index)),
306 public_input.into(),
307 caml_prover_proof,
308 )
309}
310
311#[ocaml_gen::func]
312#[ocaml::func]
313pub fn caml_pasta_fp_plonk_proof_example_with_foreign_field_mul(
314 srs: CamlFpSrs,
315) -> (
316 CamlPastaFpPlonkIndex,
317 CamlProofWithPublic<CamlGVesta, CamlFp>,
318) {
319 use ark_ff::Zero;
320 use kimchi::circuits::{
321 constraints::ConstraintSystem,
322 gate::{CircuitGate, Connect},
323 polynomials::{foreign_field_common::BigUintForeignFieldHelpers, foreign_field_mul},
324 wires::Wire,
325 };
326 use num_bigint::{BigUint, RandBigInt};
327 use o1_utils::FieldHelpers;
328 use poly_commitment::ipa::endos;
329 use rand::{rngs::StdRng, SeedableRng};
330
331 let foreign_field_modulus = Fq::modulus_biguint();
332
333 let (mut next_row, mut gates) =
348 CircuitGate::<Fp>::create_foreign_field_mul(0, &foreign_field_modulus);
349
350 let rng = &mut StdRng::from_seed([2u8; 32]);
351 let left_input = rng.gen_biguint_range(&BigUint::zero(), &foreign_field_modulus);
352 let right_input = rng.gen_biguint_range(&BigUint::zero(), &foreign_field_modulus);
353
354 let (mut witness, mut external_checks) =
356 foreign_field_mul::witness::create(&left_input, &right_input, &foreign_field_modulus);
357
358 CircuitGate::extend_compact_multi_range_check(&mut gates, &mut next_row);
360 gates.connect_cell_pair((1, 0), (4, 1)); gates.connect_cell_pair((1, 1), (2, 0)); external_checks.extend_witness_compact_multi_range_checks(&mut witness);
363 CircuitGate::extend_high_bounds(&mut gates, &mut next_row, &foreign_field_modulus);
368 gates.connect_cell_pair((6, 0), (1, 1)); external_checks.extend_witness_high_bounds_computation(&mut witness, &foreign_field_modulus);
370
371 CircuitGate::extend_multi_range_check(&mut gates, &mut next_row);
373 gates.connect_cell_pair((1, 2), (7, 0)); gates.connect_cell_pair((1, 3), (8, 0)); gates.connect_cell_pair((1, 4), (9, 0)); CircuitGate::extend_multi_range_check(&mut gates, &mut next_row);
380 gates.connect_cell_pair((1, 5), (11, 0)); gates.connect_cell_pair((0, 6), (12, 0)); gates.connect_cell_pair((1, 6), (13, 0)); external_checks.extend_witness_multi_range_checks(&mut witness);
389
390 let left_limbs = left_input.to_field_limbs();
392 let right_limbs = right_input.to_field_limbs();
393 external_checks.add_high_bound_computation(&left_limbs[2]);
395 external_checks.add_high_bound_computation(&right_limbs[2]);
396 CircuitGate::extend_high_bounds(&mut gates, &mut next_row, &foreign_field_modulus);
397 gates.connect_cell_pair((15, 0), (0, 2)); gates.connect_cell_pair((15, 3), (0, 5)); external_checks.extend_witness_high_bounds_computation(&mut witness, &foreign_field_modulus);
400
401 external_checks.add_multi_range_check(&left_limbs);
403 CircuitGate::extend_multi_range_check(&mut gates, &mut next_row);
404 gates.connect_cell_pair((0, 0), (16, 0)); gates.connect_cell_pair((0, 1), (17, 0)); gates.connect_cell_pair((0, 2), (18, 0)); external_checks.add_multi_range_check(&right_limbs);
411 CircuitGate::extend_multi_range_check(&mut gates, &mut next_row);
412 gates.connect_cell_pair((0, 3), (20, 0)); gates.connect_cell_pair((0, 4), (21, 0)); gates.connect_cell_pair((0, 5), (22, 0)); external_checks.extend_witness_multi_range_checks(&mut witness);
420
421 CircuitGate::extend_multi_range_check(&mut gates, &mut next_row);
424 gates.connect_cell_pair((6, 2), (24, 0)); let left_hi_bound =
429 foreign_field_mul::witness::compute_bound(&left_input, &foreign_field_modulus);
430 let right_hi_bound =
431 foreign_field_mul::witness::compute_bound(&right_input, &foreign_field_modulus);
432 external_checks.add_limb_check(&left_hi_bound.into());
433 external_checks.add_limb_check(&right_hi_bound.into());
434 gates.connect_cell_pair((15, 2), (25, 0)); gates.connect_cell_pair((15, 5), (26, 0)); external_checks.extend_witness_limb_checks(&mut witness);
438
439 for _ in 0..(1 << 13) {
441 gates.push(CircuitGate::zero(Wire::for_row(next_row)));
442 next_row += 1;
443 }
444
445 let cs = ConstraintSystem::<Fp>::create(gates).build().unwrap();
447
448 srs.0.with_lagrange_basis(cs.domain.d1);
449
450 let (endo_q, _endo_r) = endos::<Pallas>();
451 let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
452 let group_map = <Vesta as CommitmentCurve>::Map::setup();
453 let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
454 &group_map,
455 witness,
456 &[],
457 &index,
458 vec![],
459 None,
460 &mut rand::rngs::OsRng,
461 )
462 .unwrap();
463 (
464 CamlPastaFpPlonkIndex(Box::new(index)),
465 (proof, vec![]).into(),
466 )
467}
468
469#[ocaml_gen::func]
470#[ocaml::func]
471pub fn caml_pasta_fp_plonk_proof_example_with_range_check(
472 srs: CamlFpSrs,
473) -> (
474 CamlPastaFpPlonkIndex,
475 CamlProofWithPublic<CamlGVesta, CamlFp>,
476) {
477 use ark_ff::Zero;
478 use kimchi::circuits::{
479 constraints::ConstraintSystem,
480 gate::CircuitGate,
481 polynomials::{foreign_field_common::BigUintForeignFieldHelpers, range_check},
482 wires::Wire,
483 };
484 use num_bigint::{BigUint, RandBigInt};
485 use o1_utils::BigUintFieldHelpers;
486 use poly_commitment::ipa::endos;
487 use rand::{rngs::StdRng, SeedableRng};
488
489 let rng = &mut StdRng::from_seed([255u8; 32]);
490
491 let (mut next_row, mut gates) = CircuitGate::<Fp>::create_multi_range_check(0);
493
494 let witness = range_check::witness::create_multi::<Fp>(
496 rng.gen_biguint_range(&BigUint::zero(), &BigUint::two_to_limb())
497 .to_field()
498 .expect("failed to convert to field"),
499 rng.gen_biguint_range(&BigUint::zero(), &BigUint::two_to_limb())
500 .to_field()
501 .expect("failed to convert to field"),
502 rng.gen_biguint_range(&BigUint::zero(), &BigUint::two_to_limb())
503 .to_field()
504 .expect("failed to convert to field"),
505 );
506
507 for _ in 0..(1 << 13) {
509 gates.push(CircuitGate::zero(Wire::for_row(next_row)));
510 next_row += 1;
511 }
512
513 let cs = ConstraintSystem::<Fp>::create(gates).build().unwrap();
515
516 srs.0.with_lagrange_basis(cs.domain.d1);
517
518 let (endo_q, _endo_r) = endos::<Pallas>();
519 let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
520 let group_map = <Vesta as CommitmentCurve>::Map::setup();
521 let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
522 &group_map,
523 witness,
524 &[],
525 &index,
526 vec![],
527 None,
528 &mut rand::rngs::OsRng,
529 )
530 .unwrap();
531 (
532 CamlPastaFpPlonkIndex(Box::new(index)),
533 (proof, vec![]).into(),
534 )
535}
536
537#[ocaml_gen::func]
538#[ocaml::func]
539pub fn caml_pasta_fp_plonk_proof_example_with_range_check0(
540 srs: CamlFpSrs,
541) -> (
542 CamlPastaFpPlonkIndex,
543 CamlProofWithPublic<CamlGVesta, CamlFp>,
544) {
545 use ark_ff::Zero;
546 use kimchi::circuits::{
547 constraints::ConstraintSystem,
548 gate::{CircuitGate, Connect},
549 polynomial::COLUMNS,
550 polynomials::{generic::GenericGateSpec, range_check},
551 wires::Wire,
552 };
553 use poly_commitment::ipa::endos;
554
555 let gates = {
556 let mut gates = vec![CircuitGate::<Fp>::create_generic_gadget(
558 Wire::for_row(0),
559 GenericGateSpec::Const(Fp::zero()),
560 None,
561 )];
562 let mut row = 1;
563 CircuitGate::<Fp>::extend_range_check(&mut gates, &mut row);
564
565 for _ in 0..(1 << 13) {
567 gates.push(CircuitGate::zero(Wire::for_row(gates.len())));
568 }
569
570 gates.connect_64bit(0, 1);
572
573 gates
574 };
575
576 let witness = {
578 let mut witness: [_; COLUMNS] = core::array::from_fn(|_col| vec![Fp::zero(); 1]);
580 range_check::witness::extend_single(&mut witness, Fp::from(2u128.pow(64) - 1));
582 witness
583 };
584
585 let cs = ConstraintSystem::<Fp>::create(gates).build().unwrap();
587
588 srs.0.with_lagrange_basis(cs.domain.d1);
589
590 let (endo_q, _endo_r) = endos::<Pallas>();
591 let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
592 let group_map = <Vesta as CommitmentCurve>::Map::setup();
593 let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
594 &group_map,
595 witness,
596 &[],
597 &index,
598 vec![],
599 None,
600 &mut rand::rngs::OsRng,
601 )
602 .unwrap();
603 (
604 CamlPastaFpPlonkIndex(Box::new(index)),
605 (proof, vec![]).into(),
606 )
607}
608
609#[ocaml_gen::func]
610#[ocaml::func]
611pub fn caml_pasta_fp_plonk_proof_example_with_ffadd(
612 srs: CamlFpSrs,
613) -> (
614 CamlPastaFpPlonkIndex,
615 CamlFp,
616 CamlProofWithPublic<CamlGVesta, CamlFp>,
617) {
618 use ark_ff::Zero;
619 use kimchi::circuits::{
620 constraints::ConstraintSystem,
621 gate::{CircuitGate, Connect},
622 polynomial::COLUMNS,
623 polynomials::{
624 foreign_field_add::witness::{create_chain, FFOps},
625 generic::GenericGateSpec,
626 range_check,
627 },
628 wires::Wire,
629 };
630 use num_bigint::BigUint;
631 use poly_commitment::ipa::endos;
632
633 let num_public_inputs = 1;
635 let operation = &[FFOps::Add];
636 let modulus = BigUint::from_bytes_be(&[
637 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF,
638 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF,
639 0xFC, 0x2F,
640 ]);
641
642 let gates = {
652 let mut gates = vec![CircuitGate::<Fp>::create_generic_gadget(
654 Wire::for_row(0),
655 GenericGateSpec::Pub,
656 None,
657 )];
658
659 let mut curr_row = num_public_inputs;
660 CircuitGate::<Fp>::extend_chain_ffadd(&mut gates, 0, &mut curr_row, operation, &modulus);
662
663 for _ in 0..4 {
665 CircuitGate::extend_multi_range_check(&mut gates, &mut curr_row);
666 }
667 gates.connect_ffadd_range_checks(1, Some(4), Some(8), 12);
670 gates.connect_ffadd_range_checks(2, None, None, 16);
672
673 for _ in 0..(1 << 13) {
675 gates.push(CircuitGate::zero(Wire::for_row(curr_row)));
676 curr_row += 1;
677 }
678
679 gates
680 };
681
682 let witness = {
684 let mut witness: [_; COLUMNS] = core::array::from_fn(|_col| vec![Fp::zero(); 1]);
686 witness[0][0] = Fp::one();
687 let left = modulus.clone() - BigUint::from_bytes_be(&[1]);
689 let right = modulus.clone() - BigUint::from_bytes_be(&[1]);
690 let add_witness = create_chain::<Fp>(&[left, right], operation, modulus);
692 for col in 0..COLUMNS {
693 witness[col].extend(add_witness[col].iter());
694 }
695 let left = (witness[0][1], witness[1][1], witness[2][1]);
697 range_check::witness::extend_multi(&mut witness, left.0, left.1, left.2);
698 let right = (witness[3][1], witness[4][1], witness[5][1]);
699 range_check::witness::extend_multi(&mut witness, right.0, right.1, right.2);
700 let output = (witness[0][2], witness[1][2], witness[2][2]);
701 range_check::witness::extend_multi(&mut witness, output.0, output.1, output.2);
702 let bound = (witness[0][3], witness[1][3], witness[2][3]);
703 range_check::witness::extend_multi(&mut witness, bound.0, bound.1, bound.2);
704 witness
705 };
706
707 let cs = ConstraintSystem::<Fp>::create(gates)
710 .public(num_public_inputs)
711 .build()
712 .unwrap();
713
714 srs.0.with_lagrange_basis(cs.domain.d1);
715
716 let (endo_q, _endo_r) = endos::<Pallas>();
717 let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
718 let group_map = <Vesta as CommitmentCurve>::Map::setup();
719 let public_input = witness[0][0];
720 let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
721 &group_map,
722 witness,
723 &[],
724 &index,
725 vec![],
726 None,
727 &mut rand::rngs::OsRng,
728 )
729 .unwrap();
730 (
731 CamlPastaFpPlonkIndex(Box::new(index)),
732 public_input.into(),
733 (proof, vec![public_input]).into(),
734 )
735}
736
737#[ocaml_gen::func]
738#[ocaml::func]
739pub fn caml_pasta_fp_plonk_proof_example_with_xor(
740 srs: CamlFpSrs,
741) -> (
742 CamlPastaFpPlonkIndex,
743 (CamlFp, CamlFp),
744 CamlProofWithPublic<CamlGVesta, CamlFp>,
745) {
746 use ark_ff::Zero;
747 use kimchi::circuits::{
748 constraints::ConstraintSystem,
749 gate::{CircuitGate, Connect},
750 polynomial::COLUMNS,
751 polynomials::{generic::GenericGateSpec, xor},
752 wires::Wire,
753 };
754 use poly_commitment::ipa::endos;
755
756 let num_public_inputs = 2;
757
758 let gates = {
760 let mut gates = vec![];
762 for row in 0..num_public_inputs {
763 gates.push(CircuitGate::<Fp>::create_generic_gadget(
764 Wire::for_row(row),
765 GenericGateSpec::Pub,
766 None,
767 ));
768 }
769 CircuitGate::<Fp>::extend_xor_gadget(&mut gates, 128);
772 gates.connect_cell_pair((0, 0), (2, 0));
774 gates.connect_cell_pair((1, 0), (2, 1));
775
776 for _ in 0..(1 << 13) {
778 gates.push(CircuitGate::zero(Wire::for_row(gates.len())));
779 }
780 gates
781 };
782
783 let witness = {
785 let mut cols: [_; COLUMNS] =
786 core::array::from_fn(|_col| vec![Fp::zero(); num_public_inputs]);
787
788 let input1 = 0xDC811727DAF22EC15927D6AA275F406Bu128;
790 let input2 = 0xA4F4417AF072DF9016A1EAB458DA80D1u128;
791 cols[0][0] = input1.into();
792 cols[0][1] = input2.into();
793
794 xor::extend_xor_witness::<Fp>(&mut cols, input1.into(), input2.into(), 128);
795 cols
796 };
797
798 let cs = ConstraintSystem::<Fp>::create(gates)
801 .public(num_public_inputs)
802 .build()
803 .unwrap();
804
805 srs.0.with_lagrange_basis(cs.domain.d1);
806
807 let (endo_q, _endo_r) = endos::<Pallas>();
808 let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
809 let group_map = <Vesta as CommitmentCurve>::Map::setup();
810 let public_input = (witness[0][0], witness[0][1]);
811 let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
812 &group_map,
813 witness,
814 &[],
815 &index,
816 vec![],
817 None,
818 &mut rand::rngs::OsRng,
819 )
820 .unwrap();
821 (
822 CamlPastaFpPlonkIndex(Box::new(index)),
823 (public_input.0.into(), public_input.1.into()),
824 (proof, vec![public_input.0, public_input.1]).into(),
825 )
826}
827
828#[ocaml_gen::func]
829#[ocaml::func]
830pub fn caml_pasta_fp_plonk_proof_example_with_rot(
831 srs: CamlFpSrs,
832) -> (
833 CamlPastaFpPlonkIndex,
834 (CamlFp, CamlFp),
835 CamlProofWithPublic<CamlGVesta, CamlFp>,
836) {
837 use ark_ff::Zero;
838 use kimchi::circuits::{
839 constraints::ConstraintSystem,
840 gate::{CircuitGate, Connect},
841 polynomial::COLUMNS,
842 polynomials::{
843 generic::GenericGateSpec,
844 rot::{self, RotMode},
845 },
846 wires::Wire,
847 };
848 use poly_commitment::ipa::endos;
849
850 let num_public_inputs = 2;
852 let rot = 32;
854 let mode = RotMode::Left;
855
856 let gates = {
858 let mut gates = vec![];
859 for row in 0..num_public_inputs {
861 gates.push(CircuitGate::<Fp>::create_generic_gadget(
862 Wire::for_row(row),
863 GenericGateSpec::Pub,
864 None,
865 ));
866 }
867 CircuitGate::<Fp>::extend_rot(&mut gates, rot, mode, 1);
868 gates.connect_cell_pair((0, 0), (2, 0));
870
871 for _ in 0..(1 << 13) {
873 gates.push(CircuitGate::zero(Wire::for_row(gates.len())));
874 }
875
876 gates
877 };
878
879 let witness = {
881 let mut cols: [_; COLUMNS] = core::array::from_fn(|_col| vec![Fp::zero(); 2]);
883
884 let input = 0xDC811727DAF22EC1u64;
886 cols[0][0] = input.into();
887 rot::extend_rot::<Fp>(&mut cols, input, rot, mode);
888
889 cols
890 };
891
892 let cs = ConstraintSystem::<Fp>::create(gates)
895 .public(num_public_inputs)
896 .build()
897 .unwrap();
898
899 srs.0.with_lagrange_basis(cs.domain.d1);
900
901 let (endo_q, _endo_r) = endos::<Pallas>();
902 let index = ProverIndex::<Vesta, OpeningProof<Vesta>>::create(cs, endo_q, srs.0);
903 let group_map = <Vesta as CommitmentCurve>::Map::setup();
904 let public_input = (witness[0][0], witness[0][1]);
905 let proof = ProverProof::create_recursive::<EFqSponge, EFrSponge, _>(
906 &group_map,
907 witness,
908 &[],
909 &index,
910 vec![],
911 None,
912 &mut rand::rngs::OsRng,
913 )
914 .unwrap();
915 (
916 CamlPastaFpPlonkIndex(Box::new(index)),
917 (public_input.0.into(), public_input.1.into()),
918 (proof, vec![public_input.0, public_input.1]).into(),
919 )
920}
921
922#[ocaml_gen::func]
923#[ocaml::func]
924pub fn caml_pasta_fp_plonk_proof_verify(
925 index: CamlPastaFpPlonkVerifierIndex,
926 proof: CamlProofWithPublic<CamlGVesta, CamlFp>,
927) -> bool {
928 let group_map = <Vesta as CommitmentCurve>::Map::setup();
929
930 let (proof, public_input) = proof.into();
931 let verifier_index = index.into();
932 let context = Context {
933 verifier_index: &verifier_index,
934 proof: &proof,
935 public_input: &public_input,
936 };
937
938 batch_verify::<
939 Vesta,
940 DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>,
941 DefaultFrSponge<Fp, PlonkSpongeConstantsKimchi>,
942 OpeningProof<Vesta>,
943 >(&group_map, &[context])
944 .is_ok()
945}
946
947#[ocaml_gen::func]
948#[ocaml::func]
949pub fn caml_pasta_fp_plonk_proof_batch_verify(
950 indexes: Vec<CamlPastaFpPlonkVerifierIndex>,
951 proofs: Vec<CamlProofWithPublic<CamlGVesta, CamlFp>>,
952) -> bool {
953 let ts: Vec<_> = indexes
954 .into_iter()
955 .zip(proofs.into_iter())
956 .map(|(caml_index, caml_proof)| {
957 let verifier_index: VerifierIndex<Vesta, OpeningProof<Vesta>> = caml_index.into();
958 let (proof, public_input): (ProverProof<Vesta, OpeningProof<Vesta>>, Vec<_>) =
959 caml_proof.into();
960 (verifier_index, proof, public_input)
961 })
962 .collect();
963 let ts_ref: Vec<Context<Vesta, OpeningProof<Vesta>>> = ts
964 .iter()
965 .map(|(verifier_index, proof, public_input)| Context {
966 verifier_index,
967 proof,
968 public_input,
969 })
970 .collect();
971 let group_map = GroupMap::<Fq>::setup();
972
973 batch_verify::<
974 Vesta,
975 DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>,
976 DefaultFrSponge<Fp, PlonkSpongeConstantsKimchi>,
977 OpeningProof<Vesta>,
978 >(&group_map, &ts_ref)
979 .is_ok()
980}
981
982#[ocaml_gen::func]
983#[ocaml::func]
984pub fn caml_pasta_fp_plonk_proof_dummy() -> CamlProofWithPublic<CamlGVesta, CamlFp> {
985 fn comm() -> PolyComm<Vesta> {
986 let g = Vesta::generator();
987 PolyComm {
988 chunks: vec![g, g, g],
989 }
990 }
991
992 let prev = RecursionChallenge {
993 chals: vec![Fp::one(), Fp::one()],
994 comm: comm(),
995 };
996 let prev_challenges = vec![prev.clone(), prev.clone(), prev];
997
998 let g = Vesta::generator();
999 let proof = OpeningProof {
1000 lr: vec![(g, g), (g, g), (g, g)],
1001 z1: Fp::one(),
1002 z2: Fp::one(),
1003 delta: g,
1004 sg: g,
1005 };
1006 let eval = || PointEvaluations {
1007 zeta: vec![Fp::one()],
1008 zeta_omega: vec![Fp::one()],
1009 };
1010 let evals = ProofEvaluations {
1011 public: Some(eval()),
1012 w: core::array::from_fn(|_| eval()),
1013 coefficients: core::array::from_fn(|_| eval()),
1014 z: eval(),
1015 s: core::array::from_fn(|_| eval()),
1016 generic_selector: eval(),
1017 poseidon_selector: eval(),
1018 complete_add_selector: eval(),
1019 mul_selector: eval(),
1020 emul_selector: eval(),
1021 endomul_scalar_selector: eval(),
1022 range_check0_selector: None,
1023 range_check1_selector: None,
1024 foreign_field_add_selector: None,
1025 foreign_field_mul_selector: None,
1026 xor_selector: None,
1027 rot_selector: None,
1028 lookup_aggregation: None,
1029 lookup_table: None,
1030 lookup_sorted: array::from_fn(|_| None),
1031 runtime_lookup_table: None,
1032 runtime_lookup_table_selector: None,
1033 xor_lookup_selector: None,
1034 lookup_gate_lookup_selector: None,
1035 range_check_lookup_selector: None,
1036 foreign_field_mul_lookup_selector: None,
1037 };
1038
1039 let public = vec![Fp::one(), Fp::one()];
1040 let dlogproof = ProverProof {
1041 commitments: ProverCommitments {
1042 w_comm: core::array::from_fn(|_| comm()),
1043 z_comm: comm(),
1044 t_comm: comm(),
1045 lookup: None,
1046 },
1047 proof,
1048 evals,
1049 ft_eval1: Fp::one(),
1050 prev_challenges,
1051 };
1052
1053 (dlogproof, public).into()
1054}
1055
1056#[ocaml_gen::func]
1057#[ocaml::func]
1058pub fn caml_pasta_fp_plonk_proof_deep_copy(
1059 x: CamlProofWithPublic<CamlGVesta, CamlFp>,
1060) -> CamlProofWithPublic<CamlGVesta, CamlFp> {
1061 x
1062}