1use crate::{
2 gate_vector::fp::WasmGateVector,
3 srs::fp::WasmFpSrs as WasmSrs,
4 wasm_vector::{fp::*, WasmVector},
5};
6use ark_poly::EvaluationDomain;
7use arkworks::WasmPastaFp;
8use kimchi::{
9 circuits::{
10 constraints::ConstraintSystem,
11 gate::CircuitGate,
12 lookup::{runtime_tables::RuntimeTableCfg, tables::LookupTable},
13 },
14 linearization::expr_linearization,
15 poly_commitment::{ipa::OpeningProof, SRS as _},
16 prover_index::ProverIndex,
17};
18use mina_curves::pasta::{Fp, Pallas as GAffineOther, Vesta as GAffine, VestaParameters};
19use mina_poseidon::{constants::PlonkSpongeConstantsKimchi, sponge::DefaultFqSponge};
20use serde::{Deserialize, Serialize};
21use std::{
22 fs::{File, OpenOptions},
23 io::{BufReader, BufWriter, Seek, SeekFrom::Start},
24};
25use wasm_bindgen::prelude::*;
26use wasm_types::FlatVector as WasmFlatVector;
27
28#[wasm_bindgen]
34pub struct WasmPastaFpPlonkIndex(
35 #[wasm_bindgen(skip)] pub Box<ProverIndex<GAffine, OpeningProof<GAffine>>>,
36);
37
38#[wasm_bindgen]
40pub struct WasmPastaFpLookupTable {
41 #[wasm_bindgen(skip)]
42 pub id: i32,
43 #[wasm_bindgen(skip)]
44 pub data: WasmVecVecFp,
45}
46
47impl From<WasmPastaFpLookupTable> for LookupTable<Fp> {
50 fn from(wasm_lt: WasmPastaFpLookupTable) -> LookupTable<Fp> {
51 LookupTable {
52 id: wasm_lt.id,
53 data: wasm_lt.data.0,
54 }
55 }
56}
57
58#[wasm_bindgen]
60impl WasmPastaFpLookupTable {
61 #[wasm_bindgen(constructor)]
62 pub fn new(id: i32, data: WasmVecVecFp) -> WasmPastaFpLookupTable {
63 WasmPastaFpLookupTable { id, data }
64 }
65}
66
67#[wasm_bindgen]
70pub struct WasmPastaFpRuntimeTableCfg {
71 #[wasm_bindgen(skip)]
72 pub id: i32,
73 #[wasm_bindgen(skip)]
74 pub first_column: WasmFlatVector<WasmPastaFp>,
75}
76
77#[wasm_bindgen]
79impl WasmPastaFpRuntimeTableCfg {
80 #[wasm_bindgen(constructor)]
81 pub fn new(id: i32, first_column: WasmFlatVector<WasmPastaFp>) -> Self {
82 Self { id, first_column }
83 }
84}
85
86impl From<WasmPastaFpRuntimeTableCfg> for RuntimeTableCfg<Fp> {
87 fn from(wasm_rt_table_cfg: WasmPastaFpRuntimeTableCfg) -> Self {
88 Self {
89 id: wasm_rt_table_cfg.id,
90 first_column: wasm_rt_table_cfg
91 .first_column
92 .into_iter()
93 .map(Into::into)
94 .collect(),
95 }
96 }
97}
98
99#[wasm_bindgen]
104pub fn caml_pasta_fp_plonk_index_create(
105 gates: &WasmGateVector,
106 public_: i32,
107 lookup_tables: WasmVector<WasmPastaFpLookupTable>,
108 runtime_table_cfgs: WasmVector<WasmPastaFpRuntimeTableCfg>,
109 prev_challenges: i32,
110 srs: &WasmSrs,
111 lazy_mode: bool,
112) -> Result<WasmPastaFpPlonkIndex, JsError> {
113 console_error_panic_hook::set_once();
114 let index = crate::rayon::run_in_pool(|| {
115 let gates: Vec<_> = gates
117 .0
118 .iter()
119 .map(|gate| CircuitGate::<Fp> {
120 typ: gate.typ,
121 wires: gate.wires,
122 coeffs: gate.coeffs.clone(),
123 })
124 .collect();
125
126 let rust_runtime_table_cfgs: Vec<RuntimeTableCfg<Fp>> =
127 runtime_table_cfgs.into_iter().map(Into::into).collect();
128
129 let rust_lookup_tables: Vec<LookupTable<Fp>> =
130 lookup_tables.into_iter().map(Into::into).collect();
131
132 let cs = match ConstraintSystem::<Fp>::create(gates)
134 .public(public_ as usize)
135 .prev_challenges(prev_challenges as usize)
136 .lookup(rust_lookup_tables)
137 .max_poly_size(Some(srs.0.max_poly_size()))
138 .runtime(if rust_runtime_table_cfgs.is_empty() {
139 None
140 } else {
141 Some(rust_runtime_table_cfgs)
142 })
143 .lazy_mode(lazy_mode)
144 .build()
145 {
146 Err(_) => {
147 return Err("caml_pasta_fp_plonk_index_create: could not create constraint system");
148 }
149 Ok(cs) => cs,
150 };
151
152 let (endo_q, _endo_r) = poly_commitment::ipa::endos::<GAffineOther>();
154
155 srs.0.get_lagrange_basis(cs.domain.d1);
156
157 let mut index = ProverIndex::<GAffine, OpeningProof<GAffine>>::create(
158 cs,
159 endo_q,
160 srs.0.clone(),
161 lazy_mode,
162 );
163 index.compute_verifier_index_digest::<DefaultFqSponge<VestaParameters, PlonkSpongeConstantsKimchi>>();
165 Ok(index)
166 });
167
168 match index {
170 Ok(index) => Ok(WasmPastaFpPlonkIndex(Box::new(index))),
171 Err(str) => Err(JsError::new(str)),
172 }
173}
174
175#[wasm_bindgen]
176pub fn caml_pasta_fp_plonk_index_max_degree(index: &WasmPastaFpPlonkIndex) -> i32 {
177 index.0.srs.max_poly_size() as i32
178}
179
180#[wasm_bindgen]
181pub fn caml_pasta_fp_plonk_index_public_inputs(index: &WasmPastaFpPlonkIndex) -> i32 {
182 index.0.cs.public as i32
183}
184
185#[wasm_bindgen]
186pub fn caml_pasta_fp_plonk_index_domain_d1_size(index: &WasmPastaFpPlonkIndex) -> i32 {
187 index.0.cs.domain.d1.size() as i32
188}
189
190#[wasm_bindgen]
191pub fn caml_pasta_fp_plonk_index_domain_d4_size(index: &WasmPastaFpPlonkIndex) -> i32 {
192 index.0.cs.domain.d4.size() as i32
193}
194
195#[wasm_bindgen]
196pub fn caml_pasta_fp_plonk_index_domain_d8_size(index: &WasmPastaFpPlonkIndex) -> i32 {
197 index.0.cs.domain.d8.size() as i32
198}
199
200#[wasm_bindgen]
201pub fn caml_pasta_fp_plonk_index_decode(
202 bytes: &[u8],
203 srs: &WasmSrs,
204) -> Result<WasmPastaFpPlonkIndex, JsError> {
205 let mut deserializer = rmp_serde::Deserializer::new(bytes);
206 let mut index =
207 ProverIndex::<GAffine, OpeningProof<GAffine>>::deserialize(&mut deserializer)
208 .map_err(|e| JsError::new(&format!("caml_pasta_fp_plonk_index_decode: {}", e)))?;
209
210 index.srs = srs.0.clone();
211 let (linearization, powers_of_alpha) = expr_linearization(Some(&index.cs.feature_flags), true);
212 index.linearization = linearization;
213 index.powers_of_alpha = powers_of_alpha;
214
215 Ok(WasmPastaFpPlonkIndex(Box::new(index)))
216}
217
218#[wasm_bindgen]
219pub fn caml_pasta_fp_plonk_index_encode(index: &WasmPastaFpPlonkIndex) -> Result<Vec<u8>, JsError> {
220 let mut buffer = Vec::new();
221 let mut serializer = rmp_serde::Serializer::new(&mut buffer);
222 index
223 .0
224 .serialize(&mut serializer)
225 .map_err(|e| JsError::new(&format!("caml_pasta_fp_plonk_index_encode: {}", e)))?;
226 Ok(buffer)
227}
228
229#[wasm_bindgen]
230pub fn caml_pasta_fp_plonk_index_read(
231 offset: Option<i32>,
232 srs: &WasmSrs,
233 path: String,
234) -> Result<WasmPastaFpPlonkIndex, JsValue> {
235 let file = match File::open(path) {
237 Err(_) => return Err(JsValue::from_str("caml_pasta_fp_plonk_index_read")),
238 Ok(file) => file,
239 };
240 let mut r = BufReader::new(file);
241
242 if let Some(offset) = offset {
244 r.seek(Start(offset as u64))
245 .map_err(|err| JsValue::from_str(&format!("caml_pasta_fp_plonk_index_read: {err}")))?;
246 }
247
248 let mut t = ProverIndex::<GAffine, OpeningProof<GAffine>>::deserialize(
250 &mut rmp_serde::Deserializer::new(r),
251 )
252 .map_err(|err| JsValue::from_str(&format!("caml_pasta_fp_plonk_index_read: {err}")))?;
253 t.srs = srs.0.clone();
254 let (linearization, powers_of_alpha) = expr_linearization(Some(&t.cs.feature_flags), true);
255 t.linearization = linearization;
256 t.powers_of_alpha = powers_of_alpha;
257
258 Ok(WasmPastaFpPlonkIndex(Box::new(t)))
260}
261
262#[wasm_bindgen]
263pub fn caml_pasta_fp_plonk_index_write(
264 append: Option<bool>,
265 index: &WasmPastaFpPlonkIndex,
266 path: String,
267) -> Result<(), JsValue> {
268 let file = OpenOptions::new()
269 .append(append.unwrap_or(true))
270 .open(path)
271 .map_err(|_| JsValue::from_str("caml_pasta_fp_plonk_index_write"))?;
272 let w = BufWriter::new(file);
273 index
274 .0
275 .serialize(&mut rmp_serde::Serializer::new(w))
276 .map_err(|e| JsValue::from_str(&format!("caml_pasta_fp_plonk_index_read: {e}")))
277}
278
279#[allow(deprecated)]
280#[wasm_bindgen]
281pub fn caml_pasta_fp_plonk_index_serialize(index: &WasmPastaFpPlonkIndex) -> String {
282 let serialized = rmp_serde::to_vec(&index.0).unwrap();
283 base64::encode(serialized)
285}
286
287fn format_field(f: &Fp) -> String {
290 format!("{f}")
292}
293
294pub fn format_circuit_gate(i: usize, gate: &CircuitGate<Fp>) -> String {
295 let coeffs = gate
296 .coeffs
297 .iter()
298 .map(format_field)
299 .collect::<Vec<_>>()
300 .join("\n");
301 let wires = gate
302 .wires
303 .iter()
304 .enumerate()
305 .filter(|(j, wire)| wire.row != i || wire.col != *j)
306 .map(|(j, wire)| format!("({}, {}) --> ({}, {})", i, j, wire.row, wire.col))
307 .collect::<Vec<_>>()
308 .join("\n");
309 format!(
310 "c[{}][{:?}]:\nconstraints\n{}\nwires\n{}\n",
311 i, gate.typ, coeffs, wires
312 )
313}