frontend/worldcoin_mpc/
circuits.rs

1#![allow(clippy::type_complexity)]
2use ark_std::log2;
3use shared_types::Field;
4
5use crate::{
6    hyrax_worldcoin_mpc::mpc_prover::MPCCircuitConstData,
7    layouter::builder::{Circuit, CircuitBuilder, LayerVisibility},
8    worldcoin_mpc::{
9        components::WorldcoinMpcComponents,
10        parameters::{GR4_ELEM_BIT_LENGTH, GR4_MULTIPLICATION_WIRINGS},
11    },
12};
13use remainder::layer::gate::BinaryOperation;
14
15use super::{
16    data::MPCCircuitInputData,
17    parameters::{ENCODING_MATRIX_NUM_VARS_COLS, ENCODING_MATRIX_NUM_VARS_ROWS},
18};
19
20/// The input layer for quotients and multiplicities
21pub const MPC_AUXILIARY_LAYER: &str = "Auxiliary"; // Should be private + depend on party.
22/// all other public inputs, such as the evaluation points, the encoding matrix,
23/// the lookup_table_values. Should (probably) be public + common among parties.
24pub const MPC_AUXILIARY_INVARIANT_LAYER: &str = "Auxiliary Invariant";
25/// The input layer for shares_reduced_modulo_gr4_modulus, public
26pub const MPC_SHARES_LAYER: &str = "Shares";
27/// The private input layer for the slope (private and generated randomly).
28pub const MPC_SLOPES_LAYER: &str = "Slopes";
29/// The private input layer for the iris code (private), obtained through
30/// running the iriscode circuit
31pub const MPC_IRISCODE_INPUT_LAYER: &str = "Iris Code Input";
32/// The private input layer for the mask code (private),  obtained through
33/// running the iriscode circuit
34pub const MPC_MASKCODE_INPUT_LAYER: &str = "Mask Code Input";
35
36pub const MPC_IRISCODE_SHRED: &str = "Iris Code Input";
37pub const MPC_MASKCODE_SHRED: &str = "Mask Code Input";
38pub const MPC_SLOPES_SHRED: &str = "Slopes";
39pub const MPC_QUOTIENTS_SHRED: &str = "Quotients";
40pub const MPC_SHARES_SHRED: &str = "Shares Reduced Modulo GR4 Modulus";
41pub const MPC_MULTIPLICITIES_SHARES_SHRED: &str = "Multiplicities Shares";
42pub const MPC_MULTIPLICITIES_SLOPES_SHRED: &str = "Multiplicities Slopes";
43pub const MPC_ENCODING_MATRIX_SHRED: &str = "Encoding Matrix";
44pub const MPC_EVALUATION_POINTS_SHRED: &str = "Evaluation Points";
45pub const MPC_LOOKUP_TABLE_VALUES_SHRED: &str = "Lookup Table Values";
46
47/// Builds the mpc circuit.
48/// The full circuit spec can be referenced here:
49/// <https://www.notion.so/MPC-Circuit-Builders-8fe15c8d8f4b4db18cbf85344ccbb9df?pvs=4>
50///
51/// To summerize, this circuit takes in slope, iris code and mask code as private inputs,
52/// computes the masked iris code, encodes the masked iris code to a GR4 element.
53/// Then, the circuit does a GR4 multiplication between the evaluation points and the slopes.
54/// The result is then summed with the masked iris code to get the computed shares.
55/// The quotients, shares_reduced_modulo_gr4_modulus are to count for congruency (modulo 2^16).
56pub fn build_circuit<F: Field, const NUM_IRIS_4_CHUNKS: usize>(
57    layer_visibility: LayerVisibility,
58) -> Circuit<F> {
59    let mut builder = CircuitBuilder::<F>::new();
60
61    let num_vars_dataparallel = log2(NUM_IRIS_4_CHUNKS) as usize;
62    // the 2 extra num_vars are for the 4 chunks of the iris code (every 4 iris code values
63    // are combined into a single GR4 elements)
64    let num_vars = num_vars_dataparallel + 2;
65
66    let auxilary_input_layer_node = builder.add_input_layer(MPC_AUXILIARY_LAYER, layer_visibility);
67    let shares_input_layer_node =
68        builder.add_input_layer(MPC_SHARES_LAYER, LayerVisibility::Public);
69    let auxiliary_invariant_public_input_layer_node =
70        builder.add_input_layer(MPC_AUXILIARY_INVARIANT_LAYER, LayerVisibility::Public);
71    let slope_input_layer_node = builder.add_input_layer(MPC_SLOPES_LAYER, layer_visibility);
72    let iris_code_input_layer_node =
73        builder.add_input_layer(MPC_IRISCODE_INPUT_LAYER, layer_visibility);
74    let mask_code_input_layer_node =
75        builder.add_input_layer(MPC_MASKCODE_INPUT_LAYER, layer_visibility);
76
77    let iris_code =
78        builder.add_input_shred(MPC_IRISCODE_SHRED, num_vars, &iris_code_input_layer_node);
79    let mask_code =
80        builder.add_input_shred(MPC_MASKCODE_SHRED, num_vars, &mask_code_input_layer_node);
81    let slopes = builder.add_input_shred(MPC_SLOPES_SHRED, num_vars, &slope_input_layer_node);
82    let quotients =
83        builder.add_input_shred(MPC_QUOTIENTS_SHRED, num_vars, &auxilary_input_layer_node);
84    let shares_reduced_modulo_gr4_modulus =
85        builder.add_input_shred(MPC_SHARES_SHRED, num_vars, &shares_input_layer_node);
86    let multiplicities_shares = builder.add_input_shred(
87        MPC_MULTIPLICITIES_SHARES_SHRED,
88        GR4_ELEM_BIT_LENGTH as usize,
89        &auxilary_input_layer_node,
90    );
91    let multiplicities_slopes = builder.add_input_shred(
92        MPC_MULTIPLICITIES_SLOPES_SHRED,
93        GR4_ELEM_BIT_LENGTH as usize,
94        &auxilary_input_layer_node,
95    );
96
97    let encoding_matrix = builder.add_input_shred(
98        MPC_ENCODING_MATRIX_SHRED,
99        ENCODING_MATRIX_NUM_VARS_ROWS + ENCODING_MATRIX_NUM_VARS_COLS,
100        &auxiliary_invariant_public_input_layer_node,
101    );
102    let evaluation_points = builder.add_input_shred(
103        MPC_EVALUATION_POINTS_SHRED,
104        num_vars,
105        &auxiliary_invariant_public_input_layer_node,
106    );
107
108    let lookup_table_values = builder.add_input_shred(
109        MPC_LOOKUP_TABLE_VALUES_SHRED,
110        GR4_ELEM_BIT_LENGTH as usize,
111        &auxiliary_invariant_public_input_layer_node,
112    );
113    let fiat_shamir_challenge_node = builder.add_fiat_shamir_challenge_node(1);
114    let lookup_table = builder.add_lookup_table(&lookup_table_values, &fiat_shamir_challenge_node);
115
116    let masked_iris_code =
117        WorldcoinMpcComponents::masked_iris_code(&mut builder, &iris_code, &mask_code);
118    // The matrix multiplication node encodes the masked iris code to a GR4 element
119    let encoded_masked_iris_code = builder.add_matmult_node(
120        &masked_iris_code,
121        (num_vars_dataparallel, ENCODING_MATRIX_NUM_VARS_ROWS),
122        &encoding_matrix,
123        (ENCODING_MATRIX_NUM_VARS_ROWS, ENCODING_MATRIX_NUM_VARS_COLS),
124    );
125
126    // The gate node performs a GR4 multiplication between the evaluation points and the slopes
127    let evaluation_points_times_slopes = builder.add_gate_node(
128        &evaluation_points,
129        &slopes,
130        GR4_MULTIPLICATION_WIRINGS.to_vec(),
131        BinaryOperation::Mul,
132        Some(num_vars_dataparallel),
133    );
134
135    let computed_shares = WorldcoinMpcComponents::sum(
136        &mut builder,
137        &encoded_masked_iris_code,
138        &evaluation_points_times_slopes,
139    );
140
141    let _congruence = WorldcoinMpcComponents::congruence(
142        &mut builder,
143        &quotients,
144        &computed_shares,
145        &shares_reduced_modulo_gr4_modulus,
146    );
147
148    let _lookup_constraint_shares = builder.add_lookup_constraint(
149        &lookup_table,
150        &shares_reduced_modulo_gr4_modulus,
151        &multiplicities_shares,
152    );
153
154    let _lookup_constraint_slopes =
155        builder.add_lookup_constraint(&lookup_table, &slopes, &multiplicities_slopes);
156
157    builder.build_without_layer_combination().unwrap()
158}
159
160/// Generates a mapping from Layer IDs to their respective MLEs,
161/// by attaching the `MPCInputBuilderMetadata` onto a circuit that is
162/// described through the `input_builder_metadata` of an MPC secret share circuit.
163pub fn mpc_attach_data<F: Field>(
164    circuit: &mut Circuit<F>,
165    mpc_aux_data: MPCCircuitConstData<F>,
166    mpc_input_data: MPCCircuitInputData<F>,
167) {
168    circuit.set_input(MPC_IRISCODE_SHRED, mpc_input_data.iris_codes);
169    circuit.set_input(MPC_MASKCODE_SHRED, mpc_input_data.masks);
170    circuit.set_input(MPC_SLOPES_SHRED, mpc_input_data.slopes);
171    circuit.set_input(MPC_QUOTIENTS_SHRED, mpc_input_data.quotients);
172    circuit.set_input(
173        MPC_SHARES_SHRED,
174        mpc_input_data.shares_reduced_modulo_gr4_modulus,
175    );
176    circuit.set_input(
177        MPC_MULTIPLICITIES_SHARES_SHRED,
178        mpc_input_data.multiplicities_shares,
179    );
180    circuit.set_input(
181        MPC_MULTIPLICITIES_SLOPES_SHRED,
182        mpc_input_data.multiplicities_slopes,
183    );
184    circuit.set_input(MPC_ENCODING_MATRIX_SHRED, mpc_aux_data.encoding_matrix);
185    circuit.set_input(MPC_EVALUATION_POINTS_SHRED, mpc_aux_data.evaluation_points);
186    circuit.set_input(
187        MPC_LOOKUP_TABLE_VALUES_SHRED,
188        mpc_aux_data.lookup_table_values,
189    );
190}