Skip to main content

kimchi_stubs/
pasta_fq_plonk_proof.rs

1use crate::{
2    arkworks::{CamlFq, CamlGPallas},
3    field_vector::fq::CamlFqVector,
4    pasta_fq_plonk_index::CamlPastaFqPlonkIndexPtr,
5    pasta_fq_plonk_verifier_index::CamlPastaFqPlonkVerifierIndex,
6};
7use ark_ec::AffineRepr;
8use ark_ff::One;
9use core::{array, convert::TryInto};
10use groupmap::GroupMap;
11use kimchi::{
12    circuits::{
13        lookup::runtime_tables::{caml::CamlRuntimeTable, RuntimeTable},
14        polynomial::COLUMNS,
15    },
16    proof::{
17        PointEvaluations, ProofEvaluations, ProverCommitments, ProverProof, RecursionChallenge,
18    },
19    prover::caml::CamlProofWithPublic,
20    prover_index::ProverIndex,
21    verifier::{batch_verify, Context},
22    verifier_index::VerifierIndex,
23};
24use mina_curves::pasta::{Fp, Fq, Pallas, PallasParameters};
25use mina_poseidon::{
26    constants::PlonkSpongeConstantsKimchi,
27    pasta::FULL_ROUNDS,
28    sponge::{DefaultFqSponge, DefaultFrSponge},
29};
30use poly_commitment::{
31    commitment::{CommitmentCurve, PolyComm},
32    ipa::OpeningProof,
33    lagrange_basis::WithLagrangeBasis,
34};
35
36type Srs =
37    <OpeningProof<Pallas, FULL_ROUNDS> as poly_commitment::OpenProof<Pallas, FULL_ROUNDS>>::SRS;
38
39#[ocaml_gen::func]
40#[ocaml::func]
41pub fn caml_pasta_fq_plonk_proof_create(
42    index: CamlPastaFqPlonkIndexPtr<'static>,
43    witness: Vec<CamlFqVector>,
44    runtime_tables: Vec<CamlRuntimeTable<CamlFq>>,
45    prev_challenges: Vec<CamlFq>,
46    prev_sgs: Vec<CamlGPallas>,
47) -> Result<CamlProofWithPublic<CamlGPallas, CamlFq>, ocaml::Error> {
48    {
49        index
50            .as_ref()
51            .0
52            .srs
53            .with_lagrange_basis(index.as_ref().0.cs.domain.d1);
54    }
55    let prev = if prev_challenges.is_empty() {
56        Vec::new()
57    } else {
58        let challenges_per_sg = prev_challenges.len() / prev_sgs.len();
59        prev_sgs
60            .into_iter()
61            .map(Into::<Pallas>::into)
62            .enumerate()
63            .map(|(i, sg)| {
64                let chals = prev_challenges[(i * challenges_per_sg)..(i + 1) * challenges_per_sg]
65                    .iter()
66                    .map(Into::<Fq>::into)
67                    .collect();
68                let comm = PolyComm::<Pallas> { chunks: vec![sg] };
69                RecursionChallenge { chals, comm }
70            })
71            .collect()
72    };
73
74    let witness: Vec<Vec<_>> = witness.iter().map(|x| (**x).clone()).collect();
75    let witness: [Vec<_>; COLUMNS] = witness
76        .try_into()
77        .expect("the witness should be a column of 15 vectors");
78    let index: &ProverIndex<FULL_ROUNDS, Pallas, Srs> = &index.as_ref().0;
79
80    let runtime_tables: Vec<RuntimeTable<Fq>> =
81        runtime_tables.into_iter().map(Into::into).collect();
82
83    // public input
84    let public_input = witness[0][0..index.cs.public].to_vec();
85
86    if std::env::var("KIMCHI_PROVER_DUMP_ARGUMENTS").is_ok() {
87        kimchi::bench::bench_arguments_dump_into_file(&index.cs, &witness, &runtime_tables, &prev);
88    }
89
90    // NB: This method is designed only to be used by tests. However, since
91    // creating a new reference will cause `drop` to be called on it once we are
92    // done with it. Since `drop` calls `caml_shutdown` internally, we *really,
93    // really* do not want to do this, but we have no other way to get at the
94    // active runtime.
95    // TODO: There's actually a way to get a handle to the runtime as a function
96    // argument. Switch to doing this instead.
97    let runtime = unsafe { ocaml::Runtime::recover_handle() };
98
99    // Release the runtime lock so that other threads can run using it while we
100    // generate the proof.
101    runtime.releasing_runtime(|| {
102        let group_map = GroupMap::<Fp>::setup();
103        let proof = crate::with_prove_pool(|| {
104            ProverProof::create_recursive::<
105                DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
106                DefaultFrSponge<Fq, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
107                _,
108            >(
109                &group_map,
110                witness,
111                &runtime_tables,
112                index,
113                prev,
114                None,
115                &mut rand::rngs::OsRng,
116            )
117        })
118        .map_err(|e| ocaml::Error::Error(e.into()))?;
119        Ok((proof, public_input).into())
120    })
121}
122
123#[ocaml_gen::func]
124#[ocaml::func]
125pub fn caml_pasta_fq_plonk_proof_verify(
126    index: CamlPastaFqPlonkVerifierIndex,
127    proof: CamlProofWithPublic<CamlGPallas, CamlFq>,
128) -> bool {
129    let group_map = <Pallas as CommitmentCurve>::Map::setup();
130
131    let (proof, public_input) = proof.into();
132    let verifier_index = index.into();
133    let context = Context {
134        verifier_index: &verifier_index,
135        proof: &proof,
136        public_input: &public_input,
137    };
138
139    batch_verify::<
140        FULL_ROUNDS,
141        Pallas,
142        DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
143        DefaultFrSponge<Fq, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
144        OpeningProof<Pallas, FULL_ROUNDS>,
145    >(&group_map, &[context])
146    .is_ok()
147}
148
149#[ocaml_gen::func]
150#[ocaml::func]
151pub fn caml_pasta_fq_plonk_proof_batch_verify(
152    indexes: Vec<CamlPastaFqPlonkVerifierIndex>,
153    proofs: Vec<CamlProofWithPublic<CamlGPallas, CamlFq>>,
154) -> bool {
155    let ts: Vec<_> = indexes
156        .into_iter()
157        .zip(proofs.into_iter())
158        .map(|(caml_index, caml_proof)| {
159            let verifier_index: VerifierIndex<FULL_ROUNDS, Pallas, Srs> = caml_index.into();
160            let (proof, public_input): (
161                ProverProof<Pallas, OpeningProof<Pallas, FULL_ROUNDS>, FULL_ROUNDS>,
162                Vec<_>,
163            ) = caml_proof.into();
164            (verifier_index, proof, public_input)
165        })
166        .collect();
167    let ts_ref: Vec<Context<FULL_ROUNDS, Pallas, OpeningProof<Pallas, FULL_ROUNDS>, Srs>> = ts
168        .iter()
169        .map(|(verifier_index, proof, public_input)| Context {
170            verifier_index,
171            proof,
172            public_input,
173        })
174        .collect();
175    let group_map = GroupMap::<Fp>::setup();
176
177    batch_verify::<
178        55,
179        Pallas,
180        DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
181        DefaultFrSponge<Fq, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
182        OpeningProof<Pallas, FULL_ROUNDS>,
183    >(&group_map, &ts_ref)
184    .is_ok()
185}
186
187#[ocaml_gen::func]
188#[ocaml::func]
189pub fn caml_pasta_fq_plonk_proof_dummy() -> CamlProofWithPublic<CamlGPallas, CamlFq> {
190    fn comm() -> PolyComm<Pallas> {
191        let g = Pallas::generator();
192        PolyComm {
193            chunks: vec![g, g, g],
194        }
195    }
196
197    let prev = RecursionChallenge {
198        chals: vec![Fq::one(), Fq::one()],
199        comm: comm(),
200    };
201    let prev_challenges = vec![prev.clone(), prev.clone(), prev];
202
203    let g = Pallas::generator();
204    let proof: OpeningProof<_, FULL_ROUNDS> = OpeningProof {
205        lr: vec![(g, g), (g, g), (g, g)],
206        z1: Fq::one(),
207        z2: Fq::one(),
208        delta: g,
209        sg: g,
210    };
211    let eval = || PointEvaluations {
212        zeta: vec![Fq::one()],
213        zeta_omega: vec![Fq::one()],
214    };
215    let evals = ProofEvaluations {
216        public: Some(eval()),
217        w: core::array::from_fn(|_| eval()),
218        coefficients: core::array::from_fn(|_| eval()),
219        z: eval(),
220        s: core::array::from_fn(|_| eval()),
221        generic_selector: eval(),
222        poseidon_selector: eval(),
223        complete_add_selector: eval(),
224        mul_selector: eval(),
225        emul_selector: eval(),
226        endomul_scalar_selector: eval(),
227        range_check0_selector: None,
228        range_check1_selector: None,
229        foreign_field_add_selector: None,
230        foreign_field_mul_selector: None,
231        xor_selector: None,
232        rot_selector: None,
233        lookup_aggregation: None,
234        lookup_table: None,
235        lookup_sorted: array::from_fn(|_| None),
236        runtime_lookup_table: None,
237        runtime_lookup_table_selector: None,
238        xor_lookup_selector: None,
239        lookup_gate_lookup_selector: None,
240        range_check_lookup_selector: None,
241        foreign_field_mul_lookup_selector: None,
242    };
243
244    let public = vec![Fq::one(), Fq::one()];
245    let dlogproof = ProverProof {
246        commitments: ProverCommitments {
247            w_comm: core::array::from_fn(|_| comm()),
248            z_comm: comm(),
249            t_comm: comm(),
250            lookup: None,
251        },
252        proof,
253        evals,
254        ft_eval1: Fq::one(),
255        prev_challenges,
256    };
257
258    (dlogproof, public).into()
259}
260
261#[ocaml_gen::func]
262#[ocaml::func]
263pub fn caml_pasta_fq_plonk_proof_deep_copy(
264    x: CamlProofWithPublic<CamlGPallas, CamlFq>,
265) -> CamlProofWithPublic<CamlGPallas, CamlFq> {
266    x
267}