1use std::ops::{Index, IndexMut};
2
3use derive_more::derive::{Add, AddAssign, Sub, SubAssign};
4use primitives::{algebra::elliptic_curve::Curve, correlated_randomness::bundler::BundleConsumer};
5
6use crate::{
7 circuit::{
8 AlgebraicType,
9 BitShareBinaryOp,
10 Circuit,
11 FieldShareBinaryOp,
12 FieldShareUnaryOp,
13 FieldType,
14 Gate,
15 GateExt,
16 Input,
17 PointShareBinaryOp,
18 PointShareUnaryOp,
19 ShareOrPlaintext,
20 },
21 preprocessing::iterator::PreprocessingIterator,
22};
23
24pub(crate) const AES_S_BOX_N_NETWORK_ROUNDS: usize = 8;
29
30pub(crate) const AES_S_BOX_N_TRIPLES: usize = 34;
32
33#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Add, AddAssign, Sub, SubAssign)]
35pub struct FieldCircuitPreprocessing {
36 pub singlets: usize,
37 pub triples: usize,
38 pub dabits: usize,
39}
40
41#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Add, AddAssign, Sub, SubAssign)]
43pub struct CircuitPreprocessing {
44 pub bit_singlets: usize,
45 pub bit_triples: usize,
46 pub base_field: FieldCircuitPreprocessing,
47 pub scalar: FieldCircuitPreprocessing,
48 pub mersenne107: FieldCircuitPreprocessing,
49}
50
51impl Index<FieldType> for CircuitPreprocessing {
52 type Output = FieldCircuitPreprocessing;
53
54 fn index(&self, index: FieldType) -> &Self::Output {
55 match index {
56 FieldType::BaseField => &self.base_field,
57 FieldType::ScalarField => &self.scalar,
58 FieldType::Mersenne107 => &self.mersenne107,
59 }
60 }
61}
62
63impl IndexMut<FieldType> for CircuitPreprocessing {
64 fn index_mut(&mut self, index: FieldType) -> &mut Self::Output {
65 match index {
66 FieldType::BaseField => &mut self.base_field,
67 FieldType::ScalarField => &mut self.scalar,
68 FieldType::Mersenne107 => &mut self.mersenne107,
69 }
70 }
71}
72
73impl<C: Curve> BundleConsumer for Circuit<C> {
74 type Iterator = PreprocessingIterator<C>;
75
76 fn required_preprocessing(&self) -> CircuitPreprocessing {
77 let mut circuit_preprocessing = CircuitPreprocessing::default();
78 for gate in self.iter_gates_ext() {
79 self.add_to_required_preprocessing(gate, &mut circuit_preprocessing);
80 }
81 circuit_preprocessing
82 }
83}
84
85impl<C: Curve> Circuit<C> {
86 pub fn add_to_required_preprocessing(
88 &self,
89 gate: &GateExt<C>,
90 circuit_preprocessing: &mut CircuitPreprocessing,
91 ) {
92 let batch_size = gate.output.get_batch_size() as usize;
93 match &gate.gate {
94 Gate::Input(Input::SecretPlaintext { algebraic_type, .. })
95 | Gate::Random { algebraic_type, .. } => match algebraic_type {
96 AlgebraicType::ScalarField | AlgebraicType::Point => {
97 circuit_preprocessing.scalar.singlets += batch_size;
98 }
99 AlgebraicType::BaseField => {
100 circuit_preprocessing.base_field.singlets += batch_size;
101 }
102 AlgebraicType::Bit => {
103 circuit_preprocessing.bit_singlets += batch_size;
104 }
105 AlgebraicType::Mersenne107 => {
106 circuit_preprocessing.mersenne107.singlets += batch_size;
107 }
108 },
109 Gate::FieldShareUnaryOp { op, .. } => {
110 let field_type = gate.output.get_field_type_unchecked();
111 match op {
112 FieldShareUnaryOp::MulInverse | FieldShareUnaryOp::IsZero => {
113 circuit_preprocessing[field_type].triples += batch_size;
114 circuit_preprocessing[field_type].singlets += batch_size;
115 }
116 FieldShareUnaryOp::Open | FieldShareUnaryOp::Neg => (),
117 }
118 }
119 Gate::FieldShareBinaryOp { op, y, .. } => match op {
120 FieldShareBinaryOp::Mul => {
121 let field_type = gate.output.get_field_type_unchecked();
122 if self.gate_output_unchecked(*y).get_form() == ShareOrPlaintext::Share {
123 circuit_preprocessing[field_type].triples += batch_size;
124 }
125 }
126 FieldShareBinaryOp::Add => (),
127 },
128 Gate::PointShareUnaryOp { op, .. } => match op {
129 PointShareUnaryOp::IsZero => {
130 circuit_preprocessing.scalar.triples += batch_size;
131 circuit_preprocessing.scalar.singlets += batch_size;
132 }
133 PointShareUnaryOp::Open | PointShareUnaryOp::Neg => (),
134 },
135 Gate::PointShareBinaryOp { op, p, y, .. } => match op {
136 PointShareBinaryOp::ScalarMul => {
137 if self.gate_output_unchecked(*p).get_form() == ShareOrPlaintext::Share
138 && self.gate_output_unchecked(*y).get_form() == ShareOrPlaintext::Share
139 {
140 circuit_preprocessing.scalar.triples += batch_size;
141 }
142 }
143 PointShareBinaryOp::Add => (),
144 },
145 Gate::BitShareBinaryOp { op, y, .. } => match op {
146 BitShareBinaryOp::And | BitShareBinaryOp::Or => {
147 if self.gate_output_unchecked(*y).get_form() == ShareOrPlaintext::Share {
148 circuit_preprocessing.bit_triples += batch_size;
149 }
150 }
151 BitShareBinaryOp::Xor => (),
152 },
153 Gate::BaseFieldPow { .. } => {
154 unimplemented!("Removed from the Bundler, need to choose exponent to set it back.")
155 }
156 Gate::DaBit { field_type, .. } => {
157 circuit_preprocessing[*field_type].dabits += batch_size
158 }
159
160 Gate::Input(_)
161 | Gate::Constant { .. }
162 | Gate::BatchSummation { .. }
163 | Gate::BitShareUnaryOp { .. }
164 | Gate::FieldPlaintextUnaryOp { .. }
165 | Gate::FieldPlaintextBinaryOp { .. }
166 | Gate::BitPlaintextUnaryOp { .. }
167 | Gate::BitPlaintextBinaryOp { .. }
168 | Gate::PointPlaintextUnaryOp { .. }
169 | Gate::PointPlaintextBinaryOp { .. }
170 | Gate::GetDaBitFieldShare { .. }
171 | Gate::GetDaBitSharedBit { .. }
172 | Gate::BitPlaintextToField { .. }
173 | Gate::FieldPlaintextToBit { .. }
174 | Gate::ExtractFromBatch { .. }
175 | Gate::CollectToBatch { .. }
176 | Gate::PointFromPlaintextCoordinates { .. }
177 | Gate::PlaintextPointToCoordinates { .. }
178 | Gate::PlaintextKeccakF1600 { .. }
179 | Gate::CompressPlaintextPoint { .. }
180 | Gate::KeyRecoveryPlaintextComputeErrors { .. } => (),
181 #[cfg(any(test, feature = "dev"))]
182 Gate::AesKeySchedule { key, .. } => {
183 let key_length = self.gate_ext(*key).map(|g| g.output.batch_size).ok();
184 circuit_preprocessing.bit_triples += key_length
185 .and_then(|len| n_triples_aes_key_schedule(len as usize))
186 .expect("Something went wrong with Circuit::add_to_required_preprocessing for Gate::AesKeySchedule")
187 }
188 Gate::AesGcmKeyStream {
189 round_keys,
190 n_ciphertext_blocks,
191 ..
192 } => {
193 let round_keys_length =
194 self.gate_ext(*round_keys).map(|g| g.output.batch_size).ok();
195 circuit_preprocessing.bit_triples += round_keys_length
196 .and_then(|len| {
197 n_triples_aes_gcm_key_stream(len as usize, *n_ciphertext_blocks)
198 })
199 .expect("Something went wrong with Circuit::add_to_required_preprocessing for Gate::AesGcmKeyStream")
200 }
201 };
202 }
203}
204
205pub fn n_triples_aes_key_schedule(security_level: usize) -> Option<usize> {
206 let n_sub_bytes_calls = match security_level {
207 128 => Some(10),
208 192 => Some(8),
209 256 => Some(13),
210 _ => None,
211 };
212 n_sub_bytes_calls.map(|n_calls| 4 * AES_S_BOX_N_TRIPLES * n_calls)
214}
215
216pub fn n_triples_aes_gcm_key_stream(
217 round_keys_length: usize,
218 n_ciphertext_blocks: u32,
219) -> Option<usize> {
220 let n_rounds = match round_keys_length {
223 1408 => Some(10),
224 1664 => Some(12),
225 1920 => Some(14),
226 _ => None,
227 };
228 n_rounds.map(|n| {
232 AES_S_BOX_N_TRIPLES
233 * (12
234 + 4 * (1 + n_ciphertext_blocks as usize)
235 + (n - 1) * 16 * (1 + n_ciphertext_blocks as usize))
236 })
237}
238
239#[cfg(test)]
240mod tests {
241 use crate::circuit::preprocessing::{CircuitPreprocessing, FieldCircuitPreprocessing};
242
243 #[test]
244 fn test_circuit_preprocessing_add() {
245 let a = CircuitPreprocessing {
246 bit_singlets: 0,
247 bit_triples: 1,
248 base_field: FieldCircuitPreprocessing {
249 singlets: 3,
250 triples: 4,
251 dabits: 2,
252 },
253 scalar: FieldCircuitPreprocessing {
254 singlets: 1,
255 triples: 2,
256 dabits: 1,
257 },
258 mersenne107: FieldCircuitPreprocessing {
259 singlets: 0,
260 triples: 0,
261 dabits: 0,
262 },
263 };
264 let b = CircuitPreprocessing {
265 bit_singlets: 3,
266 bit_triples: 4,
267 base_field: FieldCircuitPreprocessing {
268 singlets: 0,
269 triples: 5,
270 dabits: 3,
271 },
272 scalar: FieldCircuitPreprocessing {
273 singlets: 2,
274 triples: 3,
275 dabits: 2,
276 },
277 mersenne107: FieldCircuitPreprocessing {
278 singlets: 3,
279 triples: 2,
280 dabits: 0,
281 },
282 };
283
284 let c = a + b;
285
286 assert_eq!(c.scalar.singlets, 3);
287 assert_eq!(c.scalar.triples, 5);
288 assert_eq!(c.base_field.singlets, 3);
289 assert_eq!(c.base_field.triples, 9);
290 assert_eq!(c.bit_singlets, 3);
291 assert_eq!(c.bit_triples, 5);
292 assert_eq!(c.mersenne107.dabits, 0);
293 assert_eq!(c.mersenne107.singlets, 3);
294 assert_eq!(c.mersenne107.triples, 2);
295 assert_eq!(c.scalar.dabits, 3);
296 assert_eq!(c.base_field.dabits, 5);
297 }
298}