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(js_name = "p_eval0")]
163 pub p_eval0: $NapiF,
164 #[napi(js_name = "p_eval1")]
165 pub p_eval1: $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: $NapiF,
178 p_eval1: $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="opening_prechallenges")]
185 pub fn opening_prechallenges(&self) -> NapiFlatVector<$NapiF> {
186 self.opening_prechallenges.clone()
187 }
188
189 #[napi(setter, js_name="set_opening_prechallenges")]
190 pub fn set_opening_prechallenges(&mut self, x: NapiFlatVector<$NapiF>) {
191 self.opening_prechallenges = x;
192 }
193 }
194
195 #[napi(js_name = [<$F:snake _oracles_create>])]
196 pub fn [<$F:snake _oracles_create>](
197 lgr_comm: NapiVector<$NapiPolyComm>, index: $index, proof: $NapiProverProof, ) -> Result<[<Napi $field_name:camel Oracles>]> {
201 let result: Result<(RandomOracles<$F>, [Vec<$F>; 2], NapiFlatVector<$NapiF>, $F), String> = {
203 let index: DlogVerifierIndex<FULL_ROUNDS, $G, IPA_SRS<$G>> = index.into();
204
205 let lgr_comm: Vec<PolyComm<$G>> = lgr_comm
206 .into_iter()
207 .take(proof.public.len())
208 .map(Into::into)
209 .collect();
210 let lgr_comm_refs: Vec<_> = lgr_comm.iter().collect();
211
212 let p_comm = PolyComm::<$G>::multi_scalar_mul(
213 &lgr_comm_refs,
214 &proof
215 .public
216 .iter()
217 .map(|a| a.clone().into())
218 .map(|s: $F| -s)
219 .collect::<Vec<_>>(),
220 );
221 let p_comm = {
222 index
223 .srs()
224 .mask_custom(
225 p_comm.clone(),
226 &p_comm.map(|_| $F::one()),
227 )
228 .unwrap()
229 .commitment
230 };
231
232 let (proof, public_input): (ProverProof<$G, OpeningProof<$G, FULL_ROUNDS>, FULL_ROUNDS>, Vec<$F>) = proof.into();
233
234 let oracles_result =
235 proof.oracles::<
236 DefaultFqSponge<$curve_params, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
237 DefaultFrSponge<$F, PlonkSpongeConstantsKimchi, FULL_ROUNDS>
238 , IPA_SRS<$G>
239 >(&index, &p_comm, Some(&public_input));
240 let oracles_result = match oracles_result {
241 Err(e) => {
242 return Err(NapiError::new(Status::GenericFailure, format!("oracles_create: {}", e)));
243 }
244 Ok(cs) => cs,
245 };
246
247 let (mut sponge, combined_inner_product, p_eval, digest, oracles) = (
248 oracles_result.fq_sponge,
249 oracles_result.combined_inner_product,
250 oracles_result.public_evals,
251 oracles_result.digest,
252 oracles_result.oracles,
253 );
254
255 sponge.absorb_fr(&[shift_scalar::<$G>(combined_inner_product)]);
256
257 let opening_prechallenges = proof
258 .proof
259 .prechallenges(&mut sponge)
260 .into_iter()
261 .map(|x| x.inner().into())
262 .collect();
263
264 Ok((oracles, p_eval, opening_prechallenges, digest))
265 };
266
267 match result {
268 Ok((oracles, p_eval, opening_prechallenges, digest)) => Ok([<Napi $field_name:camel Oracles>] {
269 o: oracles.into(),
270 p_eval0: p_eval[0][0].into(),
271 p_eval1: p_eval[1][0].into(),
272 opening_prechallenges,
273 digest_before_evaluations: digest.into()
274 }),
275 Err(err) => Err(NapiError::new(Status::GenericFailure, err)),
276 }
277 }
278
279 #[napi(js_name = [<$F:snake _oracles_dummy>])]
280 pub fn [<$F:snake _oracles_dummy>]() -> [<Napi $field_name:camel Oracles>] {
281 [<Napi $field_name:camel Oracles>] {
282 o: RandomOracles::<$F>::default().into(),
283 p_eval0: $F::zero().into(),
284 p_eval1: $F::zero().into(),
285 opening_prechallenges: vec![].into(),
286 digest_before_evaluations: $F::zero().into(),
287 }
288 }
289
290 #[napi(js_name = [<$F:snake _oracles_deep_copy>])]
291 pub fn [<$F:snake _oracles_deep_copy>](
292 x: $NapiProverProof,
293 ) -> $NapiProverProof {
294 x
295 }
296 }
297 }
298}
299
300pub mod fp {
301 use super::*;
302 use crate::{
303 plonk_verifier_index::fp::NapiFpPlonkVerifierIndex as WasmPlonkVerifierIndex,
304 poly_comm::vesta::NapiFpPolyComm as WasmPolyComm,
305 proof::fp::NapiFpProverProof as WasmProverProof,
306 };
307 use mina_curves::pasta::{Fp, Vesta as GAffine, VestaParameters};
308
309 impl_oracles!(
310 NapiPastaFp,
311 Fp,
312 WasmGVesta,
313 GAffine,
314 WasmPolyComm,
315 WasmProverProof,
316 WasmPlonkVerifierIndex,
317 VestaParameters,
318 Fp
319 );
320}
321
322pub mod fq {
323 use super::*;
324 use crate::{
325 plonk_verifier_index::fq::NapiFqPlonkVerifierIndex as WasmPlonkVerifierIndex,
326 poly_comm::pallas::NapiFqPolyComm as WasmPolyComm,
327 proof::fq::NapiFqProverProof as WasmProverProof,
328 };
329 use mina_curves::pasta::{Fq, Pallas as GAffine, PallasParameters};
330
331 impl_oracles!(
332 NapiPastaFq,
333 Fq,
334 WasmGPallas,
335 GAffine,
336 WasmPolyComm,
337 WasmProverProof,
338 WasmPlonkVerifierIndex,
339 PallasParameters,
340 Fq
341 );
342}