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(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>, // the bases to commit polynomials
198                index: $index,    // parameters
199                proof: $NapiProverProof, // the final proof (contains public elements at the beginning)
200            ) -> Result<[<Napi $field_name:camel Oracles>]> {
201                // conversions
202                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}