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#[derive(Deserialize)]
34#[serde(bound(deserialize = "Scalar<C>: Deserialize<'de>, Point<C>: Deserialize<'de>"))]
35#[repr(C)]
36pub struct Circuit<C: Curve> {
37 ops: Vec<Gate<C>>,
39 input_gates: Vec<GateIndex>,
41 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}