1#![allow(warnings)]
2use std::collections::HashMap;
3use std::fmt::Display;
4use std::hash::Hash;
5
6use crate::{
7 layouter::builder::Circuit,
8 worldcoin_mpc::circuits::MPC_IRISCODE_INPUT_LAYER,
9 zk_iriscode_ss::{
10 circuits::{
11 V3_AUXILIARY_LAYER, V3_DIGITS_LAYER, V3_INPUT_IMAGE_LAYER, V3_RH_MATMULT_SHRED,
12 V3_SIGN_BITS_LAYER, V3_TO_SUB_MATMULT_SHRED,
13 },
14 data::IriscodeCircuitAuxData,
15 parameters::IRISCODE_COMMIT_LOG_NUM_COLS,
16 v3::{circuit_description_and_inputs, load_worldcoin_data},
17 },
18};
19use clap::error;
20use rand::rngs::ThreadRng;
21use rand::{CryptoRng, Rng, RngCore};
22use remainder::layer::LayerId;
23use remainder::mle::evals::MultilinearExtension;
24use remainder::prover::GKRCircuitDescription;
25use remainder::utils::mle::pad_with;
26use remainder::{
27 circuit_building_context::CircuitBuildingContext, verifiable_circuit::VerifiableCircuit,
28};
29use serde::{Deserialize, Serialize};
30use shared_types::curves::PrimeOrderCurve;
31use shared_types::halo2curves::{bn256::G1 as Bn256Point, group::Group};
32use shared_types::pedersen::PedersenCommitter;
33use shared_types::transcript::ec_transcript::{ECTranscript, ECTranscriptTrait};
34use shared_types::transcript::poseidon_sponge::PoseidonSponge;
35use shared_types::transcript::Transcript;
36use shared_types::{
37 config::{GKRCircuitProverConfig, GKRCircuitVerifierConfig, ProofConfig},
38 halo2curves::grumpkin::G1,
39};
40use shared_types::{
41 perform_function_under_prover_config, perform_function_under_verifier_config, Fq, Fr,
42};
43use shared_types::{Field, Zeroizable};
44use zeroize::Zeroize;
45
46use super::orb::SerializedImageCommitment;
47use crate::hyrax_worldcoin::orb::{IMAGE_COMMIT_LOG_NUM_COLS, PUBLIC_STRING};
48use hyrax::utils::vandermonde::VandermondeInverse;
49use hyrax::{
50 gkr::input_layer::{
51 commit_to_input_values, HyraxInputLayerDescription, HyraxProverInputCommitment,
52 },
53 verifiable_circuit::HyraxVerifiableCircuit,
54};
55use hyrax::{
56 gkr::{self, verify_hyrax_proof, HyraxProof},
57 provable_circuit::HyraxProvableCircuit,
58};
59use sha256::digest as sha256_digest;
60use thiserror::Error;
61
62use crate::zk_iriscode_ss::circuits::iriscode_ss_attach_input_data;
63use anyhow::{anyhow, Result};
64
65type Scalar = Fr;
66type Base = Fq;
67
68#[derive(Debug, Error)]
69pub enum IriscodeError {
70 #[error("Non-zero padding bits in iris/mask code")]
71 NonZeroPaddingBits,
72 #[error("Non-binary iris/mask code")]
73 NonBinaryIrisMaskCode,
74 #[error("Incorrect kernel values or thresholds")]
75 IncorrectKernelValuesOrThresholds,
76 #[error("Image commitment does not match expected hash")]
77 WrongHash,
78}
79
80pub(crate) fn verify_v3_iriscode_proof_and_hash(
90 proof: &HyraxProof<Bn256Point>,
91 verifiable_circuit: &HyraxVerifiableCircuit<Bn256Point>,
92 expected_commitment_hash: &str,
93 committer: &PedersenCommitter<Bn256Point>,
94 proof_config: &ProofConfig,
95) -> Result<Vec<Bn256Point>> {
96 let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
98 ECTranscript::new("V3 Iriscode Circuit Pipeline");
99
100 verify_hyrax_proof(
102 &proof,
103 &verifiable_circuit,
104 &committer,
105 &mut transcript,
106 proof_config,
107 );
108
109 let image_layer_id = verifiable_circuit
110 .get_private_input_layer_id(V3_INPUT_IMAGE_LAYER)
111 .unwrap();
112 let code_layer_id = verifiable_circuit
113 .get_private_input_layer_id(V3_SIGN_BITS_LAYER)
114 .unwrap();
115
116 let image_commitment = proof.get_commitment_ref(image_layer_id).cloned().unwrap();
117 let code_commitment = proof.get_commitment_ref(code_layer_id).cloned().unwrap();
118
119 let commitment_hash = sha256_digest(
121 &image_commitment
122 .iter()
123 .flat_map(|p| p.to_bytes_compressed())
124 .collect::<Vec<u8>>(),
125 );
126
127 if commitment_hash != *expected_commitment_hash {
128 return Err(anyhow!(IriscodeError::WrongHash));
129 }
130
131 Ok(code_commitment)
133}
134
135pub fn prove_with_image_precommit(
143 mut provable_circuit: HyraxProvableCircuit<Bn256Point>,
144 image_layer_label: &str,
145 code_layer_label: &str,
146 image_precommit: HyraxProverInputCommitment<Bn256Point>,
147 committer: &PedersenCommitter<Bn256Point>,
148 blinding_rng: &mut (impl CryptoRng + RngCore),
149 converter: &mut VandermondeInverse<Scalar>,
150) -> ((
151 HyraxProof<Bn256Point>,
152 ProofConfig,
153 HyraxProverInputCommitment<Bn256Point>,
154)) {
155 provable_circuit
156 .set_pre_commitment(
157 image_layer_label,
158 image_precommit,
159 Some(IMAGE_COMMIT_LOG_NUM_COLS),
160 )
161 .unwrap();
162
163 let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
165 ECTranscript::new("V3 Iriscode Circuit Pipeline");
166
167 let (proof, proof_config) =
169 provable_circuit.prove(&committer, blinding_rng, converter, &mut transcript);
170
171 let code_layer_id = *provable_circuit
172 .layer_label_to_layer_id
173 .get(code_layer_label)
174 .unwrap();
175
176 let code_commit_in_proof = &proof
177 .hyrax_input_proofs
178 .iter()
179 .find(|hyrax_input_proof| hyrax_input_proof.layer_id == code_layer_id)
180 .unwrap()
181 .input_commitment;
182 let code_commit = provable_circuit
183 .get_commitment_ref_by_label(code_layer_label)
184 .unwrap()
185 .clone();
186 assert_eq!(*code_commit_in_proof, code_commit.commitment);
187
188 let private_input_layer_ids = provable_circuit.get_private_input_layer_ids();
190 private_input_layer_ids.iter().for_each(|layer_id| {
191 let commitment = provable_circuit.get_commitment_mut_ref(layer_id).unwrap();
192 commitment.zeroize();
193 });
194
195 (proof, proof_config, code_commit)
196}
197
198#[derive(Error, Debug)]
199pub enum V3ProofError {
200 #[error("Found empty proof field")]
201 EmptyProofField,
202
203 #[error("Verification produced an iriscode error")]
204 IriscodeError(#[from] IriscodeError),
205
206 #[error("Verifier returned an iriscode of the wrong length")]
207 IriscodeLengthMismatch,
208}
209
210#[derive(Serialize, Deserialize)]
218pub struct V3Prover {
219 #[serde(skip)]
220 #[serde(default = "V3Prover::default_committer")]
221 committer: PedersenCommitter<Bn256Point>,
222
223 #[serde(skip)]
224 #[serde(default = "VandermondeInverse::new")]
225 converter: VandermondeInverse<Scalar>,
226
227 v3_circuit: V3CircuitAndAuxData<Fr>,
230
231 prover_config: GKRCircuitProverConfig,
232
233 left_iris_proof: Option<HyraxProof<Bn256Point>>,
234 left_mask_proof: Option<HyraxProof<Bn256Point>>,
235 right_iris_proof: Option<HyraxProof<Bn256Point>>,
236 right_mask_proof: Option<HyraxProof<Bn256Point>>,
237}
238
239impl V3Prover {
240 pub fn default_committer() -> PedersenCommitter<Bn256Point> {
241 PedersenCommitter::new(1 << IMAGE_COMMIT_LOG_NUM_COLS, PUBLIC_STRING, None)
242 }
243
244 pub fn new(prover_config: GKRCircuitProverConfig, circuit: V3CircuitAndAuxData<Fr>) -> Self {
246 Self {
247 committer: Self::default_committer(),
248 converter: VandermondeInverse::new(),
249 v3_circuit: circuit,
250 prover_config,
251 left_iris_proof: None,
252 left_mask_proof: None,
253 right_iris_proof: None,
254 right_mask_proof: None,
255 }
256 }
257
258 pub fn new_from_proofs(
261 prover_config: GKRCircuitProverConfig,
262 circuit: V3CircuitAndAuxData<Fr>,
263 left_image_proof: HyraxProof<Bn256Point>,
264 left_mask_proof: HyraxProof<Bn256Point>,
265 right_image_proof: HyraxProof<Bn256Point>,
266 right_mask_proof: HyraxProof<Bn256Point>,
267 ) -> Self {
268 Self {
269 committer: Self::default_committer(),
270 converter: VandermondeInverse::new(),
271 v3_circuit: circuit,
272 prover_config,
273 left_iris_proof: Some(left_image_proof),
274 left_mask_proof: Some(left_mask_proof),
275 right_iris_proof: Some(right_image_proof),
276 right_mask_proof: Some(right_mask_proof),
277 }
278 }
279
280 pub fn prove(
281 &mut self,
282 is_mask: bool,
283 is_left_eye: bool,
284 image_bytes: Vec<u8>,
285 image_precommit: HyraxProverInputCommitment<Bn256Point>,
286 rng: &mut (impl CryptoRng + RngCore),
287 ) -> HyraxProverInputCommitment<Bn256Point> {
288 let input_data = load_worldcoin_data::<Fr>(image_bytes, is_mask);
290
291 let mut circuit = self.v3_circuit.get_circuit().clone();
293
294 let aux_data = if is_mask {
295 self.v3_circuit.get_mask_aux_data_ref().clone()
296 } else {
297 self.v3_circuit.get_iris_aux_data_ref().clone()
298 };
299
300 let circuit_with_inputs = iriscode_ss_attach_input_data::<
301 _,
302 { crate::zk_iriscode_ss::parameters::BASE },
303 >(circuit, input_data, aux_data)
304 .unwrap();
305
306 let provable_circuit = circuit_with_inputs.gen_hyrax_provable_circuit().unwrap();
307
308 let (proof, _, code_commit) = prove_with_image_precommit(
310 provable_circuit,
311 V3_INPUT_IMAGE_LAYER,
312 V3_SIGN_BITS_LAYER,
313 image_precommit,
314 &mut self.committer,
315 rng,
316 &mut self.converter,
317 );
318
319 self.set(is_mask, is_left_eye, proof);
320
321 code_commit
322 }
323
324 pub fn set(&mut self, is_mask: bool, is_left_eye: bool, proof: HyraxProof<Bn256Point>) {
327 match (is_mask, is_left_eye) {
328 (false, false) => self.set_right_iris_proof(proof),
329 (false, true) => self.set_left_iris_proof(proof),
330 (true, false) => self.set_right_mask_proof(proof),
331 (true, true) => self.set_left_mask_proof(proof),
332 }
333 }
334
335 pub fn set_left_iris_proof(&mut self, proof: HyraxProof<Bn256Point>) {
337 self.left_iris_proof = Some(proof)
338 }
339
340 pub fn set_left_mask_proof(&mut self, proof: HyraxProof<Bn256Point>) {
342 self.left_mask_proof = Some(proof)
343 }
344
345 pub fn set_right_iris_proof(&mut self, proof: HyraxProof<Bn256Point>) {
347 self.right_iris_proof = Some(proof)
348 }
349
350 pub fn set_right_mask_proof(&mut self, proof: HyraxProof<Bn256Point>) {
352 self.right_mask_proof = Some(proof)
353 }
354
355 pub fn is_set(&self, is_mask: bool, is_left_eye: bool) -> bool {
359 match (is_mask, is_left_eye) {
360 (false, false) => self.right_iris_proof.is_some(),
361 (false, true) => self.left_iris_proof.is_some(),
362 (true, false) => self.right_mask_proof.is_some(),
363 (true, true) => self.left_mask_proof.is_some(),
364 }
365 }
366
367 pub fn get(&self, is_mask: bool, is_left_eye: bool) -> Option<&HyraxProof<Bn256Point>> {
370 match (is_mask, is_left_eye) {
371 (false, false) => self.get_right_iris_proof(),
372 (false, true) => self.get_left_iris_proof(),
373 (true, false) => self.get_right_mask_proof(),
374 (true, true) => self.get_left_mask_proof(),
375 }
376 }
377
378 pub fn get_left_iris_proof(&self) -> Option<&HyraxProof<Bn256Point>> {
381 self.left_iris_proof.as_ref()
382 }
383
384 pub fn get_left_mask_proof(&self) -> Option<&HyraxProof<Bn256Point>> {
387 self.left_mask_proof.as_ref()
388 }
389
390 pub fn get_right_iris_proof(&self) -> Option<&HyraxProof<Bn256Point>> {
393 self.right_iris_proof.as_ref()
394 }
395
396 pub fn get_right_mask_proof(&self) -> Option<&HyraxProof<Bn256Point>> {
399 self.right_mask_proof.as_ref()
400 }
401
402 pub fn serialize(&self) -> Vec<u8> {
404 let serialized_proof = bincode::serialize(self).unwrap();
405
406 serialized_proof
407 }
408
409 fn is_ready_to_finalize(&self) -> bool {
412 self.is_set(false, false)
413 && self.is_set(false, true)
414 && self.is_set(true, false)
415 && self.is_set(true, true)
416 }
417 pub fn finalize(&self) -> Result<V3Proof, V3ProofError> {
422 if self.is_ready_to_finalize() {
423 let proof_config = ProofConfig::new_from_prover_config(&self.prover_config);
424
425 Ok(V3Proof::new(
426 proof_config,
427 self.left_iris_proof.as_ref().unwrap().clone(),
428 self.left_mask_proof.as_ref().unwrap().clone(),
429 self.right_iris_proof.as_ref().unwrap().clone(),
430 self.right_mask_proof.as_ref().unwrap().clone(),
431 ))
432 } else {
433 Err(V3ProofError::EmptyProofField)
434 }
435 }
436
437 pub fn deserialize(serialized_prover: &[u8]) -> Self {
439 bincode::deserialize(serialized_prover).unwrap()
440 }
441
442 pub fn get_as_mut(&mut self, is_mask: bool, is_left_eye: bool) -> &mut HyraxProof<Bn256Point> {
444 match (is_mask, is_left_eye) {
445 (false, false) => self.right_iris_proof.as_mut().unwrap(),
446 (false, true) => self.left_iris_proof.as_mut().unwrap(),
447 (true, false) => self.right_mask_proof.as_mut().unwrap(),
448 (true, true) => self.left_mask_proof.as_mut().unwrap(),
449 }
450 }
451}
452
453#[derive(Clone, Debug, Serialize, Deserialize)]
454pub struct V3Proof {
455 #[serde(skip)]
456 #[serde(default = "V3Prover::default_committer")]
457 committer: PedersenCommitter<Bn256Point>,
458
459 proof_config: ProofConfig,
460
461 left_iris_proof: HyraxProof<Bn256Point>,
462 left_mask_proof: HyraxProof<Bn256Point>,
463 right_iris_proof: HyraxProof<Bn256Point>,
464 right_mask_proof: HyraxProof<Bn256Point>,
465}
466
467impl V3Proof {
468 pub fn new(
469 proof_config: ProofConfig,
470 left_iris_proof: HyraxProof<Bn256Point>,
471 left_mask_proof: HyraxProof<Bn256Point>,
472 right_iris_proof: HyraxProof<Bn256Point>,
473 right_mask_proof: HyraxProof<Bn256Point>,
474 ) -> Self {
475 Self {
476 committer: V3Prover::default_committer(),
477 proof_config,
478 left_iris_proof,
479 left_mask_proof,
480 right_iris_proof,
481 right_mask_proof,
482 }
483 }
484
485 pub fn insert_aux_public_data(
486 &mut self,
487 aux_mle: &MultilinearExtension<Fr>,
488 is_mask: bool,
489 is_left_eye: bool,
490 aux_layer_id: LayerId,
491 ) {
492 let proof = self.get_as_mut(is_mask, is_left_eye);
493 proof.insert_aux_public_data_by_id(aux_mle, aux_layer_id);
494 }
495
496 pub fn get_as_mut(&mut self, is_mask: bool, is_left_eye: bool) -> &mut HyraxProof<Bn256Point> {
498 match (is_mask, is_left_eye) {
499 (false, false) => &mut self.right_iris_proof,
500 (false, true) => &mut self.left_iris_proof,
501 (true, false) => &mut self.right_mask_proof,
502 (true, true) => &mut self.left_mask_proof,
503 }
504 }
505
506 pub fn get(&self, is_mask: bool, is_left_eye: bool) -> &HyraxProof<Bn256Point> {
508 match (is_mask, is_left_eye) {
509 (false, false) => self.get_right_iris_proof(),
510 (false, true) => self.get_left_iris_proof(),
511 (true, false) => self.get_right_mask_proof(),
512 (true, true) => self.get_left_mask_proof(),
513 }
514 }
515
516 pub fn get_left_iris_proof(&self) -> &HyraxProof<Bn256Point> {
518 &self.left_iris_proof
519 }
520
521 pub fn get_left_mask_proof(&self) -> &HyraxProof<Bn256Point> {
523 &self.left_mask_proof
524 }
525
526 pub fn get_right_iris_proof(&self) -> &HyraxProof<Bn256Point> {
528 &self.right_iris_proof
529 }
530
531 pub fn get_right_mask_proof(&self) -> &HyraxProof<Bn256Point> {
533 &self.right_mask_proof
534 }
535
536 pub fn serialize(&self) -> Vec<u8> {
538 let serialized_proof = bincode::serialize(self).unwrap();
539
540 serialized_proof
541 }
542
543 pub fn deserialize(serialized_proof: &[u8]) -> Self {
545 bincode::deserialize(serialized_proof).unwrap()
546 }
547
548 pub fn verify(
552 &self,
553 is_mask: bool,
554 is_left_eye: bool,
555 verifiable_circuit: &HyraxVerifiableCircuit<Bn256Point>,
556 commitment_hash: &str,
557 ) -> Result<()> {
558 let proof = self.get(is_mask, is_left_eye);
559
560 verify_v3_iriscode_proof_and_hash(
561 proof,
562 verifiable_circuit,
563 commitment_hash,
564 &self.committer,
565 &self.proof_config,
566 )?;
567
568 Ok(())
569 }
570}
571
572#[derive(Clone, Debug, Serialize, Deserialize)]
581#[serde(bound = "F: Field")]
582pub struct V3CircuitAndAuxData<F: Field> {
583 circuit: Circuit<F>,
584 iris_aux_data: IriscodeCircuitAuxData<F>,
585 mask_aux_data: IriscodeCircuitAuxData<F>,
586}
587
588impl<F: Field> V3CircuitAndAuxData<F> {
589 pub fn new(
590 circuit: Circuit<F>,
591 iris_aux_data: IriscodeCircuitAuxData<F>,
592 mask_aux_data: IriscodeCircuitAuxData<F>,
593 ) -> Self {
594 assert!(!circuit
602 .input_layer_contains_data(V3_INPUT_IMAGE_LAYER)
603 .unwrap());
604 assert!(!circuit.input_layer_contains_data(V3_DIGITS_LAYER).unwrap());
605 assert!(!circuit
606 .input_layer_contains_data(V3_SIGN_BITS_LAYER)
607 .unwrap());
608 assert!(!circuit
609 .input_layer_contains_data(V3_AUXILIARY_LAYER)
610 .unwrap());
611
612 Self {
613 circuit,
614 iris_aux_data,
615 mask_aux_data,
616 }
617 }
618
619 pub fn get_circuit(&self) -> &Circuit<F> {
620 &self.circuit
621 }
622
623 pub fn get_iris_aux_data_ref(&self) -> &IriscodeCircuitAuxData<F> {
624 &self.iris_aux_data
625 }
626
627 pub fn get_mask_aux_data_ref(&self) -> &IriscodeCircuitAuxData<F> {
628 &self.mask_aux_data
629 }
630
631 pub fn serialize(&self) -> Vec<u8> {
632 bincode::serialize(&self).expect("Failed to serialize V3CircuitAndAuxData")
633 }
634
635 pub fn deserialize(bytes: &[u8]) -> Self {
636 bincode::deserialize(bytes).expect("Failed to deserialize V3CircuitAndAuxData")
637 }
638}