use primitives::algebra::{
elliptic_curve::{Curve, Point, Scalar},
field::mersenne::Mersenne107,
};
use serde::{Deserialize, Serialize};
use super::GateIndex;
use crate::{
circuit::{
errors::CircuitError,
latest,
old::v2::{errors::ConversionError, gate::Gate},
},
config::MpcConfig,
};
#[derive(Serialize, Deserialize, Default)]
#[serde(bound(
serialize = "Scalar<C>: Serialize, Point<C>: Serialize",
deserialize = "Scalar<C>: Deserialize<'de>, Point<C>: Deserialize<'de>"
))]
#[repr(C)]
pub struct Circuit<C: Curve> {
pub ops: Vec<Gate<C>>,
pub output_gates: Vec<GateIndex>,
}
impl<C: Curve> Circuit<C> {
pub fn into_latest<Cfg>(self) -> Result<latest::Circuit<Cfg>, ConversionError<Cfg>>
where
Cfg: MpcConfig<Curve = C, Field = Mersenne107>,
{
let mut circuit = latest::Circuit::new();
let mut old_to_new_idx = vec![0; self.ops.len()];
let nb_gates: u32 = self
.ops
.len()
.try_into()
.map_err(|_| ConversionError::CircuitError(CircuitError::CircuitTooBig))?;
for (old_gate_idx, gate) in self.ops.into_iter().enumerate() {
let gate = match gate {
Gate::Input(input) => latest::Gate::Input(input),
Gate::Constant(constant) => latest::Gate::Constant(constant.into()),
Gate::Random {
algebraic_type,
batch_size,
} => latest::Gate::Random {
algebraic_type,
batch_size,
},
Gate::FieldShareUnaryOp { x, op } => latest::Gate::FieldShareUnaryOp { x, op },
Gate::FieldShareBinaryOp { x, y, op } => {
latest::Gate::FieldShareBinaryOp { x, y, op }
}
Gate::BatchSummation { x } => latest::Gate::BatchSummation { x },
Gate::BitShareUnaryOp { x, op } => latest::Gate::BitShareUnaryOp { x, op },
Gate::BitShareBinaryOp { x, y, op } => latest::Gate::BitShareBinaryOp { x, y, op },
Gate::PointShareUnaryOp { p, op } => latest::Gate::PointShareUnaryOp { p, op },
Gate::PointShareBinaryOp { p, y, op } => {
latest::Gate::PointShareBinaryOp { p, y, op }
}
Gate::FieldPlaintextUnaryOp { x, op } => {
latest::Gate::FieldPlaintextUnaryOp { x, op }
}
Gate::FieldPlaintextBinaryOp { x, y, op } => {
latest::Gate::FieldPlaintextBinaryOp { x, y, op }
}
Gate::BitPlaintextUnaryOp { x, op } => latest::Gate::BitPlaintextUnaryOp { x, op },
Gate::BitPlaintextBinaryOp { x, y, op } => {
latest::Gate::BitPlaintextBinaryOp { x, y, op }
}
Gate::PointPlaintextUnaryOp { p, op } => {
latest::Gate::PointPlaintextUnaryOp { p, op }
}
Gate::PointPlaintextBinaryOp { p, y, op } => {
latest::Gate::PointPlaintextBinaryOp { p, y, op }
}
Gate::DaBit {
field_type,
batch_size,
} => latest::Gate::DaBit {
field_type: field_type.into(),
batch_size,
},
Gate::GetDaBitFieldShare { x } => latest::Gate::GetDaBitFieldShare { x },
Gate::GetDaBitSharedBit { x } => latest::Gate::GetDaBitSharedBit { x },
Gate::BaseFieldPow { x, exp } => latest::Gate::BaseFieldPow { x, exp },
Gate::BitPlaintextToField { x, field_type } => latest::Gate::BitPlaintextToField {
x,
field_type: field_type.into(),
},
Gate::FieldPlaintextToBit { x } => latest::Gate::FieldPlaintextToBit { x },
Gate::ExtractFromBatch { x, slice } => latest::Gate::ExtractFromBatch { x, slice },
Gate::CollectToBatch { wires } => latest::Gate::CollectToBatch { wires },
Gate::PointFromPlaintextCoordinates { wires } => {
latest::Gate::PointFromPlaintextCoordinates { wires }
}
Gate::PlaintextPointToCoordinates { point } => {
latest::Gate::PlaintextPointToCoordinates { point }
}
Gate::PlaintextKeccakF1600 { x } => latest::Gate::PlaintextKeccakF1600 { x },
Gate::CompressPlaintextPoint { point } => {
latest::Gate::CompressPlaintextPoint { point }
}
Gate::KeyRecoveryPlaintextComputeErrors {
d_minus_one,
syndromes,
} => latest::Gate::KeyRecoveryPlaintextComputeErrors {
d_minus_one,
syndromes,
},
Gate::AesGcmKeyStream {
round_keys,
iv,
n_ciphertext_blocks,
} => latest::Gate::AesGcmKeyStream {
round_keys,
iv,
n_ciphertext_blocks,
},
#[cfg(any(test, feature = "dev"))]
Gate::AesKeySchedule { key } => latest::Gate::AesKeySchedule { key },
Gate::GhashPowersOfH {
h,
n_ciphertext_blocks,
} => latest::Gate::GhashPowersOfH {
h,
n_ciphertext_blocks,
},
Gate::Ghash { x, powers_of_h } => latest::Gate::Ghash { x, powers_of_h },
};
gate.get_inputs().into_iter().try_for_each(|idx| {
if idx < old_gate_idx as u32 {
Ok(())
} else {
Err(ConversionError::CircuitError(
CircuitError::GateIndexOutOfBounds(idx, old_gate_idx as u32),
))
}
})?;
let gate = gate.map_inputs(|old_idx| old_to_new_idx[old_idx as usize]);
let new_gate_idx = circuit.add_gate(gate)?;
old_to_new_idx[old_gate_idx] = new_gate_idx;
}
self.output_gates.iter().try_for_each(|idx| {
if *idx < nb_gates {
Ok(())
} else {
Err(ConversionError::CircuitError(
CircuitError::GateIndexOutOfBounds(*idx, nb_gates),
))
}
})?;
for output in self.output_gates {
let output = old_to_new_idx[output as usize];
circuit.add_output(output)?;
}
Ok(circuit)
}
}