Skip to main content

core_utils/circuit/v1/
circuit.rs

1use primitives::algebra::elliptic_curve::{Curve, Point, Scalar};
2use serde::Deserialize;
3
4use super::{
5    constants::{
6        BaseFieldPlaintext,
7        BaseFieldPlaintextBatch,
8        BitPlaintext,
9        BitPlaintextBatch,
10        Mersenne107Plaintext,
11        Mersenne107PlaintextBatch,
12        PointPlaintext,
13        PointPlaintextBatch,
14        ScalarPlaintext,
15        ScalarPlaintextBatch,
16    },
17    gate::Gate,
18    ops::Input,
19};
20use crate::circuit::{v1::errors::ConversionErrorToV2, v2, AlgebraicType, BatchSize, Slice};
21
22#[derive(Deserialize)]
23#[repr(transparent)]
24pub struct GateIndex(u32);
25
26impl GateIndex {
27    fn into_usize(self) -> usize {
28        self.0 as usize
29    }
30}
31
32/// The circuit, represented as a vector of `Op`s.
33#[derive(Deserialize)]
34#[serde(bound(deserialize = "Scalar<C>: Deserialize<'de>, Point<C>: Deserialize<'de>"))]
35#[repr(C)]
36pub struct Circuit<C: Curve> {
37    /// The circuit operations.
38    ops: Vec<Gate<C>>,
39    /// The input gates in order of definition
40    input_gates: Vec<GateIndex>,
41    /// The output gates in order of definition
42    output_gates: Vec<GateIndex>,
43}
44
45impl<C: Curve> Circuit<C> {
46    pub fn into_v2(self) -> Result<v2::Circuit<C>, ConversionErrorToV2<C>> {
47        let mut circuit = v2::Circuit::new();
48        let mut old_to_new_idx = vec![0; self.ops.len()];
49
50        for (old_gate_idx, gate) in self.ops.into_iter().enumerate() {
51            let gate = match gate {
52                Gate::Input { input_type } => match input_type {
53                    Input::SecretPlaintext {
54                        inputer,
55                        algebraic_type,
56                        batched,
57                    } => v2::Gate::Input(v2::Input::SecretPlaintext {
58                        inputer,
59                        algebraic_type,
60                        batch_size: batched.count() as BatchSize,
61                    }),
62                    Input::Share {
63                        algebraic_type,
64                        batched,
65                    } => v2::Gate::Input(v2::Input::Share {
66                        algebraic_type,
67                        batch_size: batched.count() as BatchSize,
68                    }),
69                    Input::RandomShare {
70                        algebraic_type,
71                        batched,
72                    } => v2::Gate::Random {
73                        algebraic_type,
74                        batch_size: batched.count() as BatchSize,
75                    },
76                    Input::Scalar(val) => match val {
77                        ScalarPlaintext::<C>::Fixed(val) => {
78                            v2::Gate::Constant(v2::Constant::Scalar(val))
79                        }
80                        ScalarPlaintext::<C>::Input(val) => v2::Gate::Input(v2::Input::Plaintext {
81                            algebraic_type: AlgebraicType::ScalarField,
82                            batch_size: val as BatchSize,
83                        }),
84                    },
85                    Input::ScalarBatch(val) => match val {
86                        ScalarPlaintextBatch::<C>::Fixed(val) => {
87                            v2::Gate::Constant(v2::Constant::ScalarBatch(val))
88                        }
89                        ScalarPlaintextBatch::<C>::Input(val) => {
90                            v2::Gate::Input(v2::Input::Plaintext {
91                                algebraic_type: AlgebraicType::ScalarField,
92                                batch_size: val as BatchSize,
93                            })
94                        }
95                    },
96                    Input::BaseField(val) => match val {
97                        BaseFieldPlaintext::<C>::Fixed(val) => {
98                            v2::Gate::Constant(v2::Constant::BaseField(val))
99                        }
100                        BaseFieldPlaintext::<C>::Input(val) => {
101                            v2::Gate::Input(v2::Input::Plaintext {
102                                algebraic_type: AlgebraicType::BaseField,
103                                batch_size: val as BatchSize,
104                            })
105                        }
106                    },
107                    Input::BaseFieldBatch(val) => match val {
108                        BaseFieldPlaintextBatch::<C>::Fixed(val) => {
109                            v2::Gate::Constant(v2::Constant::BaseFieldBatch(val))
110                        }
111                        BaseFieldPlaintextBatch::<C>::Input(val) => {
112                            v2::Gate::Input(v2::Input::Plaintext {
113                                algebraic_type: AlgebraicType::BaseField,
114                                batch_size: val as BatchSize,
115                            })
116                        }
117                    },
118                    Input::Mersenne107(val) => match val {
119                        Mersenne107Plaintext::Fixed(val) => {
120                            v2::Gate::Constant(v2::Constant::Mersenne107(val))
121                        }
122                        Mersenne107Plaintext::Input(val) => v2::Gate::Input(v2::Input::Plaintext {
123                            algebraic_type: AlgebraicType::Mersenne107,
124                            batch_size: val as BatchSize,
125                        }),
126                    },
127                    Input::Mersenne107Batch(val) => match val {
128                        Mersenne107PlaintextBatch::Fixed(val) => {
129                            v2::Gate::Constant(v2::Constant::Mersenne107Batch(val))
130                        }
131                        Mersenne107PlaintextBatch::Input(val) => {
132                            v2::Gate::Input(v2::Input::Plaintext {
133                                algebraic_type: AlgebraicType::Mersenne107,
134                                batch_size: val as BatchSize,
135                            })
136                        }
137                    },
138                    Input::Bit(val) => match val {
139                        BitPlaintext::Fixed(val) => v2::Gate::Constant(v2::Constant::Bit(val)),
140                        BitPlaintext::Input(val) => v2::Gate::Input(v2::Input::Plaintext {
141                            algebraic_type: AlgebraicType::Bit,
142                            batch_size: val as BatchSize,
143                        }),
144                    },
145                    Input::BitBatch(val) => match val {
146                        BitPlaintextBatch::Fixed(val) => {
147                            v2::Gate::Constant(v2::Constant::BitBatch(val))
148                        }
149                        BitPlaintextBatch::Input(val) => v2::Gate::Input(v2::Input::Plaintext {
150                            algebraic_type: AlgebraicType::Bit,
151                            batch_size: val as BatchSize,
152                        }),
153                    },
154                    Input::Point(val) => match val {
155                        PointPlaintext::<C>::Fixed(val) => {
156                            v2::Gate::Constant(v2::Constant::Point(val))
157                        }
158                        PointPlaintext::<C>::Input(val) => v2::Gate::Input(v2::Input::Plaintext {
159                            algebraic_type: AlgebraicType::Point,
160                            batch_size: val as BatchSize,
161                        }),
162                    },
163                    Input::PointBatch(val) => match val {
164                        PointPlaintextBatch::<C>::Fixed(val) => {
165                            v2::Gate::Constant(v2::Constant::PointBatch(val))
166                        }
167                        PointPlaintextBatch::<C>::Input(val) => {
168                            v2::Gate::Input(v2::Input::Plaintext {
169                                algebraic_type: AlgebraicType::Point,
170                                batch_size: val as BatchSize,
171                            })
172                        }
173                    },
174                },
175                Gate::FieldShareUnaryOp { x, op, .. } => {
176                    let x = old_to_new_idx[x.into_usize()];
177                    v2::Gate::FieldShareUnaryOp { x, op }
178                }
179                Gate::FieldShareBinaryOp { x, y, op, .. } => {
180                    let x = old_to_new_idx[x.into_usize()];
181                    let y = old_to_new_idx[y.into_usize()];
182                    v2::Gate::FieldShareBinaryOp { x, y, op }
183                }
184                Gate::BatchSummation { x, .. } => {
185                    let x = old_to_new_idx[x.into_usize()];
186                    v2::Gate::BatchSummation { x }
187                }
188                Gate::BitShareUnaryOp { x, op } => {
189                    let x = old_to_new_idx[x.into_usize()];
190                    v2::Gate::BitShareUnaryOp { x, op }
191                }
192                Gate::BitShareBinaryOp { x, y, op, .. } => {
193                    let x = old_to_new_idx[x.into_usize()];
194                    let y = old_to_new_idx[y.into_usize()];
195                    v2::Gate::BitShareBinaryOp { x, y, op }
196                }
197                Gate::PointShareUnaryOp { p, op } => {
198                    let p = old_to_new_idx[p.into_usize()];
199                    v2::Gate::PointShareUnaryOp { p, op }
200                }
201                Gate::PointShareBinaryOp { p, y, op, .. } => {
202                    let p = old_to_new_idx[p.into_usize()];
203                    let y = old_to_new_idx[y.into_usize()];
204                    v2::Gate::PointShareBinaryOp { p, y, op }
205                }
206                Gate::FieldPlaintextUnaryOp { x, op, .. } => {
207                    let x = old_to_new_idx[x.into_usize()];
208                    v2::Gate::FieldPlaintextUnaryOp { x, op }
209                }
210                Gate::FieldPlaintextBinaryOp { x, y, op, .. } => {
211                    let x = old_to_new_idx[x.into_usize()];
212                    let y = old_to_new_idx[y.into_usize()];
213                    v2::Gate::FieldPlaintextBinaryOp { x, y, op }
214                }
215                Gate::BitPlaintextUnaryOp { x, op } => {
216                    let x = old_to_new_idx[x.into_usize()];
217                    v2::Gate::BitPlaintextUnaryOp {
218                        x,
219                        op: op.try_into()?,
220                    }
221                }
222                Gate::BitPlaintextBinaryOp { x, y, op } => {
223                    let x = old_to_new_idx[x.into_usize()];
224                    let y = old_to_new_idx[y.into_usize()];
225                    v2::Gate::BitPlaintextBinaryOp {
226                        x,
227                        y,
228                        op: op.try_into()?,
229                    }
230                }
231                Gate::PointPlaintextUnaryOp { p, op } => {
232                    let p = old_to_new_idx[p.into_usize()];
233                    v2::Gate::PointPlaintextUnaryOp { p, op }
234                }
235                Gate::PointPlaintextBinaryOp { p, y, op } => {
236                    let p = old_to_new_idx[p.into_usize()];
237                    let y = old_to_new_idx[y.into_usize()];
238                    v2::Gate::PointPlaintextBinaryOp { p, y, op }
239                }
240                Gate::DaBit {
241                    field_type,
242                    batched,
243                } => v2::Gate::DaBit {
244                    field_type,
245                    batch_size: batched.count() as u32,
246                },
247                Gate::GetDaBitFieldShare { x, .. } => {
248                    let x = old_to_new_idx[x.into_usize()];
249                    v2::Gate::GetDaBitFieldShare { x }
250                }
251                Gate::GetDaBitSharedBit { x, .. } => {
252                    let x = old_to_new_idx[x.into_usize()];
253                    v2::Gate::GetDaBitSharedBit { x }
254                }
255                Gate::BaseFieldPow { x, exp } => {
256                    let x = old_to_new_idx[x.into_usize()];
257                    v2::Gate::BaseFieldPow { x, exp }
258                }
259                Gate::BitPlaintextToField { x, field_type } => {
260                    let x = old_to_new_idx[x.into_usize()];
261                    v2::Gate::BitPlaintextToField { x, field_type }
262                }
263                Gate::FieldPlaintextToBit { x, .. } => {
264                    let x = old_to_new_idx[x.into_usize()];
265                    v2::Gate::FieldPlaintextToBit { x }
266                }
267                Gate::BatchGetIndex { x, index, .. } => {
268                    let x = old_to_new_idx[x.into_usize()];
269                    v2::Gate::ExtractFromBatch {
270                        x,
271                        slice: Slice::single(index as u32),
272                    }
273                }
274                Gate::CollectToBatch { wires, .. } => {
275                    let wires = wires
276                        .into_iter()
277                        .map(|w| old_to_new_idx[w.into_usize()])
278                        .collect();
279                    v2::Gate::CollectToBatch { wires }
280                }
281                Gate::PointFromPlaintextExtendedEdwards { wires } => {
282                    let wires = wires
283                        .into_iter()
284                        .map(|w| old_to_new_idx[w.into_usize()])
285                        .collect();
286                    v2::Gate::PointFromPlaintextExtendedEdwards { wires }
287                }
288                Gate::PlaintextPointToExtendedEdwards { point } => {
289                    let point = old_to_new_idx[point.into_usize()];
290                    v2::Gate::PlaintextPointToExtendedEdwards { point }
291                }
292                Gate::PlaintextKeccakF1600 { wires } => {
293                    let wires = wires
294                        .into_iter()
295                        .map(|w| old_to_new_idx[w.into_usize()])
296                        .collect();
297                    let x = circuit.add_gate(v2::Gate::CollectToBatch { wires })?;
298                    v2::Gate::PlaintextKeccakF1600 { x }
299                }
300                Gate::CompressPlaintextPoint { point } => {
301                    let point = old_to_new_idx[point.into_usize()];
302                    v2::Gate::CompressPlaintextPoint { point }
303                }
304                Gate::KeyRecoveryPlaintextComputeErrors {
305                    d_minus_one,
306                    syndromes,
307                } => {
308                    let d_minus_one = old_to_new_idx[d_minus_one.into_usize()];
309                    let syndromes = old_to_new_idx[syndromes.into_usize()];
310                    v2::Gate::KeyRecoveryPlaintextComputeErrors {
311                        d_minus_one,
312                        syndromes,
313                    }
314                }
315            };
316
317            let new_gate_idx = circuit.add_gate(gate)?;
318            old_to_new_idx[old_gate_idx] = new_gate_idx;
319        }
320        for output in self.output_gates {
321            let output = old_to_new_idx[output.into_usize()];
322            circuit.add_output(output)?;
323        }
324        Ok(circuit)
325    }
326}