jf_plonk/proof_system/
structs.rs

1// Copyright (c) 2022 Espresso Systems (espressosys.com)
2// This file is part of the Jellyfish library.
3
4// You should have received a copy of the MIT License
5// along with the Jellyfish library. If not, see <https://mit-license.org/>.
6
7//! Data structures used in Plonk proof systems
8use crate::{
9    circuit::plonk_verifier::{BatchProofVar, ProofEvaluationsVar},
10    errors::{
11        PlonkError,
12        SnarkError::{self, ParameterError, SnarkLookupUnsupported},
13    },
14};
15use ark_ec::{
16    pairing::Pairing,
17    scalar_mul::variable_base::VariableBaseMSM,
18    short_weierstrass::{Affine, SWCurveConfig},
19    CurveGroup,
20};
21use ark_ff::{FftField, Field, Fp2, Fp2Config, PrimeField, Zero};
22use ark_poly::univariate::DensePolynomial;
23use ark_serialize::*;
24use ark_std::{format, string::ToString, vec, vec::Vec};
25use derive_where::derive_where;
26use espresso_systems_common::jellyfish::tag;
27use hashbrown::HashMap;
28use jf_pcs::prelude::{
29    Commitment, UnivariateProverParam, UnivariateUniversalParams, UnivariateVerifierParam,
30};
31use jf_relation::{
32    constants::{compute_coset_representatives, GATE_WIDTH, N_TURBO_PLONK_SELECTORS},
33    gadgets::{
34        ecc::{SWToTEConParam, TEPoint},
35        ultraplonk::mod_arith::FpElemVar,
36    },
37    PlonkCircuit,
38};
39use jf_rescue::RescueParameter;
40use jf_utils::{field_switching, fq_to_fr, fr_to_fq};
41use tagged_base64::tagged;
42
43/// Universal StructuredReferenceString
44pub type UniversalSrs<E> = UnivariateUniversalParams<E>;
45/// Commitment key
46pub type CommitKey<E> = UnivariateProverParam<E>;
47/// Key for verifying PCS opening proof.
48pub type OpenKey<E> = UnivariateVerifierParam<E>;
49
50/// A Plonk SNARK proof.
51#[tagged(tag::PROOF)]
52#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
53#[derive_where(Hash; E: Pairing)]
54pub struct Proof<E: Pairing> {
55    /// Wire witness polynomials commitments.
56    pub wires_poly_comms: Vec<Commitment<E>>,
57
58    /// The polynomial commitment for the wire permutation argument.
59    pub prod_perm_poly_comm: Commitment<E>,
60
61    /// Split quotient polynomial commitments.
62    pub split_quot_poly_comms: Vec<Commitment<E>>,
63
64    /// (Aggregated) proof of evaluations at challenge point `zeta`.
65    pub opening_proof: Commitment<E>,
66
67    /// (Aggregated) proof of evaluation at challenge point `zeta * g` where `g`
68    /// is the root of unity.
69    pub shifted_opening_proof: Commitment<E>,
70
71    /// Polynomial evaluations.
72    pub poly_evals: ProofEvaluations<E::ScalarField>,
73
74    /// The partial proof for Plookup argument
75    pub plookup_proof: Option<PlookupProof<E>>,
76}
77
78impl<E, P> TryFrom<Vec<E::BaseField>> for Proof<E>
79where
80    E: Pairing<G1Affine = Affine<P>>,
81    P: SWCurveConfig<BaseField = E::BaseField, ScalarField = E::ScalarField>,
82{
83    type Error = SnarkError;
84
85    fn try_from(value: Vec<E::BaseField>) -> Result<Self, Self::Error> {
86        // both wires_poly_comms and split_quot_poly_comms are (GATE_WIDTH +1)
87        // // Commitments, each point takes two base fields elements;
88        // 3 individual commitment points;
89        // (GATE_WIDTH + 1) * 2 scalar fields in poly_evals are  converted to base
90        // fields.
91        const TURBO_PLONK_LEN: usize = (GATE_WIDTH + 1) * 2 * 2 + 2 * 3 + (GATE_WIDTH + 1) * 2;
92        if value.len() == TURBO_PLONK_LEN {
93            // NOTE: for convenience, we slightly reordered our fields in Proof.
94            let mut ptr = 0;
95            let wires_poly_comms: Vec<Commitment<E>> = value[ptr..ptr + (GATE_WIDTH + 1) * 2]
96                .chunks_exact(2)
97                .map(|chunk| {
98                    if chunk.len() == 2 {
99                        Commitment(Affine::new(chunk[0], chunk[1]))
100                    } else {
101                        unreachable!("Internal error");
102                    }
103                })
104                .collect();
105            ptr += (GATE_WIDTH + 1) * 2;
106
107            let split_quot_poly_comms = value[ptr..ptr + (GATE_WIDTH + 1) * 2]
108                .chunks_exact(2)
109                .map(|chunk| {
110                    if chunk.len() == 2 {
111                        Commitment(Affine::new(chunk[0], chunk[1]))
112                    } else {
113                        unreachable!("Internal error");
114                    }
115                })
116                .collect();
117            ptr += (GATE_WIDTH + 1) * 2;
118
119            let prod_perm_poly_comm = Commitment(Affine::new(value[ptr], value[ptr + 1]));
120            ptr += 2;
121
122            let opening_proof = Commitment(Affine::new(value[ptr], value[ptr + 1]));
123            ptr += 2;
124
125            let shifted_opening_proof = Commitment(Affine::new(value[ptr], value[ptr + 1]));
126            ptr += 2;
127
128            let poly_evals_scalars: Vec<E::ScalarField> = value[ptr..]
129                .iter()
130                .map(|f| fq_to_fr::<E::BaseField, P>(f))
131                .collect();
132            let poly_evals = poly_evals_scalars.try_into()?;
133
134            Ok(Self {
135                wires_poly_comms,
136                prod_perm_poly_comm,
137                split_quot_poly_comms,
138                opening_proof,
139                shifted_opening_proof,
140                poly_evals,
141                plookup_proof: None,
142            })
143        } else {
144            Err(SnarkError::ParameterError(
145                "Wrong number of scalars for proof, only support TurboPlonk for now".to_string(),
146            ))
147        }
148    }
149}
150
151// helper function to convert a G1Affine or G2Affine into two base fields
152fn group1_to_fields<E, P>(p: Affine<P>) -> Vec<E::BaseField>
153where
154    E: Pairing<G1Affine = Affine<P>>,
155    P: SWCurveConfig<BaseField = E::BaseField>,
156{
157    // contains x, y, infinity_flag, only need the first 2 field elements
158    vec![p.x, p.y]
159}
160
161fn group2_to_fields<E, F, P>(p: Affine<P>) -> Vec<E::BaseField>
162where
163    E: Pairing<G2Affine = Affine<P>>,
164    F: Fp2Config<Fp = E::BaseField>,
165    P: SWCurveConfig<BaseField = Fp2<F>>,
166{
167    // contains x, y, infinity_flag, only need the first 2 field elements
168    vec![p.x.c0, p.x.c1, p.y.c0, p.y.c1]
169}
170
171impl<E, P> From<Proof<E>> for Vec<E::BaseField>
172where
173    E: Pairing<G1Affine = Affine<P>>,
174    P: SWCurveConfig<BaseField = E::BaseField, ScalarField = E::ScalarField>,
175{
176    fn from(proof: Proof<E>) -> Self {
177        if proof.plookup_proof.is_some() {
178            panic!("Only support TurboPlonk for now.");
179        }
180        let poly_evals_scalars: Vec<E::ScalarField> = proof.poly_evals.into();
181
182        // NOTE: order of these fields must match deserialization
183        [
184            proof
185                .wires_poly_comms
186                .iter()
187                .map(|cm| group1_to_fields::<E, _>(cm.0))
188                .collect::<Vec<_>>()
189                .concat(),
190            proof
191                .split_quot_poly_comms
192                .iter()
193                .map(|cm| group1_to_fields::<E, _>(cm.0))
194                .collect::<Vec<_>>()
195                .concat(),
196            group1_to_fields::<E, _>(proof.prod_perm_poly_comm.0),
197            group1_to_fields::<E, _>(proof.opening_proof.0),
198            group1_to_fields::<E, _>(proof.shifted_opening_proof.0),
199            poly_evals_scalars
200                .iter()
201                .map(|s| fr_to_fq::<E::BaseField, P>(s))
202                .collect::<Vec<_>>(),
203        ]
204        .concat()
205    }
206}
207
208/// A Plookup argument proof.
209#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
210#[derive_where(Hash; E: Pairing)]
211pub struct PlookupProof<E: Pairing> {
212    /// The commitments for the polynomials that interpolate the sorted
213    /// concatenation of the lookup table and the witnesses in the lookup gates.
214    pub(crate) h_poly_comms: Vec<Commitment<E>>,
215
216    /// The product accumulation polynomial commitment for the Plookup argument
217    pub(crate) prod_lookup_poly_comm: Commitment<E>,
218
219    /// Polynomial evaluations.
220    pub(crate) poly_evals: PlookupEvaluations<E::ScalarField>,
221}
222
223/// An aggregated SNARK proof that batchly proving multiple instances.
224#[tagged(tag::BATCHPROOF)]
225#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
226#[derive_where(Hash; E: Pairing)]
227pub struct BatchProof<E: Pairing> {
228    /// The list of wire witness polynomials commitments.
229    pub(crate) wires_poly_comms_vec: Vec<Vec<Commitment<E>>>,
230
231    /// The list of polynomial commitment for the wire permutation argument.
232    pub(crate) prod_perm_poly_comms_vec: Vec<Commitment<E>>,
233
234    /// The list of polynomial evaluations.
235    pub(crate) poly_evals_vec: Vec<ProofEvaluations<E::ScalarField>>,
236
237    /// The list of partial proofs for Plookup argument
238    pub(crate) plookup_proofs_vec: Vec<Option<PlookupProof<E>>>,
239
240    /// Split quotient polynomial commitments.
241    pub(crate) split_quot_poly_comms: Vec<Commitment<E>>,
242
243    /// (Aggregated) proof of evaluations at challenge point `zeta`.
244    pub(crate) opening_proof: Commitment<E>,
245
246    /// (Aggregated) proof of evaluation at challenge point `zeta * g` where `g`
247    /// is the root of unity.
248    pub(crate) shifted_opening_proof: Commitment<E>,
249}
250
251impl<E: Pairing> BatchProof<E> {
252    /// The number of instances being proved in a batch proof.
253    pub fn len(&self) -> usize {
254        self.prod_perm_poly_comms_vec.len()
255    }
256    /// Check whether a BatchProof proves nothing.
257    pub fn is_empty(&self) -> bool {
258        self.prod_perm_poly_comms_vec.is_empty()
259    }
260    /// Create a dummy batch proof over `n` TurboPlonk instances.
261    pub fn dummy(n: usize) -> Self {
262        let num_wire_types = GATE_WIDTH + 1;
263        Self {
264            wires_poly_comms_vec: vec![vec![Commitment::default(); num_wire_types]; n],
265            prod_perm_poly_comms_vec: vec![Commitment::default(); n],
266            poly_evals_vec: vec![ProofEvaluations::default(); n],
267            plookup_proofs_vec: vec![None; n],
268            split_quot_poly_comms: vec![Commitment::default(); num_wire_types],
269            opening_proof: Commitment::default(),
270            shifted_opening_proof: Commitment::default(),
271        }
272    }
273}
274
275impl<E: Pairing> From<Proof<E>> for BatchProof<E> {
276    fn from(proof: Proof<E>) -> Self {
277        Self {
278            wires_poly_comms_vec: vec![proof.wires_poly_comms],
279            prod_perm_poly_comms_vec: vec![proof.prod_perm_poly_comm],
280            poly_evals_vec: vec![proof.poly_evals],
281            plookup_proofs_vec: vec![proof.plookup_proof],
282            split_quot_poly_comms: proof.split_quot_poly_comms,
283            opening_proof: proof.opening_proof,
284            shifted_opening_proof: proof.shifted_opening_proof,
285        }
286    }
287}
288
289impl<T: PrimeField> ProofEvaluations<T> {
290    /// create variables for the ProofEvaluations who's field
291    /// is smaller than plonk circuit field.
292    /// The output wires are in the FpElemVar form.
293    pub(crate) fn create_variables<F>(
294        &self,
295        circuit: &mut PlonkCircuit<F>,
296        m: usize,
297        two_power_m: Option<F>,
298    ) -> Result<ProofEvaluationsVar<F>, PlonkError>
299    where
300        F: RescueParameter + SWToTEConParam,
301    {
302        if T::MODULUS_BIT_SIZE >= F::MODULUS_BIT_SIZE {
303            return Err(PlonkError::InvalidParameters(format!(
304                "circuit field size {} is not greater than Plookup Evaluation field size {}",
305                F::MODULUS_BIT_SIZE,
306                T::MODULUS_BIT_SIZE
307            )));
308        }
309        let wires_evals = self
310            .wires_evals
311            .iter()
312            .map(|x| {
313                FpElemVar::new_from_field_element(circuit, &field_switching(x), m, two_power_m)
314            })
315            .collect::<Result<Vec<_>, _>>()?;
316        let wire_sigma_evals = self
317            .wire_sigma_evals
318            .iter()
319            .map(|x| {
320                FpElemVar::new_from_field_element(circuit, &field_switching(x), m, two_power_m)
321            })
322            .collect::<Result<Vec<_>, _>>()?;
323        Ok(ProofEvaluationsVar {
324            wires_evals,
325            wire_sigma_evals,
326            perm_next_eval: FpElemVar::new_from_field_element(
327                circuit,
328                &field_switching(&self.perm_next_eval),
329                m,
330                two_power_m,
331            )?,
332        })
333    }
334}
335
336impl<E: Pairing> BatchProof<E> {
337    /// Create a `BatchProofVar` variable from a `BatchProof`.
338    pub fn create_variables<F, P>(
339        &self,
340        circuit: &mut PlonkCircuit<F>,
341        m: usize,
342        two_power_m: Option<F>,
343    ) -> Result<BatchProofVar<F>, PlonkError>
344    where
345        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
346        F: RescueParameter + SWToTEConParam,
347        P: SWCurveConfig<BaseField = F>,
348    {
349        let mut wires_poly_comms_vec = Vec::new();
350        for e in self.wires_poly_comms_vec.iter() {
351            let mut tmp = Vec::new();
352            for f in e.iter() {
353                let p: TEPoint<F> = f.0.into();
354                tmp.push(circuit.create_point_variable(p)?);
355            }
356            wires_poly_comms_vec.push(tmp);
357        }
358        let mut prod_perm_poly_comms_vec = Vec::new();
359        for e in self.prod_perm_poly_comms_vec.iter() {
360            let p: TEPoint<F> = e.0.into();
361            prod_perm_poly_comms_vec.push(circuit.create_point_variable(p)?);
362        }
363
364        let poly_evals_vec = self
365            .poly_evals_vec
366            .iter()
367            .map(|x| x.create_variables(circuit, m, two_power_m))
368            .collect::<Result<Vec<_>, _>>()?;
369
370        let mut split_quot_poly_comms = Vec::new();
371        for e in self.split_quot_poly_comms.iter() {
372            let p: TEPoint<F> = e.0.into();
373            split_quot_poly_comms.push(circuit.create_point_variable(p)?);
374        }
375
376        let p: TEPoint<F> = self.opening_proof.0.into();
377        let opening_proof = circuit.create_point_variable(p)?;
378
379        let p: TEPoint<F> = self.shifted_opening_proof.0.into();
380        let shifted_opening_proof = circuit.create_point_variable(p)?;
381
382        Ok(BatchProofVar {
383            wires_poly_comms_vec,
384            prod_perm_poly_comms_vec,
385            poly_evals_vec,
386            split_quot_poly_comms,
387            opening_proof,
388            shifted_opening_proof,
389        })
390    }
391}
392
393/// A struct that stores the polynomial evaluations in a Plonk proof.
394#[derive(Debug, Clone, PartialEq, Eq, Hash, CanonicalSerialize, CanonicalDeserialize)]
395pub struct ProofEvaluations<F: Field> {
396    /// Wire witness polynomials evaluations at point `zeta`.
397    pub wires_evals: Vec<F>,
398
399    /// Extended permutation (sigma) polynomials evaluations at point `zeta`.
400    /// We do not include the last sigma polynomial evaluation.
401    pub wire_sigma_evals: Vec<F>,
402
403    /// Permutation product polynomial evaluation at point `zeta * g`.
404    pub perm_next_eval: F,
405}
406
407impl<F: Field> TryFrom<Vec<F>> for ProofEvaluations<F> {
408    type Error = SnarkError;
409
410    fn try_from(value: Vec<F>) -> Result<Self, Self::Error> {
411        // | wires_evals | = | wire_sigma_evals | + 1
412        // = GATE_WIDTH + 1 + 0/1 (0 for TurboPlonk and 1 for UltraPlonk)
413        // thanks to Maller optimization.
414        const TURBO_PLONK_EVAL_LEN: usize = (GATE_WIDTH + 1) * 2;
415        const ULTRA_PLONK_EVAL_LEN: usize = (GATE_WIDTH + 2) * 2;
416
417        if value.len() == TURBO_PLONK_EVAL_LEN || value.len() == ULTRA_PLONK_EVAL_LEN {
418            let l = value.len();
419            let wires_evals = value[..l / 2].to_vec();
420            let wire_sigma_evals = value[l / 2..l - 1].to_vec();
421            let perm_next_eval = value[l - 1];
422            Ok(Self {
423                wires_evals,
424                wire_sigma_evals,
425                perm_next_eval,
426            })
427        } else {
428            Err(SnarkError::ParameterError(
429                "Wrong number of scalars for proof evals.".to_string(),
430            ))
431        }
432    }
433}
434
435impl<F: Field> From<ProofEvaluations<F>> for Vec<F> {
436    fn from(evals: ProofEvaluations<F>) -> Self {
437        [
438            evals.wires_evals,
439            evals.wire_sigma_evals,
440            vec![evals.perm_next_eval],
441        ]
442        .concat()
443    }
444}
445
446impl<F> Default for ProofEvaluations<F>
447where
448    F: Field,
449{
450    fn default() -> Self {
451        let num_wire_types = GATE_WIDTH + 1;
452        Self {
453            wires_evals: vec![F::zero(); num_wire_types],
454            wire_sigma_evals: vec![F::zero(); num_wire_types - 1],
455            perm_next_eval: F::zero(),
456        }
457    }
458}
459
460/// A struct that stores the polynomial evaluations in a Plookup argument proof.
461#[derive(Debug, Clone, PartialEq, Eq, Hash, CanonicalSerialize, CanonicalDeserialize)]
462pub struct PlookupEvaluations<F: Field> {
463    /// Range table polynomial evaluation at point `zeta`.
464    pub(crate) range_table_eval: F,
465
466    /// Key table polynomial evaluation at point `zeta`.
467    pub(crate) key_table_eval: F,
468
469    /// Table domain separation polynomial evaluation at point `zeta`.
470    pub(crate) table_dom_sep_eval: F,
471
472    /// Domain separation selector polynomial evaluation at point `zeta`.
473    pub(crate) q_dom_sep_eval: F,
474
475    /// The first sorted vector polynomial evaluation at point `zeta`.
476    pub(crate) h_1_eval: F,
477
478    /// The lookup selector polynomial evaluation at point `zeta`.
479    pub(crate) q_lookup_eval: F,
480
481    /// Lookup product polynomial evaluation at point `zeta * g`.
482    pub(crate) prod_next_eval: F,
483
484    /// Range table polynomial evaluation at point `zeta * g`.
485    pub(crate) range_table_next_eval: F,
486
487    /// Key table polynomial evaluation at point `zeta * g`.
488    pub(crate) key_table_next_eval: F,
489
490    /// Table domain separation polynomial evaluation at point `zeta * g`.
491    pub(crate) table_dom_sep_next_eval: F,
492
493    /// The first sorted vector polynomial evaluation at point `zeta * g`.
494    pub(crate) h_1_next_eval: F,
495
496    /// The second sorted vector polynomial evaluation at point `zeta * g`.
497    pub(crate) h_2_next_eval: F,
498
499    /// The lookup selector polynomial evaluation at point `zeta * g`.
500    pub(crate) q_lookup_next_eval: F,
501
502    /// The 4th witness polynomial evaluation at point `zeta * g`.
503    pub(crate) w_3_next_eval: F,
504
505    /// The 5th witness polynomial evaluation at point `zeta * g`.
506    pub(crate) w_4_next_eval: F,
507}
508
509impl<F: Field> PlookupEvaluations<F> {
510    /// Return the list of evaluations at point `zeta`.
511    pub(crate) fn evals_vec(&self) -> Vec<F> {
512        vec![
513            self.range_table_eval,
514            self.key_table_eval,
515            self.h_1_eval,
516            self.q_lookup_eval,
517            self.table_dom_sep_eval,
518            self.q_dom_sep_eval,
519        ]
520    }
521
522    /// Return the list of evaluations at point `zeta * g`.
523    pub(crate) fn next_evals_vec(&self) -> Vec<F> {
524        vec![
525            self.prod_next_eval,
526            self.range_table_next_eval,
527            self.key_table_next_eval,
528            self.h_1_next_eval,
529            self.h_2_next_eval,
530            self.q_lookup_next_eval,
531            self.w_3_next_eval,
532            self.w_4_next_eval,
533            self.table_dom_sep_next_eval,
534        ]
535    }
536}
537
538/// Preprocessed prover parameters used to compute Plonk proofs for a certain
539/// circuit.
540#[derive(Debug, Clone, PartialEq, Eq, CanonicalSerialize, CanonicalDeserialize)]
541pub struct ProvingKey<E: Pairing> {
542    /// Extended permutation (sigma) polynomials.
543    pub(crate) sigmas: Vec<DensePolynomial<E::ScalarField>>,
544
545    /// Selector polynomials.
546    pub(crate) selectors: Vec<DensePolynomial<E::ScalarField>>,
547
548    // KZG PCS committing key.
549    pub(crate) commit_key: CommitKey<E>,
550
551    /// The verifying key. It is used by prover to initialize transcripts.
552    pub vk: VerifyingKey<E>,
553
554    /// Proving key for Plookup, None if not support lookup.
555    pub(crate) plookup_pk: Option<PlookupProvingKey<E>>,
556}
557
558/// Preprocessed prover parameters used to compute Plookup proofs for a certain
559/// circuit.
560#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
561pub struct PlookupProvingKey<E: Pairing> {
562    /// Range table polynomial.
563    pub(crate) range_table_poly: DensePolynomial<E::ScalarField>,
564
565    /// Key table polynomial.
566    pub(crate) key_table_poly: DensePolynomial<E::ScalarField>,
567
568    /// Table domain separation polynomial.
569    pub(crate) table_dom_sep_poly: DensePolynomial<E::ScalarField>,
570
571    /// Lookup domain separation selector polynomial.
572    pub(crate) q_dom_sep_poly: DensePolynomial<E::ScalarField>,
573}
574
575impl<E: Pairing> ProvingKey<E> {
576    /// The size of the evaluation domain. Should be a power of two.
577    pub(crate) fn domain_size(&self) -> usize {
578        self.vk.domain_size
579    }
580    /// The number of public inputs.
581    #[allow(dead_code)]
582    pub(crate) fn num_inputs(&self) -> usize {
583        self.vk.num_inputs
584    }
585    /// The constants K0, ..., K4 that ensure wire subsets are disjoint.
586    pub(crate) fn k(&self) -> &[E::ScalarField] {
587        &self.vk.k
588    }
589
590    /// The lookup selector polynomial
591    pub(crate) fn q_lookup_poly(&self) -> Result<&DensePolynomial<E::ScalarField>, PlonkError> {
592        if self.plookup_pk.is_none() {
593            return Err(SnarkLookupUnsupported.into());
594        }
595        Ok(self.selectors.last().unwrap())
596    }
597
598    /// Merge with another TurboPlonk proving key to obtain a new TurboPlonk
599    /// proving key. Return error if any of the following holds:
600    /// 1. the other proving key has a different domain size;
601    /// 2. the circuit underlying the other key has different number of inputs;
602    /// 3. the key or the other key is not a TurboPlonk key.
603    #[allow(dead_code)]
604    pub(crate) fn merge(&self, other_pk: &Self) -> Result<Self, PlonkError> {
605        if self.domain_size() != other_pk.domain_size() {
606            return Err(ParameterError(format!(
607                "mismatched domain size ({} vs {}) when merging proving keys",
608                self.domain_size(),
609                other_pk.domain_size()
610            ))
611            .into());
612        }
613        if self.num_inputs() != other_pk.num_inputs() {
614            return Err(ParameterError(
615                "mismatched number of public inputs when merging proving keys".to_string(),
616            )
617            .into());
618        }
619        if self.plookup_pk.is_some() || other_pk.plookup_pk.is_some() {
620            return Err(ParameterError("cannot merge UltraPlonk proving keys".to_string()).into());
621        }
622        let sigmas: Vec<DensePolynomial<E::ScalarField>> = self
623            .sigmas
624            .iter()
625            .zip(other_pk.sigmas.iter())
626            .map(|(poly1, poly2)| poly1 + poly2)
627            .collect();
628        let selectors: Vec<DensePolynomial<E::ScalarField>> = self
629            .selectors
630            .iter()
631            .zip(other_pk.selectors.iter())
632            .map(|(poly1, poly2)| poly1 + poly2)
633            .collect();
634
635        Ok(Self {
636            sigmas,
637            selectors,
638            commit_key: self.commit_key.clone(),
639            vk: self.vk.merge(&other_pk.vk)?,
640            plookup_pk: None,
641        })
642    }
643}
644
645/// Preprocessed verifier parameters used to verify Plonk proofs for a certain
646/// circuit.
647#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
648pub struct VerifyingKey<E: Pairing> {
649    /// The size of the evaluation domain. Should be a power of two.
650    pub domain_size: usize,
651
652    /// The number of public inputs.
653    pub num_inputs: usize,
654
655    /// The permutation polynomial commitments. The commitments are not hiding.
656    pub sigma_comms: Vec<Commitment<E>>,
657
658    /// The selector polynomial commitments. The commitments are not hiding.
659    pub selector_comms: Vec<Commitment<E>>,
660
661    /// The constants K0, ..., K_num_wire_types that ensure wire subsets are
662    /// disjoint.
663    pub k: Vec<E::ScalarField>,
664
665    /// KZG PCS opening key.
666    pub open_key: OpenKey<E>,
667
668    /// A flag indicating whether the key is a merged key.
669    pub is_merged: bool,
670
671    /// Plookup verifying key, None if not support lookup.
672    pub plookup_vk: Option<PlookupVerifyingKey<E>>,
673}
674
675impl<E, F, P1, P2> From<VerifyingKey<E>> for Vec<E::BaseField>
676where
677    E: Pairing<G1Affine = Affine<P1>, G2Affine = Affine<P2>, TargetField = Fp2<F>>,
678    F: Fp2Config<Fp = E::BaseField>,
679    P1: SWCurveConfig<BaseField = E::BaseField, ScalarField = E::ScalarField>,
680    P2: SWCurveConfig<BaseField = E::TargetField, ScalarField = E::ScalarField>,
681{
682    fn from(vk: VerifyingKey<E>) -> Self {
683        if vk.plookup_vk.is_some() {
684            panic!("Only support TurboPlonk VerifyingKey for now.");
685        }
686
687        [
688            vec![E::BaseField::from(vk.domain_size as u64)],
689            vec![E::BaseField::from(vk.num_inputs as u64)],
690            vk.sigma_comms
691                .iter()
692                .map(|cm| group1_to_fields::<E, _>(cm.0))
693                .collect::<Vec<_>>()
694                .concat(),
695            vk.selector_comms
696                .iter()
697                .map(|cm| group1_to_fields::<E, _>(cm.0))
698                .collect::<Vec<_>>()
699                .concat(),
700            vk.k.iter()
701                .map(|fr| fr_to_fq::<E::BaseField, P1>(fr))
702                .collect(),
703            // NOTE: only adding g, h, beta_h since only these are used.
704            group1_to_fields::<E, P1>(vk.open_key.g),
705            group2_to_fields::<E, F, P2>(vk.open_key.h),
706            group2_to_fields::<E, F, P2>(vk.open_key.beta_h),
707        ]
708        .concat()
709    }
710}
711
712impl<E, F, P> VerifyingKey<E>
713where
714    E: Pairing<BaseField = F, G1Affine = Affine<P>>,
715    F: SWToTEConParam,
716    P: SWCurveConfig<BaseField = F>,
717{
718    /// Convert the group elements to a list of scalars that represent the
719    /// Twisted Edwards coordinates.
720    pub fn convert_te_coordinates_to_scalars(&self) -> Vec<F> {
721        let mut res = vec![];
722        for sigma_comm in self.sigma_comms.iter() {
723            let point: TEPoint<F> = sigma_comm.0.into();
724            res.push(point.get_x());
725            res.push(point.get_y());
726        }
727        for selector_comm in self.selector_comms.iter() {
728            let point: TEPoint<F> = selector_comm.0.into();
729            res.push(point.get_x());
730            res.push(point.get_y());
731        }
732        res
733    }
734}
735
736/// Preprocessed verifier parameters used to verify Plookup proofs for a certain
737/// circuit.
738#[derive(Debug, Clone, Eq, PartialEq, CanonicalSerialize, CanonicalDeserialize)]
739pub struct PlookupVerifyingKey<E: Pairing> {
740    /// Range table polynomial commitment. The commitment is not hiding.
741    pub(crate) range_table_comm: Commitment<E>,
742
743    /// Key table polynomial commitment. The commitment is not hiding.
744    pub(crate) key_table_comm: Commitment<E>,
745
746    /// Table domain separation polynomial commitment. The commitment is not
747    /// hiding.
748    pub(crate) table_dom_sep_comm: Commitment<E>,
749
750    /// Lookup domain separation selector polynomial commitment. The commitment
751    /// is not hiding.
752    pub(crate) q_dom_sep_comm: Commitment<E>,
753}
754
755impl<E: Pairing> VerifyingKey<E> {
756    /// Create a dummy TurboPlonk verification key for a circuit with
757    /// `num_inputs` public inputs and domain size `domain_size`.
758    pub fn dummy(num_inputs: usize, domain_size: usize) -> Self {
759        let num_wire_types = GATE_WIDTH + 1;
760        Self {
761            domain_size,
762            num_inputs,
763            sigma_comms: vec![Commitment::default(); num_wire_types],
764            selector_comms: vec![Commitment::default(); N_TURBO_PLONK_SELECTORS],
765            k: compute_coset_representatives(num_wire_types, Some(domain_size)),
766            open_key: OpenKey::default(),
767            is_merged: false,
768            plookup_vk: None,
769        }
770    }
771    /// Merge with another TurboPlonk verifying key to obtain a new TurboPlonk
772    /// verifying key. Return error if any of the following holds:
773    /// 1. the other verifying key has a different domain size;
774    /// 2. the circuit underlying the other key has different number of inputs.
775    /// 3. the key or the other key is not a TurboPlonk key.
776    pub(crate) fn merge(&self, other_vk: &Self) -> Result<Self, PlonkError> {
777        if self.is_merged || other_vk.is_merged {
778            return Err(ParameterError("cannot merge a merged key again".to_string()).into());
779        }
780        if self.domain_size != other_vk.domain_size {
781            return Err(ParameterError(
782                "mismatched domain size when merging verifying keys".to_string(),
783            )
784            .into());
785        }
786        if self.num_inputs != other_vk.num_inputs {
787            return Err(ParameterError(
788                "mismatched number of public inputs when merging verifying keys".to_string(),
789            )
790            .into());
791        }
792        if self.plookup_vk.is_some() || other_vk.plookup_vk.is_some() {
793            return Err(
794                ParameterError("cannot merge UltraPlonk verifying keys".to_string()).into(),
795            );
796        }
797        let sigma_comms: Vec<Commitment<E>> = self
798            .sigma_comms
799            .iter()
800            .zip(other_vk.sigma_comms.iter())
801            .map(|(com1, com2)| Commitment((com1.0 + com2.0).into_affine()))
802            .collect();
803        let selector_comms: Vec<Commitment<E>> = self
804            .selector_comms
805            .iter()
806            .zip(other_vk.selector_comms.iter())
807            .map(|(com1, com2)| Commitment((com1.0 + com2.0).into_affine()))
808            .collect();
809
810        Ok(Self {
811            domain_size: self.domain_size,
812            num_inputs: self.num_inputs + other_vk.num_inputs,
813            sigma_comms,
814            selector_comms,
815            k: self.k.clone(),
816            open_key: self.open_key.clone(),
817            plookup_vk: None,
818            is_merged: true,
819        })
820    }
821
822    /// The lookup selector polynomial commitment
823    pub(crate) fn q_lookup_comm(&self) -> Result<&Commitment<E>, PlonkError> {
824        if self.plookup_vk.is_none() {
825            return Err(SnarkLookupUnsupported.into());
826        }
827        Ok(self.selector_comms.last().unwrap())
828    }
829}
830
831/// Plonk IOP verifier challenges.
832#[derive(Debug, Default)]
833pub(crate) struct Challenges<F: Field> {
834    pub(crate) tau: Option<F>,
835    pub(crate) alpha: F,
836    pub(crate) beta: F,
837    pub(crate) gamma: F,
838    pub(crate) zeta: F,
839    pub(crate) v: F,
840    pub(crate) u: F,
841}
842
843/// Plonk IOP online polynomial oracles.
844#[derive(Debug, Default, Clone)]
845pub(crate) struct Oracles<F: FftField> {
846    pub(crate) wire_polys: Vec<DensePolynomial<F>>,
847    pub(crate) pub_inp_poly: DensePolynomial<F>,
848    pub(crate) prod_perm_poly: DensePolynomial<F>,
849    pub(crate) plookup_oracles: PlookupOracles<F>,
850}
851
852/// Plookup IOP online polynomial oracles.
853#[derive(Debug, Default, Clone)]
854pub(crate) struct PlookupOracles<F: FftField> {
855    pub(crate) h_polys: Vec<DensePolynomial<F>>,
856    pub(crate) prod_lookup_poly: DensePolynomial<F>,
857}
858
859/// The vector representation of bases and corresponding scalars.
860#[derive(Debug)]
861pub(crate) struct ScalarsAndBases<E: Pairing> {
862    pub(crate) base_scalar_map: HashMap<E::G1Affine, E::ScalarField>,
863}
864
865impl<E: Pairing> ScalarsAndBases<E> {
866    pub(crate) fn new() -> Self {
867        Self {
868            base_scalar_map: HashMap::new(),
869        }
870    }
871    /// Insert a base point and the corresponding scalar.
872    pub(crate) fn push(&mut self, scalar: E::ScalarField, base: E::G1Affine) {
873        let entry_scalar = self
874            .base_scalar_map
875            .entry(base)
876            .or_insert_with(E::ScalarField::zero);
877        *entry_scalar += scalar;
878    }
879
880    /// Add a list of scalars and bases into self, where each scalar is
881    /// multiplied by a constant c.
882    pub(crate) fn merge(&mut self, c: E::ScalarField, scalars_and_bases: &Self) {
883        for (base, scalar) in &scalars_and_bases.base_scalar_map {
884            self.push(c * scalar, *base);
885        }
886    }
887    /// Compute the multi-scalar multiplication.
888    pub(crate) fn multi_scalar_mul(&self) -> E::G1 {
889        let mut bases = vec![];
890        let mut scalars = vec![];
891        for (base, scalar) in &self.base_scalar_map {
892            bases.push(*base);
893            scalars.push(scalar.into_bigint());
894        }
895        VariableBaseMSM::msm_bigint(&bases, &scalars)
896    }
897}
898
899// Utility function for computing merged table evaluations.
900#[inline]
901pub(crate) fn eval_merged_table<E: Pairing>(
902    tau: E::ScalarField,
903    range_eval: E::ScalarField,
904    key_eval: E::ScalarField,
905    q_lookup_eval: E::ScalarField,
906    w3_eval: E::ScalarField,
907    w4_eval: E::ScalarField,
908    table_dom_sep_eval: E::ScalarField,
909) -> E::ScalarField {
910    range_eval
911        + q_lookup_eval
912            * tau
913            * (table_dom_sep_eval + tau * (key_eval + tau * (w3_eval + tau * w4_eval)))
914}
915
916// Utility function for computing merged lookup witness evaluations.
917#[inline]
918pub(crate) fn eval_merged_lookup_witness<E: Pairing>(
919    tau: E::ScalarField,
920    w_range_eval: E::ScalarField,
921    w_0_eval: E::ScalarField,
922    w_1_eval: E::ScalarField,
923    w_2_eval: E::ScalarField,
924    q_lookup_eval: E::ScalarField,
925    q_dom_sep_eval: E::ScalarField,
926) -> E::ScalarField {
927    w_range_eval
928        + q_lookup_eval
929            * tau
930            * (q_dom_sep_eval + tau * (w_0_eval + tau * (w_1_eval + tau * w_2_eval)))
931}
932
933#[cfg(test)]
934mod test {
935    use super::*;
936    use ark_bn254::{g1::Config, Bn254, Fq};
937    use ark_ec::AffineRepr;
938
939    #[test]
940    fn test_group_to_field() {
941        let g1 = <Bn254 as Pairing>::G1Affine::generator();
942        let f1: Vec<Fq> = group1_to_fields::<Bn254, Config>(g1);
943        assert_eq!(f1.len(), 2);
944        let g2 = <Bn254 as Pairing>::G2Affine::generator();
945        let f2: Vec<Fq> = group2_to_fields::<Bn254, _, _>(g2);
946        assert_eq!(f2.len(), 4);
947    }
948}