frontend/hyrax_worldcoin_mpc/
mpc_prover.rs

1use crate::{
2    hyrax_worldcoin::{
3        orb::PUBLIC_STRING,
4        v3::{V3CircuitAndAuxData, V3Proof, V3ProofError, V3Prover},
5    },
6    layouter::builder::{Circuit, LayerVisibility},
7    worldcoin_mpc::{
8        circuits::{
9            build_circuit, mpc_attach_data, MPC_AUXILIARY_INVARIANT_LAYER, MPC_AUXILIARY_LAYER,
10            MPC_IRISCODE_INPUT_LAYER, MPC_MASKCODE_INPUT_LAYER, MPC_SHARES_LAYER, MPC_SLOPES_LAYER,
11        },
12        data::{gen_mpc_encoding_matrix, gen_mpc_evaluation_points, gen_mpc_input_data},
13        parameters::{GR4_MODULUS, MPC_NUM_IRIS_4_CHUNKS},
14    },
15    zk_iriscode_ss::parameters::{IRISCODE_LEN, SHAMIR_SECRET_SHARE_SLOPE_LOG_NUM_COLS},
16};
17use hyrax::{
18    gkr::{
19        input_layer::{commit_to_input_values, HyraxProverInputCommitment},
20        verify_hyrax_proof, HyraxProof,
21    },
22    provable_circuit::HyraxProvableCircuit,
23    utils::vandermonde::VandermondeInverse,
24    verifiable_circuit::HyraxVerifiableCircuit,
25};
26
27use itertools::Itertools;
28use rand::{CryptoRng, Rng, RngCore};
29use remainder::{layer::LayerId, mle::evals::MultilinearExtension};
30use serde::{Deserialize, Serialize};
31use shared_types::{
32    config::{
33        global_config::{
34            global_prover_claim_agg_constant_column_optimization, global_prover_enable_bit_packing,
35            global_prover_lazy_beta_evals,
36        },
37        GKRCircuitProverConfig, ProofConfig,
38    },
39    curves::PrimeOrderCurve,
40    pedersen::PedersenCommitter,
41    transcript::{ec_transcript::ECTranscript, poseidon_sponge::PoseidonSponge},
42    Base, Bn256Point, Field, Fr, Scalar,
43};
44use thiserror::Error;
45
46/// Errors when verifying the MPC Proof
47#[derive(Debug, Error)]
48pub enum MPCError {
49    #[error("Incorrect MLEs that should be invariant between circuits")]
50    IncorrectInvariantAuxMles,
51    #[error("Couldn't find the shares input layer MLE")]
52    NoSharesInputLayerMle,
53}
54
55// Errors when producing the MPC Proof
56#[derive(Error, Debug)]
57pub enum MPCProofError {
58    #[error("Found empty proof field")]
59    EmptyProofField,
60
61    #[error("Verification produced an MPC error")]
62    MPCError(#[from] MPCError),
63}
64
65// Errors when producing the V3-MPC Proof
66#[derive(Error, Debug)]
67pub enum V3MPCProofError {
68    #[error("Found empty proof field")]
69    EmptyProofField,
70
71    #[error("Verification produced an V3 error")]
72    V3Error(#[from] V3ProofError),
73
74    #[error("Verification produced an MPC error")]
75    MPCError(#[from] MPCProofError),
76}
77
78pub fn print_features_status() {
79    const STATUS_STR: [&str; 2] = ["OFF", "ON"];
80
81    println!("=== FEATURES ===");
82    println!(
83        "Parallel feature for prover: {}",
84        STATUS_STR[remainder::utils::is_parallel_feature_on() as usize]
85    );
86    println!(
87        "Parallel feature for hyrax: {}",
88        STATUS_STR[hyrax::utils::is_parallel_feature_on() as usize]
89    );
90    println!(
91        "Lazy beta evaluation: {}",
92        STATUS_STR[global_prover_lazy_beta_evals() as usize]
93    );
94    println!(
95        "BitPackedVector: {}",
96        STATUS_STR[global_prover_enable_bit_packing() as usize]
97    );
98    println!(
99        "Claim aggregation constant column optimization for prover: {}",
100        STATUS_STR[global_prover_claim_agg_constant_column_optimization() as usize]
101    );
102    println!("================\n");
103}
104
105#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
106#[serde(bound = "C: PrimeOrderCurve")]
107pub struct V3MPCCommitments<C: PrimeOrderCurve> {
108    left_iris_code: Vec<C>,
109    left_mask_code: Vec<C>,
110    right_iris_code: Vec<C>,
111    right_mask_code: Vec<C>,
112    slope_left_iris_code: Vec<C>,
113    slope_right_iris_code: Vec<C>,
114}
115
116impl<C: PrimeOrderCurve> V3MPCCommitments<C> {
117    pub fn new(
118        left_iris_code: Vec<C>,
119        left_mask_code: Vec<C>,
120        right_iris_code: Vec<C>,
121        right_mask_code: Vec<C>,
122        slope_left_iris_code: Vec<C>,
123        slope_right_iris_code: Vec<C>,
124    ) -> Self {
125        Self {
126            left_iris_code,
127            left_mask_code,
128            right_iris_code,
129            right_mask_code,
130            slope_left_iris_code,
131            slope_right_iris_code,
132        }
133    }
134
135    pub fn get_code_commit_ref(&self, is_mask: bool, is_left_eye: bool) -> &Vec<C> {
136        if is_mask {
137            if is_left_eye {
138                &self.left_mask_code
139            } else {
140                &self.right_mask_code
141            }
142        } else if is_left_eye {
143            &self.left_iris_code
144        } else {
145            &self.right_iris_code
146        }
147    }
148
149    pub fn get_slope_commit_ref(&self, is_left_eye: bool) -> &Vec<C> {
150        if is_left_eye {
151            &self.slope_left_iris_code
152        } else {
153            &self.slope_right_iris_code
154        }
155    }
156
157    pub fn serialize(&self) -> Vec<u8> {
158        bincode::serialize(self).unwrap()
159    }
160
161    pub fn deserialize(bytes: &[u8]) -> Self {
162        bincode::deserialize(bytes).unwrap()
163    }
164}
165
166/*
167#[allow(clippy::too_many_arguments)]
168pub fn prove_mpc_with_precommits(
169    circuit: &Circuit<Fr>,
170    iris_precommit: &HyraxProverInputCommitment<Bn256Point>,
171    mask_precommit: &HyraxProverInputCommitment<Bn256Point>,
172    slope_precommit: &HyraxProverInputCommitment<Bn256Point>,
173    committer: &PedersenCommitter<Bn256Point>,
174    blinding_rng: &mut (impl CryptoRng + RngCore),
175    converter: &mut VandermondeInverse<Scalar>,
176) -> HyraxProof<Bn256Point> {
177    // Set up Hyrax input layer specification.
178    let mut hyrax_input_layers = HashMap::new();
179
180    hyrax_input_layers.insert(
181        mpc_circuit_desc.iris_code_input_layer.layer_id,
182        (
183            mpc_circuit_desc.iris_code_input_layer.clone().into(),
184            Some(iris_precommit.clone()),
185        ),
186    );
187
188    hyrax_input_layers.insert(
189        mpc_circuit_desc.mask_code_input_layer.layer_id,
190        (
191            mpc_circuit_desc.mask_code_input_layer.clone().into(),
192            Some(mask_precommit.clone()),
193        ),
194    );
195
196    hyrax_input_layers.insert(
197        mpc_circuit_desc.slope_input_layer.layer_id,
198        (
199            mpc_circuit_desc.slope_input_layer.clone().into(),
200            Some(slope_precommit.clone()),
201        ),
202    );
203
204    hyrax_input_layers.insert(
205        mpc_circuit_desc.auxilary_input_layer.layer_id,
206        (mpc_circuit_desc.auxilary_input_layer.clone().into(), None),
207    );
208
209    // Create a fresh transcript.
210    let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
211        ECTranscript::new("V3 Iriscode Circuit Pipeline");
212
213    // Prove the relationship between iris/mask code and image.
214    let (proof, _proof_config) = HyraxProof::prove(
215        &inputs,
216        &hyrax_input_layers,
217        &mpc_circuit_desc.circuit_description,
218        committer,
219        blinding_rng,
220        converter,
221        &mut transcript,
222    );
223
224    proof
225}
226*/
227
228#[derive(Clone, Debug, Serialize, Deserialize)]
229#[serde(bound = "F: Field")]
230pub struct MPCCircuitConstData<F: Field> {
231    pub encoding_matrix: MultilinearExtension<F>,
232    pub evaluation_points: MultilinearExtension<F>,
233    pub lookup_table_values: MultilinearExtension<F>,
234}
235
236// TODO: Add similar API to V3CircuitAndAuxData/ConstData.
237#[derive(Clone, Debug, Serialize, Deserialize)]
238#[serde(bound = "F: Field")]
239pub struct MPCCircuitsAndConstData<F: Field> {
240    pub mpc_circuit: Circuit<F>,
241    pub encoding_matrix: MultilinearExtension<F>,
242    pub evaluation_points: [MultilinearExtension<F>; 3],
243}
244
245#[derive(Serialize, Deserialize)]
246pub struct MPCProver {
247    #[serde(skip)]
248    #[serde(default = "V3Prover::default_committer")]
249    committer: PedersenCommitter<Bn256Point>,
250
251    #[serde(skip)]
252    #[serde(default = "VandermondeInverse::new")]
253    converter: VandermondeInverse<Scalar>,
254
255    slope_commitments: [HyraxProverInputCommitment<Bn256Point>; 2],
256
257    prover_config: GKRCircuitProverConfig,
258    mpc_circuit_and_const_mles_all_3_parties: MPCCircuitsAndConstData<Fr>,
259
260    left_eye_proofs_all_3_parties: Option<Vec<HyraxProof<Bn256Point>>>,
261    right_eye_proofs_all_3_parties: Option<Vec<HyraxProof<Bn256Point>>>,
262}
263
264impl MPCProver {
265    /// Computes a set of random Shamir secret share slopes and creates a Hyrax
266    /// commitment for them.
267    ///
268    /// Note that `rng` should be a CSPRNG seeded with a strong source of
269    /// device entropy! Recommended to call this with `OsRng` and `ChaCha20Rng`.
270    fn generate_secure_shamir_secret_share_slopes_and_commitments<C: PrimeOrderCurve>(
271        num_vars: usize,
272        log_num_cols: usize,
273        pedersen_committer: &PedersenCommitter<C>,
274        rng: &mut impl Rng,
275    ) -> HyraxProverInputCommitment<C> {
276        // The slopes must be in the range [0, 2^{16} - 1]
277        let slopes_mle = MultilinearExtension::new(
278            (0..IRISCODE_LEN)
279                .map(|_idx| C::Scalar::from(rng.gen_range(0..GR4_MODULUS)))
280                .collect_vec(),
281        );
282
283        commit_to_input_values(num_vars, log_num_cols, &slopes_mle, pedersen_committer, rng)
284    }
285
286    pub fn default_committer() -> PedersenCommitter<Bn256Point> {
287        PedersenCommitter::new(512, PUBLIC_STRING, None)
288    }
289
290    pub fn new(
291        prover_config: GKRCircuitProverConfig,
292        mpc_circuit_and_aux_mles_all_3_parties: MPCCircuitsAndConstData<Fr>,
293        rng: &mut (impl CryptoRng + RngCore),
294    ) -> Self {
295        // Verify `circuit` contains the necessary input layers, which do _not_ contain any data
296        // yet.
297        // TODO: Provide methods in the `Circuit` struct that can check whether
298        // 1. All input MLEs are empty, and
299        // 2. The circuit contains input layers with labels corresponding exactly to a given list of
300        // labels.
301        // Having those we can replace the below tests with two such method calls.
302        let circuit = &mpc_circuit_and_aux_mles_all_3_parties.mpc_circuit;
303        assert!(!circuit
304            .input_layer_contains_data(MPC_AUXILIARY_LAYER)
305            .unwrap());
306        assert!(!circuit
307            .input_layer_contains_data(MPC_AUXILIARY_INVARIANT_LAYER)
308            .unwrap());
309        assert!(!circuit.input_layer_contains_data(MPC_SHARES_LAYER).unwrap());
310        assert!(!circuit.input_layer_contains_data(MPC_SLOPES_LAYER).unwrap());
311        assert!(!circuit
312            .input_layer_contains_data(MPC_IRISCODE_INPUT_LAYER)
313            .unwrap());
314        assert!(!circuit
315            .input_layer_contains_data(MPC_MASKCODE_INPUT_LAYER)
316            .unwrap());
317
318        let committer = Self::default_committer();
319
320        let slope_input_layer_description = &mpc_circuit_and_aux_mles_all_3_parties
321            .mpc_circuit
322            .get_input_layer_description_ref(MPC_SLOPES_LAYER)
323            .clone();
324
325        let slopes_precommitment_left_eye =
326            Self::generate_secure_shamir_secret_share_slopes_and_commitments(
327                slope_input_layer_description.num_vars,
328                SHAMIR_SECRET_SHARE_SLOPE_LOG_NUM_COLS,
329                &committer,
330                rng,
331            );
332        let slopes_precommitment_right_eye =
333            Self::generate_secure_shamir_secret_share_slopes_and_commitments(
334                slope_input_layer_description.num_vars,
335                SHAMIR_SECRET_SHARE_SLOPE_LOG_NUM_COLS,
336                &committer,
337                rng,
338            );
339
340        Self {
341            committer,
342            converter: VandermondeInverse::new(),
343            slope_commitments: [
344                slopes_precommitment_left_eye,
345                slopes_precommitment_right_eye,
346            ],
347            prover_config,
348            mpc_circuit_and_const_mles_all_3_parties: mpc_circuit_and_aux_mles_all_3_parties,
349            left_eye_proofs_all_3_parties: None,
350            right_eye_proofs_all_3_parties: None,
351        }
352    }
353
354    pub fn get_committer_ref(&self) -> &PedersenCommitter<Bn256Point> {
355        &self.committer
356    }
357
358    #[allow(clippy::too_many_arguments)]
359    pub fn prove_mpc_with_precommits(
360        mut mpc_provable_circuit: HyraxProvableCircuit<Bn256Point>,
361        iris_precommit: &HyraxProverInputCommitment<Bn256Point>,
362        mask_precommit: &HyraxProverInputCommitment<Bn256Point>,
363        slope_precommit: &HyraxProverInputCommitment<Bn256Point>,
364        committer: &PedersenCommitter<Bn256Point>,
365        blinding_rng: &mut (impl CryptoRng + RngCore),
366        converter: &mut VandermondeInverse<Scalar>,
367    ) -> HyraxProof<Bn256Point> {
368        mpc_provable_circuit
369            .set_pre_commitment(MPC_IRISCODE_INPUT_LAYER, iris_precommit.clone(), None)
370            .unwrap();
371        mpc_provable_circuit
372            .set_pre_commitment(MPC_MASKCODE_INPUT_LAYER, mask_precommit.clone(), None)
373            .unwrap();
374        mpc_provable_circuit
375            .set_pre_commitment(
376                MPC_SLOPES_LAYER,
377                slope_precommit.clone(),
378                Some(SHAMIR_SECRET_SHARE_SLOPE_LOG_NUM_COLS),
379            )
380            .unwrap();
381
382        // Create a fresh transcript.
383        let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
384            ECTranscript::new("MPC Circuit Pipeline");
385
386        // Prove the relationship between iris/mask code and image.
387        let (proof, _proof_config) =
388            mpc_provable_circuit.prove(committer, blinding_rng, converter, &mut transcript);
389
390        proof
391    }
392
393    pub fn prove(
394        &mut self,
395        is_left_eye: bool,
396        iris_code_precommit: HyraxProverInputCommitment<Bn256Point>,
397        mask_code_precommit: HyraxProverInputCommitment<Bn256Point>,
398        rng: &mut (impl CryptoRng + RngCore),
399    ) {
400        assert_eq!(
401            iris_code_precommit.blinding_factors_matrix.len(),
402            iris_code_precommit.commitment.len()
403        );
404
405        let iris_code_mle = &iris_code_precommit.mle;
406        let mask_code_mle = &mask_code_precommit.mle;
407        let slope_commitment = &self.slope_commitments[!is_left_eye as usize];
408
409        let encoding_matrix = &self
410            .mpc_circuit_and_const_mles_all_3_parties
411            .encoding_matrix;
412
413        let lookup_table_values =
414            MultilinearExtension::new((0..GR4_MODULUS).map(Fr::from).collect());
415
416        let proofs_all_3_parties: Vec<_> = (0..3)
417            .map(|party_idx| {
418                let mut circuit = self
419                    .mpc_circuit_and_const_mles_all_3_parties
420                    .mpc_circuit
421                    .clone();
422
423                let evaluation_points = &self
424                    .mpc_circuit_and_const_mles_all_3_parties
425                    .evaluation_points[party_idx];
426
427                let input_data = gen_mpc_input_data::<Fr, MPC_NUM_IRIS_4_CHUNKS>(
428                    iris_code_mle,
429                    mask_code_mle,
430                    &slope_commitment.mle,
431                    encoding_matrix,
432                    evaluation_points,
433                );
434                let const_data = MPCCircuitConstData {
435                    encoding_matrix: encoding_matrix.clone(),
436                    evaluation_points: evaluation_points.clone(),
437                    lookup_table_values: lookup_table_values.clone(),
438                };
439
440                mpc_attach_data(&mut circuit, const_data, input_data);
441
442                let provable_circuit = circuit
443                    .gen_hyrax_provable_circuit()
444                    .expect("Failed to finalize circuit");
445
446                Self::prove_mpc_with_precommits(
447                    provable_circuit,
448                    &iris_code_precommit,
449                    &mask_code_precommit,
450                    slope_commitment,
451                    &self.committer,
452                    rng,
453                    &mut self.converter,
454                )
455            })
456            .collect();
457
458        self.set(is_left_eye, proofs_all_3_parties);
459    }
460
461    /// Set the field indicated by `is_mask` and `is_left_eye` to `proof`,
462    /// overwritting any existing value.
463    pub fn set(&mut self, is_left_eye: bool, proofs_all_3_parties: Vec<HyraxProof<Bn256Point>>) {
464        match is_left_eye {
465            false => self.set_right_proof(proofs_all_3_parties),
466            true => self.set_left_proof(proofs_all_3_parties),
467        }
468    }
469
470    /// Set the left image proof to `proof`, overwritting any existing value.
471    pub fn set_left_proof(&mut self, proofs_all_3_parties: Vec<HyraxProof<Bn256Point>>) {
472        self.left_eye_proofs_all_3_parties = Some(proofs_all_3_parties)
473    }
474
475    /// Set the right image proof to `proof`, overwritting any existing value.
476    pub fn set_right_proof(&mut self, proofs_all_3_parties: Vec<HyraxProof<Bn256Point>>) {
477        self.right_eye_proofs_all_3_parties = Some(proofs_all_3_parties)
478    }
479
480    pub fn is_set(&self, is_left_eye: bool) -> bool {
481        match is_left_eye {
482            true => {
483                self.left_eye_proofs_all_3_parties.is_some()
484                    && self.left_eye_proofs_all_3_parties.as_ref().unwrap().len() == 3
485            }
486            false => {
487                self.right_eye_proofs_all_3_parties.is_some()
488                    && self.right_eye_proofs_all_3_parties.as_ref().unwrap().len() == 3
489            }
490        }
491    }
492
493    /// Checks whether `self` is ready to be finalized, i.e. whether all 4
494    /// proofs are present.`
495    fn is_ready_to_finalize(&self) -> bool {
496        self.is_set(true) && self.is_set(false)
497    }
498
499    pub fn finalize(&self) -> Result<MPCProof, MPCProofError> {
500        if self.is_ready_to_finalize() {
501            let proof_config = ProofConfig::new_from_prover_config(&self.prover_config);
502
503            Ok(MPCProof::new(
504                proof_config,
505                self.left_eye_proofs_all_3_parties.as_ref().unwrap().clone(),
506                self.right_eye_proofs_all_3_parties
507                    .as_ref()
508                    .unwrap()
509                    .clone(),
510            ))
511        } else {
512            Err(MPCProofError::EmptyProofField)
513        }
514    }
515}
516
517/// A Wrapper around the `V3Prover` and the `MPCProver`.
518/// Includes the commitments to the iris / mask codes, so that the mpc4
519/// circuits can use the pre-commitments as inputs.
520#[derive(Serialize, Deserialize)]
521pub struct V3MPCProver {
522    /// The prover for the iris circuit.
523    v3_prover: V3Prover,
524
525    /// The prover for the mpc circuit.
526    mpc_prover: MPCProver,
527
528    /// The commitments to the iris / mask codes.
529    left_iris_commit: Option<HyraxProverInputCommitment<Bn256Point>>,
530    left_mask_commit: Option<HyraxProverInputCommitment<Bn256Point>>,
531    right_iris_commit: Option<HyraxProverInputCommitment<Bn256Point>>,
532    right_mask_commit: Option<HyraxProverInputCommitment<Bn256Point>>,
533}
534
535impl V3MPCProver {
536    /// Generate an empty v3-mpc prover with the given configuration.
537    pub fn new(
538        prover_config: GKRCircuitProverConfig,
539        iris_circuit: V3CircuitAndAuxData<Fr>,
540        mpc_circuits: MPCCircuitsAndConstData<Fr>,
541        rng: &mut (impl CryptoRng + RngCore),
542    ) -> Self {
543        Self {
544            v3_prover: V3Prover::new(prover_config.clone(), iris_circuit),
545            mpc_prover: MPCProver::new(prover_config, mpc_circuits, rng),
546
547            left_iris_commit: None,
548            left_mask_commit: None,
549            right_iris_commit: None,
550            right_mask_commit: None,
551        }
552    }
553
554    pub fn prove_v3(
555        &mut self,
556        is_mask: bool,
557        is_left_eye: bool,
558        image_bytes: Vec<u8>,
559        image_precommit: HyraxProverInputCommitment<Bn256Point>,
560        rng: &mut (impl CryptoRng + RngCore),
561    ) {
562        let code_commitment =
563            self.v3_prover
564                .prove(is_mask, is_left_eye, image_bytes, image_precommit, rng);
565
566        self.set_commit(is_mask, is_left_eye, code_commitment);
567
568        // TODO: Refactor into the new builder design:
569        // Remove the public `auxiliary_input_layer` from the proofs, as these are already
570        // incorporated in the `CircuitAndAuxMles` as `iris_aux_mle` and `mask_aux_mle`.
571        // self.remove_v3_auxiliary_input_layer(is_mask, is_left_eye);
572    }
573
574    pub fn prove_mpc(&mut self, is_left_eye: bool, rng: &mut (impl CryptoRng + RngCore)) {
575        let iris_code_commitment = self.get_commit(false, is_left_eye).clone();
576        let mask_code_commitment = self.get_commit(true, is_left_eye).clone();
577
578        self.mpc_prover
579            .prove(is_left_eye, iris_code_commitment, mask_code_commitment, rng);
580
581        // TODO: Refactor into the new builder design:
582        // Remove the invariant public `auxiliary_input_layer` from the proofs, as these are already
583        // incorporated in the `MPCCircuitAndAuxMles` as `aux_mle`.
584        // self.remove_mpc_auxiliary_input_layer(is_left_eye);
585    }
586
587    pub fn finalize(&self) -> Result<V3MPCProof, V3MPCProofError> {
588        let v3_proof = self.v3_prover.finalize()?;
589        let mpc_proof = self.mpc_prover.finalize()?;
590        let commitments = V3MPCCommitments::new(
591            self.get_commit_left_iris().commitment.clone(),
592            self.get_commit_left_mask().commitment.clone(),
593            self.get_commit_right_iris().commitment.clone(),
594            self.get_commit_right_mask().commitment.clone(),
595            self.mpc_prover.slope_commitments[0].commitment.clone(),
596            self.mpc_prover.slope_commitments[1].commitment.clone(),
597        );
598
599        Ok(V3MPCProof {
600            commitments,
601            v3_proof,
602            mpc_proof,
603        })
604    }
605
606    /// Set the field indicated by `is_mask` and `is_left_eye` to `proof`,
607    /// overwritting any existing value.
608    pub fn set_commit(
609        &mut self,
610        is_mask: bool,
611        is_left_eye: bool,
612        commitment: HyraxProverInputCommitment<Bn256Point>,
613    ) {
614        match (is_mask, is_left_eye) {
615            (false, false) => self.set_commit_right_iris(commitment),
616            (false, true) => self.set_commit_left_iris(commitment),
617            (true, false) => self.set_commit_right_mask(commitment),
618            (true, true) => self.set_commit_left_mask(commitment),
619        }
620    }
621
622    /// Set the left image commitment to `commitment`, overwritting any existing value.
623    pub fn set_commit_left_iris(&mut self, commitment: HyraxProverInputCommitment<Bn256Point>) {
624        self.left_iris_commit = Some(commitment)
625    }
626
627    /// Set the left mask commitment to `commitment`, overwritting any existing value.
628    pub fn set_commit_left_mask(&mut self, commitment: HyraxProverInputCommitment<Bn256Point>) {
629        self.left_mask_commit = Some(commitment)
630    }
631
632    /// Set the right image commitment to `commitment`, overwritting any existing value.
633    pub fn set_commit_right_iris(&mut self, commitment: HyraxProverInputCommitment<Bn256Point>) {
634        self.right_iris_commit = Some(commitment)
635    }
636
637    /// Set the right mask commitment to `commitment`, overwritting any existing value.
638    pub fn set_commit_right_mask(&mut self, commitment: HyraxProverInputCommitment<Bn256Point>) {
639        self.right_mask_commit = Some(commitment)
640    }
641
642    /// Set the field indicated by `is_mask` and `is_left_eye` to `proof`,
643    /// overwritting any existing value.
644    pub fn get_commit(
645        &mut self,
646        is_mask: bool,
647        is_left_eye: bool,
648    ) -> &HyraxProverInputCommitment<Bn256Point> {
649        match (is_mask, is_left_eye) {
650            (false, false) => self.get_commit_right_iris(),
651            (false, true) => self.get_commit_left_iris(),
652            (true, false) => self.get_commit_right_mask(),
653            (true, true) => self.get_commit_left_mask(),
654        }
655    }
656
657    /// Set the left image commitment to `commitment`, overwritting any existing value.
658    pub fn get_commit_left_iris(&self) -> &HyraxProverInputCommitment<Bn256Point> {
659        self.left_iris_commit.as_ref().unwrap()
660    }
661
662    /// Set the left mask commitment to `commitment`, overwritting any existing value.
663    pub fn get_commit_left_mask(&self) -> &HyraxProverInputCommitment<Bn256Point> {
664        self.left_mask_commit.as_ref().unwrap()
665    }
666
667    /// Set the right image commitment to `commitment`, overwritting any existing value.
668    pub fn get_commit_right_iris(&self) -> &HyraxProverInputCommitment<Bn256Point> {
669        self.right_iris_commit.as_ref().unwrap()
670    }
671
672    /// Set the right mask commitment to `commitment`, overwritting any existing value.
673    pub fn get_commit_right_mask(&self) -> &HyraxProverInputCommitment<Bn256Point> {
674        self.right_mask_commit.as_ref().unwrap()
675    }
676
677    pub fn serialize(&self) -> Vec<u8> {
678        bincode::serialize(self).expect("Failed to serialize V3MPCProver")
679    }
680
681    pub fn deserialize(bytes: &[u8]) -> Self {
682        bincode::deserialize(bytes).expect("Failed to deserialize V3MPCProver")
683    }
684}
685
686#[derive(Clone, Debug, Serialize, Deserialize)]
687pub struct MPCPartyProof {
688    #[serde(skip)]
689    #[serde(default = "V3Prover::default_committer")]
690    committer: PedersenCommitter<Bn256Point>,
691
692    proof_config: ProofConfig,
693    left_eye_proof: HyraxProof<Bn256Point>,
694    right_eye_proof: HyraxProof<Bn256Point>,
695}
696
697impl MPCPartyProof {
698    pub fn new(
699        proof_config: ProofConfig,
700        left_eye_proof: HyraxProof<Bn256Point>,
701        right_eye_proof: HyraxProof<Bn256Point>,
702    ) -> Self {
703        Self {
704            committer: V3Prover::default_committer(),
705            proof_config,
706            left_eye_proof,
707            right_eye_proof,
708        }
709    }
710
711    #[cfg(feature = "print-trace")]
712    pub fn print_size(&self) {
713        println!("Left eye proof stats:");
714        self.left_eye_proof.print_size();
715
716        println!("Right eye proof stats:");
717        self.right_eye_proof.print_size();
718    }
719
720    pub fn insert_aux_public_data_by_id(
721        &mut self,
722        is_left_eye: bool,
723        aux_mle: &MultilinearExtension<Fr>,
724        id_to_insert: LayerId,
725    ) {
726        if is_left_eye {
727            self.left_eye_proof
728                .insert_aux_public_data_by_id(aux_mle, id_to_insert);
729        } else {
730            self.right_eye_proof
731                .insert_aux_public_data_by_id(aux_mle, id_to_insert);
732        }
733    }
734
735    pub fn verify_mpc_proof(
736        &self,
737        is_left_eye: bool,
738        mpc_circuit: &HyraxVerifiableCircuit<Bn256Point>,
739        secret_share_mle_layer_id: LayerId,
740    ) -> Result<MultilinearExtension<Fr>, MPCError> {
741        // Create a fresh transcript.
742        let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
743            ECTranscript::new("V3 Iriscode Circuit Pipeline");
744
745        let proof = if is_left_eye {
746            &self.left_eye_proof
747        } else {
748            &self.right_eye_proof
749        };
750
751        // Verify the relationship between iris/mask code and image.
752        verify_hyrax_proof(
753            proof,
754            mpc_circuit,
755            &self.committer,
756            &mut transcript,
757            &self.proof_config,
758        );
759
760        // Here we need to grab the actual secret share MLE and return it.
761        let secret_share_mle_should_be_singleton = proof
762            .public_inputs
763            .iter()
764            .filter(|(input_layer_id, _)| *input_layer_id == secret_share_mle_layer_id)
765            .collect_vec();
766        if secret_share_mle_should_be_singleton.len() != 1 {
767            Err(MPCError::NoSharesInputLayerMle)
768        } else {
769            Ok(secret_share_mle_should_be_singleton[0].clone().1.unwrap())
770        }
771    }
772
773    pub fn get_proof_config_ref(&self) -> &ProofConfig {
774        &self.proof_config
775    }
776
777    pub fn get_left_eye_proof_ref(&self) -> &HyraxProof<Bn256Point> {
778        &self.left_eye_proof
779    }
780
781    pub fn get_right_eye_proof_ref(&self) -> &HyraxProof<Bn256Point> {
782        &self.right_eye_proof
783    }
784
785    pub fn serialize(&self) -> Vec<u8> {
786        bincode::serialize(self).unwrap()
787    }
788
789    pub fn deserialize(serialized_proof: &[u8]) -> Self {
790        bincode::deserialize(serialized_proof).unwrap()
791    }
792}
793
794#[derive(Clone, Debug, Serialize, Deserialize)]
795pub struct MPCProof {
796    party_proofs: [MPCPartyProof; 3],
797}
798
799impl MPCProof {
800    pub fn new(
801        proof_config: ProofConfig,
802        mut left_eye_proofs_all_3_parties: Vec<HyraxProof<Bn256Point>>,
803        mut right_eye_proofs_all_3_parties: Vec<HyraxProof<Bn256Point>>,
804    ) -> Self {
805        assert_eq!(left_eye_proofs_all_3_parties.len(), 3);
806        assert_eq!(right_eye_proofs_all_3_parties.len(), 3);
807
808        let party_2_proof = MPCPartyProof::new(
809            proof_config,
810            left_eye_proofs_all_3_parties.pop().unwrap(),
811            right_eye_proofs_all_3_parties.pop().unwrap(),
812        );
813        let party_1_proof = MPCPartyProof::new(
814            proof_config,
815            left_eye_proofs_all_3_parties.pop().unwrap(),
816            right_eye_proofs_all_3_parties.pop().unwrap(),
817        );
818        let party_0_proof = MPCPartyProof::new(
819            proof_config,
820            left_eye_proofs_all_3_parties.pop().unwrap(),
821            right_eye_proofs_all_3_parties.pop().unwrap(),
822        );
823
824        Self {
825            party_proofs: [party_0_proof, party_1_proof, party_2_proof],
826        }
827    }
828
829    pub fn get_party_proof_ref(&self, party_idx: usize) -> &MPCPartyProof {
830        assert!(party_idx < 3);
831        &self.party_proofs[party_idx]
832    }
833
834    /// Get the mpc proofs for all 3 parties indicated by `is_left_eye`.
835    pub fn get(&self, is_left_eye: bool) -> Vec<&HyraxProof<Bn256Point>> {
836        match is_left_eye {
837            true => self.get_left_proof_refs(),
838            false => self.get_right_proof_refs(),
839        }
840    }
841
842    /// Return a reference to the proofs to the party_idx.
843    pub fn get_proof_refs_for_party(
844        &self,
845        party_idx: usize,
846    ) -> (&HyraxProof<Bn256Point>, &HyraxProof<Bn256Point>) {
847        assert!(party_idx < 3);
848        (
849            self.party_proofs[party_idx].get_left_eye_proof_ref(),
850            self.party_proofs[party_idx].get_right_eye_proof_ref(),
851        )
852    }
853
854    /// Return a reference to the proofs to the left eye.
855    pub fn get_left_proof_refs(&self) -> Vec<&HyraxProof<Bn256Point>> {
856        vec![
857            self.party_proofs[0].get_left_eye_proof_ref(),
858            self.party_proofs[1].get_left_eye_proof_ref(),
859            self.party_proofs[2].get_left_eye_proof_ref(),
860        ]
861    }
862
863    /// Return a reference to the proofs to the right eye.
864    pub fn get_right_proof_refs(&self) -> Vec<&HyraxProof<Bn256Point>> {
865        vec![
866            self.party_proofs[0].get_right_eye_proof_ref(),
867            self.party_proofs[1].get_right_eye_proof_ref(),
868            self.party_proofs[2].get_right_eye_proof_ref(),
869        ]
870    }
871
872    /// Serializes `self` into a binary representation.
873    pub fn serialize(&self) -> Vec<u8> {
874        bincode::serialize(self).unwrap()
875    }
876
877    /// Deserializes `serialized_proof` and returns it.
878    pub fn deserialize(serialized_proof: &[u8]) -> Self {
879        bincode::deserialize(serialized_proof).unwrap()
880    }
881}
882
883#[derive(Clone, Debug, Serialize, Deserialize)]
884pub struct V3MPCProof {
885    commitments: V3MPCCommitments<Bn256Point>,
886    v3_proof: V3Proof,
887    mpc_proof: MPCProof,
888}
889
890impl V3MPCProof {
891    pub fn get_commitments_ref(&self) -> &V3MPCCommitments<Bn256Point> {
892        &self.commitments
893    }
894
895    pub fn get_v3_proof_ref(&self) -> &V3Proof {
896        &self.v3_proof
897    }
898
899    pub fn get_party_proof_ref(&self, party_idx: usize) -> &MPCPartyProof {
900        self.mpc_proof.get_party_proof_ref(party_idx)
901    }
902
903    /// Serializes `self` into a binary representation.
904    pub fn serialize(&self) -> Vec<u8> {
905        bincode::serialize(self).unwrap()
906    }
907
908    /// Deserializes `serialized_proof` and returns it.
909    pub fn deserialize(serialized_proof: &[u8]) -> Self {
910        bincode::deserialize(serialized_proof).unwrap()
911    }
912}
913
914#[derive(Clone, Debug, Serialize, Deserialize)]
915#[serde(bound = "F: Field")]
916pub struct V3MPCCircuitAndAuxMles<F: Field> {
917    pub v3_circuit_and_aux_data: V3CircuitAndAuxData<F>,
918    pub mpc_circuit_and_aux_mles_all_3_parties: MPCCircuitsAndConstData<F>,
919}
920
921impl<F: Field> V3MPCCircuitAndAuxMles<F> {
922    pub fn serialize(&self) -> Vec<u8> {
923        bincode::serialize(&self).expect("Failed to serialize CircuitAndAuxMles")
924    }
925
926    pub fn deserialize(bytes: &[u8]) -> Self {
927        bincode::deserialize(bytes).expect("Failed to deserialize CircuitAndAuxMles")
928    }
929}
930
931// Generate the circuit description and input builder used to generate the auxiliary MLEs.
932pub fn generate_mpc_circuit_and_aux_mles_all_3_parties<F: Field>() -> MPCCircuitsAndConstData<F> {
933    let mpc_circuit = build_circuit::<F, MPC_NUM_IRIS_4_CHUNKS>(LayerVisibility::Committed);
934
935    MPCCircuitsAndConstData {
936        mpc_circuit,
937        encoding_matrix: gen_mpc_encoding_matrix::<F, MPC_NUM_IRIS_4_CHUNKS>(),
938        evaluation_points: [
939            gen_mpc_evaluation_points::<F, MPC_NUM_IRIS_4_CHUNKS, 0>(),
940            gen_mpc_evaluation_points::<F, MPC_NUM_IRIS_4_CHUNKS, 1>(),
941            gen_mpc_evaluation_points::<F, MPC_NUM_IRIS_4_CHUNKS, 2>(),
942        ],
943    }
944}