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
32pub 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
113pub 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
156pub 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}