1use crate::{
2 vector::{NapiFlatVector, NapiVector},
3 wrappers::field::{NapiPastaFp, NapiPastaFq},
4};
5use ark_ff::{One, Zero};
6use kimchi::{
7 circuits::scalars::RandomOracles, proof::ProverProof,
8 verifier_index::VerifierIndex as DlogVerifierIndex,
9};
10use mina_poseidon::{
11 self,
12 constants::PlonkSpongeConstantsKimchi,
13 pasta::FULL_ROUNDS,
14 sponge::{DefaultFqSponge, DefaultFrSponge},
15 FqSponge,
16};
17use napi::{bindgen_prelude::*, Error as NapiError, Status};
18use napi_derive::napi;
19use paste::paste;
20use poly_commitment::{
21 commitment::{shift_scalar, PolyComm},
22 ipa::{OpeningProof, SRS as IPA_SRS},
23 SRS,
24};
25
26macro_rules! impl_oracles {
27 ($NapiF: ty,
28 $F: ty,
29 $NapiG: ty,
30 $G: ty,
31 $NapiPolyComm: ty,
32 $NapiProverProof: ty,
33 $index: ty,
34 $curve_params: ty,
35 $field_name: ident) => {
36
37 paste! {
38 use mina_poseidon::sponge::ScalarChallenge;
39
40 #[napi(js_name = [<Wasm $field_name:camel RandomOracles>])]
41 #[derive(Clone, Copy)]
42 pub struct [<Napi $field_name:camel RandomOracles>] {
43 #[napi(js_name = "joint_combiner_chal")]
44 pub joint_combiner_chal: Option<$NapiF>,
45 #[napi(js_name = "joint_combiner")]
46 pub joint_combiner: Option<$NapiF>,
47 pub beta: $NapiF,
48 pub gamma: $NapiF,
49 #[napi(js_name = "alpha_chal")]
50 pub alpha_chal: $NapiF,
51 pub alpha: $NapiF,
52 pub zeta: $NapiF,
53 pub v: $NapiF,
54 pub u: $NapiF,
55 #[napi(js_name = "zeta_chal")]
56 pub zeta_chal: $NapiF,
57 #[napi(js_name = "v_chal")]
58 pub v_chal: $NapiF,
59 #[napi(js_name = "u_chal")]
60 pub u_chal: $NapiF,
61 }
62 type NapiRandomOracles = [<Napi $field_name:camel RandomOracles>];
63
64 #[napi]
65 impl [<Napi $field_name:camel RandomOracles>] {
66 #[napi(constructor)]
67 #[allow(clippy::too_many_arguments)]
68 pub fn new(
69 joint_combiner_chal: Option<$NapiF>,
70 joint_combiner: Option<$NapiF>,
71 beta: $NapiF,
72 gamma: $NapiF,
73 alpha_chal: $NapiF,
74 alpha: $NapiF,
75 zeta: $NapiF,
76 v: $NapiF,
77 u: $NapiF,
78 zeta_chal: $NapiF,
79 v_chal: $NapiF,
80 u_chal: $NapiF) -> Self {
81 Self {
82 joint_combiner_chal,
83 joint_combiner,
84 beta,
85 gamma,
86 alpha_chal,
87 alpha,
88 zeta,
89 v,
90 u,
91 zeta_chal,
92 v_chal,
93 u_chal,
94 }
95 }
96 }
97
98 impl From<RandomOracles<$F>> for NapiRandomOracles
99 {
100 fn from(ro: RandomOracles<$F>) -> Self {
101 Self {
102 joint_combiner_chal: ro.joint_combiner.as_ref().map(|x| x.0.inner().into()),
103 joint_combiner: ro.joint_combiner.as_ref().map(|x| x.1.into()),
104 beta: ro.beta.into(),
105 gamma: ro.gamma.into(),
106 alpha_chal: ro.alpha_chal.inner().into(),
107 alpha: ro.alpha.into(),
108 zeta: ro.zeta.into(),
109 v: ro.v.into(),
110 u: ro.u.into(),
111 zeta_chal: ro.zeta_chal.inner().into(),
112 v_chal: ro.v_chal.inner().into(),
113 u_chal: ro.u_chal.inner().into(),
114 }
115 }
116 }
117
118 impl From<NapiRandomOracles> for RandomOracles<$F>
119 {
120 fn from(ro: NapiRandomOracles) -> Self {
121 Self {
122 joint_combiner: ro.joint_combiner_chal.and_then(|x| {
123 ro.joint_combiner.map(|y| (ScalarChallenge::new(x.into()), y.into()))
124 }),
125 beta: ro.beta.into(),
126 gamma: ro.gamma.into(),
127 alpha_chal: ScalarChallenge::new(ro.alpha_chal.into()),
128 alpha: ro.alpha.into(),
129 zeta: ro.zeta.into(),
130 v: ro.v.into(),
131 u: ro.u.into(),
132 zeta_chal: ScalarChallenge::new(ro.zeta_chal.into()),
133 v_chal: ScalarChallenge::new(ro.v_chal.into()),
134 u_chal: ScalarChallenge::new(ro.u_chal.into()),
135 }
136 }
137 }
138
139 impl FromNapiValue for [<Napi $field_name:camel RandomOracles>] {
140 unsafe fn from_napi_value(
141 env: sys::napi_env,
142 napi_val: sys::napi_value,
143 ) -> Result<Self> {
144 let instance = <ClassInstance<[<Napi $field_name:camel RandomOracles>]> as FromNapiValue>::from_napi_value(env, napi_val)?;
145 Ok((*instance).clone())
146 }
147 }
148
149 impl<'a> ToNapiValue for &'a mut [<Napi $field_name:camel RandomOracles>] {
150 unsafe fn to_napi_value(
151 env: sys::napi_env,
152 val: Self,
153 ) -> Result<sys::napi_value> {
154 <[<Napi $field_name:camel RandomOracles>] as ToNapiValue>::to_napi_value(env, val.clone())
155 }
156 }
157
158 #[napi(js_name = [<Wasm $field_name:camel Oracles>])]
159 #[derive(Clone)]
160 pub struct [<Napi $field_name:camel Oracles>] {
161 pub o: [<Napi $field_name:camel RandomOracles>],
162 #[napi(skip)]
163 pub p_eval0: NapiFlatVector<$NapiF>,
164 #[napi(skip)]
165 pub p_eval1: NapiFlatVector<$NapiF>,
166 #[napi(skip)]
167 pub opening_prechallenges: NapiFlatVector<$NapiF>,
168 #[napi(js_name = "digest_before_evaluations")]
169 pub digest_before_evaluations: $NapiF,
170 }
171
172 #[napi]
173 impl [<Napi $field_name:camel Oracles>] {
174 #[napi(constructor)]
175 pub fn new(
176 o: NapiRandomOracles,
177 p_eval0: NapiFlatVector<$NapiF>,
178 p_eval1: NapiFlatVector<$NapiF>,
179 opening_prechallenges: NapiFlatVector<$NapiF>,
180 digest_before_evaluations: $NapiF) -> Self {
181 Self {o, p_eval0, p_eval1, opening_prechallenges, digest_before_evaluations}
182 }
183
184 #[napi(getter, js_name="p_eval0")]
185 pub fn p_eval0(&self) -> NapiFlatVector<$NapiF> {
186 self.p_eval0.clone()
187 }
188
189 #[napi(setter, js_name="set_p_eval0")]
190 pub fn set_p_eval0(&mut self, x: NapiFlatVector<$NapiF>) {
191 self.p_eval0 = x;
192 }
193
194 #[napi(getter, js_name="p_eval1")]
195 pub fn p_eval1(&self) -> NapiFlatVector<$NapiF> {
196 self.p_eval1.clone()
197 }
198
199 #[napi(setter, js_name="set_p_eval1")]
200 pub fn set_p_eval1(&mut self, x: NapiFlatVector<$NapiF>) {
201 self.p_eval1 = x;
202 }
203
204 #[napi(getter, js_name="opening_prechallenges")]
205 pub fn opening_prechallenges(&self) -> NapiFlatVector<$NapiF> {
206 self.opening_prechallenges.clone()
207 }
208
209 #[napi(setter, js_name="set_opening_prechallenges")]
210 pub fn set_opening_prechallenges(&mut self, x: NapiFlatVector<$NapiF>) {
211 self.opening_prechallenges = x;
212 }
213 }
214
215 #[napi(js_name = [<$F:snake _oracles_create>])]
216 pub fn [<$F:snake _oracles_create>](
217 lgr_comm: NapiVector<$NapiPolyComm>, index: $index, proof: $NapiProverProof, ) -> Result<[<Napi $field_name:camel Oracles>]> {
221 let result: Result<(RandomOracles<$F>, [Vec<$F>; 2], NapiFlatVector<$NapiF>, $F), String> = {
223 let index: DlogVerifierIndex<FULL_ROUNDS, $G, IPA_SRS<$G>> = index.into();
224
225 let lgr_comm: Vec<PolyComm<$G>> = lgr_comm
226 .into_iter()
227 .take(proof.public.len())
228 .map(Into::into)
229 .collect();
230 let lgr_comm_refs: Vec<_> = lgr_comm.iter().collect();
231
232 let p_comm = PolyComm::<$G>::multi_scalar_mul(
233 &lgr_comm_refs,
234 &proof
235 .public
236 .iter()
237 .map(|a| a.clone().into())
238 .map(|s: $F| -s)
239 .collect::<Vec<_>>(),
240 );
241 let p_comm = {
242 index
243 .srs()
244 .mask_custom(
245 p_comm.clone(),
246 &p_comm.map(|_| $F::one()),
247 )
248 .unwrap()
249 .commitment
250 };
251
252 let (proof, public_input): (ProverProof<$G, OpeningProof<$G, FULL_ROUNDS>, FULL_ROUNDS>, Vec<$F>) = proof.into();
253
254 let oracles_result =
255 proof.oracles::<
256 DefaultFqSponge<$curve_params, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
257 DefaultFrSponge<$F, PlonkSpongeConstantsKimchi, FULL_ROUNDS>
258 , IPA_SRS<$G>
259 >(&index, &p_comm, Some(&public_input));
260 let oracles_result = match oracles_result {
261 Err(e) => {
262 return Err(NapiError::new(Status::GenericFailure, format!("oracles_create: {}", e)));
263 }
264 Ok(cs) => cs,
265 };
266
267 let (mut sponge, combined_inner_product, p_eval, digest, oracles) = (
268 oracles_result.fq_sponge,
269 oracles_result.combined_inner_product,
270 oracles_result.public_evals,
271 oracles_result.digest,
272 oracles_result.oracles,
273 );
274
275 sponge.absorb_fr(&[shift_scalar::<$G>(combined_inner_product)]);
276
277 let opening_prechallenges = proof
278 .proof
279 .prechallenges(&mut sponge)
280 .into_iter()
281 .map(|x| x.inner().into())
282 .collect();
283
284 Ok((oracles, p_eval, opening_prechallenges, digest))
285 };
286
287 match result {
288 Ok((oracles, p_eval, opening_prechallenges, digest)) => {
289 let [pe0, pe1] = p_eval;
290 Ok([<Napi $field_name:camel Oracles>] {
291 o: oracles.into(),
292 p_eval0: pe0.into_iter().map(Into::into).collect::<Vec<_>>().into(),
293 p_eval1: pe1.into_iter().map(Into::into).collect::<Vec<_>>().into(),
294 opening_prechallenges,
295 digest_before_evaluations: digest.into()
296 })
297 },
298 Err(err) => Err(NapiError::new(Status::GenericFailure, err)),
299 }
300 }
301
302 #[napi(js_name = [<$F:snake _oracles_dummy>])]
303 pub fn [<$F:snake _oracles_dummy>]() -> [<Napi $field_name:camel Oracles>] {
304 [<Napi $field_name:camel Oracles>] {
305 o: RandomOracles::<$F>::default().into(),
306 p_eval0: vec![$F::zero().into()].into(),
307 p_eval1: vec![$F::zero().into()].into(),
308 opening_prechallenges: vec![].into(),
309 digest_before_evaluations: $F::zero().into(),
310 }
311 }
312
313 #[napi(js_name = [<$F:snake _oracles_deep_copy>])]
314 pub fn [<$F:snake _oracles_deep_copy>](
315 x: $NapiProverProof,
316 ) -> $NapiProverProof {
317 x
318 }
319 }
320 }
321}
322
323pub mod fp {
324 use super::*;
325 use crate::{
326 plonk_verifier_index::fp::NapiFpPlonkVerifierIndex as WasmPlonkVerifierIndex,
327 poly_comm::vesta::NapiFpPolyComm as WasmPolyComm,
328 proof::fp::NapiFpProverProof as WasmProverProof,
329 };
330 use mina_curves::pasta::{Fp, Vesta as GAffine, VestaParameters};
331
332 impl_oracles!(
333 NapiPastaFp,
334 Fp,
335 WasmGVesta,
336 GAffine,
337 WasmPolyComm,
338 WasmProverProof,
339 WasmPlonkVerifierIndex,
340 VestaParameters,
341 Fp
342 );
343}
344
345pub mod fq {
346 use super::*;
347 use crate::{
348 plonk_verifier_index::fq::NapiFqPlonkVerifierIndex as WasmPlonkVerifierIndex,
349 poly_comm::pallas::NapiFqPolyComm as WasmPolyComm,
350 proof::fq::NapiFqProverProof as WasmProverProof,
351 };
352 use mina_curves::pasta::{Fq, Pallas as GAffine, PallasParameters};
353
354 impl_oracles!(
355 NapiPastaFq,
356 Fq,
357 WasmGPallas,
358 GAffine,
359 WasmPolyComm,
360 WasmProverProof,
361 WasmPlonkVerifierIndex,
362 PallasParameters,
363 Fq
364 );
365}