core_utils/circuit/old/v2/
circuit.rs1use primitives::algebra::{
2 elliptic_curve::{Curve, Point, Scalar},
3 field::mersenne::Mersenne107,
4};
5use serde::{Deserialize, Serialize};
6
7use super::GateIndex;
8use crate::{
9 circuit::{
10 errors::CircuitError,
11 latest,
12 old::v2::{errors::ConversionError, gate::Gate},
13 },
14 config::MpcConfig,
15};
16
17#[derive(Serialize, Deserialize, Default)]
19#[serde(bound(
20 serialize = "Scalar<C>: Serialize, Point<C>: Serialize",
21 deserialize = "Scalar<C>: Deserialize<'de>, Point<C>: Deserialize<'de>"
22))]
23#[repr(C)]
24pub struct Circuit<C: Curve> {
25 pub ops: Vec<Gate<C>>,
27 pub output_gates: Vec<GateIndex>,
29}
30
31impl<C: Curve> Circuit<C> {
32 pub fn into_latest<Cfg>(self) -> Result<latest::Circuit<Cfg>, ConversionError<Cfg>>
33 where
34 Cfg: MpcConfig<Curve = C, Field = Mersenne107>,
35 {
36 let mut circuit = latest::Circuit::new();
37 let mut old_to_new_idx = vec![0; self.ops.len()];
38
39 let nb_gates: u32 = self
40 .ops
41 .len()
42 .try_into()
43 .map_err(|_| ConversionError::CircuitError(CircuitError::CircuitTooBig))?;
44
45 for (old_gate_idx, gate) in self.ops.into_iter().enumerate() {
46 let gate = match gate {
47 Gate::Input(input) => latest::Gate::Input(input),
48 Gate::Constant(constant) => latest::Gate::Constant(constant.into()),
49 Gate::Random {
50 algebraic_type,
51 batch_size,
52 } => latest::Gate::Random {
53 algebraic_type,
54 batch_size,
55 },
56 Gate::FieldShareUnaryOp { x, op } => latest::Gate::FieldShareUnaryOp { x, op },
57 Gate::FieldShareBinaryOp { x, y, op } => {
58 latest::Gate::FieldShareBinaryOp { x, y, op }
59 }
60 Gate::BatchSummation { x } => latest::Gate::BatchSummation { x },
61 Gate::BitShareUnaryOp { x, op } => latest::Gate::BitShareUnaryOp { x, op },
62 Gate::BitShareBinaryOp { x, y, op } => latest::Gate::BitShareBinaryOp { x, y, op },
63 Gate::PointShareUnaryOp { p, op } => latest::Gate::PointShareUnaryOp { p, op },
64 Gate::PointShareBinaryOp { p, y, op } => {
65 latest::Gate::PointShareBinaryOp { p, y, op }
66 }
67 Gate::FieldPlaintextUnaryOp { x, op } => {
68 latest::Gate::FieldPlaintextUnaryOp { x, op }
69 }
70 Gate::FieldPlaintextBinaryOp { x, y, op } => {
71 latest::Gate::FieldPlaintextBinaryOp { x, y, op }
72 }
73 Gate::BitPlaintextUnaryOp { x, op } => latest::Gate::BitPlaintextUnaryOp { x, op },
74 Gate::BitPlaintextBinaryOp { x, y, op } => {
75 latest::Gate::BitPlaintextBinaryOp { x, y, op }
76 }
77 Gate::PointPlaintextUnaryOp { p, op } => {
78 latest::Gate::PointPlaintextUnaryOp { p, op }
79 }
80 Gate::PointPlaintextBinaryOp { p, y, op } => {
81 latest::Gate::PointPlaintextBinaryOp { p, y, op }
82 }
83 Gate::DaBit {
84 field_type,
85 batch_size,
86 } => latest::Gate::DaBit {
87 field_type: field_type.into(),
88 batch_size,
89 },
90 Gate::GetDaBitFieldShare { x } => latest::Gate::GetDaBitFieldShare { x },
91 Gate::GetDaBitSharedBit { x } => latest::Gate::GetDaBitSharedBit { x },
92 Gate::BaseFieldPow { x, exp } => latest::Gate::BaseFieldPow { x, exp },
93 Gate::BitPlaintextToField { x, field_type } => latest::Gate::BitPlaintextToField {
94 x,
95 field_type: field_type.into(),
96 },
97 Gate::FieldPlaintextToBit { x } => latest::Gate::FieldPlaintextToBit { x },
98 Gate::ExtractFromBatch { x, slice } => latest::Gate::ExtractFromBatch { x, slice },
99 Gate::CollectToBatch { wires } => latest::Gate::CollectToBatch { wires },
100 Gate::PointFromPlaintextCoordinates { wires } => {
101 latest::Gate::PointFromPlaintextCoordinates { wires }
102 }
103 Gate::PlaintextPointToCoordinates { point } => {
104 latest::Gate::PlaintextPointToCoordinates { point }
105 }
106 Gate::PlaintextKeccakF1600 { x } => latest::Gate::PlaintextKeccakF1600 { x },
107 Gate::CompressPlaintextPoint { point } => {
108 latest::Gate::CompressPlaintextPoint { point }
109 }
110 Gate::KeyRecoveryPlaintextComputeErrors {
111 d_minus_one,
112 syndromes,
113 } => latest::Gate::KeyRecoveryPlaintextComputeErrors {
114 d_minus_one,
115 syndromes,
116 },
117 Gate::AesGcmKeyStream {
118 round_keys,
119 iv,
120 n_ciphertext_blocks,
121 } => latest::Gate::AesGcmKeyStream {
122 round_keys,
123 iv,
124 n_ciphertext_blocks,
125 },
126 #[cfg(any(test, feature = "dev"))]
127 Gate::AesKeySchedule { key } => latest::Gate::AesKeySchedule { key },
128 Gate::GhashPowersOfH {
129 h,
130 n_ciphertext_blocks,
131 } => latest::Gate::GhashPowersOfH {
132 h,
133 n_ciphertext_blocks,
134 },
135 Gate::Ghash { x, powers_of_h } => latest::Gate::Ghash { x, powers_of_h },
136 };
137
138 gate.get_inputs().into_iter().try_for_each(|idx| {
140 if idx < old_gate_idx as u32 {
141 Ok(())
142 } else {
143 Err(ConversionError::CircuitError(
144 CircuitError::GateIndexOutOfBounds(idx, old_gate_idx as u32),
145 ))
146 }
147 })?;
148 let gate = gate.map_inputs(|old_idx| old_to_new_idx[old_idx as usize]);
149
150 let new_gate_idx = circuit.add_gate(gate)?;
151 old_to_new_idx[old_gate_idx] = new_gate_idx;
152 }
153
154 self.output_gates.iter().try_for_each(|idx| {
156 if *idx < nb_gates {
157 Ok(())
158 } else {
159 Err(ConversionError::CircuitError(
160 CircuitError::GateIndexOutOfBounds(*idx, nb_gates),
161 ))
162 }
163 })?;
164
165 for output in self.output_gates {
166 let output = old_to_new_idx[output as usize];
167 circuit.add_output(output)?;
168 }
169 Ok(circuit)
170 }
171}