1use std::hash::Hash;
2
3use primitives::algebra::{
4 elliptic_curve::{Curve, Point, Scalar},
5 BoxedUint,
6};
7use serde::{Deserialize, Serialize};
8use wincode::{SchemaRead, SchemaWrite};
9
10use crate::circuit::{
11 errors::CircuitError,
12 AlgebraicType,
13 BatchSize,
14 BitPlaintextBinaryOp,
15 BitPlaintextUnaryOp,
16 BitShareBinaryOp,
17 BitShareUnaryOp,
18 Constant,
19 FieldPlaintextBinaryOp,
20 FieldPlaintextUnaryOp,
21 FieldShareBinaryOp,
22 FieldShareUnaryOp,
23 FieldType,
24 GateIndex,
25 Input,
26 PointPlaintextBinaryOp,
27 PointPlaintextUnaryOp,
28 PointShareBinaryOp,
29 PointShareUnaryOp,
30 Slice,
31};
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize, SchemaRead, SchemaWrite)]
35#[serde(bound(
36 serialize = "Scalar<C>: Serialize, Point<C>: Serialize",
37 deserialize = "Scalar<C>: Deserialize<'de>, Point<C>: Deserialize<'de>"
38))]
39#[repr(C)]
40pub enum Gate<C: Curve> {
41 Input(Input),
43 Constant(Constant<C>),
45 Random {
47 algebraic_type: AlgebraicType,
48 batch_size: BatchSize,
49 },
50 FieldShareUnaryOp {
52 x: GateIndex,
53 op: FieldShareUnaryOp,
54 },
55 FieldShareBinaryOp {
57 x: GateIndex,
58 y: GateIndex,
59 op: FieldShareBinaryOp,
60 },
61 BatchSummation {
62 x: GateIndex,
63 },
64 BitShareUnaryOp {
65 x: GateIndex,
66 op: BitShareUnaryOp,
67 },
68 BitShareBinaryOp {
69 x: GateIndex,
70 y: GateIndex,
71 op: BitShareBinaryOp,
72 },
73 PointShareUnaryOp {
75 p: GateIndex,
76 op: PointShareUnaryOp,
77 },
78 PointShareBinaryOp {
79 p: GateIndex,
80 y: GateIndex,
81 op: PointShareBinaryOp,
82 },
83 FieldPlaintextUnaryOp {
85 x: GateIndex,
86 op: FieldPlaintextUnaryOp,
87 },
88 FieldPlaintextBinaryOp {
90 x: GateIndex,
91 y: GateIndex,
92 op: FieldPlaintextBinaryOp,
93 },
94 BitPlaintextUnaryOp {
95 x: GateIndex,
96 op: BitPlaintextUnaryOp,
97 },
98 BitPlaintextBinaryOp {
99 x: GateIndex,
100 y: GateIndex,
101 op: BitPlaintextBinaryOp,
102 },
103 PointPlaintextUnaryOp {
104 p: GateIndex,
105 op: PointPlaintextUnaryOp,
106 },
107 PointPlaintextBinaryOp {
108 p: GateIndex,
109 y: GateIndex,
110 op: PointPlaintextBinaryOp,
111 },
112 DaBit {
114 field_type: FieldType,
115 batch_size: BatchSize,
116 },
117 GetDaBitFieldShare {
118 x: GateIndex,
119 },
120 GetDaBitSharedBit {
121 x: GateIndex,
122 },
123 BaseFieldPow {
125 x: GateIndex,
126 exp: BoxedUint,
127 },
128 BitPlaintextToField {
130 x: GateIndex,
131 field_type: FieldType,
132 },
133 FieldPlaintextToBit {
134 x: GateIndex,
135 },
136 ExtractFromBatch {
138 x: GateIndex,
139 slice: Slice,
140 },
141 CollectToBatch {
142 wires: Vec<GateIndex>,
143 },
144 PointFromPlaintextCoordinates {
145 wires: Vec<GateIndex>,
146 },
147 PlaintextPointToCoordinates {
148 point: GateIndex,
149 },
150 PlaintextKeccakF1600 {
151 x: GateIndex,
152 },
153 CompressPlaintextPoint {
154 point: GateIndex,
155 },
156 KeyRecoveryPlaintextComputeErrors {
157 d_minus_one: GateIndex,
158 syndromes: GateIndex,
159 },
160 AesGcmKeyStream {
161 round_keys: GateIndex,
162 iv: GateIndex,
163 n_ciphertext_blocks: u32,
164 },
165 #[cfg(any(test, feature = "dev"))]
166 AesKeySchedule {
167 key: GateIndex,
168 },
169}
170
171impl<C: Curve> Gate<C> {
172 pub fn is_input(&self) -> bool {
174 matches!(self, Gate::Input { .. })
175 }
176
177 pub fn get_inputs(&self) -> Vec<GateIndex> {
179 match &self {
180 Gate::Input(_) | Gate::Random { .. } | Gate::Constant(_) | Gate::DaBit { .. } => {
181 Vec::new()
182 }
183
184 Gate::FieldShareUnaryOp { x, .. }
185 | Gate::BatchSummation { x, .. }
186 | Gate::BitShareUnaryOp { x, .. }
187 | Gate::PointShareUnaryOp { p: x, .. }
188 | Gate::FieldPlaintextUnaryOp { x, .. }
189 | Gate::BitPlaintextUnaryOp { x, .. }
190 | Gate::PointPlaintextUnaryOp { p: x, .. }
191 | Gate::GetDaBitFieldShare { x, .. }
192 | Gate::GetDaBitSharedBit { x, .. }
193 | Gate::BaseFieldPow { x, .. }
194 | Gate::BitPlaintextToField { x, .. }
195 | Gate::FieldPlaintextToBit { x, .. }
196 | Gate::ExtractFromBatch { x, .. }
197 | Gate::PlaintextPointToCoordinates { point: x, .. }
198 | Gate::CompressPlaintextPoint { point: x, .. }
199 | Gate::PlaintextKeccakF1600 { x } => {
200 vec![*x]
201 }
202 #[cfg(any(test, feature = "dev"))]
203 Gate::AesKeySchedule { key } => {
204 vec![*key]
205 }
206
207 Gate::FieldShareBinaryOp { x, y, .. }
208 | Gate::BitShareBinaryOp { x, y, .. }
209 | Gate::PointShareBinaryOp { p: x, y, .. }
210 | Gate::FieldPlaintextBinaryOp { x, y, .. }
211 | Gate::BitPlaintextBinaryOp { x, y, .. }
212 | Gate::PointPlaintextBinaryOp { p: x, y, .. }
213 | Gate::KeyRecoveryPlaintextComputeErrors {
214 d_minus_one: x,
215 syndromes: y,
216 ..
217 }
218 | Gate::AesGcmKeyStream {
219 round_keys: x,
220 iv: y,
221 ..
222 } => {
223 vec![*x, *y]
224 }
225
226 Gate::CollectToBatch { wires, .. }
227 | Gate::PointFromPlaintextCoordinates { wires, .. } => wires.clone(),
228 }
229 }
230
231 pub fn map_inputs<F: FnMut(GateIndex) -> GateIndex>(mut self, mut f: F) -> Self {
233 match &mut self {
234 Gate::Input(_) | Gate::Random { .. } | Gate::Constant(_) | Gate::DaBit { .. } => (),
235
236 Gate::FieldShareUnaryOp { x, .. }
237 | Gate::BatchSummation { x, .. }
238 | Gate::BitShareUnaryOp { x, .. }
239 | Gate::PointShareUnaryOp { p: x, .. }
240 | Gate::FieldPlaintextUnaryOp { x, .. }
241 | Gate::BitPlaintextUnaryOp { x, .. }
242 | Gate::PointPlaintextUnaryOp { p: x, .. }
243 | Gate::GetDaBitFieldShare { x, .. }
244 | Gate::GetDaBitSharedBit { x, .. }
245 | Gate::BaseFieldPow { x, .. }
246 | Gate::BitPlaintextToField { x, .. }
247 | Gate::FieldPlaintextToBit { x, .. }
248 | Gate::ExtractFromBatch { x, .. }
249 | Gate::PlaintextPointToCoordinates { point: x, .. }
250 | Gate::CompressPlaintextPoint { point: x, .. }
251 | Gate::PlaintextKeccakF1600 { x } => {
252 *x = f(*x);
253 }
254
255 #[cfg(any(test, feature = "dev"))]
256 Gate::AesKeySchedule { key } => {
257 *key = f(*key);
258 }
259
260 Gate::FieldShareBinaryOp { x, y, .. }
261 | Gate::BitShareBinaryOp { x, y, .. }
262 | Gate::PointShareBinaryOp { p: x, y, .. }
263 | Gate::FieldPlaintextBinaryOp { x, y, .. }
264 | Gate::BitPlaintextBinaryOp { x, y, .. }
265 | Gate::PointPlaintextBinaryOp { p: x, y, .. }
266 | Gate::KeyRecoveryPlaintextComputeErrors {
267 d_minus_one: x,
268 syndromes: y,
269 ..
270 }
271 | Gate::AesGcmKeyStream {
272 round_keys: x,
273 iv: y,
274 ..
275 } => {
276 *x = f(*x);
277 *y = f(*y);
278 }
279
280 Gate::CollectToBatch { wires, .. }
281 | Gate::PointFromPlaintextCoordinates { wires, .. } => {
282 wires.iter_mut().for_each(|x| *x = f(*x))
283 }
284 };
285
286 self
287 }
288
289 pub fn try_replace_inputs(mut self, inputs: Vec<GateIndex>) -> Result<Self, CircuitError<C>> {
294 if inputs.len() != self.get_inputs().len() {
295 return Err(CircuitError::InvalidGateInputCount {
296 expected: self.get_inputs().len(),
297 found: inputs.len(),
298 });
299 }
300
301 match &mut self {
302 Gate::Input(_) | Gate::Random { .. } | Gate::Constant(_) | Gate::DaBit { .. } => (),
303
304 Gate::FieldShareUnaryOp { x, .. }
305 | Gate::BatchSummation { x, .. }
306 | Gate::BitShareUnaryOp { x, .. }
307 | Gate::PointShareUnaryOp { p: x, .. }
308 | Gate::FieldPlaintextUnaryOp { x, .. }
309 | Gate::BitPlaintextUnaryOp { x, .. }
310 | Gate::PointPlaintextUnaryOp { p: x, .. }
311 | Gate::GetDaBitFieldShare { x, .. }
312 | Gate::GetDaBitSharedBit { x, .. }
313 | Gate::BaseFieldPow { x, .. }
314 | Gate::BitPlaintextToField { x, .. }
315 | Gate::FieldPlaintextToBit { x, .. }
316 | Gate::ExtractFromBatch { x, .. }
317 | Gate::PlaintextPointToCoordinates { point: x, .. }
318 | Gate::CompressPlaintextPoint { point: x, .. }
319 | Gate::PlaintextKeccakF1600 { x } => {
320 *x = inputs[0];
321 }
322 #[cfg(any(test, feature = "dev"))]
323 Gate::AesKeySchedule { key } => {
324 *key = inputs[0];
325 }
326
327 Gate::FieldShareBinaryOp { x, y, .. }
328 | Gate::BitShareBinaryOp { x, y, .. }
329 | Gate::PointShareBinaryOp { p: x, y, .. }
330 | Gate::FieldPlaintextBinaryOp { x, y, .. }
331 | Gate::BitPlaintextBinaryOp { x, y, .. }
332 | Gate::PointPlaintextBinaryOp { p: x, y, .. }
333 | Gate::KeyRecoveryPlaintextComputeErrors {
334 d_minus_one: x,
335 syndromes: y,
336 ..
337 }
338 | Gate::AesGcmKeyStream {
339 round_keys: x,
340 iv: y,
341 ..
342 } => {
343 *x = inputs[0];
344 *y = inputs[1];
345 }
346
347 Gate::CollectToBatch { wires, .. }
348 | Gate::PointFromPlaintextCoordinates { wires, .. } => *wires = inputs,
349 };
350
351 Ok(self)
352 }
353}
354
355#[cfg(test)]
356mod tests {
357 use std::collections::HashSet;
358
359 use primitives::algebra::elliptic_curve::Curve25519Ristretto as C;
360
361 use super::*;
362 use crate::circuit::FieldShareBinaryOp;
363
364 #[test]
365 fn test_ser_gate() {
366 let scalar_gate: Gate<C> = Gate::FieldShareBinaryOp {
367 x: 1,
368 y: 3,
369 op: FieldShareBinaryOp::Add,
370 };
371 let point_gate: Gate<C> = Gate::PointShareBinaryOp {
372 p: 1,
373 y: 3,
374 op: PointShareBinaryOp::Add,
375 };
376
377 let scalar_gate_ser = bincode::serialize(&scalar_gate).unwrap();
378 let point_gate_ser = bincode::serialize(&point_gate).unwrap();
379
380 let scalar_gate_de: Gate<C> = bincode::deserialize(&scalar_gate_ser).unwrap();
381 let point_gate_de: Gate<C> = bincode::deserialize(&point_gate_ser).unwrap();
382
383 assert_eq!(scalar_gate, scalar_gate_de);
384 assert_eq!(point_gate, point_gate_de);
385 let set = HashSet::from([scalar_gate, scalar_gate_de, point_gate, point_gate_de]);
386 assert_eq!(set.len(), 2)
387 }
388}