plonk_wasm/
pasta_fq_plonk_index.rs1use crate::{
2 gate_vector::fq::WasmGateVector,
3 srs::fq::WasmFqSrs as WasmSrs,
4 wasm_vector::{fq::*, WasmVector},
5};
6use ark_poly::EvaluationDomain;
7use arkworks::WasmPastaFq;
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::{Fq, Pallas as GAffine, PallasParameters, Vesta as GAffineOther};
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 WasmPastaFqPlonkIndex(
35 #[wasm_bindgen(skip)] pub Box<ProverIndex<GAffine, OpeningProof<GAffine>>>,
36);
37
38#[wasm_bindgen]
39pub struct WasmPastaFqLookupTable {
40 #[wasm_bindgen(skip)]
41 pub id: i32,
42 #[wasm_bindgen(skip)]
43 pub data: WasmVecVecFq,
44}
45
46impl From<WasmPastaFqLookupTable> for LookupTable<Fq> {
47 fn from(wasm_lt: WasmPastaFqLookupTable) -> LookupTable<Fq> {
48 LookupTable {
49 id: wasm_lt.id,
50 data: wasm_lt.data.0,
51 }
52 }
53}
54
55#[wasm_bindgen]
57impl WasmPastaFqLookupTable {
58 #[wasm_bindgen(constructor)]
59 pub fn new(id: i32, data: WasmVecVecFq) -> WasmPastaFqLookupTable {
60 WasmPastaFqLookupTable { id, data }
61 }
62}
63
64#[wasm_bindgen]
67pub struct WasmPastaFqRuntimeTableCfg {
68 #[wasm_bindgen(skip)]
69 pub id: i32,
70 #[wasm_bindgen(skip)]
71 pub first_column: WasmFlatVector<WasmPastaFq>,
72}
73
74impl From<WasmPastaFqRuntimeTableCfg> for RuntimeTableCfg<Fq> {
75 fn from(wasm_rt_cfg: WasmPastaFqRuntimeTableCfg) -> Self {
76 Self {
77 id: wasm_rt_cfg.id,
78 first_column: wasm_rt_cfg
79 .first_column
80 .into_iter()
81 .map(Into::into)
82 .collect(),
83 }
84 }
85}
86
87#[wasm_bindgen]
89impl WasmPastaFqRuntimeTableCfg {
90 #[wasm_bindgen(constructor)]
91 pub fn new(id: i32, first_column: WasmFlatVector<WasmPastaFq>) -> Self {
92 Self { id, first_column }
93 }
94}
95
96#[wasm_bindgen]
102pub fn caml_pasta_fq_plonk_index_create(
103 gates: &WasmGateVector,
104 public_: i32,
105 lookup_tables: WasmVector<WasmPastaFqLookupTable>,
106 runtime_table_cfgs: WasmVector<WasmPastaFqRuntimeTableCfg>,
107 prev_challenges: i32,
108 srs: &WasmSrs,
109 lazy_mode: bool,
110) -> Result<WasmPastaFqPlonkIndex, JsError> {
111 console_error_panic_hook::set_once();
112 let index = crate::rayon::run_in_pool(|| {
113 let gates: Vec<_> = gates
115 .0
116 .iter()
117 .map(|gate| CircuitGate::<Fq> {
118 typ: gate.typ,
119 wires: gate.wires,
120 coeffs: gate.coeffs.clone(),
121 })
122 .collect();
123
124 let rust_runtime_table_cfgs: Vec<RuntimeTableCfg<Fq>> =
125 runtime_table_cfgs.into_iter().map(Into::into).collect();
126
127 let rust_lookup_tables: Vec<LookupTable<Fq>> =
128 lookup_tables.into_iter().map(Into::into).collect();
129
130 let cs = match ConstraintSystem::<Fq>::create(gates)
132 .public(public_ as usize)
133 .prev_challenges(prev_challenges as usize)
134 .lookup(rust_lookup_tables)
135 .runtime(if rust_runtime_table_cfgs.is_empty() {
136 None
137 } else {
138 Some(rust_runtime_table_cfgs)
139 })
140 .lazy_mode(lazy_mode)
141 .build()
142 {
143 Err(_) => {
144 return Err("caml_pasta_fq_plonk_index_create: could not create constraint system");
145 }
146 Ok(cs) => cs,
147 };
148
149 let (endo_q, _endo_r) = poly_commitment::ipa::endos::<GAffineOther>();
151
152 srs.0.get_lagrange_basis(cs.domain.d1);
153
154 let mut index = ProverIndex::<GAffine, OpeningProof<GAffine>>::create(
155 cs,
156 endo_q,
157 srs.0.clone(),
158 lazy_mode,
159 );
160 index.compute_verifier_index_digest::<DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi>>();
162
163 Ok(index)
164 });
165
166 match index {
168 Ok(index) => Ok(WasmPastaFqPlonkIndex(Box::new(index))),
169 Err(str) => Err(JsError::new(str)),
170 }
171}
172
173#[wasm_bindgen]
174pub fn caml_pasta_fq_plonk_index_max_degree(index: &WasmPastaFqPlonkIndex) -> i32 {
175 index.0.srs.max_poly_size() as i32
176}
177
178#[wasm_bindgen]
179pub fn caml_pasta_fq_plonk_index_public_inputs(index: &WasmPastaFqPlonkIndex) -> i32 {
180 index.0.cs.public as i32
181}
182
183#[wasm_bindgen]
184pub fn caml_pasta_fq_plonk_index_domain_d1_size(index: &WasmPastaFqPlonkIndex) -> i32 {
185 index.0.cs.domain.d1.size() as i32
186}
187
188#[wasm_bindgen]
189pub fn caml_pasta_fq_plonk_index_domain_d4_size(index: &WasmPastaFqPlonkIndex) -> i32 {
190 index.0.cs.domain.d4.size() as i32
191}
192
193#[wasm_bindgen]
194pub fn caml_pasta_fq_plonk_index_domain_d8_size(index: &WasmPastaFqPlonkIndex) -> i32 {
195 index.0.cs.domain.d8.size() as i32
196}
197
198#[wasm_bindgen]
199pub fn caml_pasta_fq_plonk_index_decode(
200 bytes: &[u8],
201 srs: &WasmSrs,
202) -> Result<WasmPastaFqPlonkIndex, JsError> {
203 let mut deserializer = rmp_serde::Deserializer::new(bytes);
204 let mut index =
205 ProverIndex::<GAffine, OpeningProof<GAffine>>::deserialize(&mut deserializer)
206 .map_err(|e| JsError::new(&format!("caml_pasta_fq_plonk_index_decode: {}", e)))?;
207
208 index.srs = srs.0.clone();
209 let (linearization, powers_of_alpha) = expr_linearization(Some(&index.cs.feature_flags), true);
210 index.linearization = linearization;
211 index.powers_of_alpha = powers_of_alpha;
212
213 Ok(WasmPastaFqPlonkIndex(Box::new(index)))
214}
215
216#[wasm_bindgen]
217pub fn caml_pasta_fq_plonk_index_encode(index: &WasmPastaFqPlonkIndex) -> Result<Vec<u8>, JsError> {
218 let mut buffer = Vec::new();
219 let mut serializer = rmp_serde::Serializer::new(&mut buffer);
220 index
221 .0
222 .serialize(&mut serializer)
223 .map_err(|e| JsError::new(&format!("caml_pasta_fq_plonk_index_encode: {}", e)))?;
224 Ok(buffer)
225}
226
227#[wasm_bindgen]
228pub fn caml_pasta_fq_plonk_index_read(
229 offset: Option<i32>,
230 srs: &WasmSrs,
231 path: String,
232) -> Result<WasmPastaFqPlonkIndex, JsValue> {
233 let file = match File::open(path) {
235 Err(_) => return Err(JsValue::from_str("caml_pasta_fq_plonk_index_read")),
236 Ok(file) => file,
237 };
238 let mut r = BufReader::new(file);
239
240 if let Some(offset) = offset {
242 r.seek(Start(offset as u64))
243 .map_err(|err| JsValue::from_str(&format!("caml_pasta_fq_plonk_index_read: {err}")))?;
244 }
245
246 let mut t = ProverIndex::<GAffine, OpeningProof<GAffine>>::deserialize(
248 &mut rmp_serde::Deserializer::new(r),
249 )
250 .map_err(|err| JsValue::from_str(&format!("caml_pasta_fq_plonk_index_read: {err}")))?;
251 t.srs = srs.0.clone();
252 let (linearization, powers_of_alpha) = expr_linearization(Some(&t.cs.feature_flags), true);
253 t.linearization = linearization;
254 t.powers_of_alpha = powers_of_alpha;
255
256 Ok(WasmPastaFqPlonkIndex(Box::new(t)))
258}
259
260#[wasm_bindgen]
261pub fn caml_pasta_fq_plonk_index_write(
262 append: Option<bool>,
263 index: &WasmPastaFqPlonkIndex,
264 path: String,
265) -> Result<(), JsValue> {
266 let file = OpenOptions::new()
267 .append(append.unwrap_or(true))
268 .open(path)
269 .map_err(|_| JsValue::from_str("caml_pasta_fq_plonk_index_write"))?;
270 let w = BufWriter::new(file);
271 index
272 .0
273 .serialize(&mut rmp_serde::Serializer::new(w))
274 .map_err(|e| JsValue::from_str(&format!("caml_pasta_fq_plonk_index_read: {e}")))
275}
276
277#[allow(deprecated)]
278#[wasm_bindgen]
279pub fn caml_pasta_fq_plonk_index_serialize(index: &WasmPastaFqPlonkIndex) -> String {
280 let serialized = rmp_serde::to_vec(&index.0).unwrap();
281 base64::encode(serialized)
283}