kimchi_stubs/
pasta_fp_plonk_index.rs1use crate::{arkworks::CamlFp, gate_vector::fp::CamlPastaFpPlonkGateVectorPtr, srs::fp::CamlFpSrs};
2use ark_poly::EvaluationDomain;
3use kimchi::{
4 circuits::{
5 constraints::ConstraintSystem,
6 gate::CircuitGate,
7 lookup::{
8 runtime_tables::{caml::CamlRuntimeTableCfg, RuntimeTableCfg},
9 tables::{caml::CamlLookupTable, LookupTable},
10 },
11 },
12 linearization::expr_linearization,
13 prover_index::ProverIndex,
14};
15use mina_curves::pasta::{Fp, Pallas, Vesta, VestaParameters};
16use mina_poseidon::{
17 constants::PlonkSpongeConstantsKimchi, pasta::FULL_ROUNDS, sponge::DefaultFqSponge,
18};
19use poly_commitment::{ipa::OpeningProof, lagrange_basis::WithLagrangeBasis, SRS as _};
20use serde::{Deserialize, Serialize};
21use std::{
22 fs::{File, OpenOptions},
23 io::{BufReader, BufWriter, Seek, SeekFrom::Start},
24};
25
26type Srs =
27 <OpeningProof<Vesta, FULL_ROUNDS> as poly_commitment::OpenProof<Vesta, FULL_ROUNDS>>::SRS;
28
29#[derive(ocaml_gen::CustomType)]
31pub struct CamlPastaFpPlonkIndex(pub Box<ProverIndex<FULL_ROUNDS, Vesta, Srs>>);
32pub type CamlPastaFpPlonkIndexPtr<'a> = ocaml::Pointer<'a, CamlPastaFpPlonkIndex>;
33
34extern "C" fn caml_pasta_fp_plonk_index_finalize(v: ocaml::Raw) {
35 unsafe {
36 let mut v: CamlPastaFpPlonkIndexPtr = v.as_pointer();
37 v.as_mut_ptr().drop_in_place();
38 }
39}
40
41impl ocaml::custom::Custom for CamlPastaFpPlonkIndex {
42 const NAME: &'static str = "CamlPastaFpPlonkIndex\0";
43 const USED: usize = 1;
44 const MAX: usize = 12;
46 const OPS: ocaml::custom::CustomOps = ocaml::custom::CustomOps {
47 identifier: Self::NAME.as_ptr() as *const ocaml::sys::Char,
48 finalize: Some(caml_pasta_fp_plonk_index_finalize),
49 ..ocaml::custom::DEFAULT_CUSTOM_OPS
50 };
51}
52
53#[ocaml_gen::func]
54#[ocaml::func]
55pub fn caml_pasta_fp_plonk_index_create(
56 gates: CamlPastaFpPlonkGateVectorPtr,
57 public: ocaml::Int,
58 lookup_tables: Vec<CamlLookupTable<CamlFp>>,
59 runtime_tables: Vec<CamlRuntimeTableCfg<CamlFp>>,
60 prev_challenges: ocaml::Int,
61 srs: CamlFpSrs,
62 lazy_mode: bool,
63) -> Result<CamlPastaFpPlonkIndex, ocaml::Error> {
64 let gates: Vec<_> = gates
65 .as_ref()
66 .0
67 .iter()
68 .map(|gate| CircuitGate::<Fp> {
69 typ: gate.typ,
70 wires: gate.wires,
71 coeffs: gate.coeffs.clone(),
72 })
73 .collect();
74
75 let runtime_tables: Vec<RuntimeTableCfg<Fp>> =
76 runtime_tables.into_iter().map(Into::into).collect();
77
78 let lookup_tables: Vec<LookupTable<Fp>> = lookup_tables.into_iter().map(Into::into).collect();
79
80 let cs = ConstraintSystem::<Fp>::create(gates)
82 .public(public as usize)
83 .prev_challenges(prev_challenges as usize)
84 .max_poly_size(Some(srs.0.max_poly_size()))
85 .lookup(lookup_tables)
86 .runtime(if runtime_tables.is_empty() {
87 None
88 } else {
89 Some(runtime_tables)
90 })
91 .lazy_mode(lazy_mode)
92 .build()?;
93
94 let (endo_q, _endo_r) = poly_commitment::ipa::endos::<Pallas>();
96
97 srs.0.with_lagrange_basis(cs.domain.d1);
98
99 let mut index = ProverIndex::create(cs, endo_q, srs.clone(), lazy_mode);
101 index.compute_verifier_index_digest::<DefaultFqSponge<
103 VestaParameters,
104 PlonkSpongeConstantsKimchi,
105 FULL_ROUNDS,
106 >>();
107
108 Ok(CamlPastaFpPlonkIndex(Box::new(index)))
109}
110
111#[ocaml_gen::func]
112#[ocaml::func]
113pub fn caml_pasta_fp_plonk_index_max_degree(index: CamlPastaFpPlonkIndexPtr) -> ocaml::Int {
114 index.as_ref().0.srs.max_poly_size() as isize
115}
116
117#[ocaml_gen::func]
118#[ocaml::func]
119pub fn caml_pasta_fp_plonk_index_public_inputs(index: CamlPastaFpPlonkIndexPtr) -> ocaml::Int {
120 index.as_ref().0.cs.public as isize
121}
122
123#[ocaml_gen::func]
124#[ocaml::func]
125pub fn caml_pasta_fp_plonk_index_domain_d1_size(index: CamlPastaFpPlonkIndexPtr) -> ocaml::Int {
126 index.as_ref().0.cs.domain.d1.size() as isize
127}
128
129#[ocaml_gen::func]
130#[ocaml::func]
131pub fn caml_pasta_fp_plonk_index_domain_d4_size(index: CamlPastaFpPlonkIndexPtr) -> ocaml::Int {
132 index.as_ref().0.cs.domain.d4.size() as isize
133}
134
135#[ocaml_gen::func]
136#[ocaml::func]
137pub fn caml_pasta_fp_plonk_index_domain_d8_size(index: CamlPastaFpPlonkIndexPtr) -> ocaml::Int {
138 index.as_ref().0.cs.domain.d8.size() as isize
139}
140
141#[ocaml_gen::func]
142#[ocaml::func]
143pub fn caml_pasta_fp_plonk_index_read(
144 offset: Option<ocaml::Int>,
145 srs: CamlFpSrs,
146 path: String,
147) -> Result<CamlPastaFpPlonkIndex, ocaml::Error> {
148 let file = match File::open(path) {
150 Err(_) => {
151 return Err(
152 ocaml::Error::invalid_argument("caml_pasta_fp_plonk_index_read")
153 .err()
154 .unwrap(),
155 )
156 }
157 Ok(file) => file,
158 };
159 let mut r = BufReader::new(file);
160
161 if let Some(offset) = offset {
163 r.seek(Start(offset as u64))?;
164 }
165
166 let mut t =
168 ProverIndex::<FULL_ROUNDS, Vesta, Srs>::deserialize(&mut rmp_serde::Deserializer::new(r))?;
169 t.srs = srs.clone();
170
171 let (linearization, powers_of_alpha) = expr_linearization(Some(&t.cs.feature_flags), true);
172 t.linearization = linearization;
173 t.powers_of_alpha = powers_of_alpha;
174
175 Ok(CamlPastaFpPlonkIndex(Box::new(t)))
176}
177
178#[ocaml_gen::func]
179#[ocaml::func]
180pub fn caml_pasta_fp_plonk_index_write(
181 append: Option<bool>,
182 index: CamlPastaFpPlonkIndexPtr<'static>,
183 path: String,
184) -> Result<(), ocaml::Error> {
185 let file = OpenOptions::new()
186 .append(append.unwrap_or(true))
187 .open(path)
188 .map_err(|_| {
189 ocaml::Error::invalid_argument("caml_pasta_fp_plonk_index_write")
190 .err()
191 .unwrap()
192 })?;
193 let w = BufWriter::new(file);
194 index
195 .as_ref()
196 .0
197 .serialize(&mut rmp_serde::Serializer::new(w))
198 .map_err(|e| e.into())
199}