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 = ProverProof::create_recursive::<
104            DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
105            DefaultFrSponge<Fq, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
106            _,
107        >(
108            &group_map,
109            witness,
110            &runtime_tables,
111            index,
112            prev,
113            None,
114            &mut rand::rngs::OsRng,
115        )
116        .map_err(|e| ocaml::Error::Error(e.into()))?;
117        Ok((proof, public_input).into())
118    })
119}
120
121#[ocaml_gen::func]
122#[ocaml::func]
123pub fn caml_pasta_fq_plonk_proof_verify(
124    index: CamlPastaFqPlonkVerifierIndex,
125    proof: CamlProofWithPublic<CamlGPallas, CamlFq>,
126) -> bool {
127    let group_map = <Pallas as CommitmentCurve>::Map::setup();
128
129    let (proof, public_input) = proof.into();
130    let verifier_index = index.into();
131    let context = Context {
132        verifier_index: &verifier_index,
133        proof: &proof,
134        public_input: &public_input,
135    };
136
137    batch_verify::<
138        FULL_ROUNDS,
139        Pallas,
140        DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
141        DefaultFrSponge<Fq, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
142        OpeningProof<Pallas, FULL_ROUNDS>,
143    >(&group_map, &[context])
144    .is_ok()
145}
146
147#[ocaml_gen::func]
148#[ocaml::func]
149pub fn caml_pasta_fq_plonk_proof_batch_verify(
150    indexes: Vec<CamlPastaFqPlonkVerifierIndex>,
151    proofs: Vec<CamlProofWithPublic<CamlGPallas, CamlFq>>,
152) -> bool {
153    let ts: Vec<_> = indexes
154        .into_iter()
155        .zip(proofs.into_iter())
156        .map(|(caml_index, caml_proof)| {
157            let verifier_index: VerifierIndex<FULL_ROUNDS, Pallas, Srs> = caml_index.into();
158            let (proof, public_input): (
159                ProverProof<Pallas, OpeningProof<Pallas, FULL_ROUNDS>, FULL_ROUNDS>,
160                Vec<_>,
161            ) = caml_proof.into();
162            (verifier_index, proof, public_input)
163        })
164        .collect();
165    let ts_ref: Vec<Context<FULL_ROUNDS, Pallas, OpeningProof<Pallas, FULL_ROUNDS>, Srs>> = ts
166        .iter()
167        .map(|(verifier_index, proof, public_input)| Context {
168            verifier_index,
169            proof,
170            public_input,
171        })
172        .collect();
173    let group_map = GroupMap::<Fp>::setup();
174
175    batch_verify::<
176        55,
177        Pallas,
178        DefaultFqSponge<PallasParameters, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
179        DefaultFrSponge<Fq, PlonkSpongeConstantsKimchi, FULL_ROUNDS>,
180        OpeningProof<Pallas, FULL_ROUNDS>,
181    >(&group_map, &ts_ref)
182    .is_ok()
183}
184
185#[ocaml_gen::func]
186#[ocaml::func]
187pub fn caml_pasta_fq_plonk_proof_dummy() -> CamlProofWithPublic<CamlGPallas, CamlFq> {
188    fn comm() -> PolyComm<Pallas> {
189        let g = Pallas::generator();
190        PolyComm {
191            chunks: vec![g, g, g],
192        }
193    }
194
195    let prev = RecursionChallenge {
196        chals: vec![Fq::one(), Fq::one()],
197        comm: comm(),
198    };
199    let prev_challenges = vec![prev.clone(), prev.clone(), prev];
200
201    let g = Pallas::generator();
202    let proof: OpeningProof<_, FULL_ROUNDS> = OpeningProof {
203        lr: vec![(g, g), (g, g), (g, g)],
204        z1: Fq::one(),
205        z2: Fq::one(),
206        delta: g,
207        sg: g,
208    };
209    let eval = || PointEvaluations {
210        zeta: vec![Fq::one()],
211        zeta_omega: vec![Fq::one()],
212    };
213    let evals = ProofEvaluations {
214        public: Some(eval()),
215        w: core::array::from_fn(|_| eval()),
216        coefficients: core::array::from_fn(|_| eval()),
217        z: eval(),
218        s: core::array::from_fn(|_| eval()),
219        generic_selector: eval(),
220        poseidon_selector: eval(),
221        complete_add_selector: eval(),
222        mul_selector: eval(),
223        emul_selector: eval(),
224        endomul_scalar_selector: eval(),
225        range_check0_selector: None,
226        range_check1_selector: None,
227        foreign_field_add_selector: None,
228        foreign_field_mul_selector: None,
229        xor_selector: None,
230        rot_selector: None,
231        lookup_aggregation: None,
232        lookup_table: None,
233        lookup_sorted: array::from_fn(|_| None),
234        runtime_lookup_table: None,
235        runtime_lookup_table_selector: None,
236        xor_lookup_selector: None,
237        lookup_gate_lookup_selector: None,
238        range_check_lookup_selector: None,
239        foreign_field_mul_lookup_selector: None,
240    };
241
242    let public = vec![Fq::one(), Fq::one()];
243    let dlogproof = ProverProof {
244        commitments: ProverCommitments {
245            w_comm: core::array::from_fn(|_| comm()),
246            z_comm: comm(),
247            t_comm: comm(),
248            lookup: None,
249        },
250        proof,
251        evals,
252        ft_eval1: Fq::one(),
253        prev_challenges,
254    };
255
256    (dlogproof, public).into()
257}
258
259#[ocaml_gen::func]
260#[ocaml::func]
261pub fn caml_pasta_fq_plonk_proof_deep_copy(
262    x: CamlProofWithPublic<CamlGPallas, CamlFq>,
263) -> CamlProofWithPublic<CamlGPallas, CamlFq> {
264    x
265}