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

Commit

Permalink
feat!: serialise RAM and ROM opcodes (#153)
Browse files Browse the repository at this point in the history
* Serialise RAM and ROM opcodes

* Add unit test for block constraints

* Fix block serialisation

* chore: bump barretenberg to version with blocks

* add a failing test case for dynamic memory

* code review

---------

Co-authored-by: Tom French <tom@tomfren.ch>
  • Loading branch information
guipublic and TomAFrench authored May 15, 2023
1 parent dbaa186 commit 3d3847d
Show file tree
Hide file tree
Showing 3 changed files with 208 additions and 8 deletions.
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());
}

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

0 comments on commit 3d3847d

Please sign in to comment.