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