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