frontend/zk_iriscode_ss/
v3.rs

1use itertools::Itertools;
2use ndarray::Array2;
3use shared_types::{Field, Fr};
4
5use crate::{
6    hyrax_worldcoin::v3::V3CircuitAndAuxData,
7    layouter::builder::{Circuit, LayerVisibility},
8    zk_iriscode_ss::{
9        data::{
10            build_iriscode_circuit_auxiliary_data, build_iriscode_circuit_data,
11            IriscodeCircuitAuxData,
12        },
13        parameters::LOG_NUM_STRIPS,
14    },
15};
16
17use super::{
18    circuits::{build_iriscode_circuit_description, iriscode_ss_attach_input_data},
19    data::{wirings_to_reroutings, IriscodeCircuitInputData},
20    decode::{decode_i32_array, decode_i64_array, decode_wirings},
21    io::read_bytes_from_file,
22    parameters::{
23        BASE, IMAGE_STRIP_WIRINGS, IM_NUM_COLS, IM_NUM_ROWS, IM_NUM_VARS, IM_STRIP_NUM_COLS,
24        IM_STRIP_NUM_ROWS, IRIS_RH_MULTIPLICAND, IRIS_THRESHOLDS, LH_MATRIX_WIRINGS,
25        MASK_RH_MULTIPLICAND, MASK_THRESHOLDS, MATMULT_COLS_NUM_VARS,
26        MATMULT_INTERNAL_DIM_NUM_VARS, MATMULT_ROWS_NUM_VARS, NUM_DIGITS,
27    },
28};
29
30use anyhow::Result;
31
32/// Loads circuit structure data and witnesses for a run of the iris code circuit from disk for
33/// either the iris or mask case.
34///
35/// # Arguments:
36/// * `image_bytes` gives the bytes of an image (could be the iris or the mask).
37/// * `is_mask` indicates whether to load the files for the mask or the iris.
38pub fn load_worldcoin_data<F: Field>(
39    image_bytes: Vec<u8>,
40    is_mask: bool,
41) -> IriscodeCircuitInputData<F> {
42    let image: Array2<u8> =
43        Array2::from_shape_vec((IM_NUM_ROWS, IM_NUM_COLS), image_bytes).unwrap();
44    if is_mask {
45        build_iriscode_circuit_data::<
46            F,
47            IM_STRIP_NUM_ROWS,
48            IM_STRIP_NUM_COLS,
49            MATMULT_ROWS_NUM_VARS,
50            MATMULT_COLS_NUM_VARS,
51            MATMULT_INTERNAL_DIM_NUM_VARS,
52            BASE,
53            NUM_DIGITS,
54        >(
55            image,
56            &decode_i32_array(MASK_RH_MULTIPLICAND),
57            &decode_i64_array(MASK_THRESHOLDS),
58            IMAGE_STRIP_WIRINGS
59                .iter()
60                .map(|wirings| decode_wirings(wirings))
61                .collect_vec(),
62            &decode_wirings(LH_MATRIX_WIRINGS),
63        )
64    } else {
65        build_iriscode_circuit_data::<
66            F,
67            IM_STRIP_NUM_ROWS,
68            IM_STRIP_NUM_COLS,
69            MATMULT_ROWS_NUM_VARS,
70            MATMULT_COLS_NUM_VARS,
71            MATMULT_INTERNAL_DIM_NUM_VARS,
72            BASE,
73            NUM_DIGITS,
74        >(
75            image,
76            &decode_i32_array(IRIS_RH_MULTIPLICAND),
77            &decode_i64_array(IRIS_THRESHOLDS),
78            IMAGE_STRIP_WIRINGS
79                .iter()
80                .map(|wirings| decode_wirings(wirings))
81                .collect_vec(),
82            &decode_wirings(LH_MATRIX_WIRINGS),
83        )
84    }
85}
86
87pub fn build_worldcoin_aux_data<F: Field>(is_mask: bool) -> IriscodeCircuitAuxData<F> {
88    if is_mask {
89        build_iriscode_circuit_auxiliary_data::<
90            F,
91            MATMULT_COLS_NUM_VARS,
92            MATMULT_INTERNAL_DIM_NUM_VARS,
93            { 1 << (LOG_NUM_STRIPS) },
94            { 1 << MATMULT_ROWS_NUM_VARS },
95        >(
96            &decode_i32_array(MASK_RH_MULTIPLICAND),
97            &decode_i64_array(MASK_THRESHOLDS),
98        )
99    } else {
100        build_iriscode_circuit_auxiliary_data::<
101            F,
102            MATMULT_COLS_NUM_VARS,
103            MATMULT_INTERNAL_DIM_NUM_VARS,
104            { 1 << (LOG_NUM_STRIPS) },
105            { 1 << MATMULT_ROWS_NUM_VARS },
106        >(
107            &decode_i32_array(IRIS_RH_MULTIPLICAND),
108            &decode_i64_array(IRIS_THRESHOLDS),
109        )
110    }
111}
112
113/// Return the [Circuit] for the v3 iris code circuit.
114pub fn circuit_description() -> Result<Circuit<Fr>> {
115    let image_strip_reroutings = IMAGE_STRIP_WIRINGS
116        .iter()
117        .map(|wirings| {
118            wirings_to_reroutings(
119                &decode_wirings(wirings),
120                IM_STRIP_NUM_COLS,
121                IM_STRIP_NUM_COLS,
122            )
123        })
124        .collect::<Vec<_>>();
125    let lh_matrix_reroutings = wirings_to_reroutings(
126        &decode_wirings(LH_MATRIX_WIRINGS),
127        IM_STRIP_NUM_COLS,
128        1 << MATMULT_INTERNAL_DIM_NUM_VARS,
129    );
130    build_iriscode_circuit_description::<
131        Fr,
132        IM_STRIP_NUM_ROWS,
133        IM_STRIP_NUM_COLS,
134        IM_NUM_VARS,
135        MATMULT_ROWS_NUM_VARS,
136        MATMULT_COLS_NUM_VARS,
137        MATMULT_INTERNAL_DIM_NUM_VARS,
138        BASE,
139        NUM_DIGITS,
140    >(
141        LayerVisibility::Committed,
142        image_strip_reroutings,
143        lh_matrix_reroutings,
144    )
145}
146
147pub fn generate_iriscode_circuit_and_aux_data() -> V3CircuitAndAuxData<Fr> {
148    let iriscode_circuit = circuit_description().unwrap();
149
150    let iris_aux_data = build_worldcoin_aux_data(false);
151    let mask_aux_data = build_worldcoin_aux_data(true);
152
153    V3CircuitAndAuxData::new(iriscode_circuit, iris_aux_data, mask_aux_data)
154}
155
156/// Return the circuit description, and inputs for the iris code circuit, in either the mask (true)
157/// or iris (false) case.
158/// If `image_bytes` is `None`, the default test image is used.
159/// # Example:
160/// ```
161/// use frontend::zk_iriscode_ss::v3::circuit_description_and_inputs;
162/// let circuit_result = circuit_description_and_inputs(false, None);
163/// ```
164pub fn circuit_description_and_inputs(
165    is_mask: bool,
166    image_bytes: Option<Vec<u8>>,
167) -> Result<Circuit<Fr>> {
168    let image_bytes = if let Some(image_bytes) = image_bytes {
169        image_bytes
170    } else {
171        let image_type = if is_mask { "mask" } else { "iris" };
172        let prover_root_dir = env!("CARGO_MANIFEST_DIR");
173        let image_path =
174            format!("{prover_root_dir}/src/zk_iriscode_ss/constants/v3-split-images/{image_type}/test_image.bin");
175        read_bytes_from_file(&image_path)
176    };
177    let circuit = circuit_description().unwrap();
178    let aux_data = build_worldcoin_aux_data::<Fr>(is_mask);
179    let input_data = load_worldcoin_data::<Fr>(image_bytes, is_mask);
180    iriscode_ss_attach_input_data::<Fr, BASE>(circuit, input_data, aux_data)
181}