Skip to content
This repository was archived by the owner on Apr 9, 2024. It is now read-only.

Commit 097cfb0

Browse files
feat!: add block opcode (#114)
* add block opcode * Code review * rename blockop into memop * Code review * Remove the GateResolution change from the branch * use ok_or instead of a if for readability * Code review * Code review * code review * Code review Update acir/src/circuit/opcodes.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * Code review Update acvm/src/pwg/block.rs Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> * fix clippy * fix clippy * comment any_witness * Code review * move any_witness --------- Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>
1 parent 9a82723 commit 097cfb0

11 files changed

Lines changed: 252 additions & 56 deletions

File tree

acir/src/circuit/opcodes.rs

Lines changed: 45 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,25 @@ use crate::serialization::{read_n, read_u16, read_u32, write_bytes, write_u16, w
66
use crate::BlackBoxFunc;
77
use serde::{Deserialize, Serialize};
88

9+
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Copy, Default)]
10+
pub struct BlockId(u32);
11+
12+
/// Operation on a block
13+
/// We can either write or read at a block index
14+
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
15+
pub struct MemOp {
16+
pub operation: Expression,
17+
pub index: Expression,
18+
pub value: Expression,
19+
}
20+
921
#[derive(Clone, PartialEq, Eq, Serialize, Deserialize)]
1022
pub enum Opcode {
1123
Arithmetic(Expression),
1224
BlackBoxFuncCall(BlackBoxFuncCall),
1325
Directive(Directive),
26+
// Abstract read/write operations on a block of data
27+
Block(BlockId, Vec<MemOp>),
1428
}
1529

1630
impl Opcode {
@@ -21,17 +35,18 @@ impl Opcode {
2135
Opcode::Arithmetic(_) => "arithmetic",
2236
Opcode::Directive(directive) => directive.name(),
2337
Opcode::BlackBoxFuncCall(g) => g.name.name(),
38+
Opcode::Block(_, _) => "block",
2439
}
2540
}
26-
// We have three types of opcodes allowed in the IR
27-
// Expression, BlackBoxFuncCall and Directives
28-
// When we serialize these opcodes, we use the index
41+
42+
// When we serialize the opcodes, we use the index
2943
// to uniquely identify which category of opcode we are dealing with.
3044
pub(crate) fn to_index(&self) -> u8 {
3145
match self {
3246
Opcode::Arithmetic(_) => 0,
3347
Opcode::BlackBoxFuncCall(_) => 1,
3448
Opcode::Directive(_) => 2,
49+
Opcode::Block(_, _) => 3,
3550
}
3651
}
3752

@@ -53,6 +68,17 @@ impl Opcode {
5368
Opcode::Arithmetic(expr) => expr.write(writer),
5469
Opcode::BlackBoxFuncCall(func_call) => func_call.write(writer),
5570
Opcode::Directive(directive) => directive.write(writer),
71+
Opcode::Block(id, trace) => {
72+
write_u32(&mut writer, id.0)?;
73+
write_u32(&mut writer, trace.len() as u32)?;
74+
75+
for op in trace {
76+
op.operation.write(&mut writer)?;
77+
op.index.write(&mut writer)?;
78+
op.value.write(&mut writer)?;
79+
}
80+
Ok(())
81+
}
5682
}
5783
}
5884
pub fn read<R: Read>(mut reader: R) -> std::io::Result<Self> {
@@ -74,6 +100,18 @@ impl Opcode {
74100
let directive = Directive::read(reader)?;
75101
Ok(Opcode::Directive(directive))
76102
}
103+
3 => {
104+
let id = read_u32(&mut reader)?;
105+
let len = read_u32(&mut reader)?;
106+
let mut trace = Vec::with_capacity(len as usize);
107+
for _i in 0..len {
108+
let operation = Expression::read(&mut reader)?;
109+
let index = Expression::read(&mut reader)?;
110+
let value = Expression::read(&mut reader)?;
111+
trace.push(MemOp { operation, index, value });
112+
}
113+
Ok(Opcode::Block(BlockId(id), trace))
114+
}
77115
_ => Err(std::io::ErrorKind::InvalidData.into()),
78116
}
79117
}
@@ -175,6 +213,10 @@ impl std::fmt::Display for Opcode {
175213
witnesses.last().unwrap().witness_index()
176214
),
177215
},
216+
Opcode::Block(id, trace) => {
217+
write!(f, "BLOCK ")?;
218+
write!(f, "(id: {}, len: {}) ", id.0, trace.len())
219+
}
178220
}
179221
}
180222
}

acir/src/native_types/arithmetic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ impl Expression {
171171
self.mul_terms.is_empty() && self.linear_combinations.is_empty()
172172
}
173173

174-
/// Returns `true` if highest degree term in the expression is one.
174+
/// Returns `true` if highest degree term in the expression is one or less.
175175
///
176176
/// - `mul_term` in an expression contains degree-2 terms
177177
/// - `linear_combinations` contains degree-1 terms

acvm/src/compiler/transformers/fallback.rs

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,8 @@ impl FallbackTransformer {
2222

2323
for opcode in acir.opcodes {
2424
let bb_func_call = match &opcode {
25-
Opcode::Arithmetic(_) | Opcode::Directive(_) => {
26-
// If it is not a black box function, then it is a directive or
27-
// an arithmetic expression which are always supported
25+
Opcode::Arithmetic(_) | Opcode::Directive(_) | Opcode::Block(_, _) => {
26+
// directive, arithmetic expression or block are handled by acvm
2827
acir_supported_opcodes.push(opcode);
2928
continue;
3029
}

acvm/src/lib.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ use acir::{
1313
native_types::{Expression, Witness},
1414
BlackBoxFunc,
1515
};
16+
use pwg::block::Blocks;
1617
use std::collections::BTreeMap;
1718
use thiserror::Error;
1819

@@ -61,13 +62,14 @@ pub trait PartialWitnessGenerator {
6162
fn solve(
6263
&self,
6364
initial_witness: &mut BTreeMap<Witness, FieldElement>,
64-
mut opcodes: Vec<Opcode>,
65+
mut opcode_to_solve: Vec<Opcode>,
6566
) -> Result<(), OpcodeResolutionError> {
6667
let mut unresolved_opcodes: Vec<Opcode> = Vec::new();
67-
while !opcodes.is_empty() {
68+
let mut blocks = Blocks::default();
69+
while !opcode_to_solve.is_empty() {
6870
unresolved_opcodes.clear();
6971

70-
for opcode in &opcodes {
72+
for opcode in &opcode_to_solve {
7173
let resolution = match opcode {
7274
Opcode::Arithmetic(expr) => ArithmeticSolver::solve(initial_witness, expr),
7375
Opcode::BlackBoxFuncCall(bb_func) => {
@@ -76,8 +78,8 @@ pub trait PartialWitnessGenerator {
7678
Opcode::Directive(directive) => {
7779
Self::solve_directives(initial_witness, directive)
7880
}
81+
Opcode::Block(id, trace) => blocks.solve(*id, trace, initial_witness),
7982
};
80-
8183
match resolution {
8284
Ok(_) => {
8385
// We do nothing in the happy case
@@ -91,7 +93,7 @@ pub trait PartialWitnessGenerator {
9193
Err(err) => return Err(err),
9294
}
9395
}
94-
std::mem::swap(&mut opcodes, &mut unresolved_opcodes);
96+
std::mem::swap(&mut opcode_to_solve, &mut unresolved_opcodes);
9597
}
9698
Ok(())
9799
}

acvm/src/pwg.rs

Lines changed: 12 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,14 @@ use acir::{
77
};
88
use std::collections::BTreeMap;
99

10+
use self::arithmetic::ArithmeticSolver;
11+
1012
// arithmetic
1113
pub mod arithmetic;
1214
// Directives
1315
pub mod directives;
1416
// black box functions
17+
pub mod block;
1518
pub mod hash;
1619
pub mod logic;
1720
pub mod range;
@@ -30,37 +33,22 @@ pub fn witness_to_value(
3033
None => Err(OpcodeNotSolvable::MissingAssignment(witness.0).into()),
3134
}
3235
}
36+
3337
// TODO: There is an issue open to decide on whether we need to get values from Expressions
3438
// TODO versus just getting values from Witness
3539
pub fn get_value(
3640
expr: &Expression,
3741
initial_witness: &BTreeMap<Witness, FieldElement>,
3842
) -> Result<FieldElement, OpcodeResolutionError> {
39-
let mut result = expr.q_c;
40-
41-
for term in &expr.linear_combinations {
42-
let coefficient = term.0;
43-
let variable = term.1;
44-
45-
// Get the value assigned to that variable
46-
let assignment = *witness_to_value(initial_witness, variable)?;
47-
48-
result += coefficient * assignment;
49-
}
50-
51-
for term in &expr.mul_terms {
52-
let coefficient = term.0;
53-
let lhs_variable = term.1;
54-
let rhs_variable = term.2;
55-
56-
// Get the values assigned to those variables
57-
let lhs_assignment = *witness_to_value(initial_witness, lhs_variable)?;
58-
let rhs_assignment = *witness_to_value(initial_witness, rhs_variable)?;
59-
60-
result += coefficient * lhs_assignment * rhs_assignment;
43+
let expr = ArithmeticSolver::evaluate(expr, initial_witness);
44+
match expr.to_const() {
45+
Some(value) => Ok(value),
46+
None => {
47+
Err(OpcodeResolutionError::OpcodeNotSolvable(OpcodeNotSolvable::MissingAssignment(
48+
ArithmeticSolver::any_witness_from_expression(&expr).unwrap().0,
49+
)))
50+
}
6151
}
62-
63-
Ok(result)
6452
}
6553

6654
// Inserts `value` into the initial witness map

acvm/src/pwg/arithmetic.rs

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use crate::{OpcodeNotSolvable, OpcodeResolutionError};
1111
pub struct ArithmeticSolver;
1212

1313
#[allow(clippy::enum_variant_names)]
14-
enum GateStatus {
14+
pub enum GateStatus {
1515
GateSatisfied(FieldElement),
1616
GateSolvable(FieldElement, (FieldElement, Witness)),
1717
GateUnsolvable,
@@ -162,7 +162,7 @@ impl ArithmeticSolver {
162162
/// Returns the summation of all of the variables, plus the unknown variable
163163
/// Returns None, if there is more than one unknown variable
164164
/// We cannot assign
165-
fn solve_fan_in_term(
165+
pub fn solve_fan_in_term(
166166
arith_gate: &Expression,
167167
witness_assignments: &BTreeMap<Witness, FieldElement>,
168168
) -> GateStatus {
@@ -229,6 +229,21 @@ impl ArithmeticSolver {
229229
result.q_c += expr.q_c;
230230
result
231231
}
232+
233+
// Returns one witness belonging to an expression, in no relevant order
234+
// Returns None if the expression is const
235+
// The function is used during partial witness generation to report unsolved witness
236+
pub fn any_witness_from_expression(expr: &Expression) -> Option<Witness> {
237+
if expr.linear_combinations.is_empty() {
238+
if expr.mul_terms.is_empty() {
239+
None
240+
} else {
241+
Some(expr.mul_terms[0].1)
242+
}
243+
} else {
244+
Some(expr.linear_combinations[0].1)
245+
}
246+
}
232247
}
233248

234249
#[test]

0 commit comments

Comments
 (0)