use primitives::algebra::elliptic_curve::Curve;
use crate::{
circuit::{
errors::{CircuitError, ConversionError},
gate::Gate,
AlgebraicType,
BitShareBinaryOp,
BitShareUnaryOp,
FieldShareBinaryOp,
FieldShareUnaryOp,
FieldType,
GateIndex,
Input,
PointPlaintextBinaryOp,
PointShareBinaryOp,
PointShareUnaryOp,
ShareOrPlaintext,
},
key_recovery::{MXE_KEY_RECOVERY_D, MXE_KEY_RECOVERY_N},
};
#[derive(Default, PartialEq, Debug, Clone)]
pub struct Circuit<C: Curve> {
pub(super) gates: Vec<GateExt<C>>,
pub(super) inputs: Vec<GateIndex>,
pub(super) outputs: Vec<GateIndex>,
}
#[derive(Clone, Debug, PartialEq)]
pub struct GateExt<C: Curve> {
pub gate: Gate<C>,
pub output: GateOutput,
pub level: GateLevel,
}
#[derive(PartialEq, Copy, Clone, Debug)]
pub struct GateOutput {
pub(super) algebraic_type: AlgebraicType,
pub(super) form: ShareOrPlaintext,
pub(super) batch_size: u32,
}
#[derive(Copy, Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Default)]
pub struct GateLevel {
comm_level: usize,
level: usize, }
impl<C: Curve> GateExt<C> {
pub fn new(gate: Gate<C>, output: GateOutput, level: GateLevel) -> Self {
Self {
gate,
output,
level,
}
}
}
impl GateOutput {
pub fn get_type(&self) -> AlgebraicType {
self.algebraic_type
}
pub fn get_field_type(&self) -> Result<FieldType, ConversionError> {
FieldType::try_from(self.algebraic_type)
}
pub fn get_field_type_unchecked(&self) -> FieldType {
self.get_field_type().unwrap()
}
pub fn get_form(&self) -> ShareOrPlaintext {
self.form
}
pub fn get_batch_size(&self) -> u32 {
self.batch_size
}
fn is_field(&self) -> bool {
FieldType::try_from(self.algebraic_type).is_ok()
}
fn is_bit(&self) -> bool {
self.algebraic_type == AlgebraicType::Bit
}
fn is_point(&self) -> bool {
self.algebraic_type == AlgebraicType::Point
}
fn is_base_field(&self) -> bool {
self.algebraic_type == AlgebraicType::BaseField
}
fn is_scalar_field(&self) -> bool {
self.algebraic_type == AlgebraicType::ScalarField
}
fn is_share(&self) -> bool {
self.form == ShareOrPlaintext::Share
}
pub fn is_plaintext(&self) -> bool {
self.form == ShareOrPlaintext::Plaintext
}
fn with_new_form(self, form: ShareOrPlaintext) -> Self {
let mut res = self;
res.form = form;
res
}
fn with_new_type(self, algebraic_type: AlgebraicType) -> Self {
let mut res = self;
res.algebraic_type = algebraic_type;
res
}
fn with_new_batch_size(self, batch_size: u32) -> Self {
let mut res = self;
res.batch_size = batch_size;
res
}
}
impl GateLevel {
fn next(&self, comm_rounds: usize) -> GateLevel {
if comm_rounds > 0 {
GateLevel {
comm_level: self.comm_level + comm_rounds,
level: 0,
}
} else {
GateLevel {
comm_level: self.comm_level,
level: self.level + 1,
}
}
}
pub fn comm_level(&self) -> usize {
self.comm_level
}
}
impl<C: Curve> Circuit<C> {
pub fn new() -> Self {
Self::default()
}
pub fn add_gate(&mut self, gate: Gate<C>) -> Result<GateIndex, CircuitError<C>> {
self.validate_gate(&gate)?;
let index = self.nb_gates();
if index == GateIndex::MAX {
return Err(CircuitError::CircuitTooBig);
}
let gate_output = self.comp_gate_output(&gate);
let level = self.comp_gate_level(&gate);
if gate.is_input() {
self.inputs.push(index);
}
self.gates.push(GateExt::new(gate, gate_output?, level));
Ok(index)
}
pub fn add_output(&mut self, index: GateIndex) -> Result<(), CircuitError<C>> {
if index < self.nb_gates() {
self.outputs.push(index);
Ok(())
} else {
Err(CircuitError::GateIndexOutOfBounds(index, self.nb_gates()))
}
}
pub fn nb_gates(&self) -> GateIndex {
self.gates.len() as GateIndex
}
pub fn nb_inputs(&self) -> GateIndex {
self.inputs.len() as GateIndex
}
pub fn nb_outputs(&self) -> GateIndex {
self.outputs.len() as GateIndex
}
pub fn into_gates(self) -> Vec<GateExt<C>> {
self.gates
}
pub fn iter_gates_ext(
&self,
) -> impl ExactSizeIterator<Item = &GateExt<C>> + DoubleEndedIterator {
self.gates.iter()
}
pub fn iter_gates(&self) -> impl ExactSizeIterator<Item = &Gate<C>> + DoubleEndedIterator {
self.gates.iter().map(|g| &g.gate)
}
pub fn iter_output_indices(&self) -> impl ExactSizeIterator<Item = &GateIndex> {
self.outputs.iter()
}
pub fn iter_input_indices(&self) -> impl ExactSizeIterator<Item = &GateIndex> {
self.inputs.iter()
}
pub fn gate_ext(&self, index: GateIndex) -> Result<&GateExt<C>, CircuitError<C>> {
if index < self.nb_gates() {
Ok(&self.gates[index as usize])
} else {
Err(CircuitError::GateIndexOutOfBounds(index, self.nb_gates()))
}
}
pub fn gate_ext_unchecked(&self, index: GateIndex) -> &GateExt<C> {
&self.gates[index as usize]
}
pub fn gate(&self, index: GateIndex) -> Result<&Gate<C>, CircuitError<C>> {
self.gate_ext(index).map(|g| &g.gate)
}
pub fn gate_unchecked(&self, index: GateIndex) -> &Gate<C> {
&self.gate_ext_unchecked(index).gate
}
pub fn gate_output(&self, index: GateIndex) -> Result<GateOutput, CircuitError<C>> {
self.gate_ext(index).map(|g| g.output)
}
pub fn gate_output_unchecked(&self, index: GateIndex) -> GateOutput {
self.gate_ext_unchecked(index).output
}
pub fn gate_level(&self, index: GateIndex) -> Result<GateLevel, CircuitError<C>> {
self.gate_ext(index).map(|g| g.level)
}
pub fn gate_level_unchecked(&self, index: GateIndex) -> GateLevel {
self.gate_ext_unchecked(index).level
}
}
macro_rules! check_algebraic_type {
($exp_type:expr, $found_type:expr) => {
if $exp_type != $found_type {
return Err(CircuitError::InvalidGateAlgebraicType {
expected: $exp_type,
found: $found_type,
});
}
};
}
impl<C: Curve> Circuit<C> {
pub fn open_and_output_scalar(&mut self, x: GateIndex) -> Result<(), CircuitError<C>> {
check_algebraic_type!(AlgebraicType::ScalarField, self.gate_output(x)?.get_type());
let opening_index = self.add_gate(Gate::FieldShareUnaryOp {
x,
op: FieldShareUnaryOp::Open,
})?;
self.add_output(opening_index)
}
pub fn open_and_output_base_field(&mut self, x: GateIndex) -> Result<(), CircuitError<C>> {
check_algebraic_type!(AlgebraicType::BaseField, self.gate_output(x)?.get_type());
let opening_index = self.add_gate(Gate::FieldShareUnaryOp {
x,
op: FieldShareUnaryOp::Open,
})?;
self.add_output(opening_index)
}
pub fn open_and_output_mersenne107(&mut self, x: GateIndex) -> Result<(), CircuitError<C>> {
check_algebraic_type!(AlgebraicType::Mersenne107, self.gate_output(x)?.get_type());
let opening_index = self.add_gate(Gate::FieldShareUnaryOp {
x,
op: FieldShareUnaryOp::Open,
})?;
self.add_output(opening_index)
}
pub fn open_and_output_point(&mut self, p: GateIndex) -> Result<(), CircuitError<C>> {
check_algebraic_type!(AlgebraicType::Point, self.gate_output(p)?.get_type());
let opening_index = self.add_gate(Gate::PointShareUnaryOp {
p,
op: PointShareUnaryOp::Open,
})?;
self.add_output(opening_index)
}
pub fn open_and_output_bit(&mut self, x: GateIndex) -> Result<(), CircuitError<C>> {
check_algebraic_type!(AlgebraicType::Bit, self.gate_output(x)?.get_type());
let opening_index = self.add_gate(Gate::BitShareUnaryOp {
x,
op: BitShareUnaryOp::Open,
})?;
self.add_output(opening_index)
}
}
impl<C: Curve> Circuit<C> {
fn validate_gate(&self, gate: &Gate<C>) -> Result<(), CircuitError<C>> {
macro_rules! check_op {
($msg:expr, $gate:expr => $($val1:expr, $op:tt, $val2:expr);+$(;)?) => {
$(if !($val1 $op $val2) {
return Err(CircuitError::InvalidGate(
$gate.clone(),
format!("{}: {:?} {:?} {:?}", $msg, $val1, stringify!($op), $val2),
));
})+
};
}
macro_rules! check_gate_properties {
($gate:expr, $($func:ident),* $(,)?) => {
$(if !($gate.output.$func()) {
return Err(CircuitError::InvalidGate(
$gate.gate.clone(),
format!("{:?} fails - {}", $gate.output, stringify!($func)))); }
)*
};
}
match gate {
Gate::Input(input) => {
check_op!(
"input batch size must be non-zero",
gate =>
0, <, input.batch_size();
);
}
Gate::Constant(constant) => {
check_op!(
"constant batch size must be non-zero",
gate =>
0, <, constant.batch_size()?;
);
}
Gate::Random { batch_size, .. } => {
check_op!(
"random batch size must be non-zero",
gate =>
0, <, *batch_size;
);
}
Gate::FieldShareUnaryOp { x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_field, is_share);
}
Gate::FieldShareBinaryOp { x, y, .. } => {
let (gx, gy) = (self.gate_ext(*x)?, self.gate_ext(*y)?);
check_gate_properties!(gx, is_field, is_share);
check_gate_properties!(gy, is_field);
check_op!(
"inputs must have same batch-size and field type",
gate =>
gx.output.batch_size, ==, gy.output.batch_size;
gx.output.algebraic_type, ==, gy.output.algebraic_type
);
}
Gate::BatchSummation { x } => {
self.gate_ext(*x)?;
}
Gate::BitShareUnaryOp { x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_bit, is_share);
}
Gate::BitShareBinaryOp { x, y, .. } => {
let (gx, gy) = (self.gate_ext(*x)?, self.gate_ext(*y)?);
check_gate_properties!(gx, is_bit, is_share);
check_gate_properties!(gy, is_bit);
check_op!(
"inputs must have same batch-size",
gate =>
gx.output.batch_size, ==, gy.output.batch_size
);
}
Gate::PointShareUnaryOp { p: x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_point, is_share);
}
Gate::PointShareBinaryOp { p: x, y, op } => {
let (gx, gy) = (self.gate_ext(*x)?, self.gate_ext(*y)?);
if gx.output.is_plaintext() && gy.output.is_plaintext() {
return Err(CircuitError::InvalidGate(
gate.clone(),
"at least one input must be share".to_string(),
));
}
check_gate_properties!(gx, is_point);
match op {
PointShareBinaryOp::Add => {
check_gate_properties!(gy, is_point);
}
PointShareBinaryOp::ScalarMul => {
check_gate_properties!(gy, is_scalar_field);
}
};
check_op!(
"inputs must have same batch-size",
gate =>
gx.output.batch_size, ==, gy.output.batch_size
);
}
Gate::FieldPlaintextUnaryOp { x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_field, is_plaintext);
}
Gate::FieldPlaintextBinaryOp { x, y, .. } => {
let (gx, gy) = (self.gate_ext(*x)?, self.gate_ext(*y)?);
check_gate_properties!(gx, is_field, is_plaintext);
check_gate_properties!(gy, is_field, is_plaintext);
check_op!(
"inputs must have same field type",
gate =>
gx.output.algebraic_type, ==, gy.output.algebraic_type;
gx.output.batch_size, ==, gy.output.batch_size
);
}
Gate::BitPlaintextUnaryOp { x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_bit, is_plaintext);
}
Gate::BitPlaintextBinaryOp { x, y, .. } => {
let (gx, gy) = (self.gate_ext(*x)?, self.gate_ext(*y)?);
check_gate_properties!(gx, is_bit, is_plaintext);
check_gate_properties!(gy, is_bit, is_plaintext);
check_op!(
"inputs must have same batch-size",
gate =>
gx.output.batch_size, ==, gy.output.batch_size
);
}
Gate::PointPlaintextUnaryOp { p: x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_point, is_plaintext);
}
Gate::PointPlaintextBinaryOp { p: x, y, op } => {
let (gx, gy) = (self.gate_ext(*x)?, self.gate_ext(*y)?);
check_gate_properties!(gx, is_point, is_plaintext);
match op {
PointPlaintextBinaryOp::Add => {
check_gate_properties!(gy, is_point, is_plaintext);
}
PointPlaintextBinaryOp::ScalarMul => {
check_gate_properties!(gy, is_scalar_field, is_plaintext);
}
}
check_op!(
"inputs must have same batch-size",
gate =>
gx.output.batch_size, ==, gy.output.batch_size
);
}
Gate::DaBit { batch_size, .. } => {
check_op!(
"input batch size must be non-zero",
gate =>
0, <, *batch_size
);
}
Gate::GetDaBitFieldShare { x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_field, is_share);
}
Gate::GetDaBitSharedBit { x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_field, is_share);
}
Gate::BaseFieldPow { x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_base_field, is_share);
}
Gate::BitPlaintextToField { x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_bit, is_plaintext);
}
Gate::FieldPlaintextToBit { x, .. } => {
check_gate_properties!(self.gate_ext(*x)?, is_field, is_plaintext);
}
Gate::ExtractFromBatch { x, slice, .. } => {
let gx = self.gate_ext(*x)?;
if slice.is_empty() {
return Err(CircuitError::InvalidGate(
gate.clone(),
format!("slice must be non-empty: {slice:?}"),
));
}
if slice.get_indices()
.into_iter()
.max()
.expect("non-empty slice expected") >= gx.output.batch_size
{
return Err(CircuitError::InvalidGate(
gate.clone(),
format!("slice indices out-of-range: {slice:?}"),
));
}
}
Gate::CollectToBatch { wires } => {
check_op!("expected at least one input", gate => 0, <, wires.len());
let first = self.gate_ext(wires[0])?.output;
for x in wires.iter().skip(1) {
let gx = self.gate_ext(*x)?.output;
check_op!(
"all inputs must have the same type",
gate =>
first.algebraic_type, ==, gx.algebraic_type;
first.form, ==, gx.form
);
}
}
Gate::PointFromPlaintextExtendedEdwards { wires } => {
check_op!("expected exactly 4 inputs", gate => wires.len(), ==, 4);
for x in wires {
let gx = self.gate_ext(*x)?;
check_gate_properties!(gx, is_base_field, is_plaintext);
check_op!("expected batch-size 1", gate => gx.output.batch_size, ==, 1);
}
}
Gate::PlaintextPointToExtendedEdwards { point: x, .. } => {
let gx = self.gate_ext(*x)?;
check_gate_properties!(gx, is_point, is_plaintext);
check_op!("expected batch-size 1", gate => gx.output.batch_size, ==, 1);
}
Gate::PlaintextKeccakF1600 { x } => {
let gx = self.gate_ext(*x)?;
check_gate_properties!(gx, is_bit, is_plaintext);
check_op!("expected batch-size 1600", gate => gx.output.batch_size, ==, 1600);
}
Gate::CompressPlaintextPoint { point: x, .. } => {
let gx = self.gate_ext(*x)?;
check_gate_properties!(gx, is_point, is_plaintext);
check_op!("expected batch-size 1", gate => gx.output.batch_size, ==, 1);
}
Gate::KeyRecoveryPlaintextComputeErrors {
d_minus_one,
syndromes,
} => {
let g1 = self.gate_ext(*d_minus_one)?;
let g2 = self.gate_ext(*syndromes)?;
check_gate_properties!(g1, is_base_field, is_plaintext);
check_gate_properties!(g2, is_base_field, is_plaintext);
check_op!("expected batch-size 1", gate => g1.output.batch_size, ==, 1);
check_op!(format!("expected batch-size {}", MXE_KEY_RECOVERY_D - 1),
gate => g2.output.batch_size, ==, MXE_KEY_RECOVERY_D as u32 - 1);
}
}
Ok(())
}
fn comp_gate_output(&self, gate: &Gate<C>) -> Result<GateOutput, CircuitError<C>> {
let r = match gate {
Gate::Input(input_type) => GateOutput {
batch_size: input_type.batch_size(),
algebraic_type: input_type.algebraic_type(),
form: input_type.share_or_plaintext(),
},
Gate::Constant(const_type) => GateOutput {
batch_size: const_type.batch_size()?,
algebraic_type: const_type.algebraic_type(),
form: ShareOrPlaintext::Plaintext,
},
Gate::Random {
algebraic_type,
batch_size,
} => GateOutput {
batch_size: *batch_size,
algebraic_type: *algebraic_type,
form: ShareOrPlaintext::Share,
},
Gate::FieldShareUnaryOp { x, op } => match op {
FieldShareUnaryOp::Neg | FieldShareUnaryOp::MulInverse => {
self.gate_output_unchecked(*x)
}
FieldShareUnaryOp::Open | FieldShareUnaryOp::IsZero => self
.gate_output_unchecked(*x)
.with_new_form(ShareOrPlaintext::Plaintext),
},
Gate::FieldShareBinaryOp { x, .. }
| Gate::BitShareBinaryOp { x, .. }
| Gate::FieldPlaintextUnaryOp { x, .. }
| Gate::FieldPlaintextBinaryOp { x, .. }
| Gate::BitPlaintextUnaryOp { x, .. }
| Gate::BitPlaintextBinaryOp { x, .. }
| Gate::PointPlaintextUnaryOp { p: x, .. }
| Gate::PointPlaintextBinaryOp { p: x, .. }
| Gate::GetDaBitFieldShare { x, .. }
| Gate::BaseFieldPow { x, .. } => self.gate_output_unchecked(*x),
Gate::BatchSummation { x, .. } => self.gate_output_unchecked(*x).with_new_batch_size(1),
Gate::PointShareBinaryOp { p: x, .. } => self
.gate_output_unchecked(*x)
.with_new_form(ShareOrPlaintext::Share),
Gate::BitShareUnaryOp { x, op } => match op {
BitShareUnaryOp::Not => self.gate_output_unchecked(*x),
BitShareUnaryOp::Open => self
.gate_output_unchecked(*x)
.with_new_form(ShareOrPlaintext::Plaintext),
},
Gate::PointShareUnaryOp { p: x, op } => match op {
PointShareUnaryOp::Neg => self.gate_output_unchecked(*x),
PointShareUnaryOp::Open => self
.gate_output_unchecked(*x)
.with_new_form(ShareOrPlaintext::Plaintext),
PointShareUnaryOp::IsZero => self
.gate_output_unchecked(*x)
.with_new_form(ShareOrPlaintext::Plaintext)
.with_new_type(AlgebraicType::ScalarField),
},
Gate::DaBit {
field_type,
batch_size,
} => GateOutput {
batch_size: *batch_size,
algebraic_type: AlgebraicType::from(*field_type),
form: ShareOrPlaintext::Share,
},
Gate::GetDaBitSharedBit { x, .. } => self
.gate_output_unchecked(*x)
.with_new_type(AlgebraicType::Bit),
Gate::BitPlaintextToField { x, field_type } => self
.gate_output_unchecked(*x)
.with_new_type(AlgebraicType::from(*field_type)),
Gate::FieldPlaintextToBit { x } => self
.gate_output_unchecked(*x)
.with_new_type(AlgebraicType::Bit),
Gate::ExtractFromBatch { x, slice } => self
.gate_output_unchecked(*x)
.with_new_batch_size(slice.len()),
Gate::CollectToBatch { wires, .. } => {
let batch_size = wires
.iter()
.map(|x| self.gate_output_unchecked(*x).batch_size)
.sum();
self.gate_output_unchecked(wires[0])
.with_new_batch_size(batch_size)
}
Gate::PointFromPlaintextExtendedEdwards { .. } => GateOutput {
algebraic_type: AlgebraicType::Point,
form: ShareOrPlaintext::Plaintext,
batch_size: 1,
},
Gate::PlaintextPointToExtendedEdwards { .. } => GateOutput {
algebraic_type: AlgebraicType::BaseField,
form: ShareOrPlaintext::Plaintext,
batch_size: 4,
},
Gate::PlaintextKeccakF1600 { .. } => GateOutput {
algebraic_type: AlgebraicType::Bit,
form: ShareOrPlaintext::Plaintext,
batch_size: 1600,
},
Gate::CompressPlaintextPoint { .. } => GateOutput {
algebraic_type: AlgebraicType::Bit,
form: ShareOrPlaintext::Plaintext,
batch_size: 256,
},
Gate::KeyRecoveryPlaintextComputeErrors { .. } => GateOutput {
algebraic_type: AlgebraicType::BaseField,
form: ShareOrPlaintext::Plaintext,
batch_size: MXE_KEY_RECOVERY_N as u32,
},
};
Ok(r)
}
fn comp_gate_comm_rounds(&self, gate: &Gate<C>) -> usize {
match gate {
Gate::Input(input_type) => match input_type {
Input::SecretPlaintext { .. } => 1,
_ => 0,
},
Gate::Constant(_) | Gate::Random { .. } => 0,
Gate::FieldShareUnaryOp { op, .. } => match op {
FieldShareUnaryOp::Neg => 0,
FieldShareUnaryOp::MulInverse => 2,
FieldShareUnaryOp::Open => 1,
FieldShareUnaryOp::IsZero => 2,
},
Gate::FieldShareBinaryOp { op, y, .. } => {
match (op, self.gate_output_unchecked(*y).form) {
(FieldShareBinaryOp::Mul, ShareOrPlaintext::Share) => 1,
(FieldShareBinaryOp::Mul, ShareOrPlaintext::Plaintext)
| (FieldShareBinaryOp::Add, _) => 0,
}
}
Gate::BatchSummation { .. } => 0,
Gate::BitShareUnaryOp { op, .. } => match op {
BitShareUnaryOp::Not => 0,
BitShareUnaryOp::Open => 1,
},
Gate::BitShareBinaryOp { op, y, .. } => {
match (op, self.gate_output_unchecked(*y).form) {
(BitShareBinaryOp::Xor, _) => 0,
(_, ShareOrPlaintext::Share) => 1,
(_, ShareOrPlaintext::Plaintext) => 0,
}
}
Gate::PointShareUnaryOp { op, .. } => match op {
PointShareUnaryOp::Neg => 0,
PointShareUnaryOp::Open => 1,
PointShareUnaryOp::IsZero => 2,
},
Gate::PointShareBinaryOp { y, op, .. } => {
match (op, self.gate_output_unchecked(*y).form) {
(PointShareBinaryOp::Add, _) => 0,
(PointShareBinaryOp::ScalarMul, ShareOrPlaintext::Share) => 1,
(PointShareBinaryOp::ScalarMul, ShareOrPlaintext::Plaintext) => 0,
}
}
Gate::BaseFieldPow { .. } => 2,
Gate::FieldPlaintextUnaryOp { .. }
| Gate::FieldPlaintextBinaryOp { .. }
| Gate::BitPlaintextUnaryOp { .. }
| Gate::BitPlaintextBinaryOp { .. }
| Gate::PointPlaintextUnaryOp { .. }
| Gate::PointPlaintextBinaryOp { .. }
| Gate::DaBit { .. }
| Gate::GetDaBitFieldShare { .. }
| Gate::GetDaBitSharedBit { .. }
| Gate::BitPlaintextToField { .. }
| Gate::FieldPlaintextToBit { .. }
| Gate::ExtractFromBatch { .. }
| Gate::CollectToBatch { .. }
| Gate::PointFromPlaintextExtendedEdwards { .. }
| Gate::PlaintextPointToExtendedEdwards { .. }
| Gate::PlaintextKeccakF1600 { .. }
| Gate::CompressPlaintextPoint { .. }
| Gate::KeyRecoveryPlaintextComputeErrors { .. } => 0,
}
}
fn comp_gate_level(&self, gate: &Gate<C>) -> GateLevel {
let comm_rounds = self.comp_gate_comm_rounds(gate);
match gate
.get_inputs()
.iter()
.map(|pred| self.gate_level_unchecked(*pred))
.max()
{
None => GateLevel::default(),
Some(preds_level) => preds_level.next(comm_rounds),
}
}
}
#[cfg(test)]
mod tests {
use primitives::algebra::elliptic_curve::Curve25519Ristretto as C;
use crate::circuit::{AlgebraicType, Circuit, FieldShareBinaryOp, Gate, Input};
#[test]
fn test_circuit_new() {
let mut circuit = Circuit::<C>::new();
let x = circuit
.add_gate(Gate::Input(Input::SecretPlaintext {
inputer: 0,
algebraic_type: AlgebraicType::Mersenne107,
batch_size: 3,
}))
.unwrap();
let y = circuit
.add_gate(Gate::Input(Input::SecretPlaintext {
inputer: 0,
algebraic_type: AlgebraicType::Mersenne107,
batch_size: 3,
}))
.unwrap();
let z = circuit
.add_gate(Gate::FieldShareBinaryOp {
x,
y,
op: FieldShareBinaryOp::Mul,
})
.unwrap();
circuit.add_output(z).unwrap();
assert_eq!(circuit.nb_inputs(), 2);
assert_eq!(circuit.nb_gates(), 2 + 1);
assert_eq!(circuit.nb_outputs(), 1);
}
}