jf_plonk/circuit/plonk_verifier/
mod.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//! Circuits for Plonk verifiers.
8use crate::proof_system::{structs::VerifyingKey, verifier::Verifier};
9use ark_ec::{
10    pairing::Pairing,
11    short_weierstrass::{Affine, SWCurveConfig as SWParam},
12    twisted_edwards::TECurveConfig as TEParam,
13};
14use ark_ff::{BigInteger, PrimeField};
15use ark_std::{format, string::ToString, vec, vec::Vec};
16use jf_relation::{
17    gadgets::{
18        ecc::{MultiScalarMultiplicationCircuit, PointVariable, SWToTEConParam, TEPoint},
19        ultraplonk::mod_arith::{FpElem, FpElemVar},
20    },
21    Circuit, CircuitError,
22    CircuitError::ParameterError,
23    PlonkCircuit, Variable,
24};
25use jf_rescue::RescueParameter;
26
27mod gadgets;
28mod poly;
29mod structs;
30
31use gadgets::*;
32pub use structs::*;
33
34#[derive(Debug, Clone, Eq, PartialEq)]
35/// Represent variable of a Plonk verifying key.
36pub struct VerifyingKeyVar<E: Pairing> {
37    /// The variables for the permutation polynomial commitments.
38    pub(crate) sigma_comms: Vec<PointVariable>,
39    /// The variables for the selector polynomial commitments.
40    pub(crate) selector_comms: Vec<PointVariable>,
41    /// A flag indicating whether the key is a merged key.
42    is_merged: bool,
43
44    /// The size of the evaluation domain. Should be a power of two.
45    domain_size: usize,
46
47    /// The number of public inputs.
48    num_inputs: usize,
49
50    /// The constants K0, ..., K_num_wire_types that ensure wire subsets are
51    /// disjoint.
52    k: Vec<E::ScalarField>,
53}
54
55impl<E: Pairing> VerifyingKeyVar<E> {
56    /// Create a variable for a Plonk verifying key.
57    pub fn new<F, P>(
58        circuit: &mut PlonkCircuit<F>,
59        verify_key: &VerifyingKey<E>,
60    ) -> Result<Self, CircuitError>
61    where
62        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
63        F: PrimeField + SWToTEConParam,
64        P: SWParam<BaseField = F>,
65    {
66        let sigma_comms = verify_key
67            .sigma_comms
68            .iter()
69            .map(|comm| circuit.create_point_variable(TEPoint::from(comm.0)))
70            .collect::<Result<Vec<_>, CircuitError>>()?;
71        let selector_comms = verify_key
72            .selector_comms
73            .iter()
74            .map(|comm| circuit.create_point_variable(TEPoint::from(comm.0)))
75            .collect::<Result<Vec<_>, CircuitError>>()?;
76        Ok(Self {
77            sigma_comms,
78            selector_comms,
79            is_merged: verify_key.is_merged,
80            domain_size: verify_key.domain_size,
81            num_inputs: verify_key.num_inputs,
82            k: verify_key.k.clone(),
83        })
84    }
85
86    /// Convert to a list of variables.
87    pub fn to_vec(&self) -> Vec<Variable> {
88        let mut res = vec![];
89        for sigma_comm in self.sigma_comms.iter() {
90            res.push(sigma_comm.get_x());
91            res.push(sigma_comm.get_y());
92        }
93        for selector_comm in self.selector_comms.iter() {
94            res.push(selector_comm.get_x());
95            res.push(selector_comm.get_y());
96        }
97        res
98    }
99
100    /// Merge with another Plonk verifying key variable.
101    pub(crate) fn merge<F, P>(
102        &self,
103        circuit: &mut PlonkCircuit<F>,
104        other: &Self,
105    ) -> Result<Self, CircuitError>
106    where
107        F: PrimeField,
108        P: TEParam<BaseField = F>,
109    {
110        if self.is_merged || other.is_merged {
111            return Err(ParameterError(
112                "cannot merge a merged key again".to_string(),
113            ));
114        }
115        if self.domain_size != other.domain_size {
116            return Err(ParameterError(
117                "cannot merge a verifying key with different domain size".to_string(),
118            ));
119        }
120        if self.num_inputs != other.num_inputs {
121            return Err(ParameterError(
122                "cannot merge a verifying key with different public input length".to_string(),
123            ));
124        }
125        let sigma_comms = self
126            .sigma_comms
127            .iter()
128            .zip(other.sigma_comms.iter())
129            .map(|(com1, com2)| circuit.ecc_add::<P>(com1, com2))
130            .collect::<Result<Vec<_>, CircuitError>>()?;
131        let selector_comms = self
132            .selector_comms
133            .iter()
134            .zip(other.selector_comms.iter())
135            .map(|(com1, com2)| circuit.ecc_add::<P>(com1, com2))
136            .collect::<Result<Vec<_>, CircuitError>>()?;
137        Ok(Self {
138            sigma_comms,
139            selector_comms,
140            is_merged: true,
141            domain_size: self.domain_size,
142            num_inputs: self.num_inputs + other.num_inputs,
143            k: self.k.clone(),
144        })
145    }
146
147    /// Circuit for partially verifying a batched proof without performing the
148    /// pairing. Return the variables for the two group elements used in the
149    /// final pairing.
150    /// The public inputs are already in the form of FpElemVars.
151    pub fn partial_verify_circuit<F, P>(
152        circuit: &mut PlonkCircuit<F>,
153        beta_g: &TEPoint<F>,
154        generator_g: &TEPoint<F>,
155        merged_vks: &[Self],
156        shared_public_input_vars: &[FpElemVar<F>],
157        batch_proof: &BatchProofVar<F>,
158        blinding_factor: Variable,
159    ) -> Result<(PointVariable, PointVariable), CircuitError>
160    where
161        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
162        F: RescueParameter + SWToTEConParam,
163        P: SWParam<BaseField = F> + TEParam,
164    {
165        if merged_vks.is_empty() {
166            return Err(ParameterError("empty merged verification keys".to_string()));
167        }
168        if merged_vks.len() != batch_proof.len() {
169            return Err(ParameterError(format!(
170                "the number of verification keys {} is different from the number of instances {}.",
171                merged_vks.len(),
172                batch_proof.len()
173            )));
174        }
175
176        let domain_size = merged_vks[0].domain_size;
177        for (i, vk) in merged_vks.iter().skip(1).enumerate() {
178            if vk.domain_size != domain_size {
179                return Err(ParameterError(format!(
180                    "the {}-th verification key's domain size {} is different from {}.",
181                    i, vk.domain_size, domain_size
182                )));
183            }
184        }
185
186        let range_bit_len = circuit.range_bit_len()?;
187        let m2 = (<E::ScalarField as PrimeField>::MODULUS_BIT_SIZE as usize + 1) >> 1;
188        // m should be a multiple of `range_bit_len`
189        let m = (m2 - 1) / range_bit_len * range_bit_len + range_bit_len;
190
191        // constants
192        let two_power_m = Some(E::BaseField::from(2u8).pow([m as u64]));
193
194        let fr_modulus_bits = <E::ScalarField as PrimeField>::MODULUS.to_bytes_le();
195        let modulus_in_f = F::from_le_bytes_mod_order(&fr_modulus_bits);
196        let modulus_fp_elem = FpElem::new(&modulus_in_f, m, two_power_m)?;
197
198        let non_native_field_info = NonNativeFieldInfo::<F> {
199            m,
200            two_power_m,
201            modulus_in_f,
202            modulus_fp_elem,
203        };
204
205        let verifier = Verifier::<E>::new(domain_size)?;
206        let domain = verifier.domain;
207
208        // we need to copy the public input once after merging the circuit
209        let shared_public_input_vars =
210            [shared_public_input_vars, shared_public_input_vars].concat();
211        let public_inputs = vec![&shared_public_input_vars[..]; merged_vks.len()];
212        let merged_vks_ref: Vec<&VerifyingKeyVar<E>> = merged_vks.iter().collect();
213
214        // generate the PCS info
215        let pcs_info_var = prepare_pcs_info_var(
216            circuit,
217            &merged_vks_ref,
218            &public_inputs,
219            batch_proof,
220            &None,
221            domain,
222            non_native_field_info,
223        )?;
224
225        // inner1
226        //  = [open_proof]
227        //  + u * [shifted_open_proof]
228        //  + blinding_factor * [1]1
229        let generator_g_var = circuit.create_constant_point_variable(*generator_g)?;
230        let bases = [
231            pcs_info_var.opening_proof,
232            pcs_info_var.shifted_opening_proof,
233            generator_g_var,
234        ];
235        let u_var = pcs_info_var.u.convert_to_var(circuit)?;
236        let scalars = [circuit.one(), u_var, blinding_factor];
237
238        let inner1 = MultiScalarMultiplicationCircuit::<_, P>::msm(circuit, &bases, &scalars)?;
239
240        // inner2
241        //  = eval_point * [open_proof]
242        //  + next_eval_point * u * [shifted_open_proof]
243        //  + [aggregated_comm]
244        //  - aggregated_eval * [1]1
245        //  + blinding_factor * [beta]1
246        let mut scalars_and_bases = pcs_info_var.comm_scalars_and_bases;
247        scalars_and_bases.scalars.push(pcs_info_var.eval_point);
248        scalars_and_bases.bases.push(pcs_info_var.opening_proof);
249
250        let tmp = circuit.mod_mul(
251            &pcs_info_var.next_eval_point,
252            &pcs_info_var.u,
253            &modulus_fp_elem,
254        )?;
255        scalars_and_bases.scalars.push(tmp);
256        scalars_and_bases
257            .bases
258            .push(pcs_info_var.shifted_opening_proof);
259
260        let generator_g_inv_var = circuit.create_constant_point_variable(generator_g.inverse())?;
261        scalars_and_bases.scalars.push(pcs_info_var.eval);
262        scalars_and_bases.bases.push(generator_g_inv_var);
263
264        let mut scalars = scalars_and_bases
265            .scalars
266            .iter()
267            .map(|x| x.convert_to_var(circuit))
268            .collect::<Result<Vec<_>, _>>()?;
269        scalars.push(blinding_factor);
270
271        let mut bases = scalars_and_bases.bases;
272        let beta_g = circuit.create_constant_point_variable(*beta_g)?;
273        bases.push(beta_g);
274        let inner2 = MultiScalarMultiplicationCircuit::<_, P>::msm(circuit, &bases, &scalars)?;
275
276        Ok((inner1, inner2))
277    }
278}
279
280/// Plonk Circuit that support batch verification
281pub trait BatchableCircuit<F> {
282    /// Aggregate verification keys
283    fn aggregate_verify_keys<E, P>(
284        &mut self,
285        vk_type_a_vars: &[VerifyingKeyVar<E>],
286        vk_type_b_vars: &[VerifyingKeyVar<E>],
287    ) -> Result<Vec<VerifyingKeyVar<E>>, CircuitError>
288    where
289        E: Pairing,
290        P: TEParam<BaseField = F>;
291}
292
293/// Instances batching scheme related gates
294impl<F> BatchableCircuit<F> for PlonkCircuit<F>
295where
296    F: PrimeField,
297{
298    fn aggregate_verify_keys<E, P>(
299        &mut self,
300        vk_type_a_vars: &[VerifyingKeyVar<E>],
301        vk_type_b_vars: &[VerifyingKeyVar<E>],
302    ) -> Result<Vec<VerifyingKeyVar<E>>, CircuitError>
303    where
304        E: Pairing,
305        P: TEParam<BaseField = F>,
306    {
307        if vk_type_a_vars.len() != vk_type_b_vars.len() {
308            return Err(ParameterError(format!(
309                "the number of type A verification key variables {} is different from the number of type B verification key variables {}.",
310                vk_type_a_vars.len(),
311                vk_type_b_vars.len())
312            ));
313        }
314        vk_type_a_vars
315            .iter()
316            .zip(vk_type_b_vars.iter())
317            .map(|(vk_b, vk_d)| vk_b.merge::<F, P>(self, vk_d))
318            .collect::<Result<Vec<_>, CircuitError>>()
319    }
320}
321
322#[cfg(test)]
323mod test {
324    use super::*;
325    use crate::{
326        proof_system::{
327            batch_arg::{new_mergeable_circuit_for_test, BatchArgument},
328            structs::BatchProof,
329            PlonkKzgSnark, UniversalSNARK,
330        },
331        transcript::{PlonkTranscript, RescueTranscript},
332    };
333    use ark_bls12_377::{g1::Config as Param377, Bls12_377, Fq as Fq377};
334    use ark_ec::{short_weierstrass::SWCurveConfig, twisted_edwards::TECurveConfig, CurveGroup};
335    use ark_std::{vec, UniformRand};
336    use jf_relation::{
337        gadgets::test_utils::test_variable_independence_for_circuit, MergeableCircuitType,
338    };
339    use jf_utils::{field_switching, test_rng};
340
341    const RANGE_BIT_LEN_FOR_TEST: usize = 16;
342
343    #[test]
344    fn test_aggregate_vks() -> Result<(), CircuitError> {
345        test_aggregate_vks_helper::<Bls12_377, Fq377, _, Param377>()
346    }
347
348    fn test_aggregate_vks_helper<E, F, P, Q>() -> Result<(), CircuitError>
349    where
350        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
351        F: PrimeField + RescueParameter + SWToTEConParam,
352        P: SWParam<BaseField = F>,
353        Q: TEParam<BaseField = F>,
354    {
355        // Simulate universal setup
356        let rng = &mut test_rng();
357        let n = 32;
358        let max_degree = n + 2;
359        let srs = PlonkKzgSnark::<E>::universal_setup_for_testing(max_degree, rng)?;
360
361        // Setup instances and create verifying keys
362        let mut vks_type_a = vec![];
363        let mut vks_type_b = vec![];
364        let shared_public_input = E::ScalarField::rand(rng);
365        for i in 0..5 {
366            let circuit = new_mergeable_circuit_for_test::<E>(
367                shared_public_input,
368                i,
369                MergeableCircuitType::TypeA,
370            )?;
371            let instance =
372                BatchArgument::setup_instance(&srs, circuit, MergeableCircuitType::TypeA)?;
373            vks_type_a.push(instance.verify_key_ref().clone());
374
375            let circuit = new_mergeable_circuit_for_test::<E>(
376                shared_public_input,
377                i,
378                MergeableCircuitType::TypeB,
379            )?;
380            let instance =
381                BatchArgument::setup_instance(&srs, circuit, MergeableCircuitType::TypeB)?;
382            vks_type_b.push(instance.verify_key_ref().clone());
383        }
384        // Compute merged verifying keys
385        let vks_type_a_ref: Vec<&VerifyingKey<E>> = vks_type_a.iter().collect();
386        let vks_type_b_ref: Vec<&VerifyingKey<E>> = vks_type_b.iter().collect();
387        let merged_vks = BatchArgument::aggregate_verify_keys(&vks_type_a_ref, &vks_type_b_ref)?;
388
389        // Check circuits
390        let mut circuit: PlonkCircuit<F> = PlonkCircuit::new_ultra_plonk(RANGE_BIT_LEN_FOR_TEST);
391        let vk_type_a_vars = vks_type_a
392            .iter()
393            .map(|vk| VerifyingKeyVar::new(&mut circuit, vk))
394            .collect::<Result<Vec<_>, CircuitError>>()?;
395        for (vk_var, vk) in vk_type_a_vars.iter().zip(vks_type_a.iter()) {
396            check_vk_equality(&circuit, vk_var, vk);
397        }
398
399        let vk_type_b_vars = vks_type_b
400            .iter()
401            .map(|vk| VerifyingKeyVar::new(&mut circuit, vk))
402            .collect::<Result<Vec<_>, CircuitError>>()?;
403        for (vk_var, vk) in vk_type_b_vars.iter().zip(vks_type_b.iter()) {
404            check_vk_equality(&circuit, vk_var, vk);
405        }
406
407        let merged_vk_vars =
408            circuit.aggregate_verify_keys::<E, Q>(&vk_type_a_vars, &vk_type_b_vars)?;
409        for (vk_var, vk) in merged_vk_vars.iter().zip(merged_vks.iter()) {
410            check_vk_equality(&circuit, vk_var, vk);
411        }
412
413        assert!(circuit.check_circuit_satisfiability(&[]).is_ok());
414
415        // Error paths
416        // wrong witness
417        let tmp = circuit.witness(merged_vk_vars[0].sigma_comms[0].get_x())?;
418        *circuit.witness_mut(merged_vk_vars[0].sigma_comms[0].get_x()) = F::from(0u8);
419        assert!(circuit.check_circuit_satisfiability(&[]).is_err());
420        *circuit.witness_mut(merged_vk_vars[0].sigma_comms[0].get_x()) = tmp;
421
422        // inconsistent length between `vk_type_a_vars` and `vk_type_b_vars`
423        assert!(circuit
424            .aggregate_verify_keys::<E, Q>(&vk_type_a_vars[1..], &vk_type_b_vars)
425            .is_err());
426
427        // merged keys can't be merged again.
428        let mut bad_vk_vars = vk_type_a_vars.clone();
429        bad_vk_vars[0].is_merged = true;
430        assert!(circuit
431            .aggregate_verify_keys::<E, Q>(&bad_vk_vars, &vk_type_b_vars)
432            .is_err());
433
434        Ok(())
435    }
436
437    fn check_vk_equality<E, F, P>(
438        circuit: &PlonkCircuit<F>,
439        vk_var: &VerifyingKeyVar<E>,
440        vk: &VerifyingKey<E>,
441    ) where
442        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
443        F: PrimeField + SWToTEConParam,
444        P: SWParam<BaseField = F>,
445    {
446        for (comm_var, comm) in vk_var.sigma_comms.iter().zip(vk.sigma_comms.iter()) {
447            let expected_comm = TEPoint::from(comm.0);
448            assert_eq!(circuit.point_witness(comm_var).unwrap(), expected_comm);
449        }
450        for (comm_var, comm) in vk_var.selector_comms.iter().zip(vk.selector_comms.iter()) {
451            let expected_comm = TEPoint::from(comm.0);
452            assert_eq!(circuit.point_witness(comm_var).unwrap(), expected_comm);
453        }
454        assert_eq!(vk_var.is_merged, vk.is_merged);
455    }
456
457    #[test]
458    fn test_partial_verification_circuit() -> Result<(), CircuitError> {
459        test_partial_verification_circuit_helper::<Bls12_377, _, _, RescueTranscript<_>>()
460    }
461
462    fn test_partial_verification_circuit_helper<E, F, P, T>() -> Result<(), CircuitError>
463    where
464        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
465        F: RescueParameter + SWToTEConParam,
466        P: SWCurveConfig<BaseField = F> + TECurveConfig,
467        T: PlonkTranscript<F>,
468    {
469        let rng = &mut test_rng();
470
471        for log_circuit_size in 8..12 {
472            // =======================================
473            // setup
474            // =======================================
475
476            // 1. Simulate universal setup
477            let n = 1 << log_circuit_size;
478            let max_degree = n + 2;
479            let srs = PlonkKzgSnark::<E>::universal_setup_for_testing(max_degree, rng)?;
480
481            // 2. Setup instances
482            let shared_public_input = E::ScalarField::rand(rng);
483            let mut instances_type_a = vec![];
484            let mut instances_type_b = vec![];
485            for i in 32..50 {
486                let circuit = new_mergeable_circuit_for_test::<E>(
487                    shared_public_input,
488                    i,
489                    MergeableCircuitType::TypeA,
490                )?;
491                let instance =
492                    BatchArgument::setup_instance(&srs, circuit, MergeableCircuitType::TypeA)?;
493                instances_type_a.push(instance);
494
495                let circuit = new_mergeable_circuit_for_test::<E>(
496                    shared_public_input,
497                    i,
498                    MergeableCircuitType::TypeB,
499                )?;
500                let instance =
501                    BatchArgument::setup_instance(&srs, circuit, MergeableCircuitType::TypeB)?;
502                instances_type_b.push(instance);
503            }
504            // 3. Batch Proving
505            let batch_proof =
506                BatchArgument::batch_prove::<_, T>(rng, &instances_type_a, &instances_type_b)?;
507
508            // 4. Aggregate verification keys
509            let vks_type_a: Vec<&VerifyingKey<E>> = instances_type_a
510                .iter()
511                .map(|pred| pred.verify_key_ref())
512                .collect();
513            let vks_type_b: Vec<&VerifyingKey<E>> = instances_type_b
514                .iter()
515                .map(|pred| pred.verify_key_ref())
516                .collect();
517            let merged_vks = BatchArgument::aggregate_verify_keys(&vks_type_a, &vks_type_b)?;
518            // error path: inconsistent length between vks_type_a and vks_type_b
519            assert!(BatchArgument::aggregate_verify_keys(&vks_type_a[1..], &vks_type_b).is_err());
520
521            // 5. Verification
522            let open_key_ref = &vks_type_a[0].open_key;
523            let beta_g_ref = &srs.powers_of_g[1];
524            let blinding_factor = E::ScalarField::rand(rng);
525            let (inner1, inner2) = BatchArgument::partial_verify::<T>(
526                beta_g_ref,
527                &open_key_ref.g,
528                &merged_vks,
529                &[shared_public_input],
530                &batch_proof,
531                blinding_factor,
532            )?;
533            assert!(BatchArgument::decide(open_key_ref, inner1, inner2)?);
534
535            {
536                // =======================================
537                // good path
538                // =======================================
539                let public_inputs = [[field_switching(&shared_public_input)].as_ref()].concat();
540
541                let (mut circuit, partial_verify_points) = build_circuit::<E, F, P>(
542                    &shared_public_input,
543                    &merged_vks,
544                    &batch_proof,
545                    beta_g_ref,
546                    &open_key_ref.g,
547                    &blinding_factor,
548                )?;
549
550                assert!(
551                    circuit.check_circuit_satisfiability(&public_inputs).is_ok(),
552                    "{:?}",
553                    circuit.check_circuit_satisfiability(&public_inputs)
554                );
555                assert_eq!(
556                    circuit.point_witness(&partial_verify_points.0)?,
557                    TEPoint::<F>::from(inner1.into_affine())
558                );
559                assert_eq!(
560                    circuit.point_witness(&partial_verify_points.1)?,
561                    TEPoint::<F>::from(inner2.into_affine())
562                );
563
564                // ark_std::println!("#variables: {}", circuit.num_vars());
565                // ark_std::println!("#constraints: {}\n", circuit.num_gates());
566
567                // =======================================
568                // bad path: wrong pub inputs
569                // =======================================
570                // instance inputs = partial verify inputs != satisfiability inputs
571                let wrong_public_inputs = [[F::rand(rng)].as_ref()].concat();
572                assert!(circuit
573                    .check_circuit_satisfiability(&wrong_public_inputs)
574                    .is_err(),);
575
576                // =======================================
577                // bad path: wrong number of pub inputs
578                // =======================================
579                let wrong_public_inputs =
580                    [[field_switching(&shared_public_input); 3].as_ref()].concat();
581                assert!(circuit
582                    .check_circuit_satisfiability(&wrong_public_inputs)
583                    .is_err(),);
584
585                // =======================================
586                // bad path: wrong witness
587                // =======================================
588                *circuit.witness_mut(10) = F::from(0u32);
589                assert!(circuit
590                    .check_circuit_satisfiability(&public_inputs)
591                    .is_err());
592            }
593            // ==============================================
594            // more bad path: wrong inputs length
595            // ==============================================
596            {
597                // wrong vks length (less by 1)
598                // should not be able to generate circuit
599                let mut wrong_merge_vks = merged_vks.clone();
600                let tmp = wrong_merge_vks.pop().unwrap();
601                assert!(build_circuit::<E, F, P>(
602                    &shared_public_input,
603                    &wrong_merge_vks,
604                    &batch_proof,
605                    beta_g_ref,
606                    &open_key_ref.g,
607                    &blinding_factor,
608                )
609                .is_err());
610
611                // wrong vks length (more by 1)
612                // should not be able to generate circuit
613                let mut wrong_merge_vks = merged_vks.clone();
614                wrong_merge_vks.push(tmp);
615                assert!(build_circuit::<E, F, P>(
616                    &shared_public_input,
617                    &wrong_merge_vks,
618                    &batch_proof,
619                    beta_g_ref,
620                    &open_key_ref.g,
621                    &blinding_factor,
622                )
623                .is_err());
624            }
625
626            // ==============================================
627            // more bad path: wrong inputs to the function
628            // ==============================================
629            {
630                // wrong shared input, the circuit is not satisfied
631                // instance inputs = satisfiability inputs != partial verify inputs
632                let public_inputs = [[field_switching(&shared_public_input)].as_ref()].concat();
633                let wrong_shared_public_input = E::ScalarField::rand(rng);
634                let (circuit, partial_verify_points) = build_circuit::<E, F, P>(
635                    &wrong_shared_public_input,
636                    &merged_vks,
637                    &batch_proof,
638                    beta_g_ref,
639                    &open_key_ref.g,
640                    &blinding_factor,
641                )?;
642
643                assert!(
644                    circuit
645                        .check_circuit_satisfiability(&public_inputs)
646                        .is_err(),
647                    "{:?}",
648                    circuit.check_circuit_satisfiability(public_inputs.as_ref())
649                );
650                assert_ne!(
651                    circuit.point_witness(&partial_verify_points.0)?,
652                    TEPoint::<F>::from(inner1.into_affine())
653                );
654                assert_ne!(
655                    circuit.point_witness(&partial_verify_points.1)?,
656                    TEPoint::<F>::from(inner2.into_affine())
657                );
658
659                // wrong shared input and circuit input
660                // instance inputs != partial verify inputs = satisfiability inputs
661                // the circuit is satisfied because partial verify inputs = satisfiability
662                // inputs both output must be different so it will not verify
663                // original instance
664                let wrong_public_inputs =
665                    [[field_switching(&wrong_shared_public_input)].as_ref()].concat();
666                assert!(
667                    circuit
668                        .check_circuit_satisfiability(&wrong_public_inputs)
669                        .is_ok(),
670                    "{:?}",
671                    circuit.check_circuit_satisfiability(wrong_public_inputs.as_ref())
672                );
673                assert_ne!(
674                    circuit.point_witness(&partial_verify_points.0)?,
675                    TEPoint::<F>::from(inner1.into_affine())
676                );
677                assert_ne!(
678                    circuit.point_witness(&partial_verify_points.1)?,
679                    TEPoint::<F>::from(inner2.into_affine())
680                );
681            }
682        }
683
684        Ok(())
685    }
686
687    fn build_circuit<E, F, P>(
688        shared_public_input: &E::ScalarField,
689        merged_vks: &[VerifyingKey<E>],
690        batch_proof: &BatchProof<E>,
691        beta_g_ref: &Affine<P>,
692        generator_g: &Affine<P>,
693        blinding_factor: &E::ScalarField,
694    ) -> Result<(PlonkCircuit<F>, (PointVariable, PointVariable)), CircuitError>
695    where
696        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
697        F: RescueParameter + SWToTEConParam,
698        P: SWCurveConfig<BaseField = F> + TECurveConfig,
699    {
700        let mut circuit = PlonkCircuit::<E::BaseField>::new_ultra_plonk(RANGE_BIT_LEN_FOR_TEST);
701
702        // constants
703        let m = 128;
704        let two_power_m = Some(E::BaseField::from(2u8).pow([m as u64]));
705
706        // public inputs
707        let shared_public_input_var =
708            circuit.create_public_variable(field_switching(shared_public_input))?;
709        let shared_public_input_fp_elem_var =
710            FpElemVar::new_unchecked(&mut circuit, shared_public_input_var, m, two_power_m)?;
711
712        // vk
713        let vk_vars = merged_vks
714            .iter()
715            .map(|x| VerifyingKeyVar::new(&mut circuit, x))
716            .collect::<Result<Vec<_>, _>>()?;
717
718        // proof
719        let batch_proof_vars = (*batch_proof).create_variables(&mut circuit, m, two_power_m)?;
720
721        let beta_g: TEPoint<F> = (*beta_g_ref).into();
722        let generator_g = &(*generator_g).into();
723        let blinding_factor_var = circuit.create_variable(field_switching(blinding_factor))?;
724
725        let partial_verify_points = VerifyingKeyVar::partial_verify_circuit(
726            &mut circuit,
727            &beta_g,
728            generator_g,
729            &vk_vars,
730            &[shared_public_input_fp_elem_var],
731            &batch_proof_vars,
732            blinding_factor_var,
733        )?;
734
735        Ok((circuit, partial_verify_points))
736    }
737
738    #[test]
739    fn test_variable_independence_for_partial_verification_circuit() -> Result<(), CircuitError> {
740        test_variable_independence_for_partial_verification_circuit_helper::<
741            Bls12_377,
742            _,
743            _,
744            RescueTranscript<_>,
745        >()
746    }
747
748    fn test_variable_independence_for_partial_verification_circuit_helper<E, F, P, T>(
749    ) -> Result<(), CircuitError>
750    where
751        E: Pairing<BaseField = F, G1Affine = Affine<P>>,
752        F: RescueParameter + SWToTEConParam,
753        P: SWCurveConfig<BaseField = F> + TECurveConfig,
754        T: PlonkTranscript<F>,
755    {
756        let rng = &mut test_rng();
757        let i = 8;
758        let mut circuits = vec![];
759
760        // 1. Simulate universal setup
761        let n = 1 << i;
762        let max_degree = n + 2;
763        let srs = PlonkKzgSnark::<E>::universal_setup_for_testing(max_degree, rng)?;
764
765        for _ in 0..2 {
766            // =======================================
767            // set up
768            // =======================================
769
770            // 2. Setup instances
771            let shared_public_input = E::ScalarField::rand(rng);
772            let mut instances_type_a = vec![];
773            let mut instances_type_b = vec![];
774
775            let circuit = new_mergeable_circuit_for_test::<E>(
776                shared_public_input,
777                i,
778                MergeableCircuitType::TypeA,
779            )?;
780            let instance =
781                BatchArgument::setup_instance(&srs, circuit, MergeableCircuitType::TypeA)?;
782            instances_type_a.push(instance);
783
784            let circuit = new_mergeable_circuit_for_test::<E>(
785                shared_public_input,
786                i,
787                MergeableCircuitType::TypeB,
788            )?;
789            let instance =
790                BatchArgument::setup_instance(&srs, circuit, MergeableCircuitType::TypeB)?;
791            instances_type_b.push(instance);
792
793            // 3. Batch Proving
794            let batch_proof =
795                BatchArgument::batch_prove::<_, T>(rng, &instances_type_a, &instances_type_b)?;
796
797            // 4. Aggregate verification keys
798            let vks_type_a: Vec<&VerifyingKey<E>> = instances_type_a
799                .iter()
800                .map(|pred| pred.verify_key_ref())
801                .collect();
802            let vks_type_b: Vec<&VerifyingKey<E>> = instances_type_b
803                .iter()
804                .map(|pred| pred.verify_key_ref())
805                .collect();
806            let merged_vks = BatchArgument::aggregate_verify_keys(&vks_type_a, &vks_type_b)?;
807
808            // 5. Build circuit
809            let open_key_ref = &vks_type_a[0].open_key;
810            let beta_g_ref = &srs.powers_of_g[1];
811            let blinding_factor = E::ScalarField::rand(rng);
812
813            let (mut circuit, _partial_verify_points) = build_circuit::<E, F, P>(
814                &shared_public_input,
815                &merged_vks,
816                &batch_proof,
817                beta_g_ref,
818                &open_key_ref.g,
819                &blinding_factor,
820            )?;
821
822            circuit.finalize_for_arithmetization()?;
823            circuits.push(circuit);
824        }
825
826        test_variable_independence_for_circuit(circuits[0].clone(), circuits[1].clone())?;
827
828        Ok(())
829    }
830}