1use crate::{wasm_flat_vector::WasmFlatVector, wasm_vector::WasmVector};
2use ark_poly::{univariate::DensePolynomial, DenseUVPolynomial, EvaluationDomain, Evaluations};
3use core::ops::Deref;
4use paste::paste;
5use poly_commitment::{
6 commitment::b_poly_coefficients, hash_map_cache::HashMapCache, ipa::SRS, SRS as ISRS,
7};
8use serde::{Deserialize, Serialize};
9use std::{
10 fs::{File, OpenOptions},
11 io::{BufReader, BufWriter, Seek, SeekFrom::Start},
12 sync::Arc,
13};
14use wasm_bindgen::prelude::*;
15
16macro_rules! impl_srs {
17 ($name: ident,
18 $WasmF: ty,
19 $WasmG: ty,
20 $F: ty,
21 $G: ty,
22 $WasmPolyComm: ty,
23 $field_name: ident) => {
24 paste! {
25 #[wasm_bindgen]
26 #[derive(Clone)]
27 pub struct [<Wasm $field_name:camel Srs>](
28 #[wasm_bindgen(skip)]
29 pub Arc<SRS<$G>>);
30
31 impl Deref for [<Wasm $field_name:camel Srs>] {
32 type Target = Arc<SRS<$G>>;
33
34 fn deref(&self) -> &Self::Target { &self.0 }
35 }
36
37 impl From<Arc<SRS<$G>>> for [<Wasm $field_name:camel Srs>] {
38 fn from(x: Arc<SRS<$G>>) -> Self {
39 [<Wasm $field_name:camel Srs>](x)
40 }
41 }
42
43 impl From<&Arc<SRS<$G>>> for [<Wasm $field_name:camel Srs>] {
44 fn from(x: &Arc<SRS<$G>>) -> Self {
45 [<Wasm $field_name:camel Srs>](x.clone())
46 }
47 }
48
49 impl From<[<Wasm $field_name:camel Srs>]> for Arc<SRS<$G>> {
50 fn from(x: [<Wasm $field_name:camel Srs>]) -> Self {
51 x.0
52 }
53 }
54
55 impl From<&[<Wasm $field_name:camel Srs>]> for Arc<SRS<$G>> {
56 fn from(x: &[<Wasm $field_name:camel Srs>]) -> Self {
57 x.0.clone()
58 }
59 }
60
61 impl<'a> From<&'a [<Wasm $field_name:camel Srs>]> for &'a Arc<SRS<$G>> {
62 fn from(x: &'a [<Wasm $field_name:camel Srs>]) -> Self {
63 &x.0
64 }
65 }
66
67 #[wasm_bindgen]
68 pub fn [<$name:snake _create>](depth: i32) -> [<Wasm $field_name:camel Srs>] {
69 Arc::new(SRS::create(depth as usize)).into()
70 }
71
72 #[wasm_bindgen]
73 pub fn [<$name:snake _add_lagrange_basis>](
74 srs: &[<Wasm $field_name:camel Srs>],
75 log2_size: i32,
76 ) {
77 crate::rayon::run_in_pool(|| {
78 let domain = EvaluationDomain::<$F>::new(1 << (log2_size as usize)).expect("invalid domain size");
79 srs.get_lagrange_basis(domain);
80 });
81 }
82
83 #[wasm_bindgen]
84 pub fn [<$name:snake _write>](
85 append: Option<bool>,
86 srs: &[<Wasm $field_name:camel Srs>],
87 path: String,
88 ) -> Result<(), JsValue> {
89 let file = OpenOptions::new()
90 .append(append.unwrap_or(true))
91 .open(path)
92 .map_err(|err| {
93 JsValue::from_str(format!("caml_pasta_fp_urs_write: {}", err).as_str())
94 })?;
95 let file = BufWriter::new(file);
96
97 srs.0.serialize(&mut rmp_serde::Serializer::new(file))
98 .map_err(|e| JsValue::from_str(format!("caml_pasta_fp_urs_write: {}", e).as_str()))
99 }
100
101 #[wasm_bindgen]
102 pub fn [<$name:snake _read>](
103 offset: Option<i32>,
104 path: String,
105 ) -> Result<Option<[<Wasm $field_name:camel Srs>]>, JsValue> {
106 let file = File::open(path).map_err(|err| {
107 JsValue::from_str(format!("caml_pasta_fp_urs_read: {}", err).as_str())
108 })?;
109 let mut reader = BufReader::new(file);
110
111 if let Some(offset) = offset {
112 reader.seek(Start(offset as u64)).map_err(|err| {
113 JsValue::from_str(format!("caml_pasta_fp_urs_read: {}", err).as_str())
114 })?;
115 }
116
117 let srs = match SRS::<$G>::deserialize(&mut rmp_serde::Deserializer::new(reader)) {
119 Ok(srs) => srs,
120 Err(_) => return Ok(None),
121 };
122
123 Ok(Some(Arc::new(srs).into()))
124 }
125
126 #[wasm_bindgen]
127 pub fn [<$name:snake _lagrange_commitments_whole_domain_ptr>](
128 srs: &[<Wasm $field_name:camel Srs>],
129 domain_size: i32,
130 ) -> *mut WasmVector<$WasmPolyComm> {
131 let comm = srs
135 .get_lagrange_basis_from_domain_size(domain_size as usize)
136 .clone()
137 .into_iter()
138 .map(|x| x.into())
139 .collect();
140 let boxed_comm = Box::<WasmVector<WasmPolyComm>>::new(comm);
141 Box::into_raw(boxed_comm)
142 }
143
144 #[wasm_bindgen]
151 pub unsafe fn [<$name:snake _lagrange_commitments_whole_domain_read_from_ptr>](
152 ptr: *mut WasmVector<$WasmPolyComm>,
153 ) -> WasmVector<$WasmPolyComm> {
154 let b = unsafe { Box::from_raw(ptr) };
157 b.as_ref().clone()
158 }
159
160 #[wasm_bindgen]
161 pub fn [<$name:snake _lagrange_commitment>](
162 srs: &[<Wasm $field_name:camel Srs>],
163 domain_size: i32,
164 i: i32,
165 ) -> Result<$WasmPolyComm, JsValue> {
166 let x_domain = EvaluationDomain::<$F>::new(domain_size as usize).ok_or_else(|| {
167 JsValue::from_str("caml_pasta_fp_urs_lagrange_commitment")
168 })?;
169 let basis =
170 crate::rayon::run_in_pool(|| {
171 srs.get_lagrange_basis(x_domain)
172 });
173
174 Ok(basis[i as usize].clone().into())
175 }
176
177 #[wasm_bindgen]
178 pub fn [<$name:snake _commit_evaluations>](
179 srs: &[<Wasm $field_name:camel Srs>],
180 domain_size: i32,
181 evals: WasmFlatVector<$WasmF>,
182 ) -> Result<$WasmPolyComm, JsValue> {
183 let x_domain = EvaluationDomain::<$F>::new(domain_size as usize).ok_or_else(|| {
184 JsValue::from_str("caml_pasta_fp_urs_commit_evaluations")
185 })?;
186
187 let evals = evals.into_iter().map(Into::into).collect();
188 let p = Evaluations::<$F>::from_vec_and_domain(evals, x_domain).interpolate();
189
190 Ok(srs.commit_non_hiding(&p, 1).into())
191 }
192
193 #[wasm_bindgen]
194 pub fn [<$name:snake _b_poly_commitment>](
195 srs: &[<Wasm $field_name:camel Srs>],
196 chals: WasmFlatVector<$WasmF>,
197 ) -> Result<$WasmPolyComm, JsValue> {
198 let result = crate::rayon::run_in_pool(|| {
199 let chals: Vec<$F> = chals.into_iter().map(Into::into).collect();
200 let coeffs = b_poly_coefficients(&chals);
201 let p = DensePolynomial::<$F>::from_coefficients_vec(coeffs);
202 srs.commit_non_hiding(&p, 1)
203 });
204 Ok(result.into())
205 }
206
207 #[wasm_bindgen]
208 pub fn [<$name:snake _batch_accumulator_check>](
209 srs: &[<Wasm $field_name:camel Srs>],
210 comms: WasmVector<$WasmG>,
211 chals: WasmFlatVector<$WasmF>,
212 ) -> bool {
213 crate::rayon::run_in_pool(|| {
214 let comms: Vec<_> = comms.into_iter().map(Into::into).collect();
215 let chals: Vec<_> = chals.into_iter().map(Into::into).collect();
216 poly_commitment::utils::batch_dlog_accumulator_check(&srs, &comms, &chals)
217 })
218 }
219
220 #[wasm_bindgen]
221 pub fn [<$name:snake _batch_accumulator_generate>](
222 srs: &[<Wasm $field_name:camel Srs>],
223 comms: i32,
224 chals: WasmFlatVector<$WasmF>,
225 ) -> WasmVector<$WasmG> {
226 poly_commitment::utils::batch_dlog_accumulator_generate::<$G>(
227 &srs,
228 comms as usize,
229 &chals.into_iter().map(From::from).collect(),
230 ).into_iter().map(Into::into).collect()
231 }
232
233 #[wasm_bindgen]
234 pub fn [<$name:snake _h>](srs: &[<Wasm $field_name:camel Srs>]) -> $WasmG {
235 srs.h.into()
236 }
237 }
238 }
239}
240
241pub mod fp {
246 use super::*;
247 use crate::{
248 arkworks::{WasmGVesta as WasmG, WasmPastaFp},
249 poly_comm::vesta::WasmFpPolyComm as WasmPolyComm,
250 };
251 use mina_curves::pasta::{Fp, Vesta as G};
252
253 impl_srs!(caml_fp_srs, WasmPastaFp, WasmG, Fp, G, WasmPolyComm, Fp);
254 #[wasm_bindgen]
255 pub fn caml_fp_srs_create_parallel(depth: i32) -> WasmFpSrs {
256 crate::rayon::run_in_pool(|| Arc::new(SRS::<G>::create_parallel(depth as usize)).into())
257 }
258
259 #[wasm_bindgen]
261 pub fn caml_fp_srs_get(srs: &WasmFpSrs) -> WasmVector<WasmG> {
262 let mut h_and_gs: Vec<WasmG> = vec![srs.0.h.into()];
264 h_and_gs.extend(srs.0.g.iter().map(|x: &G| WasmG::from(*x)));
265 h_and_gs.into()
266 }
267
268 #[wasm_bindgen]
270 pub fn caml_fp_srs_set(h_and_gs: WasmVector<WasmG>) -> WasmFpSrs {
271 let mut h_and_gs: Vec<G> = h_and_gs.into_iter().map(|x| x.into()).collect();
273 let h = h_and_gs.remove(0);
274 let g = h_and_gs;
275 let srs = SRS::<G> {
276 h,
277 g,
278 lagrange_bases: HashMapCache::new(),
279 };
280 Arc::new(srs).into()
281 }
282
283 #[wasm_bindgen]
285 pub fn caml_fp_srs_maybe_lagrange_commitment(
286 srs: &WasmFpSrs,
287 domain_size: i32,
288 i: i32,
289 ) -> Option<WasmPolyComm> {
290 if !(srs.0.lagrange_bases.contains_key(&(domain_size as usize))) {
291 return None;
292 }
293 let basis = srs.get_lagrange_basis_from_domain_size(domain_size as usize);
294 Some(basis[i as usize].clone().into())
295 }
296
297 #[wasm_bindgen]
299 pub fn caml_fp_srs_set_lagrange_basis(
300 srs: &WasmFpSrs,
301 domain_size: i32,
302 input_bases: WasmVector<WasmPolyComm>,
303 ) {
304 srs.lagrange_bases
305 .get_or_generate(domain_size as usize, || {
306 input_bases.into_iter().map(Into::into).collect()
307 });
308 }
309
310 #[wasm_bindgen]
312 pub fn caml_fp_srs_get_lagrange_basis(
313 srs: &WasmFpSrs,
314 domain_size: i32,
315 ) -> WasmVector<WasmPolyComm> {
316 let basis = crate::rayon::run_in_pool(|| {
318 let domain =
319 EvaluationDomain::<Fp>::new(domain_size as usize).expect("invalid domain size");
320 srs.get_lagrange_basis(domain)
321 });
322 basis.iter().map(Into::into).collect()
323 }
324}
325
326pub mod fq {
327 use super::*;
328 use crate::{
329 arkworks::{WasmGPallas as WasmG, WasmPastaFq},
330 poly_comm::pallas::WasmFqPolyComm as WasmPolyComm,
331 };
332 use mina_curves::pasta::{Fq, Pallas as G};
333
334 impl_srs!(caml_fq_srs, WasmPastaFq, WasmG, Fq, G, WasmPolyComm, Fq);
335
336 #[wasm_bindgen]
337 pub fn caml_fq_srs_create_parallel(depth: i32) -> WasmFqSrs {
338 crate::rayon::run_in_pool(|| Arc::new(SRS::<G>::create_parallel(depth as usize)).into())
339 }
340
341 #[wasm_bindgen]
343 pub fn caml_fq_srs_get(srs: &WasmFqSrs) -> WasmVector<WasmG> {
344 let mut h_and_gs: Vec<WasmG> = vec![srs.0.h.into()];
346 h_and_gs.extend(srs.0.g.iter().map(|x: &G| WasmG::from(*x)));
347 h_and_gs.into()
348 }
349
350 #[wasm_bindgen]
352 pub fn caml_fq_srs_set(h_and_gs: WasmVector<WasmG>) -> WasmFqSrs {
353 let mut h_and_gs: Vec<G> = h_and_gs.into_iter().map(|x| x.into()).collect();
355 let h = h_and_gs.remove(0);
356 let g = h_and_gs;
357 let srs = SRS::<G> {
358 h,
359 g,
360 lagrange_bases: HashMapCache::new(),
361 };
362 Arc::new(srs).into()
363 }
364
365 #[wasm_bindgen]
367 pub fn caml_fq_srs_maybe_lagrange_commitment(
368 srs: &WasmFqSrs,
369 domain_size: i32,
370 i: i32,
371 ) -> Option<WasmPolyComm> {
372 if !(srs.0.lagrange_bases.contains_key(&(domain_size as usize))) {
373 return None;
374 }
375 let basis = srs.get_lagrange_basis_from_domain_size(domain_size as usize);
376 Some(basis[i as usize].clone().into())
377 }
378
379 #[wasm_bindgen]
381 pub fn caml_fq_srs_set_lagrange_basis(
382 srs: &WasmFqSrs,
383 domain_size: i32,
384 input_bases: WasmVector<WasmPolyComm>,
385 ) {
386 srs.lagrange_bases
387 .get_or_generate(domain_size as usize, || {
388 input_bases.into_iter().map(Into::into).collect()
389 });
390 }
391
392 #[wasm_bindgen]
394 pub fn caml_fq_srs_get_lagrange_basis(
395 srs: &WasmFqSrs,
396 domain_size: i32,
397 ) -> WasmVector<WasmPolyComm> {
398 let basis = crate::rayon::run_in_pool(|| {
400 let domain =
401 EvaluationDomain::<Fq>::new(domain_size as usize).expect("invalid domain size");
402 srs.get_lagrange_basis(domain)
403 });
404 basis.iter().map(Into::into).collect()
405 }
406}