Skip to main content

kimchi_napi/
oracles.rs

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>, // the bases to commit polynomials
218                index: $index,    // parameters
219                proof: $NapiProverProof, // the final proof (contains public elements at the beginning)
220            ) -> Result<[<Napi $field_name:camel Oracles>]> {
221                // conversions
222                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}