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