Skip to main content

core_utils/circuit/v1/
circuit.rs

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/// The circuit, represented as a vector of `Op`s.
39#[derive(Deserialize)]
40#[serde(bound(deserialize = "Scalar<C>: Deserialize<'de>, Point<C>: Deserialize<'de>"))]
41#[repr(C)]
42pub struct Circuit<C: Curve> {
43    /// The circuit operations.
44    ops: Vec<Gate<C>>,
45    /// The input gates in order of definition
46    input_gates: Vec<GateIndex>,
47    /// The output gates in order of definition
48    output_gates: Vec<GateIndex>,
49}
50
51impl<C: Curve> Circuit<C> {
52    /// Converts this legacy v1 circuit into the v2 representation.
53    ///
54    /// v1 circuits predate the configurable MPC field and embed `Mersenne107` constants, so the
55    /// target config must use `Mersenne107` as its MPC field.
56    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}