use primitives::{
algebra::{
elliptic_curve::{BaseFieldElement, Curve25519Ristretto as EC, Point, Scalar},
field::{subfield_element::Mersenne107Element, Bit},
BoxedUint,
},
utils::codec::bincode_io,
};
use crate::circuit::old::v1::{
circuit::{Circuit, GateIndex},
constants::{
BaseFieldPlaintext,
BaseFieldPlaintextBatch,
BitPlaintext,
BitPlaintextBatch,
Mersenne107Plaintext,
Mersenne107PlaintextBatch,
PointPlaintext,
PointPlaintextBatch,
ScalarPlaintext,
ScalarPlaintextBatch,
},
gate::Gate,
ops::{
Batched,
BitShareBinaryOp,
BitShareUnaryOp,
FieldPlaintextBinaryOp,
FieldPlaintextUnaryOp,
FieldShareBinaryOp,
FieldShareUnaryOp,
Input,
PointPlaintextBinaryOp,
PointPlaintextUnaryOp,
PointShareBinaryOp,
PointShareUnaryOp,
},
AlgebraicType,
FieldType,
ShareOrPlaintext,
};
fn all_gates() -> Vec<Gate<EC>> {
let scalar = || Scalar::<EC>::from(1u64);
let base_field = || BaseFieldElement::<EC>::from(1u64);
let mersenne107 = || Mersenne107Element::from(1u64);
let bit = || Bit::from(false);
let point = || Point::<EC>::identity();
let exp = || BoxedUint::from(vec![1u64]);
let gi = GateIndex::new;
vec![
Gate::Input {
input_type: Input::SecretPlaintext {
inputer: 0,
algebraic_type: AlgebraicType::ScalarField,
batched: Batched::No,
},
},
Gate::Input {
input_type: Input::SecretPlaintext {
inputer: 0,
algebraic_type: AlgebraicType::ScalarField,
batched: Batched::Yes(1),
},
},
Gate::Input {
input_type: Input::Share {
algebraic_type: AlgebraicType::Point,
batched: Batched::No,
},
},
Gate::Input {
input_type: Input::Share {
algebraic_type: AlgebraicType::Point,
batched: Batched::Yes(1),
},
},
Gate::Input {
input_type: Input::RandomShare {
algebraic_type: AlgebraicType::Bit,
batched: Batched::No,
},
},
Gate::Input {
input_type: Input::RandomShare {
algebraic_type: AlgebraicType::Bit,
batched: Batched::Yes(1),
},
},
Gate::Input {
input_type: Input::Scalar(ScalarPlaintext::<EC>::Fixed(scalar())),
},
Gate::Input {
input_type: Input::Scalar(ScalarPlaintext::<EC>::Input(1)),
},
Gate::Input {
input_type: Input::ScalarBatch(ScalarPlaintextBatch::<EC>::Fixed(vec![scalar()])),
},
Gate::Input {
input_type: Input::ScalarBatch(ScalarPlaintextBatch::<EC>::Input(1)),
},
Gate::Input {
input_type: Input::BaseField(BaseFieldPlaintext::<EC>::Fixed(base_field())),
},
Gate::Input {
input_type: Input::BaseField(BaseFieldPlaintext::<EC>::Input(1)),
},
Gate::Input {
input_type: Input::BaseFieldBatch(BaseFieldPlaintextBatch::<EC>::Fixed(vec![
base_field(),
])),
},
Gate::Input {
input_type: Input::BaseFieldBatch(BaseFieldPlaintextBatch::<EC>::Input(1)),
},
Gate::Input {
input_type: Input::Mersenne107(Mersenne107Plaintext::Fixed(mersenne107())),
},
Gate::Input {
input_type: Input::Mersenne107(Mersenne107Plaintext::Input(1)),
},
Gate::Input {
input_type: Input::Mersenne107Batch(Mersenne107PlaintextBatch::Fixed(vec![
mersenne107(),
])),
},
Gate::Input {
input_type: Input::Mersenne107Batch(Mersenne107PlaintextBatch::Input(1)),
},
Gate::Input {
input_type: Input::Bit(BitPlaintext::Fixed(bit())),
},
Gate::Input {
input_type: Input::Bit(BitPlaintext::Input(1)),
},
Gate::Input {
input_type: Input::BitBatch(BitPlaintextBatch::Fixed(vec![bit()])),
},
Gate::Input {
input_type: Input::BitBatch(BitPlaintextBatch::Input(1)),
},
Gate::Input {
input_type: Input::Point(PointPlaintext::<EC>::Fixed(point())),
},
Gate::Input {
input_type: Input::Point(PointPlaintext::<EC>::Input(1)),
},
Gate::Input {
input_type: Input::PointBatch(PointPlaintextBatch::<EC>::Fixed(vec![point()])),
},
Gate::Input {
input_type: Input::PointBatch(PointPlaintextBatch::<EC>::Input(1)),
},
Gate::FieldShareUnaryOp {
x: gi(0),
op: FieldShareUnaryOp::Neg,
field_type: FieldType::ScalarField,
},
Gate::FieldShareUnaryOp {
x: gi(0),
op: FieldShareUnaryOp::MulInverse,
field_type: FieldType::ScalarField,
},
Gate::FieldShareUnaryOp {
x: gi(0),
op: FieldShareUnaryOp::Open,
field_type: FieldType::ScalarField,
},
Gate::FieldShareUnaryOp {
x: gi(0),
op: FieldShareUnaryOp::IsZero,
field_type: FieldType::ScalarField,
},
Gate::FieldShareBinaryOp {
x: gi(0),
y: gi(1),
y_form: ShareOrPlaintext::Share,
op: FieldShareBinaryOp::Add,
field_type: FieldType::ScalarField,
},
Gate::FieldShareBinaryOp {
x: gi(0),
y: gi(1),
y_form: ShareOrPlaintext::Plaintext,
op: FieldShareBinaryOp::Mul,
field_type: FieldType::ScalarField,
},
Gate::BatchSummation {
x: gi(0),
x_form: ShareOrPlaintext::Share,
algebraic_type: AlgebraicType::ScalarField,
},
Gate::BitShareUnaryOp {
x: gi(0),
op: BitShareUnaryOp::Not,
},
Gate::BitShareUnaryOp {
x: gi(0),
op: BitShareUnaryOp::Open,
},
Gate::BitShareBinaryOp {
x: gi(0),
y: gi(1),
y_form: ShareOrPlaintext::Share,
op: BitShareBinaryOp::Xor,
},
Gate::BitShareBinaryOp {
x: gi(0),
y: gi(1),
y_form: ShareOrPlaintext::Plaintext,
op: BitShareBinaryOp::Or,
},
Gate::BitShareBinaryOp {
x: gi(0),
y: gi(1),
y_form: ShareOrPlaintext::Share,
op: BitShareBinaryOp::And,
},
Gate::PointShareUnaryOp {
p: gi(0),
op: PointShareUnaryOp::Neg,
},
Gate::PointShareUnaryOp {
p: gi(0),
op: PointShareUnaryOp::Open,
},
Gate::PointShareUnaryOp {
p: gi(0),
op: PointShareUnaryOp::IsZero,
},
Gate::PointShareBinaryOp {
p: gi(0),
y: gi(1),
p_form: ShareOrPlaintext::Share,
y_form: ShareOrPlaintext::Share,
op: PointShareBinaryOp::Add,
},
Gate::PointShareBinaryOp {
p: gi(0),
y: gi(1),
p_form: ShareOrPlaintext::Share,
y_form: ShareOrPlaintext::Plaintext,
op: PointShareBinaryOp::ScalarMul,
},
Gate::FieldPlaintextUnaryOp {
x: gi(0),
op: FieldPlaintextUnaryOp::Neg,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextUnaryOp {
x: gi(0),
op: FieldPlaintextUnaryOp::MulInverse,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextUnaryOp {
x: gi(0),
op: FieldPlaintextUnaryOp::BitExtract {
little_endian_bit_idx: 0,
signed: false,
},
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextUnaryOp {
x: gi(0),
op: FieldPlaintextUnaryOp::Sqrt,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextUnaryOp {
x: gi(0),
op: FieldPlaintextUnaryOp::Pow { exp: exp() },
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextBinaryOp {
x: gi(0),
y: gi(1),
op: FieldPlaintextBinaryOp::Add,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextBinaryOp {
x: gi(0),
y: gi(1),
op: FieldPlaintextBinaryOp::Mul,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextBinaryOp {
x: gi(0),
y: gi(1),
op: FieldPlaintextBinaryOp::EuclDiv,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextBinaryOp {
x: gi(0),
y: gi(1),
op: FieldPlaintextBinaryOp::Mod,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextBinaryOp {
x: gi(0),
y: gi(1),
op: FieldPlaintextBinaryOp::Gt,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextBinaryOp {
x: gi(0),
y: gi(1),
op: FieldPlaintextBinaryOp::Ge,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextBinaryOp {
x: gi(0),
y: gi(1),
op: FieldPlaintextBinaryOp::Eq,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextBinaryOp {
x: gi(0),
y: gi(1),
op: FieldPlaintextBinaryOp::Xor,
field_type: FieldType::ScalarField,
},
Gate::FieldPlaintextBinaryOp {
x: gi(0),
y: gi(1),
op: FieldPlaintextBinaryOp::Or,
field_type: FieldType::ScalarField,
},
Gate::BitPlaintextUnaryOp {
x: gi(0),
op: FieldPlaintextUnaryOp::Neg,
},
Gate::BitPlaintextBinaryOp {
x: gi(0),
y: gi(1),
op: FieldPlaintextBinaryOp::Mul,
},
Gate::PointPlaintextUnaryOp {
p: gi(0),
op: PointPlaintextUnaryOp::Neg,
},
Gate::PointPlaintextBinaryOp {
p: gi(0),
y: gi(1),
op: PointPlaintextBinaryOp::Add,
},
Gate::PointPlaintextBinaryOp {
p: gi(0),
y: gi(1),
op: PointPlaintextBinaryOp::ScalarMul,
},
Gate::DaBit {
field_type: FieldType::BaseField,
batched: Batched::No,
},
Gate::DaBit {
field_type: FieldType::ScalarField,
batched: Batched::Yes(1),
},
Gate::DaBit {
field_type: FieldType::MpcField,
batched: Batched::No,
},
Gate::GetDaBitFieldShare {
x: gi(0),
field_type: FieldType::ScalarField,
},
Gate::GetDaBitSharedBit {
x: gi(0),
field_type: FieldType::ScalarField,
},
Gate::BaseFieldPow {
x: gi(0),
exp: exp(),
},
Gate::BitPlaintextToField {
x: gi(0),
field_type: FieldType::BaseField,
},
Gate::BitPlaintextToField {
x: gi(0),
field_type: FieldType::ScalarField,
},
Gate::BitPlaintextToField {
x: gi(0),
field_type: FieldType::MpcField,
},
Gate::FieldPlaintextToBit {
x: gi(0),
field_type: FieldType::ScalarField,
},
Gate::BatchGetIndex {
x: gi(0),
x_type: AlgebraicType::ScalarField,
x_form: ShareOrPlaintext::Share,
index: 0,
},
Gate::CollectToBatch {
wires: vec![gi(0), gi(1)],
x_type: AlgebraicType::ScalarField,
x_form: ShareOrPlaintext::Share,
},
Gate::PointFromPlaintextCoordinates {
wires: vec![gi(0), gi(1)],
},
Gate::PlaintextPointToCoordinates { point: gi(0) },
Gate::PlaintextKeccakF1600 {
wires: vec![gi(0), gi(1)],
},
Gate::CompressPlaintextPoint { point: gi(0) },
Gate::KeyRecoveryPlaintextComputeErrors {
d_minus_one: gi(0),
syndromes: gi(1),
},
]
}
fn sample_circuit() -> Circuit<EC> {
Circuit::new_for_test(
vec![
Gate::Input {
input_type: Input::SecretPlaintext {
inputer: 0,
algebraic_type: AlgebraicType::ScalarField,
batched: Batched::No,
},
},
Gate::Input {
input_type: Input::SecretPlaintext {
inputer: 1,
algebraic_type: AlgebraicType::ScalarField,
batched: Batched::No,
},
},
],
vec![GateIndex::new(0), GateIndex::new(1)],
vec![GateIndex::new(1)],
)
}
const EXPECTED_FINGERPRINT: &str =
"861b86ca2b29c0618706023addae0e0cfd763531472e7b8afe24fa908f9352a9";
#[test]
fn wire_format_matches_frozen_v1() {
let bytes = bincode_io::serialize(&(sample_circuit(), all_gates()))
.expect("circuit/gate bincode serialization");
let fingerprint = blake3::hash(&bytes).to_hex().to_string();
assert_eq!(
fingerprint, EXPECTED_FINGERPRINT,
"\n\n`old::v1` wire format changed -- it must never change. Revert whatever touched \
`old::v1::gate`/`ops`/`constants`/`circuit::Circuit`; note that v1's `FieldType`, \
`AlgebraicType`, `ShareOrPlaintext`, and all of its op enums are type aliases to \
`latest::mod`/`latest::ops`, so a variant change there breaks v1 too. Do not update \
EXPECTED_FINGERPRINT.\n"
);
}
#[test]
fn fixture_round_trips() {
let fixture = include_bytes!("testdata/circuit.bin");
let (circuit, gates): (Circuit<EC>, Vec<Gate<EC>>) =
bincode_io::deserialize(fixture).expect("fixture must still deserialize");
let bytes =
bincode_io::serialize(&(circuit, gates)).expect("circuit/gate bincode serialization");
assert_eq!(
bytes, fixture,
"\n\nRe-encoding the decoded `testdata/circuit.bin` fixture didn't reproduce the original \
bytes -- `old::v1` must never change. Revert whatever touched it.\n"
);
}