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