frontend/hyrax_worldcoin/
test_worldcoin.rs

1use crate::zk_iriscode_ss::v3::circuit_description_and_inputs;
2use ark_std::{end_timer, start_timer};
3
4use shared_types::{
5    config::{GKRCircuitProverConfig, GKRCircuitVerifierConfig},
6    halo2curves::bn256::G1 as Bn256Point,
7    pedersen::PedersenCommitter,
8    perform_function_under_prover_config, perform_function_under_verifier_config,
9    transcript::{ec_transcript::ECTranscript, poseidon_sponge::PoseidonSponge},
10    Base, Scalar,
11};
12
13use hyrax::{
14    gkr::verify_hyrax_proof, provable_circuit::HyraxProvableCircuit,
15    utils::vandermonde::VandermondeInverse,
16};
17
18#[cfg(test)]
19mod tests {
20    use std::path::Path;
21
22    use super::{
23        super::orb::{load_image_commitment, IMAGE_COMMIT_LOG_NUM_COLS, PUBLIC_STRING},
24        test_iriscode_v3_with_hyrax_helper,
25    };
26    use crate::{
27        hyrax_worldcoin::{
28            test_worldcoin::{
29                test_iriscode_circuit_with_hyrax_helper,
30                test_iriscode_circuit_with_public_layers_helper,
31            },
32            v3::verify_v3_iriscode_proof_and_hash,
33        },
34        layouter::builder::Circuit,
35        zk_iriscode_ss::{
36            circuits::{iriscode_ss_attach_input_data, V3_INPUT_IMAGE_LAYER, V3_SIGN_BITS_LAYER},
37            test_helpers::{
38                small_hyrax_circuit_with_private_inputs, small_hyrax_circuit_with_public_inputs,
39            },
40            v3::{build_worldcoin_aux_data, circuit_description, load_worldcoin_data},
41        },
42    };
43    use hyrax::{
44        gkr::{input_layer::HyraxProverInputCommitment, HyraxProof},
45        utils::vandermonde::VandermondeInverse,
46        verifiable_circuit::HyraxVerifiableCircuit,
47    };
48    use rand::rngs::ThreadRng;
49    use shared_types::{
50        config::{GKRCircuitProverConfig, GKRCircuitVerifierConfig, ProofConfig},
51        curves::PrimeOrderCurve,
52        halo2curves::bn256::G1 as Bn256Point,
53        pedersen::PedersenCommitter,
54        perform_function_under_prover_config, perform_function_under_verifier_config,
55        transcript::{ec_transcript::ECTranscript, poseidon_sponge::PoseidonSponge},
56        Base, Fr, Scalar,
57    };
58
59    #[test]
60    fn test_small_circuit_both_layers_public() {
61        let provable_circuit = small_hyrax_circuit_with_public_inputs().unwrap();
62        test_iriscode_circuit_with_public_layers_helper(provable_circuit);
63    }
64
65    #[test]
66    /// Test a small version of the iriscode circuit with a Hyrax input layer.
67    fn test_small_circuit_with_hyrax_layer() {
68        let provable_circuit = small_hyrax_circuit_with_private_inputs().unwrap();
69        test_iriscode_circuit_with_hyrax_helper(provable_circuit);
70    }
71
72    fn v3_masked_iriscode_prove(
73        is_mask: bool,
74        is_left_eye: bool,
75        committer: &PedersenCommitter<Bn256Point>,
76        blinding_rng: &mut ThreadRng,
77        converter: &mut VandermondeInverse<Scalar>,
78        ic_circuit: Circuit<Fr>,
79    ) -> (
80        HyraxVerifiableCircuit<Bn256Point>,
81        HyraxProof<Bn256Point>,
82        ProofConfig,
83        String,
84        HyraxProverInputCommitment<Bn256Point>,
85        HyraxProverInputCommitment<Bn256Point>,
86    ) {
87        use sha256::digest;
88
89        // Get the pre-existing commitment to the image.
90        let serialized_image_commitment = load_image_commitment(
91            &Path::new("iriscode_pcp_example").to_path_buf(),
92            3,
93            is_mask,
94            is_left_eye,
95        );
96        let image_commitment: HyraxProverInputCommitment<Bn256Point> =
97            serialized_image_commitment.clone().into();
98
99        // Derive the hash of the image commitment.  In production, this has been calculated by the Orb and sent over in a signed file.
100        let expected_commitment_hash = digest(
101            &image_commitment
102                .commitment
103                .iter()
104                .flat_map(|p| p.to_bytes_compressed())
105                .collect::<Vec<u8>>(),
106        );
107
108        // Load the inputs to the circuit (these are all MLEs, i.e. in the clear).
109        let input_data = load_worldcoin_data::<Fr>(serialized_image_commitment.image, is_mask);
110        let aux_data = build_worldcoin_aux_data::<Fr>(is_mask);
111        let circuit =
112            iriscode_ss_attach_input_data::<_, { crate::zk_iriscode_ss::parameters::BASE }>(
113                ic_circuit.clone(),
114                input_data,
115                aux_data,
116            )
117            .unwrap();
118
119        let mut provable_circuit = circuit.gen_hyrax_provable_circuit().unwrap();
120
121        provable_circuit
122            .set_pre_commitment(
123                V3_INPUT_IMAGE_LAYER,
124                image_commitment.into(),
125                Some(IMAGE_COMMIT_LOG_NUM_COLS),
126            )
127            .unwrap();
128
129        let verifiable_circuit = provable_circuit._gen_hyrax_verifiable_circuit();
130
131        // Create a fresh transcript.
132        let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
133            ECTranscript::new("V3 Iriscode Circuit Pipeline");
134
135        // Prove the relationship between iris/mask code and image.
136        let (proof, proof_config) =
137            provable_circuit.prove(&committer, blinding_rng, converter, &mut transcript);
138
139        let code_commit = provable_circuit
140            .get_commitment_ref_by_label(V3_SIGN_BITS_LAYER)
141            .unwrap()
142            .clone();
143        let image_commit = provable_circuit
144            .get_commitment_ref_by_label(V3_INPUT_IMAGE_LAYER)
145            .unwrap()
146            .clone();
147
148        (
149            verifiable_circuit,
150            proof,
151            proof_config,
152            expected_commitment_hash,
153            image_commit,
154            code_commit,
155        )
156    }
157
158    #[ignore] // Takes a long time to run
159    #[test]
160    // Test the proving and verifying of the v3 iriscode circuit with the image precommit;
161    // verification includes checking the hash. This is testing the fundamental prove and verify
162    // functions that will be used by the user/smartphone and the server.
163    fn test_v3_masked_iriscode_proof_and_verification() {
164        // Create the Pedersen committer using the same reference string and parameters as on the Orb
165        let committer: PedersenCommitter<Bn256Point> =
166            PedersenCommitter::new(1 << IMAGE_COMMIT_LOG_NUM_COLS, PUBLIC_STRING, None);
167        // Create a single RNG and Vandermonde inverse converter for all proofs.
168        let blinding_rng = &mut rand::thread_rng();
169        let converter: &mut VandermondeInverse<Scalar> = &mut VandermondeInverse::new();
170
171        // Prover config is Hyrax-compatible, memory-efficient config
172        let gkr_circuit_prover_config =
173            GKRCircuitProverConfig::hyrax_compatible_memory_optimized_default();
174        let gkr_circuit_verifier_config =
175            GKRCircuitVerifierConfig::new_from_prover_config(&gkr_circuit_prover_config, false);
176
177        // Get the proof description and input builder.
178        // This is shared by the prover and the verifier.
179        let ic_circuit =
180            perform_function_under_prover_config!(circuit_description, &gkr_circuit_prover_config,)
181                .unwrap();
182
183        for is_mask in [false, true] {
184            for is_left_eye in [false, true] {
185                let (
186                    verifiable_circuit,
187                    proof,
188                    proof_config,
189                    expected_commitment_hash,
190                    _image_commit,
191                    _code_commit,
192                ) = perform_function_under_prover_config!(
193                    v3_masked_iriscode_prove,
194                    &gkr_circuit_prover_config,
195                    is_mask,
196                    is_left_eye,
197                    &committer,
198                    blinding_rng,
199                    converter,
200                    ic_circuit.clone()
201                );
202
203                // let (_code_commitment, _image_commitment) =
204                perform_function_under_verifier_config!(
205                    verify_v3_iriscode_proof_and_hash,
206                    &gkr_circuit_verifier_config,
207                    &proof,
208                    &verifiable_circuit,
209                    &expected_commitment_hash,
210                    &committer,
211                    &proof_config
212                )
213                .unwrap();
214            }
215        }
216    }
217
218    #[ignore] // Takes a long time to run
219    #[test]
220    fn test_v3_iris_with_hyrax_layer() {
221        test_iriscode_v3_with_hyrax_helper(false);
222    }
223
224    #[ignore] // Takes a long time to run
225    #[test]
226    fn test_v3_mask_with_hyrax_layer() {
227        test_iriscode_v3_with_hyrax_helper(true);
228    }
229}
230
231/// Test the iriscode circuit v3 with a Hyrax input layer in either the mask (true) or iris (false)
232/// case.
233pub fn test_iriscode_v3_with_hyrax_helper(mask: bool) {
234    let circuit = circuit_description_and_inputs(mask, None).unwrap();
235    let provable_circuit = circuit.gen_hyrax_provable_circuit().unwrap();
236    test_iriscode_circuit_with_hyrax_helper(provable_circuit);
237}
238
239/// Helper function for testing an iriscode circuit (with any data) with a Hyrax input layer.
240pub fn test_iriscode_circuit_with_public_layers_helper(
241    mut provable_circuit: HyraxProvableCircuit<Bn256Point>,
242) {
243    let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
244        ECTranscript::new("modulus modulus modulus modulus modulus");
245    let blinding_rng = &mut rand::thread_rng();
246    let converter: &mut VandermondeInverse<Scalar> = &mut VandermondeInverse::new();
247    let num_generators = 512;
248    let committer = PedersenCommitter::<Bn256Point>::new(
249        num_generators + 1,
250        "modulus modulus modulus modulus modulus",
251        None,
252    );
253
254    // --- Create GKR circuit prover + verifier configs which work with Hyrax ---
255    let gkr_circuit_prover_config =
256        GKRCircuitProverConfig::hyrax_compatible_runtime_optimized_default();
257    let gkr_circuit_verifier_config =
258        GKRCircuitVerifierConfig::new_from_prover_config(&gkr_circuit_prover_config, false);
259
260    let verifiable_circuit = provable_circuit._gen_hyrax_verifiable_circuit();
261
262    // --- Compute actual Hyrax proof ---
263    let (proof, proof_config) = perform_function_under_prover_config!(
264        HyraxProvableCircuit::prove,
265        &gkr_circuit_prover_config,
266        &mut provable_circuit,
267        &committer,
268        blinding_rng,
269        converter,
270        &mut transcript
271    );
272
273    let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
274        ECTranscript::new("modulus modulus modulus modulus modulus");
275
276    // Verify.
277    perform_function_under_verifier_config!(
278        verify_hyrax_proof,
279        &gkr_circuit_verifier_config,
280        &proof,
281        &verifiable_circuit,
282        &committer,
283        &mut transcript,
284        &proof_config
285    );
286}
287
288/// Helper function for testing an iriscode circuit (with any data) with Hyrax input
289/// layers for the private data.
290pub fn test_iriscode_circuit_with_hyrax_helper(
291    mut provable_circuit: HyraxProvableCircuit<Bn256Point>,
292) {
293    let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
294        ECTranscript::new("modulus modulus modulus modulus modulus");
295    let blinding_rng = &mut rand::thread_rng();
296    let converter: &mut VandermondeInverse<Scalar> = &mut VandermondeInverse::new();
297    let num_generators = 512;
298    let committer = PedersenCommitter::<Bn256Point>::new(
299        num_generators + 1,
300        "modulus modulus modulus modulus modulus",
301        None,
302    );
303
304    // Prove.
305    // --- Create GKR circuit prover + verifier configs which work with Hyrax ---
306    let gkr_circuit_prover_config =
307        GKRCircuitProverConfig::hyrax_compatible_memory_optimized_default();
308    let gkr_circuit_verifier_config =
309        GKRCircuitVerifierConfig::new_from_prover_config(&gkr_circuit_prover_config, false);
310
311    let verifiable_circuit = provable_circuit._gen_hyrax_verifiable_circuit();
312
313    // --- Compute actual Hyrax proof ---
314    let prove_timer = start_timer!(|| "Proving");
315    let (proof, proof_config) = perform_function_under_prover_config!(
316        HyraxProvableCircuit::prove,
317        &gkr_circuit_prover_config,
318        &mut provable_circuit,
319        &committer,
320        blinding_rng,
321        converter,
322        &mut transcript
323    );
324    end_timer!(prove_timer);
325
326    // Verify.
327    let mut transcript: ECTranscript<Bn256Point, PoseidonSponge<Base>> =
328        ECTranscript::new("modulus modulus modulus modulus modulus");
329
330    let verification_timer = start_timer!(|| "verification timer");
331    perform_function_under_verifier_config!(
332        verify_hyrax_proof,
333        &gkr_circuit_verifier_config,
334        &proof,
335        &verifiable_circuit,
336        &committer,
337        &mut transcript,
338        &proof_config
339    );
340    end_timer!(verification_timer);
341}