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
24#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Add, AddAssign, Sub, SubAssign)]
26pub struct FieldCircuitPreprocessing {
27 pub singlets: usize,
28 pub triples: usize,
29 pub dabits: usize,
30}
31
32#[derive(Debug, Copy, Clone, Default, PartialEq, Eq, Add, AddAssign, Sub, SubAssign)]
34pub struct CircuitPreprocessing {
35 pub bit_singlets: usize,
36 pub bit_triples: usize,
37 pub base_field: FieldCircuitPreprocessing,
38 pub scalar: FieldCircuitPreprocessing,
39 pub mersenne107: FieldCircuitPreprocessing,
40}
41
42impl Index<FieldType> for CircuitPreprocessing {
43 type Output = FieldCircuitPreprocessing;
44
45 fn index(&self, index: FieldType) -> &Self::Output {
46 match index {
47 FieldType::BaseField => &self.base_field,
48 FieldType::ScalarField => &self.scalar,
49 FieldType::Mersenne107 => &self.mersenne107,
50 }
51 }
52}
53
54impl IndexMut<FieldType> for CircuitPreprocessing {
55 fn index_mut(&mut self, index: FieldType) -> &mut Self::Output {
56 match index {
57 FieldType::BaseField => &mut self.base_field,
58 FieldType::ScalarField => &mut self.scalar,
59 FieldType::Mersenne107 => &mut self.mersenne107,
60 }
61 }
62}
63
64impl<C: Curve> BundleConsumer for Circuit<C> {
65 type Iterator = PreprocessingIterator<C>;
66
67 fn required_preprocessing(&self) -> CircuitPreprocessing {
68 let mut circuit_preprocessing = CircuitPreprocessing::default();
69 for gate in self.iter_gates_ext() {
70 self.add_to_required_preprocessing(gate, &mut circuit_preprocessing);
71 }
72 circuit_preprocessing
73 }
74}
75
76impl<C: Curve> Circuit<C> {
77 pub fn add_to_required_preprocessing(
79 &self,
80 gate: &GateExt<C>,
81 circuit_preprocessing: &mut CircuitPreprocessing,
82 ) {
83 let batch_size = gate.output.get_batch_size() as usize;
84 match &gate.gate {
85 Gate::Input(Input::SecretPlaintext { algebraic_type, .. })
86 | Gate::Random { algebraic_type, .. } => match algebraic_type {
87 AlgebraicType::ScalarField | AlgebraicType::Point => {
88 circuit_preprocessing.scalar.singlets += batch_size;
89 }
90 AlgebraicType::BaseField => {
91 circuit_preprocessing.base_field.singlets += batch_size;
92 }
93 AlgebraicType::Bit => {
94 circuit_preprocessing.bit_singlets += batch_size;
95 }
96 AlgebraicType::Mersenne107 => {
97 circuit_preprocessing.mersenne107.singlets += batch_size;
98 }
99 },
100 Gate::FieldShareUnaryOp { op, .. } => {
101 let field_type = gate.output.get_field_type_unchecked();
102 match op {
103 FieldShareUnaryOp::MulInverse | FieldShareUnaryOp::IsZero => {
104 circuit_preprocessing[field_type].triples += batch_size;
105 circuit_preprocessing[field_type].singlets += batch_size;
106 }
107 FieldShareUnaryOp::Open | FieldShareUnaryOp::Neg => (),
108 }
109 }
110 Gate::FieldShareBinaryOp { op, y, .. } => match op {
111 FieldShareBinaryOp::Mul => {
112 let field_type = gate.output.get_field_type_unchecked();
113 if self.gate_output_unchecked(*y).get_form() == ShareOrPlaintext::Share {
114 circuit_preprocessing[field_type].triples += batch_size;
115 }
116 }
117 FieldShareBinaryOp::Add => (),
118 },
119 Gate::PointShareUnaryOp { op, .. } => match op {
120 PointShareUnaryOp::IsZero => {
121 circuit_preprocessing.scalar.triples += batch_size;
122 circuit_preprocessing.scalar.singlets += batch_size;
123 }
124 PointShareUnaryOp::Open | PointShareUnaryOp::Neg => (),
125 },
126 Gate::PointShareBinaryOp { op, p, y, .. } => match op {
127 PointShareBinaryOp::ScalarMul => {
128 if self.gate_output_unchecked(*p).get_form() == ShareOrPlaintext::Share
129 && self.gate_output_unchecked(*y).get_form() == ShareOrPlaintext::Share
130 {
131 circuit_preprocessing.scalar.triples += batch_size;
132 }
133 }
134 PointShareBinaryOp::Add => (),
135 },
136 Gate::BitShareBinaryOp { op, y, .. } => match op {
137 BitShareBinaryOp::And | BitShareBinaryOp::Or => {
138 if self.gate_output_unchecked(*y).get_form() == ShareOrPlaintext::Share {
139 circuit_preprocessing.bit_triples += batch_size;
140 }
141 }
142 BitShareBinaryOp::Xor => (),
143 },
144 Gate::BaseFieldPow { .. } => {
145 unimplemented!("Removed from the Bundler, need to choose exponent to set it back.")
146 }
147 Gate::DaBit { field_type, .. } => {
148 circuit_preprocessing[*field_type].dabits += batch_size
149 }
150
151 Gate::Input(_)
152 | Gate::Constant { .. }
153 | Gate::BatchSummation { .. }
154 | Gate::BitShareUnaryOp { .. }
155 | Gate::FieldPlaintextUnaryOp { .. }
156 | Gate::FieldPlaintextBinaryOp { .. }
157 | Gate::BitPlaintextUnaryOp { .. }
158 | Gate::BitPlaintextBinaryOp { .. }
159 | Gate::PointPlaintextUnaryOp { .. }
160 | Gate::PointPlaintextBinaryOp { .. }
161 | Gate::GetDaBitFieldShare { .. }
162 | Gate::GetDaBitSharedBit { .. }
163 | Gate::BitPlaintextToField { .. }
164 | Gate::FieldPlaintextToBit { .. }
165 | Gate::ExtractFromBatch { .. }
166 | Gate::CollectToBatch { .. }
167 | Gate::PointFromPlaintextExtendedEdwards { .. }
168 | Gate::PlaintextPointToExtendedEdwards { .. }
169 | Gate::PlaintextKeccakF1600 { .. }
170 | Gate::CompressPlaintextPoint { .. }
171 | Gate::KeyRecoveryPlaintextComputeErrors { .. } => (),
172 };
173 }
174}
175
176#[cfg(test)]
177mod tests {
178 use crate::circuit::preprocessing::{CircuitPreprocessing, FieldCircuitPreprocessing};
179
180 #[test]
181 fn test_circuit_preprocessing_add() {
182 let a = CircuitPreprocessing {
183 bit_singlets: 0,
184 bit_triples: 1,
185 base_field: FieldCircuitPreprocessing {
186 singlets: 3,
187 triples: 4,
188 dabits: 2,
189 },
190 scalar: FieldCircuitPreprocessing {
191 singlets: 1,
192 triples: 2,
193 dabits: 1,
194 },
195 mersenne107: FieldCircuitPreprocessing {
196 singlets: 0,
197 triples: 0,
198 dabits: 0,
199 },
200 };
201 let b = CircuitPreprocessing {
202 bit_singlets: 3,
203 bit_triples: 4,
204 base_field: FieldCircuitPreprocessing {
205 singlets: 0,
206 triples: 5,
207 dabits: 3,
208 },
209 scalar: FieldCircuitPreprocessing {
210 singlets: 2,
211 triples: 3,
212 dabits: 2,
213 },
214 mersenne107: FieldCircuitPreprocessing {
215 singlets: 3,
216 triples: 2,
217 dabits: 0,
218 },
219 };
220
221 let c = a + b;
222
223 assert_eq!(c.scalar.singlets, 3);
224 assert_eq!(c.scalar.triples, 5);
225 assert_eq!(c.base_field.singlets, 3);
226 assert_eq!(c.base_field.triples, 9);
227 assert_eq!(c.bit_singlets, 3);
228 assert_eq!(c.bit_triples, 5);
229 assert_eq!(c.mersenne107.dabits, 0);
230 assert_eq!(c.mersenne107.singlets, 3);
231 assert_eq!(c.mersenne107.triples, 2);
232 assert_eq!(c.scalar.dabits, 3);
233 assert_eq!(c.base_field.dabits, 5);
234 }
235}