Skip to main content

core_utils/circuit/v2/
preprocessing.rs

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/// Field specific preprocessing requirements for a circuit.
25#[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/// Preprocessing requirements for a circuit.
33#[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    /// Updates the circuit preprocessing structure with the requirements of this gate.
78    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}