Skip to content
This repository has been archived by the owner on Oct 31, 2023. It is now read-only.

feat!: serialise RAM and ROM opcodes #153

Merged
merged 9 commits into from
May 15, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions flake.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

99 changes: 96 additions & 3 deletions src/barretenberg_structures.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use acvm::acir::circuit::opcodes::MemoryBlock;
use acvm::acir::circuit::{Circuit, Opcode};
use acvm::acir::native_types::Expression;
use acvm::acir::BlackBoxFunc;
Expand Down Expand Up @@ -426,6 +427,7 @@ pub(crate) struct ConstraintSystem {
schnorr_constraints: Vec<SchnorrConstraint>,
ecdsa_secp256k1_constraints: Vec<EcdsaConstraint>,
blake2s_constraints: Vec<Blake2sConstraint>,
block_constraints: Vec<BlockConstraint>,
keccak_constraints: Vec<Keccak256Constraint>,
pedersen_constraints: Vec<PedersenConstraint>,
hash_to_field_constraints: Vec<HashToFieldConstraint>,
Expand Down Expand Up @@ -538,6 +540,11 @@ impl ConstraintSystem {
self.constraints = constraints;
self
}

pub(crate) fn block_constraints(mut self, block_constraints: Vec<BlockConstraint>) -> Self {
self.block_constraints = block_constraints;
self
}
}

impl ConstraintSystem {
Expand Down Expand Up @@ -641,13 +648,91 @@ impl ConstraintSystem {
buffer.extend(&constraint.to_bytes());
}

// Serialize each Block constraint
let len = self.block_constraints.len() as u32;
buffer.extend_from_slice(&len.to_be_bytes());
for constraint in self.block_constraints.iter() {
buffer.extend(&constraint.to_bytes());
}

buffer
}
}

#[derive(Clone, Hash, Debug)]
pub(crate) struct MemOpBarretenberg {
pub(crate) is_store: i8,
pub(crate) index: Constraint,
pub(crate) value: Constraint,
}
impl MemOpBarretenberg {
fn to_bytes(&self) -> Vec<u8> {
let mut buffer = Vec::new();

buffer.extend_from_slice(&self.is_store.to_be_bytes());
buffer.extend_from_slice(&self.index.to_bytes());
buffer.extend_from_slice(&self.value.to_bytes());

buffer
}
}

#[derive(Clone, Hash, Debug)]
pub(crate) struct BlockConstraint {
pub(crate) init: Vec<Constraint>,
pub(crate) trace: Vec<MemOpBarretenberg>,
pub(crate) is_ram: i8,
}

impl BlockConstraint {
fn to_bytes(&self) -> Vec<u8> {
let mut buffer = Vec::new();

let len = self.init.len() as u32;
buffer.extend_from_slice(&len.to_be_bytes());
for value in self.init.iter() {
buffer.extend_from_slice(&value.to_bytes());
}
guipublic marked this conversation as resolved.
Show resolved Hide resolved

let len = self.trace.len() as u32;
buffer.extend_from_slice(&len.to_be_bytes());
for op in self.trace.iter() {
buffer.extend_from_slice(&op.to_bytes());
}
buffer.extend_from_slice(&self.is_ram.to_be_bytes());

buffer
}

fn from_memory_block(b: &MemoryBlock, is_ram_block: bool) -> BlockConstraint {
let mut init = Vec::new();
let mut trace = Vec::new();
let len = b.len as usize;
for op in b.trace.iter().take(len) {
assert_eq!(op.operation, Expression::one());
init.push(serialize_arithmetic_gates(&op.value));
}
for op in b.trace.iter().skip(len) {
let index = serialize_arithmetic_gates(&op.index);
let value = serialize_arithmetic_gates(&op.value);
let bb_op = MemOpBarretenberg {
is_store: op.operation.to_const().unwrap().to_u128() as i8,
index,
value,
};
trace.push(bb_op);
}
let is_ram = i8::from(is_ram_block);
BlockConstraint {
init,
trace,
is_ram,
}
}
}

impl TryFrom<&Circuit> for ConstraintSystem {
type Error = Error;

/// Converts an `IR` into the `StandardFormat` constraint system
fn try_from(circuit: &Circuit) -> Result<Self, Self::Error> {
// Create constraint system
Expand All @@ -656,6 +741,7 @@ impl TryFrom<&Circuit> for ConstraintSystem {
let mut logic_constraints: Vec<LogicConstraint> = Vec::new();
let mut sha256_constraints: Vec<Sha256Constraint> = Vec::new();
let mut blake2s_constraints: Vec<Blake2sConstraint> = Vec::new();
let mut block_constraints: Vec<BlockConstraint> = Vec::new();
let mut keccak_constraints: Vec<Keccak256Constraint> = Vec::new();
let mut pedersen_constraints: Vec<PedersenConstraint> = Vec::new();
let mut compute_merkle_root_constraints: Vec<ComputeMerkleRootConstraint> = Vec::new();
Expand Down Expand Up @@ -1044,8 +1130,14 @@ impl TryFrom<&Circuit> for ConstraintSystem {
Opcode::Directive(_) | Opcode::Oracle(_) => {
// Directives & Oracles are only needed by the pwg
}
Opcode::Block(_) | Opcode::RAM(_) | Opcode::ROM(_) => {
// TODO: implement serialization to match BB's interface
Opcode::Block(_) => {
// Block is managed by ACVM
}
Opcode::RAM(block) => {
block_constraints.push(BlockConstraint::from_memory_block(block, true))
}
Opcode::ROM(block) => {
block_constraints.push(BlockConstraint::from_memory_block(block, false))
}
}
}
Expand All @@ -1062,6 +1154,7 @@ impl TryFrom<&Circuit> for ConstraintSystem {
schnorr_constraints,
ecdsa_secp256k1_constraints,
blake2s_constraints,
block_constraints,
keccak_constraints,
hash_to_field_constraints,
constraints,
Expand Down
111 changes: 109 additions & 2 deletions src/composer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,8 +398,9 @@ mod test {
use super::*;
use crate::{
barretenberg_structures::{
ComputeMerkleRootConstraint, Constraint, Keccak256Constraint, LogicConstraint,
PedersenConstraint, RangeConstraint, SchnorrConstraint,
BlockConstraint, ComputeMerkleRootConstraint, Constraint, Keccak256Constraint,
LogicConstraint, MemOpBarretenberg, PedersenConstraint, RangeConstraint,
SchnorrConstraint,
},
merkle::{MerkleTree, MessageHasher},
};
Expand Down Expand Up @@ -769,6 +770,112 @@ mod test {
test_composer_with_pk_vk(constraint_system, vec![case_1])
}

#[test]
fn test_memory_constraints() -> Result<(), Error> {
let two_field = FieldElement::one() + FieldElement::one();
let one = Constraint {
a: 0,
b: 0,
c: 0,
qm: FieldElement::zero(),
ql: FieldElement::zero(),
qr: FieldElement::zero(),
qo: FieldElement::zero(),
qc: FieldElement::one(),
};

let two_x_constraint = Constraint {
a: 1,
b: 0,
c: 0,
qm: FieldElement::zero(),
ql: two_field,
qr: FieldElement::zero(),
qo: FieldElement::zero(),
qc: FieldElement::zero(),
};
let x_1_constraint = Constraint {
a: 1,
b: 0,
c: 0,
qm: FieldElement::zero(),
ql: FieldElement::one(),
qr: FieldElement::zero(),
qo: FieldElement::zero(),
qc: FieldElement::one(),
};

let y_constraint = Constraint {
a: 2,
b: 0,
c: 0,
qm: FieldElement::zero(),
ql: FieldElement::one(),
qr: FieldElement::zero(),
qo: FieldElement::zero(),
qc: FieldElement::zero(),
};
let z_constraint = Constraint {
a: 3,
b: 0,
c: 0,
qm: FieldElement::zero(),
ql: FieldElement::one(),
qr: FieldElement::zero(),
qo: FieldElement::zero(),
qc: FieldElement::zero(),
};
let op1 = MemOpBarretenberg {
index: two_x_constraint,
value: y_constraint,
is_store: 0,
};
let op2 = MemOpBarretenberg {
index: x_1_constraint.clone(),
value: z_constraint,
is_store: 0,
};
let block_constraint = BlockConstraint {
init: vec![one, x_1_constraint],
trace: vec![op1, op2],
is_ram: 0,
};

let result_constraint = Constraint {
a: 2,
b: 3,
c: 0,
qm: FieldElement::zero(),
ql: FieldElement::one(),
qr: FieldElement::one(),
qo: FieldElement::zero(),
qc: -(two_field),
};
let constraint_system = ConstraintSystem::new()
.var_num(4)
.block_constraints(vec![block_constraint])
.constraints(vec![result_constraint]);

let scalar_0 = FieldElement::zero();
let scalar_1 = FieldElement::one();
let witness_values = vec![scalar_0, scalar_1, scalar_1];

let case_1 = WitnessResult {
witness: witness_values.into(),
public_inputs: Assignments::default(),
result: true,
};

let bad_values = vec![scalar_0, scalar_1, scalar_1 + scalar_1];
let case_2 = WitnessResult {
witness: bad_values.into(),
public_inputs: Assignments::default(),
result: false,
};

test_composer_with_pk_vk(constraint_system, vec![case_1, case_2])
}

#[test]
fn test_compute_merkle_root_constraint() -> Result<(), Error> {
use tempfile::tempdir;
Expand Down