Skip to main content

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    pub lookup_table_values_2_19: MultilinearExtension<F>,
235}
236
237// TODO: Add similar API to V3CircuitAndAuxData/ConstData.
238#[derive(Clone, Debug, Serialize, Deserialize)]
239#[serde(bound = "F: Field")]
240pub struct MPCCircuitsAndConstData<F: Field> {
241    pub mpc_circuit: Circuit<F>,
242    pub encoding_matrix: MultilinearExtension<F>,
243    pub evaluation_points: [MultilinearExtension<F>; 3],
244}
245
246#[derive(Serialize, Deserialize)]
247pub struct MPCProver {
248    #[serde(skip)]
249    #[serde(default = "MPCProver::default_committer")]
250    committer: PedersenCommitter<Bn256Point>,
251
252    #[serde(skip)]
253    #[serde(default = "VandermondeInverse::new")]
254    converter: VandermondeInverse<Scalar>,
255
256    slope_commitments: [HyraxProverInputCommitment<Bn256Point>; 2],
257
258    prover_config: GKRCircuitProverConfig,
259    mpc_circuit_and_const_mles_all_3_parties: MPCCircuitsAndConstData<Fr>,
260
261    left_eye_proofs_all_3_parties: Option<Vec<HyraxProof<Bn256Point>>>,
262    right_eye_proofs_all_3_parties: Option<Vec<HyraxProof<Bn256Point>>>,
263}
264
265impl MPCProver {
266    /// Computes a set of random Shamir secret share slopes and creates a Hyrax
267    /// commitment for them.
268    ///
269    /// Note that `rng` should be a CSPRNG seeded with a strong source of
270    /// device entropy! Recommended to call this with `OsRng` and `ChaCha20Rng`.
271    fn generate_secure_shamir_secret_share_slopes_and_commitments<C: PrimeOrderCurve>(
272        num_vars: usize,
273        log_num_cols: usize,
274        pedersen_committer: &PedersenCommitter<C>,
275        rng: &mut impl Rng,
276    ) -> HyraxProverInputCommitment<C> {
277        // The slopes must be in the range [0, 2^{16} - 1]
278        let slopes_mle = MultilinearExtension::new(
279            (0..IRISCODE_LEN)
280                .map(|_idx| C::Scalar::from(rng.gen_range(0..GR4_MODULUS)))
281                .collect_vec(),
282        );
283
284        commit_to_input_values(num_vars, log_num_cols, &slopes_mle, pedersen_committer, rng)
285    }
286
287    pub fn default_committer() -> PedersenCommitter<Bn256Point> {
288        PedersenCommitter::new(1024, PUBLIC_STRING, None)
289    }
290
291    pub fn new(
292        prover_config: GKRCircuitProverConfig,
293        mpc_circuit_and_aux_mles_all_3_parties: MPCCircuitsAndConstData<Fr>,
294        rng: &mut (impl CryptoRng + RngCore),
295    ) -> Self {
296        // Verify `circuit` contains the necessary input layers, which do _not_ contain any data
297        // yet.
298        // TODO: Provide methods in the `Circuit` struct that can check whether
299        // 1. All input MLEs are empty, and
300        // 2. The circuit contains input layers with labels corresponding exactly to a given list of
301        // labels.
302        // Having those we can replace the below tests with two such method calls.
303        let circuit = &mpc_circuit_and_aux_mles_all_3_parties.mpc_circuit;
304        assert!(!circuit
305            .input_layer_contains_data(MPC_AUXILIARY_LAYER)
306            .unwrap());
307        assert!(!circuit
308            .input_layer_contains_data(MPC_AUXILIARY_INVARIANT_LAYER)
309            .unwrap());
310        assert!(!circuit.input_layer_contains_data(MPC_SHARES_LAYER).unwrap());
311        assert!(!circuit.input_layer_contains_data(MPC_SLOPES_LAYER).unwrap());
312        assert!(!circuit
313            .input_layer_contains_data(MPC_IRISCODE_INPUT_LAYER)
314            .unwrap());
315        assert!(!circuit
316            .input_layer_contains_data(MPC_MASKCODE_INPUT_LAYER)
317            .unwrap());
318
319        let committer = Self::default_committer();
320
321        let slope_input_layer_description = &mpc_circuit_and_aux_mles_all_3_parties
322            .mpc_circuit
323            .get_input_layer_description_ref(MPC_SLOPES_LAYER)
324            .clone();
325
326        let slopes_precommitment_left_eye =
327            Self::generate_secure_shamir_secret_share_slopes_and_commitments(
328                slope_input_layer_description.num_vars,
329                SHAMIR_SECRET_SHARE_SLOPE_LOG_NUM_COLS,
330                &committer,
331                rng,
332            );
333        let slopes_precommitment_right_eye =
334            Self::generate_secure_shamir_secret_share_slopes_and_commitments(
335                slope_input_layer_description.num_vars,
336                SHAMIR_SECRET_SHARE_SLOPE_LOG_NUM_COLS,
337                &committer,
338                rng,
339            );
340
341        Self {
342            committer,
343            converter: VandermondeInverse::new(),
344            slope_commitments: [
345                slopes_precommitment_left_eye,
346                slopes_precommitment_right_eye,
347            ],
348            prover_config,
349            mpc_circuit_and_const_mles_all_3_parties: mpc_circuit_and_aux_mles_all_3_parties,
350            left_eye_proofs_all_3_parties: None,
351            right_eye_proofs_all_3_parties: None,
352        }
353    }
354
355    pub fn get_committer_ref(&self) -> &PedersenCommitter<Bn256Point> {
356        &self.committer
357    }
358
359    #[allow(clippy::too_many_arguments)]
360    pub fn prove_mpc_with_precommits(
361        mut mpc_provable_circuit: HyraxProvableCircuit<Bn256Point>,
362        iris_precommit: &HyraxProverInputCommitment<Bn256Point>,
363        mask_precommit: &HyraxProverInputCommitment<Bn256Point>,
364        slope_precommit: &HyraxProverInputCommitment<Bn256Point>,
365        committer: &PedersenCommitter<Bn256Point>,
366        blinding_rng: &mut (impl CryptoRng + RngCore),
367        converter: &mut VandermondeInverse<Scalar>,
368    ) -> HyraxProof<Bn256Point> {
369        mpc_provable_circuit
370            .set_pre_commitment(MPC_IRISCODE_INPUT_LAYER, iris_precommit.clone(), None)
371            .unwrap();
372        mpc_provable_circuit
373            .set_pre_commitment(MPC_MASKCODE_INPUT_LAYER, mask_precommit.clone(), None)
374            .unwrap();
375        mpc_provable_circuit
376            .set_pre_commitment(
377                MPC_SLOPES_LAYER,
378                slope_precommit.clone(),
379                Some(SHAMIR_SECRET_SHARE_SLOPE_LOG_NUM_COLS),
380            )
381            .unwrap();
382
383        // Create a fresh transcript.
384        let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
385            ECTranscript::new("MPC Circuit Pipeline");
386
387        // Prove the relationship between iris/mask code and image.
388        let (proof, _proof_config) =
389            mpc_provable_circuit.prove(committer, blinding_rng, converter, &mut transcript);
390
391        proof
392    }
393
394    pub fn prove(
395        &mut self,
396        is_left_eye: bool,
397        iris_code_precommit: HyraxProverInputCommitment<Bn256Point>,
398        mask_code_precommit: HyraxProverInputCommitment<Bn256Point>,
399        rng: &mut (impl CryptoRng + RngCore),
400    ) {
401        assert_eq!(
402            iris_code_precommit.blinding_factors_matrix.len(),
403            iris_code_precommit.commitment.len()
404        );
405
406        let iris_code_mle = &iris_code_precommit.mle;
407        let mask_code_mle = &mask_code_precommit.mle;
408        let slope_commitment = &self.slope_commitments[!is_left_eye as usize];
409
410        let encoding_matrix = &self
411            .mpc_circuit_and_const_mles_all_3_parties
412            .encoding_matrix;
413
414        let lookup_table_values =
415            MultilinearExtension::new((0..GR4_MODULUS).map(Fr::from).collect());
416        let lookup_table_values_2_19 =
417            MultilinearExtension::new((0..(1 << 19)).map(Fr::from).collect());
418
419        let proofs_all_3_parties: Vec<_> = (0..3)
420            .map(|party_idx| {
421                let mut circuit = self
422                    .mpc_circuit_and_const_mles_all_3_parties
423                    .mpc_circuit
424                    .clone();
425
426                let evaluation_points = &self
427                    .mpc_circuit_and_const_mles_all_3_parties
428                    .evaluation_points[party_idx];
429
430                let input_data = gen_mpc_input_data::<Fr, MPC_NUM_IRIS_4_CHUNKS>(
431                    iris_code_mle,
432                    mask_code_mle,
433                    &slope_commitment.mle,
434                    encoding_matrix,
435                    evaluation_points,
436                );
437                let const_data = MPCCircuitConstData {
438                    encoding_matrix: encoding_matrix.clone(),
439                    evaluation_points: evaluation_points.clone(),
440                    lookup_table_values: lookup_table_values.clone(),
441                    lookup_table_values_2_19: lookup_table_values_2_19.clone(),
442                };
443
444                mpc_attach_data(&mut circuit, const_data, input_data);
445
446                let provable_circuit = circuit
447                    .gen_hyrax_provable_circuit()
448                    .expect("Failed to finalize circuit");
449
450                Self::prove_mpc_with_precommits(
451                    provable_circuit,
452                    &iris_code_precommit,
453                    &mask_code_precommit,
454                    slope_commitment,
455                    &self.committer,
456                    rng,
457                    &mut self.converter,
458                )
459            })
460            .collect();
461
462        self.set(is_left_eye, proofs_all_3_parties);
463    }
464
465    /// Set the field indicated by `is_mask` and `is_left_eye` to `proof`,
466    /// overwritting any existing value.
467    pub fn set(&mut self, is_left_eye: bool, proofs_all_3_parties: Vec<HyraxProof<Bn256Point>>) {
468        match is_left_eye {
469            false => self.set_right_proof(proofs_all_3_parties),
470            true => self.set_left_proof(proofs_all_3_parties),
471        }
472    }
473
474    /// Set the left image proof to `proof`, overwritting any existing value.
475    pub fn set_left_proof(&mut self, proofs_all_3_parties: Vec<HyraxProof<Bn256Point>>) {
476        self.left_eye_proofs_all_3_parties = Some(proofs_all_3_parties)
477    }
478
479    /// Set the right image proof to `proof`, overwritting any existing value.
480    pub fn set_right_proof(&mut self, proofs_all_3_parties: Vec<HyraxProof<Bn256Point>>) {
481        self.right_eye_proofs_all_3_parties = Some(proofs_all_3_parties)
482    }
483
484    pub fn is_set(&self, is_left_eye: bool) -> bool {
485        match is_left_eye {
486            true => {
487                self.left_eye_proofs_all_3_parties.is_some()
488                    && self.left_eye_proofs_all_3_parties.as_ref().unwrap().len() == 3
489            }
490            false => {
491                self.right_eye_proofs_all_3_parties.is_some()
492                    && self.right_eye_proofs_all_3_parties.as_ref().unwrap().len() == 3
493            }
494        }
495    }
496
497    /// Checks whether `self` is ready to be finalized, i.e. whether all 4
498    /// proofs are present.`
499    fn is_ready_to_finalize(&self) -> bool {
500        self.is_set(true) && self.is_set(false)
501    }
502
503    pub fn finalize(&self) -> Result<MPCProof, MPCProofError> {
504        if self.is_ready_to_finalize() {
505            let proof_config = ProofConfig::new_from_prover_config(&self.prover_config);
506
507            Ok(MPCProof::new(
508                proof_config,
509                self.left_eye_proofs_all_3_parties.as_ref().unwrap().clone(),
510                self.right_eye_proofs_all_3_parties
511                    .as_ref()
512                    .unwrap()
513                    .clone(),
514            ))
515        } else {
516            Err(MPCProofError::EmptyProofField)
517        }
518    }
519}
520
521/// A Wrapper around the `V3Prover` and the `MPCProver`.
522/// Includes the commitments to the iris / mask codes, so that the mpc4
523/// circuits can use the pre-commitments as inputs.
524#[derive(Serialize, Deserialize)]
525pub struct V3MPCProver {
526    /// The prover for the iris circuit.
527    v3_prover: V3Prover,
528
529    /// The prover for the mpc circuit.
530    mpc_prover: MPCProver,
531
532    /// The commitments to the iris / mask codes.
533    left_iris_commit: Option<HyraxProverInputCommitment<Bn256Point>>,
534    left_mask_commit: Option<HyraxProverInputCommitment<Bn256Point>>,
535    right_iris_commit: Option<HyraxProverInputCommitment<Bn256Point>>,
536    right_mask_commit: Option<HyraxProverInputCommitment<Bn256Point>>,
537}
538
539impl V3MPCProver {
540    /// Generate an empty v3-mpc prover with the given configuration.
541    pub fn new(
542        prover_config: GKRCircuitProverConfig,
543        iris_circuit: V3CircuitAndAuxData<Fr>,
544        mpc_circuits: MPCCircuitsAndConstData<Fr>,
545        rng: &mut (impl CryptoRng + RngCore),
546    ) -> Self {
547        Self {
548            v3_prover: V3Prover::new(prover_config.clone(), iris_circuit),
549            mpc_prover: MPCProver::new(prover_config, mpc_circuits, rng),
550
551            left_iris_commit: None,
552            left_mask_commit: None,
553            right_iris_commit: None,
554            right_mask_commit: None,
555        }
556    }
557
558    pub fn prove_v3(
559        &mut self,
560        is_mask: bool,
561        is_left_eye: bool,
562        image_bytes: Vec<u8>,
563        image_precommit: HyraxProverInputCommitment<Bn256Point>,
564        rng: &mut (impl CryptoRng + RngCore),
565    ) {
566        let code_commitment =
567            self.v3_prover
568                .prove(is_mask, is_left_eye, image_bytes, image_precommit, rng);
569
570        self.set_commit(is_mask, is_left_eye, code_commitment);
571
572        // TODO: Refactor into the new builder design:
573        // Remove the public `auxiliary_input_layer` from the proofs, as these are already
574        // incorporated in the `CircuitAndAuxMles` as `iris_aux_mle` and `mask_aux_mle`.
575        // self.remove_v3_auxiliary_input_layer(is_mask, is_left_eye);
576    }
577
578    pub fn prove_mpc(&mut self, is_left_eye: bool, rng: &mut (impl CryptoRng + RngCore)) {
579        let iris_code_commitment = self.get_commit(false, is_left_eye).clone();
580        let mask_code_commitment = self.get_commit(true, is_left_eye).clone();
581
582        self.mpc_prover
583            .prove(is_left_eye, iris_code_commitment, mask_code_commitment, rng);
584
585        // TODO: Refactor into the new builder design:
586        // Remove the invariant public `auxiliary_input_layer` from the proofs, as these are already
587        // incorporated in the `MPCCircuitAndAuxMles` as `aux_mle`.
588        // self.remove_mpc_auxiliary_input_layer(is_left_eye);
589    }
590
591    pub fn finalize(&self) -> Result<V3MPCProof, V3MPCProofError> {
592        let v3_proof = self.v3_prover.finalize()?;
593        let mpc_proof = self.mpc_prover.finalize()?;
594        let commitments = V3MPCCommitments::new(
595            self.get_commit_left_iris().commitment.clone(),
596            self.get_commit_left_mask().commitment.clone(),
597            self.get_commit_right_iris().commitment.clone(),
598            self.get_commit_right_mask().commitment.clone(),
599            self.mpc_prover.slope_commitments[0].commitment.clone(),
600            self.mpc_prover.slope_commitments[1].commitment.clone(),
601        );
602
603        Ok(V3MPCProof {
604            commitments,
605            v3_proof,
606            mpc_proof,
607        })
608    }
609
610    /// Set the field indicated by `is_mask` and `is_left_eye` to `proof`,
611    /// overwritting any existing value.
612    pub fn set_commit(
613        &mut self,
614        is_mask: bool,
615        is_left_eye: bool,
616        commitment: HyraxProverInputCommitment<Bn256Point>,
617    ) {
618        match (is_mask, is_left_eye) {
619            (false, false) => self.set_commit_right_iris(commitment),
620            (false, true) => self.set_commit_left_iris(commitment),
621            (true, false) => self.set_commit_right_mask(commitment),
622            (true, true) => self.set_commit_left_mask(commitment),
623        }
624    }
625
626    /// Set the left image commitment to `commitment`, overwritting any existing value.
627    pub fn set_commit_left_iris(&mut self, commitment: HyraxProverInputCommitment<Bn256Point>) {
628        self.left_iris_commit = Some(commitment)
629    }
630
631    /// Set the left mask commitment to `commitment`, overwritting any existing value.
632    pub fn set_commit_left_mask(&mut self, commitment: HyraxProverInputCommitment<Bn256Point>) {
633        self.left_mask_commit = Some(commitment)
634    }
635
636    /// Set the right image commitment to `commitment`, overwritting any existing value.
637    pub fn set_commit_right_iris(&mut self, commitment: HyraxProverInputCommitment<Bn256Point>) {
638        self.right_iris_commit = Some(commitment)
639    }
640
641    /// Set the right mask commitment to `commitment`, overwritting any existing value.
642    pub fn set_commit_right_mask(&mut self, commitment: HyraxProverInputCommitment<Bn256Point>) {
643        self.right_mask_commit = Some(commitment)
644    }
645
646    /// Set the field indicated by `is_mask` and `is_left_eye` to `proof`,
647    /// overwritting any existing value.
648    pub fn get_commit(
649        &mut self,
650        is_mask: bool,
651        is_left_eye: bool,
652    ) -> &HyraxProverInputCommitment<Bn256Point> {
653        match (is_mask, is_left_eye) {
654            (false, false) => self.get_commit_right_iris(),
655            (false, true) => self.get_commit_left_iris(),
656            (true, false) => self.get_commit_right_mask(),
657            (true, true) => self.get_commit_left_mask(),
658        }
659    }
660
661    /// Set the left image commitment to `commitment`, overwritting any existing value.
662    pub fn get_commit_left_iris(&self) -> &HyraxProverInputCommitment<Bn256Point> {
663        self.left_iris_commit.as_ref().unwrap()
664    }
665
666    /// Set the left mask commitment to `commitment`, overwritting any existing value.
667    pub fn get_commit_left_mask(&self) -> &HyraxProverInputCommitment<Bn256Point> {
668        self.left_mask_commit.as_ref().unwrap()
669    }
670
671    /// Set the right image commitment to `commitment`, overwritting any existing value.
672    pub fn get_commit_right_iris(&self) -> &HyraxProverInputCommitment<Bn256Point> {
673        self.right_iris_commit.as_ref().unwrap()
674    }
675
676    /// Set the right mask commitment to `commitment`, overwritting any existing value.
677    pub fn get_commit_right_mask(&self) -> &HyraxProverInputCommitment<Bn256Point> {
678        self.right_mask_commit.as_ref().unwrap()
679    }
680
681    pub fn serialize(&self) -> Vec<u8> {
682        bincode::serialize(self).expect("Failed to serialize V3MPCProver")
683    }
684
685    pub fn deserialize(bytes: &[u8]) -> Self {
686        bincode::deserialize(bytes).expect("Failed to deserialize V3MPCProver")
687    }
688}
689
690#[derive(Clone, Debug, Serialize, Deserialize)]
691pub struct MPCPartyProof {
692    #[serde(skip)]
693    #[serde(default = "MPCProver::default_committer")]
694    committer: PedersenCommitter<Bn256Point>,
695
696    proof_config: ProofConfig,
697    left_eye_proof: HyraxProof<Bn256Point>,
698    right_eye_proof: HyraxProof<Bn256Point>,
699}
700
701impl MPCPartyProof {
702    pub fn new(
703        proof_config: ProofConfig,
704        left_eye_proof: HyraxProof<Bn256Point>,
705        right_eye_proof: HyraxProof<Bn256Point>,
706    ) -> Self {
707        Self {
708            committer: MPCProver::default_committer(),
709            proof_config,
710            left_eye_proof,
711            right_eye_proof,
712        }
713    }
714
715    #[cfg(feature = "print-trace")]
716    pub fn print_size(&self) {
717        println!("Left eye proof stats:");
718        self.left_eye_proof.print_size();
719
720        println!("Right eye proof stats:");
721        self.right_eye_proof.print_size();
722    }
723
724    pub fn insert_aux_public_data_by_id(
725        &mut self,
726        is_left_eye: bool,
727        aux_mle: &MultilinearExtension<Fr>,
728        id_to_insert: LayerId,
729    ) {
730        if is_left_eye {
731            self.left_eye_proof
732                .insert_aux_public_data_by_id(aux_mle, id_to_insert);
733        } else {
734            self.right_eye_proof
735                .insert_aux_public_data_by_id(aux_mle, id_to_insert);
736        }
737    }
738
739    pub fn verify_mpc_proof(
740        &self,
741        is_left_eye: bool,
742        mpc_circuit: &HyraxVerifiableCircuit<Bn256Point>,
743        secret_share_mle_layer_id: LayerId,
744    ) -> Result<MultilinearExtension<Fr>, MPCError> {
745        // Create a fresh transcript.
746        let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
747            ECTranscript::new("V3 Iriscode Circuit Pipeline");
748
749        let proof = if is_left_eye {
750            &self.left_eye_proof
751        } else {
752            &self.right_eye_proof
753        };
754
755        // Verify the relationship between iris/mask code and image.
756        verify_hyrax_proof(
757            proof,
758            mpc_circuit,
759            &self.committer,
760            &mut transcript,
761            &self.proof_config,
762        );
763
764        // Here we need to grab the actual secret share MLE and return it.
765        let secret_share_mle_should_be_singleton = proof
766            .public_inputs
767            .iter()
768            .filter(|(input_layer_id, _)| *input_layer_id == secret_share_mle_layer_id)
769            .collect_vec();
770        if secret_share_mle_should_be_singleton.len() != 1 {
771            Err(MPCError::NoSharesInputLayerMle)
772        } else {
773            Ok(secret_share_mle_should_be_singleton[0].clone().1.unwrap())
774        }
775    }
776
777    pub fn get_proof_config_ref(&self) -> &ProofConfig {
778        &self.proof_config
779    }
780
781    pub fn get_left_eye_proof_ref(&self) -> &HyraxProof<Bn256Point> {
782        &self.left_eye_proof
783    }
784
785    pub fn get_right_eye_proof_ref(&self) -> &HyraxProof<Bn256Point> {
786        &self.right_eye_proof
787    }
788
789    pub fn serialize(&self) -> Vec<u8> {
790        bincode::serialize(self).unwrap()
791    }
792
793    pub fn deserialize(serialized_proof: &[u8]) -> Self {
794        bincode::deserialize(serialized_proof).unwrap()
795    }
796}
797
798#[derive(Clone, Debug, Serialize, Deserialize)]
799pub struct MPCProof {
800    party_proofs: [MPCPartyProof; 3],
801}
802
803impl MPCProof {
804    pub fn new(
805        proof_config: ProofConfig,
806        mut left_eye_proofs_all_3_parties: Vec<HyraxProof<Bn256Point>>,
807        mut right_eye_proofs_all_3_parties: Vec<HyraxProof<Bn256Point>>,
808    ) -> Self {
809        assert_eq!(left_eye_proofs_all_3_parties.len(), 3);
810        assert_eq!(right_eye_proofs_all_3_parties.len(), 3);
811
812        let party_2_proof = MPCPartyProof::new(
813            proof_config,
814            left_eye_proofs_all_3_parties.pop().unwrap(),
815            right_eye_proofs_all_3_parties.pop().unwrap(),
816        );
817        let party_1_proof = MPCPartyProof::new(
818            proof_config,
819            left_eye_proofs_all_3_parties.pop().unwrap(),
820            right_eye_proofs_all_3_parties.pop().unwrap(),
821        );
822        let party_0_proof = MPCPartyProof::new(
823            proof_config,
824            left_eye_proofs_all_3_parties.pop().unwrap(),
825            right_eye_proofs_all_3_parties.pop().unwrap(),
826        );
827
828        Self {
829            party_proofs: [party_0_proof, party_1_proof, party_2_proof],
830        }
831    }
832
833    pub fn get_party_proof_ref(&self, party_idx: usize) -> &MPCPartyProof {
834        assert!(party_idx < 3);
835        &self.party_proofs[party_idx]
836    }
837
838    /// Get the mpc proofs for all 3 parties indicated by `is_left_eye`.
839    pub fn get(&self, is_left_eye: bool) -> Vec<&HyraxProof<Bn256Point>> {
840        match is_left_eye {
841            true => self.get_left_proof_refs(),
842            false => self.get_right_proof_refs(),
843        }
844    }
845
846    /// Return a reference to the proofs to the party_idx.
847    pub fn get_proof_refs_for_party(
848        &self,
849        party_idx: usize,
850    ) -> (&HyraxProof<Bn256Point>, &HyraxProof<Bn256Point>) {
851        assert!(party_idx < 3);
852        (
853            self.party_proofs[party_idx].get_left_eye_proof_ref(),
854            self.party_proofs[party_idx].get_right_eye_proof_ref(),
855        )
856    }
857
858    /// Return a reference to the proofs to the left eye.
859    pub fn get_left_proof_refs(&self) -> Vec<&HyraxProof<Bn256Point>> {
860        vec![
861            self.party_proofs[0].get_left_eye_proof_ref(),
862            self.party_proofs[1].get_left_eye_proof_ref(),
863            self.party_proofs[2].get_left_eye_proof_ref(),
864        ]
865    }
866
867    /// Return a reference to the proofs to the right eye.
868    pub fn get_right_proof_refs(&self) -> Vec<&HyraxProof<Bn256Point>> {
869        vec![
870            self.party_proofs[0].get_right_eye_proof_ref(),
871            self.party_proofs[1].get_right_eye_proof_ref(),
872            self.party_proofs[2].get_right_eye_proof_ref(),
873        ]
874    }
875
876    /// Serializes `self` into a binary representation.
877    pub fn serialize(&self) -> Vec<u8> {
878        bincode::serialize(self).unwrap()
879    }
880
881    /// Deserializes `serialized_proof` and returns it.
882    pub fn deserialize(serialized_proof: &[u8]) -> Self {
883        bincode::deserialize(serialized_proof).unwrap()
884    }
885}
886
887#[derive(Clone, Debug, Serialize, Deserialize)]
888pub struct V3MPCProof {
889    commitments: V3MPCCommitments<Bn256Point>,
890    v3_proof: V3Proof,
891    mpc_proof: MPCProof,
892}
893
894impl V3MPCProof {
895    pub fn get_commitments_ref(&self) -> &V3MPCCommitments<Bn256Point> {
896        &self.commitments
897    }
898
899    pub fn get_v3_proof_ref(&self) -> &V3Proof {
900        &self.v3_proof
901    }
902
903    pub fn get_party_proof_ref(&self, party_idx: usize) -> &MPCPartyProof {
904        self.mpc_proof.get_party_proof_ref(party_idx)
905    }
906
907    /// Serializes `self` into a binary representation.
908    pub fn serialize(&self) -> Vec<u8> {
909        bincode::serialize(self).unwrap()
910    }
911
912    /// Deserializes `serialized_proof` and returns it.
913    pub fn deserialize(serialized_proof: &[u8]) -> Self {
914        bincode::deserialize(serialized_proof).unwrap()
915    }
916}
917
918#[derive(Clone, Debug, Serialize, Deserialize)]
919#[serde(bound = "F: Field")]
920pub struct V3MPCCircuitAndAuxMles<F: Field> {
921    pub v3_circuit_and_aux_data: V3CircuitAndAuxData<F>,
922    pub mpc_circuit_and_aux_mles_all_3_parties: MPCCircuitsAndConstData<F>,
923}
924
925impl<F: Field> V3MPCCircuitAndAuxMles<F> {
926    pub fn serialize(&self) -> Vec<u8> {
927        bincode::serialize(&self).expect("Failed to serialize CircuitAndAuxMles")
928    }
929
930    pub fn deserialize(bytes: &[u8]) -> Self {
931        bincode::deserialize(bytes).expect("Failed to deserialize CircuitAndAuxMles")
932    }
933}
934
935// Generate the circuit description and input builder used to generate the auxiliary MLEs.
936pub fn generate_mpc_circuit_and_aux_mles_all_3_parties<F: Field>() -> MPCCircuitsAndConstData<F> {
937    let mpc_circuit = build_circuit::<F, MPC_NUM_IRIS_4_CHUNKS>(LayerVisibility::Committed);
938
939    MPCCircuitsAndConstData {
940        mpc_circuit,
941        encoding_matrix: gen_mpc_encoding_matrix::<F, MPC_NUM_IRIS_4_CHUNKS>(),
942        evaluation_points: [
943            gen_mpc_evaluation_points::<F, MPC_NUM_IRIS_4_CHUNKS, 0>(),
944            gen_mpc_evaluation_points::<F, MPC_NUM_IRIS_4_CHUNKS, 1>(),
945            gen_mpc_evaluation_points::<F, MPC_NUM_IRIS_4_CHUNKS, 2>(),
946        ],
947    }
948}