From bcb631dbfe39f9d8069d0b2dfd9a2754b2b86f40 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 13 Feb 2023 17:15:43 +0000 Subject: [PATCH 01/37] assign a VM per array --- crates/noirc_evaluator/src/ssa/acir_gen.rs | 18 ++++++------- .../acir_gen/{memory_map.rs => acir_mem.rs} | 27 +++++++++---------- .../src/ssa/acir_gen/operations/binary.rs | 4 +-- .../src/ssa/acir_gen/operations/cmp.rs | 8 +++--- .../src/ssa/acir_gen/operations/intrinsics.rs | 17 ++++++------ .../src/ssa/acir_gen/operations/load.rs | 4 +-- .../src/ssa/acir_gen/operations/return.rs | 4 +-- .../src/ssa/acir_gen/operations/store.rs | 8 +++--- .../src/hir/resolution/errors.rs | 2 +- 9 files changed, 45 insertions(+), 47 deletions(-) rename crates/noirc_evaluator/src/ssa/acir_gen/{memory_map.rs => acir_mem.rs} (81%) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 52fe4de857f..80008275e81 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -18,12 +18,12 @@ use internal_var_cache::InternalVarCache; // Expose this to the crate as we need to apply range constraints when // converting the ABI(main parameters) to Noir types pub(crate) use constraints::range_constraint; -mod memory_map; -use memory_map::MemoryMap; +mod acir_mem; +use acir_mem::AcirMem; #[derive(Default)] pub struct Acir { - memory_map: MemoryMap, + memory_trace: AcirMem, var_cache: InternalVarCache, } @@ -39,12 +39,12 @@ impl Acir { binary, condition, constrain, intrinsics, load, not, r#return, store, truncate, }; - let memory_map = &mut self.memory_map; + let acir_mem = &mut self.memory_trace; let var_cache = &mut self.var_cache; let output = match &ins.operation { Operation::Binary(binary) => { - binary::evaluate(binary, ins.res_type, var_cache, memory_map, evaluator, ctx) + binary::evaluate(binary, ins.res_type, var_cache, acir_mem, evaluator, ctx) } Operation::Constrain(value, ..) => { constrain::evaluate(value, var_cache, evaluator, ctx) @@ -57,19 +57,19 @@ impl Acir { truncate::evaluate(value, *bit_size, *max_bit_size, var_cache, evaluator, ctx) } Operation::Intrinsic(opcode, args) => { - intrinsics::evaluate(args, ins, *opcode, var_cache, memory_map, ctx, evaluator) + intrinsics::evaluate(args, ins, *opcode, var_cache, acir_mem, ctx, evaluator) } Operation::Return(node_ids) => { - r#return::evaluate(node_ids, memory_map, var_cache, evaluator, ctx)? + r#return::evaluate(node_ids, acir_mem, var_cache, evaluator, ctx)? } Operation::Cond { condition, val_true: lhs, val_false: rhs } => { condition::evaluate(*condition, *lhs, *rhs, var_cache, evaluator, ctx) } Operation::Load { array_id, index } => { - load::evaluate(*array_id, *index, memory_map, var_cache, evaluator, ctx) + load::evaluate(*array_id, *index, acir_mem, var_cache, evaluator, ctx) } Operation::Store { array_id, index, value } => { - store::evaluate(*array_id, *index, *value, memory_map, var_cache, evaluator, ctx) + store::evaluate(*array_id, *index, *value, acir_mem, var_cache, evaluator, ctx) } Operation::Nop => None, i @ Operation::Jne(..) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/memory_map.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs similarity index 81% rename from crates/noirc_evaluator/src/ssa/acir_gen/memory_map.rs rename to crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 5e91ad52aa3..d3106a06428 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/memory_map.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -5,26 +5,31 @@ use crate::ssa::{ }; use acvm::acir::native_types::Witness; use iter_extended::vecmap; -use std::collections::HashMap; +use std::collections::BTreeMap; -// maps memory address to expression #[derive(Default)] -pub struct MemoryMap { - inner: HashMap, +pub struct AcirMem { + // maps memory address to InternalVar + memory_map: BTreeMap>, } -impl MemoryMap { +impl AcirMem { + // returns the memory_map for the array + pub fn array_map_mut(&mut self, array_id: ArrayId) -> &mut BTreeMap { + let entry = self.memory_map.entry(array_id); + entry.or_insert(BTreeMap::new()) + } + //Map the outputs into the array pub(crate) fn map_array(&mut self, a: ArrayId, outputs: &[Witness], ctx: &SsaContext) { let array = &ctx.mem[a]; - let address = array.adr; for i in 0..array.len { let var = if i < outputs.len() as u32 { InternalVar::from(outputs[i as usize]) } else { InternalVar::zero_expr() }; - self.inner.insert(address + i, var); + self.array_map_mut(array.id).insert(i, var); } } @@ -60,10 +65,8 @@ impl MemoryMap { return None; // IndexOutOfBoundsError } - let address_of_element = array.absolute_adr(offset); - // Check the memory_map to see if the element is there - if let Some(internal_var) = self.inner.get(&address_of_element) { + if let Some(internal_var) = self.array_map_mut(array.id).get(&offset) { return Some(internal_var.clone()); }; @@ -78,8 +81,4 @@ impl MemoryMap { Some(array_element) } - - pub(crate) fn insert(&mut self, key: u32, value: InternalVar) -> Option { - self.inner.insert(key, value) - } } diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/binary.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/binary.rs index 57bc0782d16..286ba988eec 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/binary.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/binary.rs @@ -1,7 +1,7 @@ use crate::{ ssa::{ acir_gen::{ - constraints, internal_var_cache::InternalVarCache, memory_map::MemoryMap, operations, + acir_mem::AcirMem, constraints, internal_var_cache::InternalVarCache, operations, InternalVar, }, context::SsaContext, @@ -30,7 +30,7 @@ pub(crate) fn evaluate( binary: &node::Binary, res_type: ObjectType, var_cache: &mut InternalVarCache, - memory_map: &mut MemoryMap, + memory_map: &mut AcirMem, evaluator: &mut Evaluator, ctx: &SsaContext, ) -> Option { diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/cmp.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/cmp.rs index 7a282fdf0f9..86e5c0211d6 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/cmp.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/cmp.rs @@ -1,6 +1,6 @@ use crate::{ ssa::{ - acir_gen::{constraints, memory_map::MemoryMap, InternalVar}, + acir_gen::{acir_mem::AcirMem, constraints, InternalVar}, context::SsaContext, mem::{MemArray, Memory}, node::NodeId, @@ -26,7 +26,7 @@ use iter_extended::vecmap; // so in reality, the NEQ instruction will be done on the fields // of the struct pub(crate) fn evaluate_neq( - memory_map: &mut MemoryMap, + memory_map: &mut AcirMem, lhs: NodeId, rhs: NodeId, l_c: Option, @@ -89,7 +89,7 @@ pub(crate) fn evaluate_neq( } pub(crate) fn evaluate_eq( - memory_map: &mut MemoryMap, + memory_map: &mut AcirMem, lhs: NodeId, rhs: NodeId, l_c: Option, @@ -107,7 +107,7 @@ pub(crate) fn evaluate_eq( // // N.B. We assumes the lengths of a and b are the same but it is not checked inside the function. fn array_eq( - memory_map: &mut MemoryMap, + memory_map: &mut AcirMem, a: &MemArray, b: &MemArray, evaluator: &mut Evaluator, diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs index 8beed8119cf..ccd1ce15ea8 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs @@ -1,6 +1,6 @@ use crate::{ ssa::{ - acir_gen::{constraints::to_radix_base, InternalVar, InternalVarCache, MemoryMap}, + acir_gen::{constraints::to_radix_base, AcirMem, InternalVar, InternalVarCache}, builtin, context::SsaContext, mem::ArrayId, @@ -24,7 +24,7 @@ pub(crate) fn evaluate( instruction: &Instruction, opcode: builtin::Opcode, var_cache: &mut InternalVarCache, - memory_map: &mut MemoryMap, + memory_map: &mut AcirMem, ctx: &SsaContext, evaluator: &mut Evaluator, ) -> Option { @@ -77,7 +77,7 @@ pub(crate) fn evaluate( // Transform the arguments of intrinsic functions into witnesses fn prepare_inputs( var_cache: &mut InternalVarCache, - memory_map: &mut MemoryMap, + memory_map: &mut AcirMem, arguments: &[NodeId], cfg: &SsaContext, evaluator: &mut Evaluator, @@ -93,7 +93,7 @@ fn prepare_inputs( fn resolve_node_id( node_id: &NodeId, var_cache: &mut InternalVarCache, - memory_map: &mut MemoryMap, + memory_map: &mut AcirMem, cfg: &SsaContext, evaluator: &mut Evaluator, ) -> Vec { @@ -135,7 +135,7 @@ fn resolve_node_id( fn resolve_array( array_id: ArrayId, - memory_map: &mut MemoryMap, + acir_mem: &mut AcirMem, cfg: &SsaContext, evaluator: &mut Evaluator, ) -> Vec { @@ -144,7 +144,7 @@ fn resolve_array( let array = &cfg.mem[array_id]; let num_bits = array.element_type.bits(); for i in 0..array.len { - let mut arr_element = memory_map + let mut arr_element = acir_mem .load_array_element_constant_index(array, i) .expect("array index out of bounds"); @@ -153,8 +153,7 @@ fn resolve_array( ); let func_input = FunctionInput { witness, num_bits }; - let address = array.adr + i; - memory_map.insert(address, arr_element); + acir_mem.array_map_mut(array.id).insert(i, arr_element); //todo ca sert a qqchose ?? inputs.push(func_input) } @@ -163,7 +162,7 @@ fn resolve_array( } fn prepare_outputs( - memory_map: &mut MemoryMap, + memory_map: &mut AcirMem, pointer: NodeId, output_nb: u32, ctx: &SsaContext, diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/load.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/load.rs index b12e9c487b6..c28e77e8220 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/load.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/load.rs @@ -1,6 +1,6 @@ use crate::{ ssa::{ - acir_gen::{internal_var_cache::InternalVarCache, memory_map::MemoryMap, InternalVar}, + acir_gen::{acir_mem::AcirMem, internal_var_cache::InternalVarCache, InternalVar}, context::SsaContext, mem::{self, ArrayId}, node::NodeId, @@ -11,7 +11,7 @@ use crate::{ pub(crate) fn evaluate( array_id: ArrayId, index: NodeId, - memory_map: &mut MemoryMap, + memory_map: &mut AcirMem, var_cache: &mut InternalVarCache, evaluator: &mut Evaluator, ctx: &SsaContext, diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/return.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/return.rs index 2fc08cdf486..96b637d99c2 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/return.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/return.rs @@ -1,7 +1,7 @@ use crate::{ errors::RuntimeErrorKind, ssa::{ - acir_gen::{internal_var_cache::InternalVarCache, memory_map::MemoryMap, InternalVar}, + acir_gen::{acir_mem::AcirMem, internal_var_cache::InternalVarCache, InternalVar}, context::SsaContext, mem::Memory, node::NodeId, @@ -11,7 +11,7 @@ use crate::{ pub(crate) fn evaluate( node_ids: &[NodeId], - memory_map: &mut MemoryMap, + memory_map: &mut AcirMem, var_cache: &mut InternalVarCache, evaluator: &mut Evaluator, ctx: &SsaContext, diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs index 1fd72793eb6..329513f06a0 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs @@ -1,6 +1,6 @@ use crate::{ ssa::{ - acir_gen::{internal_var_cache::InternalVarCache, memory_map::MemoryMap, InternalVar}, + acir_gen::{acir_mem::AcirMem, internal_var_cache::InternalVarCache, InternalVar}, context::SsaContext, mem::{self, ArrayId}, node::NodeId, @@ -12,7 +12,7 @@ pub(crate) fn evaluate( array_id: ArrayId, index: NodeId, value: NodeId, - memory_map: &mut MemoryMap, + acir_mem: &mut AcirMem, var_cache: &mut InternalVarCache, evaluator: &mut Evaluator, ctx: &SsaContext, @@ -24,8 +24,8 @@ pub(crate) fn evaluate( match index.to_const() { Some(index) => { let idx = mem::Memory::as_u32(index); - let absolute_adr = ctx.mem[array_id].absolute_adr(idx); - memory_map.insert(absolute_adr, value); + let mem_map = acir_mem.array_map_mut(array_id); + mem_map.insert(idx, value); //we do not generate constraint, so no output. None } diff --git a/crates/noirc_frontend/src/hir/resolution/errors.rs b/crates/noirc_frontend/src/hir/resolution/errors.rs index bf1d1ddfcf4..155288203d7 100644 --- a/crates/noirc_frontend/src/hir/resolution/errors.rs +++ b/crates/noirc_frontend/src/hir/resolution/errors.rs @@ -222,7 +222,7 @@ impl From for Diagnostic { ), ResolverError::NonStructUsedInConstructor { typ, span } => Diagnostic::simple_error( "Only struct types can be used in constructor expressions".into(), - format!("{} has no fields to construct it with", typ), + format!("{typ} has no fields to construct it with"), span, ), ResolverError::NonStructWithGenerics { span } => Diagnostic::simple_error( From 520c2f959b913c534bb4ed80ef1f48cc0e0eaa22 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 13 Feb 2023 17:26:52 +0000 Subject: [PATCH 02/37] cargo format --- .../noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs index 2891f1ad4bc..3bf4db01f6b 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs @@ -4,7 +4,7 @@ use crate::{ constraints::{bound_constraint_with_offset, to_radix_base}, expression_from_witness, operations::sort::evaluate_permutation, - InternalVar, InternalVarCache, AcirMem, + AcirMem, InternalVar, InternalVarCache, }, builtin, context::SsaContext, From 9764650b28f395bf7af4d3c70d941163f0677bfd Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 14 Feb 2023 09:50:14 +0000 Subject: [PATCH 03/37] Code review --- .../src/ssa/acir_gen/acir_mem.rs | 22 ++++++++++++++----- .../src/ssa/acir_gen/operations/cmp.rs | 4 ++-- .../src/ssa/acir_gen/operations/intrinsics.rs | 2 +- .../src/ssa/acir_gen/operations/store.rs | 3 +-- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index d3106a06428..29aa254f52a 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -8,16 +8,26 @@ use iter_extended::vecmap; use std::collections::BTreeMap; #[derive(Default)] -pub struct AcirMem { +pub struct ArrayHeap { // maps memory address to InternalVar - memory_map: BTreeMap>, + memory_map: BTreeMap, +} + +/// Handle virtual memory access +#[derive(Default)] +pub struct AcirMem { + virtual_memory: BTreeMap, } impl AcirMem { - // returns the memory_map for the array - pub fn array_map_mut(&mut self, array_id: ArrayId) -> &mut BTreeMap { - let entry = self.memory_map.entry(array_id); - entry.or_insert(BTreeMap::new()) + // Returns the memory_map for the array + fn array_map_mut(&mut self, array_id: ArrayId) -> &mut BTreeMap { + &mut self.virtual_memory.entry(array_id).or_default().memory_map + } + + // Write the value to the array's VM at the specified index + pub fn insert(&mut self, array_id: ArrayId, index: u32, value: InternalVar) { + self.array_map_mut(array_id).insert(index, value); } //Map the outputs into the array diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/cmp.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/cmp.rs index 86e5c0211d6..fdf411acb74 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/cmp.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/cmp.rs @@ -26,7 +26,7 @@ use iter_extended::vecmap; // so in reality, the NEQ instruction will be done on the fields // of the struct pub(crate) fn evaluate_neq( - memory_map: &mut AcirMem, + acir_mem: &mut AcirMem, lhs: NodeId, rhs: NodeId, l_c: Option, @@ -55,7 +55,7 @@ pub(crate) fn evaluate_neq( ) } - let mut x = InternalVar::from(array_eq(memory_map, array_a, array_b, evaluator)); + let mut x = InternalVar::from(array_eq(acir_mem, array_a, array_b, evaluator)); // TODO we need a witness because of the directive, but we should use an expression // TODO if we change the Invert directive to take an `Expression`, then we // TODO can get rid of this extra gate. diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs index 3bf4db01f6b..942a00f0137 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/intrinsics.rs @@ -197,7 +197,7 @@ fn resolve_array( ); let func_input = FunctionInput { witness, num_bits }; - acir_mem.array_map_mut(array.id).insert(i, arr_element); //todo ca sert a qqchose ?? + acir_mem.insert(array.id, i, arr_element); inputs.push(func_input) } diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs index 329513f06a0..ead9429f642 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs @@ -24,8 +24,7 @@ pub(crate) fn evaluate( match index.to_const() { Some(index) => { let idx = mem::Memory::as_u32(index); - let mem_map = acir_mem.array_map_mut(array_id); - mem_map.insert(idx, value); + acir_mem.insert(array_id, idx, value); //we do not generate constraint, so no output. None } From 50e7d572f0cf7d9b630cc4c99aea4c98781061c8 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 14 Feb 2023 09:52:01 +0000 Subject: [PATCH 04/37] code review --- crates/noirc_evaluator/src/ssa/acir_gen.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 80008275e81..6ac54ef7afa 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -23,7 +23,7 @@ use acir_mem::AcirMem; #[derive(Default)] pub struct Acir { - memory_trace: AcirMem, + memory: AcirMem, var_cache: InternalVarCache, } @@ -39,7 +39,7 @@ impl Acir { binary, condition, constrain, intrinsics, load, not, r#return, store, truncate, }; - let acir_mem = &mut self.memory_trace; + let acir_mem = &mut self.memory; let var_cache = &mut self.var_cache; let output = match &ins.operation { From 8f8d0c5c8fb4359d706bbca357f039850b938fd2 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 21 Feb 2023 13:09:06 +0000 Subject: [PATCH 05/37] enable dynamic arrays --- Cargo.lock | 8 - .../nargo/tests/test_data/6_array/src/main.nr | 22 +- crates/nargo/tests/test_data/config.toml | 2 +- .../tests/test_data/merkle_insert/Prover.toml | 257 +++++++++++++++++- .../tests/test_data/merkle_insert/src/main.nr | 103 +++++-- crates/noirc_evaluator/src/ssa/acir_gen.rs | 32 ++- .../src/ssa/acir_gen/acir_mem.rs | 211 ++++++++++++-- .../src/ssa/acir_gen/operations.rs | 2 +- .../src/ssa/acir_gen/operations/binary.rs | 3 +- .../src/ssa/acir_gen/operations/load.rs | 44 ++- .../src/ssa/acir_gen/operations/sort.rs | 57 +++- .../src/ssa/acir_gen/operations/store.rs | 78 +++--- crates/noirc_evaluator/src/ssa/context.rs | 17 +- .../noirc_frontend/src/hir/type_check/expr.rs | 23 +- .../noirc_frontend/src/hir/type_check/stmt.rs | 10 +- crates/noirc_frontend/src/hir_def/types.rs | 2 +- 16 files changed, 712 insertions(+), 159 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aade42f6e62..69e07a39dba 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,8 +17,6 @@ dependencies = [ [[package]] name = "acir" version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5d756bcab90b3a4a84dc53245890cf9bb8fcde31a1394931f5abca551b48eb20" dependencies = [ "acir_field 0.4.1", "flate2", @@ -46,8 +44,6 @@ dependencies = [ [[package]] name = "acir_field" version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "deb7e1e30625a9125a0e700c6c6fd7442ffbcb1d235933100b791ba3786ef49e" dependencies = [ "ark-bn254", "ark-ff", @@ -81,8 +77,6 @@ dependencies = [ [[package]] name = "acvm" version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c4fae94e7f3fe0d21bec4796de00bbf0cd8f781271b5203dea54897aa5387b9" dependencies = [ "acir 0.4.1", "acvm_stdlib 0.4.1", @@ -109,8 +103,6 @@ dependencies = [ [[package]] name = "acvm_stdlib" version = "0.4.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eaf6617b72c2cd4e965d425bc768bb77a803e485a7e37cbc09cccc5967becd7a" dependencies = [ "acir 0.4.1", ] diff --git a/crates/nargo/tests/test_data/6_array/src/main.nr b/crates/nargo/tests/test_data/6_array/src/main.nr index 4fcd1c6f2cc..2ff8503dbc3 100644 --- a/crates/nargo/tests/test_data/6_array/src/main.nr +++ b/crates/nargo/tests/test_data/6_array/src/main.nr @@ -1,8 +1,7 @@ //Basic tests for arrays fn main(x: [u32; 5], y: [u32; 5], mut z: u32, t: u32) { - let mut c = (z-z+2301) as u32; - - //t= t+x[0]-x[0]; + let mut c = 2301; + let idx = (z - 5*t - 5) as Field; z = y[4]; //Test 1: for i in 0..5 { @@ -52,4 +51,21 @@ fn main(x: [u32; 5], y: [u32; 5], mut z: u32, t: u32) { constrain x_elem != y_elem; } } + + //dynamic array test + dyn_array(x, idx, idx - 3); } + +fn dyn_array(mut x: [u32; 5], y: Field, z: Field) { + constrain x[y] == 111; + constrain x[z] == 101; + x[z] = 0; + constrain x[y] == 111; + constrain x[1] == 0; + if y as u32 < 10 { + x[y] = x[y] - 2; + } else { + x[y] = 0; + } + constrain x[4] == 109; +} \ No newline at end of file diff --git a/crates/nargo/tests/test_data/config.toml b/crates/nargo/tests/test_data/config.toml index d15dcfd20d3..c606068daef 100644 --- a/crates/nargo/tests/test_data/config.toml +++ b/crates/nargo/tests/test_data/config.toml @@ -2,7 +2,7 @@ # "1_mul", "2_div","3_add","4_sub","5_over", "6","6_array", "7_function","7","8_integration", "9_conditional", "10_slices", "assign_ex", "bool_not", "bool_or", "pedersen_check", "pred_eq", "schnorr", "sha256", "tuples", # "array_len", "array_neq", "bit_and", "cast_bool", "comptime_array_access", "generics", "global_comptime", "main_bool_arg", "main_return", "merkle_insert", "modules", "modules_more", "scalar_mul", "simple_shield", "struct", "submodules", # Exclude "sha2_byte" due to relatively long computation time and "sha2_blocks" due to very long computation time. -exclude = ["comptime_fail", "sha2_blocks", "sha2_byte"] +exclude = ["comptime_fail", "sha2_blocks", "sha2_byte", "merkle_insert", "pos"] # List of tests (as their directory name in test_data) expecting to fail: if the test pass, we report an error. diff --git a/crates/nargo/tests/test_data/merkle_insert/Prover.toml b/crates/nargo/tests/test_data/merkle_insert/Prover.toml index 44d00763d78..004d41beb42 100644 --- a/crates/nargo/tests/test_data/merkle_insert/Prover.toml +++ b/crates/nargo/tests/test_data/merkle_insert/Prover.toml @@ -1,11 +1,248 @@ -old_root = "0x083b35b32ba24436c1614e4262cb4ad8f98f99cdb5fb0da8932ab2a290034867" -old_leaf = "0x0b81829b478114d28b964bd382ebff8be0216741aa72ff2896909110aef1704a" -old_hash_path = [ - "0x0000000000000000000000000000000000000000000000000000000000000000", - "0x0e4223f3925f98934393c74975142bd73079ab0621f4ee133cee050a3c194f1a", - "0x2fd7bb412155bf8693a3bd2a3e7581a679c95c68a052f835dddca85fa1569a40" +# old_root = "0x083b35b32ba24436c1614e4262cb4ad8f98f99cdb5fb0da8932ab2a290034867" +# old_leaf = "0x0b81829b478114d28b964bd382ebff8be0216741aa72ff2896909110aef1704a" +# old_hash_path = [ +# "0x0000000000000000000000000000000000000000000000000000000000000000", +# "0x0e4223f3925f98934393c74975142bd73079ab0621f4ee133cee050a3c194f1a", +# "0x2fd7bb412155bf8693a3bd2a3e7581a679c95c68a052f835dddca85fa1569a40" +# ] +# new_root = "0x256c13d7694e2f900f55756246aa1104169efd9fb9e7c6be54c15794795d476f" +# leaf = "0x2e5ba44f3c5329aeb915c703e39b33c5872f1542500cbb22f12b71640aba502f" +# index = "0" +# mimc_input = [12,45,78,41] + + +#return = [... + +index = "0x00" +signer = [ + "0xa2", + "0x28", + "0xec", + "0x8e", + "0x5e", + "0x4d", + "0xd1", + "0x2d", + "0x23", + "0x52", + "0x13", + "0x10", + "0x6b", + "0x41", + "0x2f", + "0xd1", + "0x0c", + "0x24", + "0xd2", + "0xf6", + "0xe5", + "0x6d", + "0xb6", + "0xef", + "0xbf", + "0x84", + "0x41", + "0x66", + "0x15", + "0x19", + "0x10", + "0x59", + "0x28", + "0x66", + "0x4a", + "0x3c", + "0xc6", + "0xe8", + "0x1f", + "0x59", + "0x46", + "0xf5", + "0x1f", + "0xaf", + "0x92", + "0xe0", + "0xad", + "0x2a", + "0x2f", + "0x62", + "0x26", + "0x97", + "0x31", + "0x87", + "0x0c", + "0x32", + "0xfc", + "0x61", + "0x77", + "0x9c", + "0xa9", + "0xc3", + "0x35", + "0x68", ] -new_root = "0x256c13d7694e2f900f55756246aa1104169efd9fb9e7c6be54c15794795d476f" -leaf = "0x2e5ba44f3c5329aeb915c703e39b33c5872f1542500cbb22f12b71640aba502f" -index = "0" -mimc_input = [12,45,78,41] \ No newline at end of file +sig = [ + "0x15", + "0xaf", + "0x15", + "0x96", + "0x77", + "0x88", + "0x08", + "0xc1", + "0x91", + "0x18", + "0xc2", + "0xf8", + "0x21", + "0xdc", + "0x60", + "0xfd", + "0xc4", + "0x1a", + "0x77", + "0xee", + "0xce", + "0x40", + "0x56", + "0xb2", + "0x27", + "0x46", + "0x50", + "0x98", + "0xa0", + "0x20", + "0xd4", + "0x42", + "0x4f", + "0x46", + "0x4e", + "0x5e", + "0x3a", + "0x54", + "0xdb", + "0xe0", + "0xb6", + "0x2c", + "0x27", + "0x8c", + "0x1a", + "0x74", + "0xe2", + "0x19", + "0x51", + "0xb9", + "0xa1", + "0xf8", + "0x02", + "0x81", + "0xea", + "0xa1", + "0x98", + "0xe8", + "0x4f", + "0x14", + "0xc8", + "0x5c", + "0xe2", + "0xb3", +] +msg = [ + "0x99", + "0x46", + "0x28", + "0x7f", + "0xc5", + "0xc0", + "0x2c", + "0x2c", + "0xaf", + "0xc1", + "0x59", + "0x5d", + "0xe4", + "0xd0", + "0x9b", + "0x6d", + "0x78", + "0xa2", + "0x39", + "0x37", + "0x43", + "0xd6", + "0x33", + "0x1c", + "0x93", + "0x90", + "0x77", + "0xec", + "0x2c", + "0x1e", + "0xef", + "0x12", +] +hash_path = [ + "0xde", + "0x47", + "0xc9", + "0xb2", + "0x7e", + "0xb8", + "0xd3", + "0x00", + "0xdb", + "0xb5", + "0xf2", + "0xc3", + "0x53", + "0xe6", + "0x32", + "0xc3", + "0x93", + "0x26", + "0x2c", + "0xf0", + "0x63", + "0x40", + "0xc4", + "0xfa", + "0x7f", + "0x1b", + "0x40", + "0xc4", + "0xcb", + "0xd3", + "0x6f", + "0x90", + "0x4d", + "0x75", + "0x53", + "0x87", + "0x7a", + "0x80", + "0xec", + "0x8d", + "0x79", + "0xa2", + "0x31", + "0x71", + "0x36", + "0x05", + "0xb9", + "0x1f", + "0x42", + "0x07", + "0x52", + "0x2d", + "0x7c", + "0x45", + "0x20", + "0x62", + "0xce", + "0x17", + "0x3e", + "0xb9", + "0xf6", + "0x1a", + "0x02", + "0xc8", +] \ No newline at end of file diff --git a/crates/nargo/tests/test_data/merkle_insert/src/main.nr b/crates/nargo/tests/test_data/merkle_insert/src/main.nr index 6078bef79d6..ba166817675 100644 --- a/crates/nargo/tests/test_data/merkle_insert/src/main.nr +++ b/crates/nargo/tests/test_data/merkle_insert/src/main.nr @@ -1,21 +1,92 @@ use dep::std; fn main( - old_root: Field, - old_leaf: Field, - old_hash_path: [Field; 3], - new_root: pub Field, - leaf: Field, - index: Field, - mimc_input: [Field; 4], -) { - let old_leaf_exists = std::merkle::check_membership(old_root, old_leaf, index, old_hash_path); - constrain old_leaf_exists == 1; - constrain old_root == std::merkle::compute_root_from_leaf(old_leaf, index, old_hash_path); - let new_leaf_exists = std::merkle::check_membership(new_root, leaf, index, old_hash_path); - constrain new_leaf_exists == 1; - - let h = std::hash::mimc_bn254(mimc_input); - constrain h == 18226366069841799622585958305961373004333097209608110160936134895615261821931; + // old_root: Field, + // old_leaf: Field, + // old_hash_path: [Field; 3], + // new_root: pub Field, + // leaf: Field, + // index: Field, + // mimc_input: [Field; 4], + + index: Field, + signer: [u8; 64], + sig: [u8; 64], + msg: [u8; 32], + hash_path: [u8; 64] +) //-> pub [u8; 32] +{ + // let old_leaf_exists = std::merkle::check_membership(old_root, old_leaf, index, old_hash_path); + // constrain old_leaf_exists == 1; + // constrain old_root == std::merkle::compute_root_from_leaf(old_leaf, index, old_hash_path); + // let new_leaf_exists = std::merkle::check_membership(new_root, leaf, index, old_hash_path); + // constrain new_leaf_exists == 1; + + // let h = std::hash::mimc_bn254(mimc_input); + // constrain h == 18226366069841799622585958305961373004333097209608110160936134895615261821931; +let w = std::to_bits(1,129); +constrain w[127]==0; + + verify_sig(sig, msg, signer); + let leaf = std::hash::sha256(signer); + // compute_root_from_leaf(leaf, index, hash_path) } +fn verify_sig(sig: [u8; 64], msg: [u8; 32], signer: [u8; 64]) { + let mut pub_x: [u8; 32] = [0; 32]; + let mut pub_y: [u8; 32] = [0; 32]; + + for i in 0..32 { + pub_x[i] = signer[i]; + pub_y[i] = signer[i + 32]; + }; + + constrain(std::ecdsa_secp256k1::verify_signature( + pub_x, + pub_y, + sig, + msg + ) == 1); +} + +fn compute_root_from_leaf(leaf: [u8; 32], _index: Field, hash_path: [u8]) -> [u8; 32] { + let n = std::array::len(hash_path) / 32; + let _index_bits = std::to_bits(_index, n as u32); + + let mut current = [0; 32]; + let mut neighbour = [0; 32]; + for i in 0..32 { + current[i] = leaf[i]; + } + + for i in 0..n { + let offset = i * 32; + for j in 0..32 { + neighbour[j] = hash_path[j + offset]; + } + + // Dying if _is_right is computed, works if constant. + // Fails with "cannot find witness assignment" + // _is_right = false will compile, _index_bits[i] as bool; will not + //let _is_right = false; // _index_bits[i] as bool; + let _is_right = _index_bits[i] as bool; + let to_hash = concat(current, neighbour, _is_right); + current = std::hash::sha256(to_hash); + } + current +} + +fn concat(left: [u8; 32], right: [u8; 32], flip: bool) -> [u8; 64] { + let mut concat = [0; 64]; + for i in 0..32 { + let (l, r) = if flip { + (right[i], left[i]) + } else { + (left[i], right[i]) + }; + + concat[i] = l; + concat[i + 32] = r; + } + concat +} \ No newline at end of file diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 7e1b5078877..55a192faf75 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -1,7 +1,11 @@ -use crate::ssa::{ - builtin, - context::SsaContext, - node::{Instruction, Operation}, +use crate::{ + errors::RuntimeError, + ssa::{ + block::BasicBlock, + builtin, + context::SsaContext, + node::{Instruction, Operation}, + }, }; use crate::{Evaluator, RuntimeErrorKind}; use acvm::{ @@ -29,6 +33,26 @@ pub struct Acir { } impl Acir { + pub fn acir_gen( + &mut self, + evaluator: &mut Evaluator, + ctx: &SsaContext, + root: &BasicBlock, + show_output: bool, + ) -> Result<(), RuntimeError> { + let mut current_block = Some(root); + while let Some(block) = current_block { + for iter in &block.instructions { + let ins = ctx.instruction(*iter); + self.acir_gen_instruction(ins, evaluator, ctx, show_output)?; + } + //TODO we should rather follow the jumps + current_block = block.left.map(|block_id| &ctx[block_id]); + } + self.memory.acir_gen(evaluator); + Ok(()) + } + /// Generate ACIR opcodes based on the given instruction pub fn acir_gen_instruction( &mut self, diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 2e72fb8ac74..632d769fd74 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -1,22 +1,163 @@ -use crate::ssa::{ - acir_gen::InternalVar, - context::SsaContext, - mem::{ArrayId, MemArray}, +use crate::{ + ssa::{ + acir_gen::InternalVar, + context::SsaContext, + mem::{ArrayId, MemArray}, + }, + Evaluator, }; -use acvm::acir::native_types::Witness; +use acvm::{ + acir::{ + circuit::{directives::Directive, opcodes::Opcode as AcirOpcode}, + native_types::{Expression, Witness}, + }, + FieldElement, +}; + use iter_extended::vecmap; use std::collections::BTreeMap; +use super::{ + constraints::{self, mul_with_witness, subtract}, + expression_from_witness, + operations::{self}, +}; + +#[derive(Clone, Debug)] +struct MemItem { + counter: u64, + op: Expression, + value: Expression, + index: Expression, +} + #[derive(Default)] pub struct ArrayHeap { // maps memory address to InternalVar memory_map: BTreeMap, + trace: Vec, + staged: BTreeMap, + counter: u64, +} + +impl ArrayHeap { + pub fn commit_staged(&mut self) { + for (idx, (value, op)) in &self.staged { + let item = MemItem { + counter: self.counter, + op: op.clone(), + value: value.clone(), + index: Expression::from_field(FieldElement::from(*idx as i128)), + }; + self.trace.push(item); + self.counter += 1; + } + self.staged.clear(); + } + + pub fn push(&mut self, index: Expression, value: Expression, op: Expression) { + let item = MemItem { counter: self.counter, op, value, index }; + self.trace.push(item); + self.counter += 1; + } + + pub fn stage(&mut self, index: u32, value: Expression, op: Expression) { + self.staged.insert(index, (value, op)); + } + + pub fn acir_gen(&self, evaluator: &mut Evaluator) { + let len = self.trace.len(); + if len == 0 { + return; + } + let len_bits = AcirMem::bits(len); + // permutations + let mut in_counter = Vec::new(); + let mut in_index = Vec::new(); + let mut in_value = Vec::new(); + let mut in_op = Vec::new(); + let mut out_counter = Vec::new(); + let mut out_index = Vec::new(); + let mut out_value = Vec::new(); + let mut out_op = Vec::new(); + let mut tuple_expressions = Vec::new(); + for item in &self.trace { + let counter_expr = Expression::from_field(FieldElement::from(item.counter as i128)); + in_counter.push(counter_expr.clone()); + in_index.push(item.index.clone()); + in_value.push(item.value.clone()); + in_op.push(item.op.clone()); + out_counter.push(expression_from_witness(evaluator.add_witness_to_cs())); + out_index.push(expression_from_witness(evaluator.add_witness_to_cs())); + out_value.push(expression_from_witness(evaluator.add_witness_to_cs())); + out_op.push(expression_from_witness(evaluator.add_witness_to_cs())); + tuple_expressions.push(vec![item.index.clone(), counter_expr.clone()]); + } + let bit_counter = + operations::sort::evaluate_permutation(&in_counter, &out_counter, evaluator); + operations::sort::evaluate_permutation_with_witness( + &in_index, + &out_index, + &bit_counter, + evaluator, + ); + operations::sort::evaluate_permutation_with_witness( + &in_value, + &out_value, + &bit_counter, + evaluator, + ); + operations::sort::evaluate_permutation_with_witness( + &in_op, + &out_op, + &bit_counter, + evaluator, + ); + // sort directive + evaluator.opcodes.push(AcirOpcode::Directive(Directive::PermutationSort { + inputs: tuple_expressions, + tuple: 2, + bits: bit_counter, + sort_by: vec![0, 1], + })); + let init = subtract(&out_op[0], FieldElement::one(), &Expression::one()); + evaluator.opcodes.push(AcirOpcode::Arithmetic(init)); + for i in 0..len - 1 { + // index sort + let index_sub = subtract(&out_index[i + 1], FieldElement::one(), &out_index[i]); + let primary_order = constraints::boolean_expr(&index_sub, evaluator); + evaluator.opcodes.push(AcirOpcode::Arithmetic(primary_order)); + // counter sort + let cmp = constraints::evaluate_cmp( + &out_counter[i], + &out_counter[i + 1], + len_bits, + false, + evaluator, + ); + let sub_cmp = subtract(&cmp, FieldElement::one(), &Expression::one()); + let secondary_order = subtract( + &mul_with_witness(evaluator, &index_sub, &sub_cmp), + FieldElement::one(), + &sub_cmp, + ); + evaluator.opcodes.push(AcirOpcode::Arithmetic(secondary_order)); + // consistency checks + let sub1 = subtract(&Expression::one(), FieldElement::one(), &out_op[i + 1]); + let sub2 = subtract(&out_value[i + 1], FieldElement::one(), &out_value[i]); + let load_on_same_adr = mul_with_witness(evaluator, &sub1, &sub2); + let store_on_new_adr = mul_with_witness(evaluator, &index_sub, &sub1); + evaluator.opcodes.push(AcirOpcode::Arithmetic(store_on_new_adr)); + evaluator.opcodes.push(AcirOpcode::Arithmetic(load_on_same_adr)); + } + } } /// Handle virtual memory access #[derive(Default)] pub struct AcirMem { virtual_memory: BTreeMap, + pub dummy: Witness, } impl AcirMem { @@ -25,9 +166,19 @@ impl AcirMem { &mut self.virtual_memory.entry(array_id).or_default().memory_map } + // returns the memory trace for the array + pub fn array_heap_mut(&mut self, array_id: ArrayId) -> &mut ArrayHeap { + let e = self.virtual_memory.entry(array_id); + e.or_default() + } + // Write the value to the array's VM at the specified index pub fn insert(&mut self, array_id: ArrayId, index: u32, value: InternalVar) { - self.array_map_mut(array_id).insert(index, value); + let e = self.virtual_memory.entry(array_id).or_default(); + let value_expr = value.to_expression(); + e.memory_map.insert(index, value); + + e.stage(index, value_expr, Expression::one()); } //Map the outputs into the array @@ -52,6 +203,16 @@ impl AcirMem { }) } + // number of bits required to store the input + fn bits(mut t: usize) -> u32 { + let mut r = 0; + while t != 0 { + t >>= 1; + r += 1; + } + r + } + // Loads the associated `InternalVar` for the element // in the `array` at the given `offset`. // @@ -59,23 +220,37 @@ impl AcirMem { // is in the memory_map. // // - // Returns `None` if `offset` is out of bounds. + // Returns `None` if not found pub(crate) fn load_array_element_constant_index( &mut self, array: &MemArray, offset: u32, ) -> Option { - // Check to see if the index has gone out of bounds - let array_length = array.len; - if offset >= array_length { - return None; // IndexOutOfBoundsError - } - // Check the memory_map to see if the element is there - let array_element = self - .array_map_mut(array.id) - .get(&offset) - .expect("ICE: Could not find value at index {offset}"); - Some(array_element.clone()) + self.array_map_mut(array.id).get(&offset).cloned() + } + + // Apply staged stores to the memory trace + pub fn commit(&mut self, array_id: &ArrayId, clear: bool) { + let e = self.virtual_memory.entry(*array_id).or_default(); + e.commit_staged(); + if clear { + e.memory_map.clear(); + } + } + pub fn add_to_trace( + &mut self, + array_id: &ArrayId, + index: Expression, + value: Expression, + op: Expression, + ) { + self.commit(array_id, op != Expression::zero()); + self.array_heap_mut(*array_id).push(index, value, op); + } + pub fn acir_gen(&self, evaluator: &mut Evaluator) { + for mem in &self.virtual_memory { + mem.1.acir_gen(evaluator); + } } } diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations.rs index 1af21131ee9..a62cdecdc57 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations.rs @@ -8,6 +8,6 @@ pub mod intrinsics; pub mod load; pub mod not; pub mod r#return; -mod sort; +pub mod sort; pub mod store; pub mod truncate; diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/binary.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/binary.rs index 286ba988eec..2b339ec161a 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/binary.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/binary.rs @@ -63,8 +63,7 @@ pub(crate) fn evaluate( } else { //we need the type of rhs and its max value, then: //lhs-rhs+k*2^bit_size where k=ceil(max_value/2^bit_size) - // TODO: what is this code doing? - let bit_size = r_size; + let bit_size = ctx[binary.rhs].get_type().bits(); let r_big = BigUint::one() << bit_size; let mut k = max_rhs_value / &r_big; if max_rhs_value % &r_big != BigUint::zero() { diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/load.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/load.rs index c28e77e8220..c46cb013d71 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/load.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/load.rs @@ -1,6 +1,11 @@ +use acvm::acir::native_types::Expression; + use crate::{ ssa::{ - acir_gen::{acir_mem::AcirMem, internal_var_cache::InternalVarCache, InternalVar}, + acir_gen::{ + acir_mem::AcirMem, expression_from_witness, internal_var_cache::InternalVarCache, + InternalVar, + }, context::SsaContext, mem::{self, ArrayId}, node::NodeId, @@ -8,28 +13,39 @@ use crate::{ Evaluator, }; +// Returns a variable corresponding to the element at the provided index in the array +// Returns None if index is constant and out-of-bound. pub(crate) fn evaluate( array_id: ArrayId, index: NodeId, - memory_map: &mut AcirMem, + acir_mem: &mut AcirMem, var_cache: &mut InternalVarCache, evaluator: &mut Evaluator, ctx: &SsaContext, ) -> Option { - //retrieves the value from the map if address is known at compile time: - //address = l_c and should be constant + let mem_array = &ctx.mem[array_id]; let index = var_cache.get_or_compute_internal_var_unwrap(index, evaluator, ctx); - let array_element = match index.to_const() { - Some(index) => { - let idx = mem::Memory::as_u32(index); - let mem_array = &ctx.mem[array_id]; + if let Some(idx) = index.to_const() { + let idx = mem::Memory::as_u32(idx); + // Check to see if the index has gone out of bounds + let array_length = mem_array.len; + if idx >= array_length { + return None; // IndexOutOfBoundsError + } - memory_map - .load_array_element_constant_index(mem_array, idx) - .expect("ICE: index {idx} was out of bounds for array of length {mem_array.len}") + let array_element = acir_mem.load_array_element_constant_index(mem_array, idx); + if array_element.is_some() { + return array_element; } - None => unimplemented!("dynamic arrays are not implemented yet"), - }; - Some(array_element) + } + + let w = evaluator.add_witness_to_cs(); + acir_mem.add_to_trace( + &array_id, + index.to_expression(), + expression_from_witness(w), + Expression::zero(), + ); + Some(InternalVar::from_witness(w)) } diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs index eab75742ab8..a6b5534e7b0 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs @@ -19,19 +19,40 @@ pub fn evaluate_permutation( out_expr: &Vec, evaluator: &mut Evaluator, ) -> Vec { - let (w, b) = permutation_layer(in_expr, evaluator); - // we constrain the network output to out_expr + let bits = Vec::new(); + let (w, b) = permutation_layer(in_expr, &bits, true, evaluator); + // we contrain the network output to out_expr for (b, o) in b.iter().zip(out_expr) { evaluator.opcodes.push(AcirOpcode::Arithmetic(subtract(b, FieldElement::one(), o))); } w } +// Same as evaluate_permutation() but uses the provided witness as network control bits +pub fn evaluate_permutation_with_witness( + in_expr: &Vec, + out_expr: &Vec, + bits: &Vec, + evaluator: &mut Evaluator, +) { + let (w, b) = permutation_layer(in_expr, bits, false, evaluator); + debug_assert_eq!(w, *bits); + // we contrain the network output to out_expr + for (b, o) in b.iter().zip(out_expr) { + evaluator.opcodes.push(AcirOpcode::Arithmetic(subtract(b, FieldElement::one(), o))); + } +} + // Generates gates for a sorting network // returns witness corresponding to the network configuration and the expressions corresponding to the network output // in_expr: inputs of the sorting network -pub fn permutation_layer( +// if generate_witness is false, it uses the witness provided in bits instead of generating them +// in both cases it returns the witness of the network configuration +// if generate_witnes is true, bits is ignored +fn permutation_layer( in_expr: &Vec, + bits: &[Witness], + generate_witness: bool, evaluator: &mut Evaluator, ) -> (Vec, Vec) { let n = in_expr.len(); @@ -40,10 +61,17 @@ pub fn permutation_layer( } let n1 = n / 2; let mut conf = Vec::new(); + // witness for the input switches - for _ in 0..n1 { - conf.push(evaluator.add_witness_to_cs()); + #[allow(clippy::needless_range_loop)] + for i in 0..n1 { + if generate_witness { + conf.push(evaluator.add_witness_to_cs()); + } else { + conf.push(bits[i]); + } } + // compute expressions after the input switches // If inputs are a1,a2, and the switch value is c, then we compute expressions b1,b2 where // b1 = a1+q, b2 = a2-q, q = c(a2-a1) @@ -66,11 +94,13 @@ pub fn permutation_layer( } let mut out_expr = Vec::new(); // compute results for the sub networks - let (w1, b1) = permutation_layer(&in_sub1, evaluator); - let (w2, b2) = permutation_layer(&in_sub2, evaluator); - // apply the output switches + let bits1 = if generate_witness { bits } else { &bits[n1 + (n - 1) / 2..] }; + let (w1, b1) = permutation_layer(&in_sub1, bits1, generate_witness, evaluator); + let bits2 = if generate_witness { bits } else { &bits[n1 + (n - 1) / 2 + w1.len()..] }; + let (w2, b2) = permutation_layer(&in_sub2, bits2, generate_witness, evaluator); + // apply the output swithces for i in 0..(n - 1) / 2 { - let c = evaluator.add_witness_to_cs(); + let c = if generate_witness { evaluator.add_witness_to_cs() } else { bits[n1 + i] }; conf.push(c); let intermediate = mul_with_witness( evaluator, @@ -99,7 +129,10 @@ mod test { }; use crate::{ - ssa::acir_gen::{expression_from_witness, operations::sort::evaluate_permutation}, + ssa::acir_gen::{ + expression_from_witness, + operations::sort::{evaluate_permutation, permutation_layer}, + }, Evaluator, }; use rand::prelude::*; @@ -141,7 +174,9 @@ mod test { } //generate constraints for the inputs let w = evaluate_permutation(&input, &output, &mut eval); - + //checks that it generate the same witness + let (w1, _) = permutation_layer(&input, &w, false, &mut eval); + assert_eq!(w, w1); //we generate random network let mut c = Vec::new(); for _i in 0..w.len() { diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs index 250a8a64bed..462e7be7725 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs @@ -1,15 +1,20 @@ +use acvm::acir::native_types::Expression; + use crate::{ ssa::{ - acir_gen::{acir_mem::AcirMem, internal_var_cache::InternalVarCache, InternalVar}, + acir_gen::{ + acir_mem::AcirMem, + internal_var_cache::InternalVarCache, + operations::{condition, load}, + InternalVar, + }, context::SsaContext, - mem::{self}, + mem, node::Operation, }, Evaluator, }; -use super::condition; - pub(crate) fn evaluate( store: &Operation, acir_mem: &mut AcirMem, @@ -19,41 +24,46 @@ pub(crate) fn evaluate( ) -> Option { if let Operation::Store { array_id, index, value, predicate } = *store { //maps the address to the rhs if address is known at compile time - let index = var_cache.get_or_compute_internal_var_unwrap(index, evaluator, ctx); - let value = var_cache.get_or_compute_internal_var_unwrap(value, evaluator, ctx); + let index_var = var_cache.get_or_compute_internal_var_unwrap(index, evaluator, ctx); + let value_var = var_cache.get_or_compute_internal_var_unwrap(value, evaluator, ctx); + let value_with_predicate = if let Some(predicate) = predicate { + if predicate.is_dummy() || ctx.is_one(predicate) { + value_var + } else if ctx.is_zero(predicate) { + return None; + } else { + let pred = var_cache.get_or_compute_internal_var_unwrap(predicate, evaluator, ctx); + let dummy_load = + load::evaluate(array_id, index, acir_mem, var_cache, evaluator, ctx).unwrap(); + let result = condition::evaluate_expression( + pred.expression(), + value_var.expression(), + dummy_load.expression(), + evaluator, + ); + result.into() + } + } else { + value_var + }; - match index.to_const() { - Some(index) => { - let idx = mem::Memory::as_u32(index); - let value_with_predicate = if let Some(predicate) = predicate { - if predicate.is_dummy() || ctx.is_one(predicate) { - value - } else if ctx.is_zero(predicate) { - return None; - } else { - let pred = - var_cache.get_or_compute_internal_var_unwrap(predicate, evaluator, ctx); - let dummy_load = acir_mem - .load_array_element_constant_index(&ctx.mem[array_id], idx) - .unwrap(); - let result = condition::evaluate_expression( - pred.expression(), - value.expression(), - dummy_load.expression(), - evaluator, - ); - result.into() - } - } else { - value - }; + match index_var.to_const() { + Some(idx) => { + let idx = mem::Memory::as_u32(idx); acir_mem.insert(array_id, idx, value_with_predicate); - //we do not generate constraint, so no output. - None } - None => todo!("dynamic arrays are not implemented yet"), + None => { + acir_mem.add_to_trace( + &array_id, + index_var.to_expression(), + value_with_predicate.to_expression(), + Expression::one(), + ); + } } } else { unreachable!("Expected store, got {:?}", store.opcode()); } + //we do not generate constraint, so no output. + None } diff --git a/crates/noirc_evaluator/src/ssa/context.rs b/crates/noirc_evaluator/src/ssa/context.rs index 0784a19e51c..5dd83af2c51 100644 --- a/crates/noirc_evaluator/src/ssa/context.rs +++ b/crates/noirc_evaluator/src/ssa/context.rs @@ -723,7 +723,8 @@ impl SsaContext { integer::overflow_strategy(self)?; self.log(enable_logging, "\noverflow:", ""); //ACIR - self.acir(evaluator, show_output)?; + let mut acir = Acir::default(); + acir.acir_gen(evaluator, self, &self[self.first_block], show_output)?; if enable_logging { print_acir_circuit(&evaluator.opcodes); println!("DONE"); @@ -732,20 +733,6 @@ impl SsaContext { Ok(()) } - pub fn acir(&self, evaluator: &mut Evaluator, show_output: bool) -> Result<(), RuntimeError> { - let mut acir = Acir::default(); - let mut fb = Some(&self[self.first_block]); - while let Some(block) = fb { - for iter in &block.instructions { - let ins = self.instruction(*iter); - acir.acir_gen_instruction(ins, evaluator, self, show_output)?; - } - //TODO we should rather follow the jumps - fb = block.left.map(|block_id| &self[block_id]); - } - Ok(()) - } - pub fn generate_empty_phi(&mut self, target_block: BlockId, phi_root: NodeId) -> NodeId { //Ensure there is not already a phi for the variable (n.b. probably not useful) for i in &self[target_block].instructions { diff --git a/crates/noirc_frontend/src/hir/type_check/expr.rs b/crates/noirc_frontend/src/hir/type_check/expr.rs index 88f768a71af..8bc17b8fcd1 100644 --- a/crates/noirc_frontend/src/hir/type_check/expr.rs +++ b/crates/noirc_frontend/src/hir/type_check/expr.rs @@ -256,22 +256,13 @@ fn type_check_index_expression( ) -> Type { let index_type = type_check_expression(interner, &index_expr.index, errors); let span = interner.expr_span(&index_expr.index); - - index_type.unify(&Type::comp_time(Some(span)), span, errors, || { - // Specialize the error in the case the user has a Field, just not a `comptime` one. - if matches!(index_type, Type::FieldElement(..)) { - TypeCheckError::Unstructured { - msg: format!("Array index must be known at compile-time, but here a non-comptime {index_type} was used instead"), - span, - } - } else { - TypeCheckError::TypeMismatch { - expected_typ: "comptime Field".to_owned(), - expr_typ: index_type.to_string(), - expr_span: span, - } - } - }); + if index_type.is_subtype_of(&Type::field(Some(span)), span).is_err() { + errors.push(TypeCheckError::TypeMismatch { + expected_typ: "Field".to_owned(), + expr_typ: index_type.to_string(), + expr_span: span, + }); + } let lhs_type = type_check_expression(interner, &index_expr.collection, errors); match lhs_type { diff --git a/crates/noirc_frontend/src/hir/type_check/stmt.rs b/crates/noirc_frontend/src/hir/type_check/stmt.rs index f79df00dbec..1c1e027bbed 100644 --- a/crates/noirc_frontend/src/hir/type_check/stmt.rs +++ b/crates/noirc_frontend/src/hir/type_check/stmt.rs @@ -181,13 +181,13 @@ fn type_check_lvalue( let index_type = type_check_expression(interner, &index, errors); let expr_span = interner.expr_span(&index); - index_type.unify(&Type::comp_time(Some(expr_span)), expr_span, errors, || { - TypeCheckError::TypeMismatch { - expected_typ: "comptime Field".to_owned(), + if index_type.is_subtype_of(&Type::field(Some(expr_span)), expr_span).is_err() { + errors.push(TypeCheckError::TypeMismatch { + expected_typ: "Field".to_owned(), expr_typ: index_type.to_string(), expr_span, - } - }); + }); + } let (result, array) = type_check_lvalue(interner, *array, assign_span, errors); let array = Box::new(array); diff --git a/crates/noirc_frontend/src/hir_def/types.rs b/crates/noirc_frontend/src/hir_def/types.rs index 10b70ad2db1..d17f9832f72 100644 --- a/crates/noirc_frontend/src/hir_def/types.rs +++ b/crates/noirc_frontend/src/hir_def/types.rs @@ -861,7 +861,7 @@ impl Type { } } - fn is_subtype_of(&self, other: &Type, span: Span) -> Result<(), SpanKind> { + pub fn is_subtype_of(&self, other: &Type, span: Span) -> Result<(), SpanKind> { use Type::*; match (self, other) { (Error, _) | (_, Error) => Ok(()), From 2d51e6fa0df1146be9ba2660ce308be23a497c9b Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 21 Feb 2023 13:53:50 +0000 Subject: [PATCH 06/37] use trace index as counter --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 632d769fd74..ee4d507abc6 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -25,7 +25,6 @@ use super::{ #[derive(Clone, Debug)] struct MemItem { - counter: u64, op: Expression, value: Expression, index: Expression, @@ -37,28 +36,24 @@ pub struct ArrayHeap { memory_map: BTreeMap, trace: Vec, staged: BTreeMap, - counter: u64, } impl ArrayHeap { pub fn commit_staged(&mut self) { for (idx, (value, op)) in &self.staged { let item = MemItem { - counter: self.counter, op: op.clone(), value: value.clone(), index: Expression::from_field(FieldElement::from(*idx as i128)), }; self.trace.push(item); - self.counter += 1; } self.staged.clear(); } pub fn push(&mut self, index: Expression, value: Expression, op: Expression) { - let item = MemItem { counter: self.counter, op, value, index }; + let item = MemItem { op, value, index }; self.trace.push(item); - self.counter += 1; } pub fn stage(&mut self, index: u32, value: Expression, op: Expression) { @@ -81,8 +76,8 @@ impl ArrayHeap { let mut out_value = Vec::new(); let mut out_op = Vec::new(); let mut tuple_expressions = Vec::new(); - for item in &self.trace { - let counter_expr = Expression::from_field(FieldElement::from(item.counter as i128)); + for (counter, item) in self.trace.iter().enumerate() { + let counter_expr = Expression::from_field(FieldElement::from(counter as i128)); in_counter.push(counter_expr.clone()); in_index.push(item.index.clone()); in_value.push(item.value.clone()); From cb43e94dd101a1d78310e2b2351050a1fc40fa28 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 21 Feb 2023 15:31:37 +0000 Subject: [PATCH 07/37] restore bad commit --- crates/nargo/tests/test_data/config.toml | 2 +- .../tests/test_data/merkle_insert/Prover.toml | 257 +----------------- .../tests/test_data/merkle_insert/src/main.nr | 103 ++----- 3 files changed, 27 insertions(+), 335 deletions(-) diff --git a/crates/nargo/tests/test_data/config.toml b/crates/nargo/tests/test_data/config.toml index c606068daef..d15dcfd20d3 100644 --- a/crates/nargo/tests/test_data/config.toml +++ b/crates/nargo/tests/test_data/config.toml @@ -2,7 +2,7 @@ # "1_mul", "2_div","3_add","4_sub","5_over", "6","6_array", "7_function","7","8_integration", "9_conditional", "10_slices", "assign_ex", "bool_not", "bool_or", "pedersen_check", "pred_eq", "schnorr", "sha256", "tuples", # "array_len", "array_neq", "bit_and", "cast_bool", "comptime_array_access", "generics", "global_comptime", "main_bool_arg", "main_return", "merkle_insert", "modules", "modules_more", "scalar_mul", "simple_shield", "struct", "submodules", # Exclude "sha2_byte" due to relatively long computation time and "sha2_blocks" due to very long computation time. -exclude = ["comptime_fail", "sha2_blocks", "sha2_byte", "merkle_insert", "pos"] +exclude = ["comptime_fail", "sha2_blocks", "sha2_byte"] # List of tests (as their directory name in test_data) expecting to fail: if the test pass, we report an error. diff --git a/crates/nargo/tests/test_data/merkle_insert/Prover.toml b/crates/nargo/tests/test_data/merkle_insert/Prover.toml index 004d41beb42..909fc1bbf6b 100644 --- a/crates/nargo/tests/test_data/merkle_insert/Prover.toml +++ b/crates/nargo/tests/test_data/merkle_insert/Prover.toml @@ -1,248 +1,11 @@ -# old_root = "0x083b35b32ba24436c1614e4262cb4ad8f98f99cdb5fb0da8932ab2a290034867" -# old_leaf = "0x0b81829b478114d28b964bd382ebff8be0216741aa72ff2896909110aef1704a" -# old_hash_path = [ -# "0x0000000000000000000000000000000000000000000000000000000000000000", -# "0x0e4223f3925f98934393c74975142bd73079ab0621f4ee133cee050a3c194f1a", -# "0x2fd7bb412155bf8693a3bd2a3e7581a679c95c68a052f835dddca85fa1569a40" -# ] -# new_root = "0x256c13d7694e2f900f55756246aa1104169efd9fb9e7c6be54c15794795d476f" -# leaf = "0x2e5ba44f3c5329aeb915c703e39b33c5872f1542500cbb22f12b71640aba502f" -# index = "0" -# mimc_input = [12,45,78,41] - - -#return = [... - -index = "0x00" -signer = [ - "0xa2", - "0x28", - "0xec", - "0x8e", - "0x5e", - "0x4d", - "0xd1", - "0x2d", - "0x23", - "0x52", - "0x13", - "0x10", - "0x6b", - "0x41", - "0x2f", - "0xd1", - "0x0c", - "0x24", - "0xd2", - "0xf6", - "0xe5", - "0x6d", - "0xb6", - "0xef", - "0xbf", - "0x84", - "0x41", - "0x66", - "0x15", - "0x19", - "0x10", - "0x59", - "0x28", - "0x66", - "0x4a", - "0x3c", - "0xc6", - "0xe8", - "0x1f", - "0x59", - "0x46", - "0xf5", - "0x1f", - "0xaf", - "0x92", - "0xe0", - "0xad", - "0x2a", - "0x2f", - "0x62", - "0x26", - "0x97", - "0x31", - "0x87", - "0x0c", - "0x32", - "0xfc", - "0x61", - "0x77", - "0x9c", - "0xa9", - "0xc3", - "0x35", - "0x68", +old_root = "0x083b35b32ba24436c1614e4262cb4ad8f98f99cdb5fb0da8932ab2a290034867" +old_leaf = "0x0b81829b478114d28b964bd382ebff8be0216741aa72ff2896909110aef1704a" +old_hash_path = [ + "0x0000000000000000000000000000000000000000000000000000000000000000", + "0x0e4223f3925f98934393c74975142bd73079ab0621f4ee133cee050a3c194f1a", + "0x2fd7bb412155bf8693a3bd2a3e7581a679c95c68a052f835dddca85fa1569a40" ] -sig = [ - "0x15", - "0xaf", - "0x15", - "0x96", - "0x77", - "0x88", - "0x08", - "0xc1", - "0x91", - "0x18", - "0xc2", - "0xf8", - "0x21", - "0xdc", - "0x60", - "0xfd", - "0xc4", - "0x1a", - "0x77", - "0xee", - "0xce", - "0x40", - "0x56", - "0xb2", - "0x27", - "0x46", - "0x50", - "0x98", - "0xa0", - "0x20", - "0xd4", - "0x42", - "0x4f", - "0x46", - "0x4e", - "0x5e", - "0x3a", - "0x54", - "0xdb", - "0xe0", - "0xb6", - "0x2c", - "0x27", - "0x8c", - "0x1a", - "0x74", - "0xe2", - "0x19", - "0x51", - "0xb9", - "0xa1", - "0xf8", - "0x02", - "0x81", - "0xea", - "0xa1", - "0x98", - "0xe8", - "0x4f", - "0x14", - "0xc8", - "0x5c", - "0xe2", - "0xb3", -] -msg = [ - "0x99", - "0x46", - "0x28", - "0x7f", - "0xc5", - "0xc0", - "0x2c", - "0x2c", - "0xaf", - "0xc1", - "0x59", - "0x5d", - "0xe4", - "0xd0", - "0x9b", - "0x6d", - "0x78", - "0xa2", - "0x39", - "0x37", - "0x43", - "0xd6", - "0x33", - "0x1c", - "0x93", - "0x90", - "0x77", - "0xec", - "0x2c", - "0x1e", - "0xef", - "0x12", -] -hash_path = [ - "0xde", - "0x47", - "0xc9", - "0xb2", - "0x7e", - "0xb8", - "0xd3", - "0x00", - "0xdb", - "0xb5", - "0xf2", - "0xc3", - "0x53", - "0xe6", - "0x32", - "0xc3", - "0x93", - "0x26", - "0x2c", - "0xf0", - "0x63", - "0x40", - "0xc4", - "0xfa", - "0x7f", - "0x1b", - "0x40", - "0xc4", - "0xcb", - "0xd3", - "0x6f", - "0x90", - "0x4d", - "0x75", - "0x53", - "0x87", - "0x7a", - "0x80", - "0xec", - "0x8d", - "0x79", - "0xa2", - "0x31", - "0x71", - "0x36", - "0x05", - "0xb9", - "0x1f", - "0x42", - "0x07", - "0x52", - "0x2d", - "0x7c", - "0x45", - "0x20", - "0x62", - "0xce", - "0x17", - "0x3e", - "0xb9", - "0xf6", - "0x1a", - "0x02", - "0xc8", -] \ No newline at end of file +new_root = "0x256c13d7694e2f900f55756246aa1104169efd9fb9e7c6be54c15794795d476f" +leaf = "0x2e5ba44f3c5329aeb915c703e39b33c5872f1542500cbb22f12b71640aba502f" +index = "0" +mimc_input = [12,45,78,41] diff --git a/crates/nargo/tests/test_data/merkle_insert/src/main.nr b/crates/nargo/tests/test_data/merkle_insert/src/main.nr index ba166817675..26405d9991d 100644 --- a/crates/nargo/tests/test_data/merkle_insert/src/main.nr +++ b/crates/nargo/tests/test_data/merkle_insert/src/main.nr @@ -1,92 +1,21 @@ use dep::std; fn main( - // old_root: Field, - // old_leaf: Field, - // old_hash_path: [Field; 3], - // new_root: pub Field, - // leaf: Field, - // index: Field, - // mimc_input: [Field; 4], - - index: Field, - signer: [u8; 64], - sig: [u8; 64], - msg: [u8; 32], - hash_path: [u8; 64] -) //-> pub [u8; 32] + old_root: Field, + old_leaf: Field, + old_hash_path: [Field; 3], + new_root: pub Field, + leaf: Field, + index: Field, + mimc_input: [Field; 4], +) { - // let old_leaf_exists = std::merkle::check_membership(old_root, old_leaf, index, old_hash_path); - // constrain old_leaf_exists == 1; - // constrain old_root == std::merkle::compute_root_from_leaf(old_leaf, index, old_hash_path); - // let new_leaf_exists = std::merkle::check_membership(new_root, leaf, index, old_hash_path); - // constrain new_leaf_exists == 1; - - // let h = std::hash::mimc_bn254(mimc_input); - // constrain h == 18226366069841799622585958305961373004333097209608110160936134895615261821931; -let w = std::to_bits(1,129); -constrain w[127]==0; - - verify_sig(sig, msg, signer); - let leaf = std::hash::sha256(signer); - // compute_root_from_leaf(leaf, index, hash_path) -} - -fn verify_sig(sig: [u8; 64], msg: [u8; 32], signer: [u8; 64]) { - let mut pub_x: [u8; 32] = [0; 32]; - let mut pub_y: [u8; 32] = [0; 32]; - - for i in 0..32 { - pub_x[i] = signer[i]; - pub_y[i] = signer[i + 32]; - }; - - constrain(std::ecdsa_secp256k1::verify_signature( - pub_x, - pub_y, - sig, - msg - ) == 1); -} - -fn compute_root_from_leaf(leaf: [u8; 32], _index: Field, hash_path: [u8]) -> [u8; 32] { - let n = std::array::len(hash_path) / 32; - let _index_bits = std::to_bits(_index, n as u32); - - let mut current = [0; 32]; - let mut neighbour = [0; 32]; - for i in 0..32 { - current[i] = leaf[i]; - } - - for i in 0..n { - let offset = i * 32; - for j in 0..32 { - neighbour[j] = hash_path[j + offset]; - } - - // Dying if _is_right is computed, works if constant. - // Fails with "cannot find witness assignment" - // _is_right = false will compile, _index_bits[i] as bool; will not - //let _is_right = false; // _index_bits[i] as bool; - let _is_right = _index_bits[i] as bool; - let to_hash = concat(current, neighbour, _is_right); - current = std::hash::sha256(to_hash); - } - current -} - -fn concat(left: [u8; 32], right: [u8; 32], flip: bool) -> [u8; 64] { - let mut concat = [0; 64]; - for i in 0..32 { - let (l, r) = if flip { - (right[i], left[i]) - } else { - (left[i], right[i]) - }; - - concat[i] = l; - concat[i + 32] = r; - } - concat + let old_leaf_exists = std::merkle::check_membership(old_root, old_leaf, index, old_hash_path); + constrain old_leaf_exists == 1; + constrain old_root == std::merkle::compute_root_from_leaf(old_leaf, index, old_hash_path); + let new_leaf_exists = std::merkle::check_membership(new_root, leaf, index, old_hash_path); + constrain new_leaf_exists == 1; + + let h = std::hash::mimc_bn254(mimc_input); + constrain h == 18226366069841799622585958305961373004333097209608110160936134895615261821931; } \ No newline at end of file From c5a0bf993c76c3be4899abe447b2294f244e0fe1 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 21 Feb 2023 15:33:32 +0000 Subject: [PATCH 08/37] restore bad commit --- crates/nargo/tests/test_data/merkle_insert/src/main.nr | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/nargo/tests/test_data/merkle_insert/src/main.nr b/crates/nargo/tests/test_data/merkle_insert/src/main.nr index 26405d9991d..c1752cf3274 100644 --- a/crates/nargo/tests/test_data/merkle_insert/src/main.nr +++ b/crates/nargo/tests/test_data/merkle_insert/src/main.nr @@ -8,8 +8,7 @@ fn main( leaf: Field, index: Field, mimc_input: [Field; 4], -) -{ +) { let old_leaf_exists = std::merkle::check_membership(old_root, old_leaf, index, old_hash_path); constrain old_leaf_exists == 1; constrain old_root == std::merkle::compute_root_from_leaf(old_leaf, index, old_hash_path); @@ -18,4 +17,4 @@ fn main( let h = std::hash::mimc_bn254(mimc_input); constrain h == 18226366069841799622585958305961373004333097209608110160936134895615261821931; -} \ No newline at end of file +} From 327fe572cc97d76bc3f6f872ce2352024959ffcf Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 21 Feb 2023 16:26:01 +0000 Subject: [PATCH 09/37] restore bad commit --- Cargo.lock | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 69e07a39dba..aade42f6e62 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -17,6 +17,8 @@ dependencies = [ [[package]] name = "acir" version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d756bcab90b3a4a84dc53245890cf9bb8fcde31a1394931f5abca551b48eb20" dependencies = [ "acir_field 0.4.1", "flate2", @@ -44,6 +46,8 @@ dependencies = [ [[package]] name = "acir_field" version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "deb7e1e30625a9125a0e700c6c6fd7442ffbcb1d235933100b791ba3786ef49e" dependencies = [ "ark-bn254", "ark-ff", @@ -77,6 +81,8 @@ dependencies = [ [[package]] name = "acvm" version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c4fae94e7f3fe0d21bec4796de00bbf0cd8f781271b5203dea54897aa5387b9" dependencies = [ "acir 0.4.1", "acvm_stdlib 0.4.1", @@ -103,6 +109,8 @@ dependencies = [ [[package]] name = "acvm_stdlib" version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eaf6617b72c2cd4e965d425bc768bb77a803e485a7e37cbc09cccc5967becd7a" dependencies = [ "acir 0.4.1", ] From 2aa2fb5fe16863ca7fabb269dbef601adf9585fa Mon Sep 17 00:00:00 2001 From: guipublic Date: Wed, 22 Feb 2023 09:58:35 +0000 Subject: [PATCH 10/37] Code review --- .../src/ssa/acir_gen/acir_mem.rs | 72 +++++++++---------- .../src/ssa/acir_gen/operations/sort.rs | 2 +- .../noirc_frontend/src/hir/type_check/expr.rs | 8 +-- .../noirc_frontend/src/hir/type_check/stmt.rs | 8 +-- crates/noirc_frontend/src/hir_def/types.rs | 2 +- 5 files changed, 44 insertions(+), 48 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index ee4d507abc6..3c9cab707d7 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -23,9 +23,11 @@ use super::{ operations::{self}, }; +/// Represent a memory operation on the ArrayHeap, at the specified index +/// Operation is one for a store and 0 for a load #[derive(Clone, Debug)] -struct MemItem { - op: Expression, +struct MemOp { + operation: Expression, value: Expression, index: Expression, } @@ -34,15 +36,16 @@ struct MemItem { pub struct ArrayHeap { // maps memory address to InternalVar memory_map: BTreeMap, - trace: Vec, + trace: Vec, + // maps memory address to (values,operation) that must be committed to the trace staged: BTreeMap, } impl ArrayHeap { pub fn commit_staged(&mut self) { for (idx, (value, op)) in &self.staged { - let item = MemItem { - op: op.clone(), + let item = MemOp { + operation: op.clone(), value: value.clone(), index: Expression::from_field(FieldElement::from(*idx as i128)), }; @@ -52,7 +55,7 @@ impl ArrayHeap { } pub fn push(&mut self, index: Expression, value: Expression, op: Expression) { - let item = MemItem { op, value, index }; + let item = MemOp { operation: op, value, index }; self.trace.push(item); } @@ -60,6 +63,20 @@ impl ArrayHeap { self.staged.insert(index, (value, op)); } + fn generate_outputs( + inputs: Vec, + bits: &mut Vec, + evaluator: &mut Evaluator, + ) -> Vec { + let outputs = + vecmap(0..inputs.len(), |_| expression_from_witness(evaluator.add_witness_to_cs())); + if bits.is_empty() { + *bits = operations::sort::evaluate_permutation(&inputs, &outputs, evaluator); + } else { + operations::sort::evaluate_permutation_with_witness(&inputs, &outputs, bits, evaluator); + } + outputs + } pub fn acir_gen(&self, evaluator: &mut Evaluator) { let len = self.trace.len(); if len == 0 { @@ -71,43 +88,22 @@ impl ArrayHeap { let mut in_index = Vec::new(); let mut in_value = Vec::new(); let mut in_op = Vec::new(); - let mut out_counter = Vec::new(); - let mut out_index = Vec::new(); - let mut out_value = Vec::new(); - let mut out_op = Vec::new(); + let mut tuple_expressions = Vec::new(); for (counter, item) in self.trace.iter().enumerate() { let counter_expr = Expression::from_field(FieldElement::from(counter as i128)); in_counter.push(counter_expr.clone()); in_index.push(item.index.clone()); in_value.push(item.value.clone()); - in_op.push(item.op.clone()); - out_counter.push(expression_from_witness(evaluator.add_witness_to_cs())); - out_index.push(expression_from_witness(evaluator.add_witness_to_cs())); - out_value.push(expression_from_witness(evaluator.add_witness_to_cs())); - out_op.push(expression_from_witness(evaluator.add_witness_to_cs())); + in_op.push(item.operation.clone()); tuple_expressions.push(vec![item.index.clone(), counter_expr.clone()]); } - let bit_counter = - operations::sort::evaluate_permutation(&in_counter, &out_counter, evaluator); - operations::sort::evaluate_permutation_with_witness( - &in_index, - &out_index, - &bit_counter, - evaluator, - ); - operations::sort::evaluate_permutation_with_witness( - &in_value, - &out_value, - &bit_counter, - evaluator, - ); - operations::sort::evaluate_permutation_with_witness( - &in_op, - &out_op, - &bit_counter, - evaluator, - ); + let mut bit_counter = Vec::new(); + let out_counter = Self::generate_outputs(in_counter, &mut bit_counter, evaluator); + let out_index = Self::generate_outputs(in_index, &mut bit_counter, evaluator); + let out_value = Self::generate_outputs(in_value, &mut bit_counter, evaluator); + let out_op = Self::generate_outputs(in_op, &mut bit_counter, evaluator); + // sort directive evaluator.opcodes.push(AcirOpcode::Directive(Directive::PermutationSort { inputs: tuple_expressions, @@ -169,11 +165,11 @@ impl AcirMem { // Write the value to the array's VM at the specified index pub fn insert(&mut self, array_id: ArrayId, index: u32, value: InternalVar) { - let e = self.virtual_memory.entry(array_id).or_default(); + let entry = self.virtual_memory.entry(array_id).or_default(); let value_expr = value.to_expression(); - e.memory_map.insert(index, value); + entry.memory_map.insert(index, value); - e.stage(index, value_expr, Expression::one()); + entry.stage(index, value_expr, Expression::one()); } //Map the outputs into the array diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs index a6b5534e7b0..745cdd58833 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs @@ -37,7 +37,7 @@ pub fn evaluate_permutation_with_witness( ) { let (w, b) = permutation_layer(in_expr, bits, false, evaluator); debug_assert_eq!(w, *bits); - // we contrain the network output to out_expr + // we constrain the network output to out_expr for (b, o) in b.iter().zip(out_expr) { evaluator.opcodes.push(AcirOpcode::Arithmetic(subtract(b, FieldElement::one(), o))); } diff --git a/crates/noirc_frontend/src/hir/type_check/expr.rs b/crates/noirc_frontend/src/hir/type_check/expr.rs index 8bc17b8fcd1..9b3675b69ee 100644 --- a/crates/noirc_frontend/src/hir/type_check/expr.rs +++ b/crates/noirc_frontend/src/hir/type_check/expr.rs @@ -256,13 +256,13 @@ fn type_check_index_expression( ) -> Type { let index_type = type_check_expression(interner, &index_expr.index, errors); let span = interner.expr_span(&index_expr.index); - if index_type.is_subtype_of(&Type::field(Some(span)), span).is_err() { - errors.push(TypeCheckError::TypeMismatch { + index_type.make_subtype_of(&Type::field(Some(span)), span, errors, || { + TypeCheckError::TypeMismatch { expected_typ: "Field".to_owned(), expr_typ: index_type.to_string(), expr_span: span, - }); - } + } + }); let lhs_type = type_check_expression(interner, &index_expr.collection, errors); match lhs_type { diff --git a/crates/noirc_frontend/src/hir/type_check/stmt.rs b/crates/noirc_frontend/src/hir/type_check/stmt.rs index 1c1e027bbed..bfbbd48f422 100644 --- a/crates/noirc_frontend/src/hir/type_check/stmt.rs +++ b/crates/noirc_frontend/src/hir/type_check/stmt.rs @@ -181,13 +181,13 @@ fn type_check_lvalue( let index_type = type_check_expression(interner, &index, errors); let expr_span = interner.expr_span(&index); - if index_type.is_subtype_of(&Type::field(Some(expr_span)), expr_span).is_err() { - errors.push(TypeCheckError::TypeMismatch { + index_type.make_subtype_of(&Type::field(Some(expr_span)), expr_span, errors, || { + TypeCheckError::TypeMismatch { expected_typ: "Field".to_owned(), expr_typ: index_type.to_string(), expr_span, - }); - } + } + }); let (result, array) = type_check_lvalue(interner, *array, assign_span, errors); let array = Box::new(array); diff --git a/crates/noirc_frontend/src/hir_def/types.rs b/crates/noirc_frontend/src/hir_def/types.rs index d17f9832f72..10b70ad2db1 100644 --- a/crates/noirc_frontend/src/hir_def/types.rs +++ b/crates/noirc_frontend/src/hir_def/types.rs @@ -861,7 +861,7 @@ impl Type { } } - pub fn is_subtype_of(&self, other: &Type, span: Span) -> Result<(), SpanKind> { + fn is_subtype_of(&self, other: &Type, span: Span) -> Result<(), SpanKind> { use Type::*; match (self, other) { (Error, _) | (_, Error) => Ok(()), From 55afff40026d5c6b45d19ad8b09ef9bc37554d29 Mon Sep 17 00:00:00 2001 From: guipublic Date: Thu, 23 Feb 2023 10:17:17 +0000 Subject: [PATCH 11/37] Code review --- .../src/ssa/acir_gen/acir_mem.rs | 18 ++++++++---------- .../src/ssa/acir_gen/operations/sort.rs | 2 +- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 3c9cab707d7..05b850d2fc0 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -165,11 +165,10 @@ impl AcirMem { // Write the value to the array's VM at the specified index pub fn insert(&mut self, array_id: ArrayId, index: u32, value: InternalVar) { - let entry = self.virtual_memory.entry(array_id).or_default(); + let heap = self.virtual_memory.entry(array_id).or_default(); let value_expr = value.to_expression(); - entry.memory_map.insert(index, value); - - entry.stage(index, value_expr, Expression::one()); + heap.memory_map.insert(index, value); + heap.stage(index, value_expr, Expression::one()); } //Map the outputs into the array @@ -195,13 +194,12 @@ impl AcirMem { } // number of bits required to store the input - fn bits(mut t: usize) -> u32 { - let mut r = 0; - while t != 0 { - t >>= 1; - r += 1; + fn bits(t: usize) -> u32 { + if t > 0 { + t.ilog2() + 1 + } else { + 1 } - r } // Loads the associated `InternalVar` for the element diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs index 745cdd58833..9c80446b263 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs @@ -21,7 +21,7 @@ pub fn evaluate_permutation( ) -> Vec { let bits = Vec::new(); let (w, b) = permutation_layer(in_expr, &bits, true, evaluator); - // we contrain the network output to out_expr + // we constrain the network output to out_expr for (b, o) in b.iter().zip(out_expr) { evaluator.opcodes.push(AcirOpcode::Arithmetic(subtract(b, FieldElement::one(), o))); } From af17ec6a2c2f5af1a8b01683470620bf84c7b546 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 28 Feb 2023 11:30:25 +0000 Subject: [PATCH 12/37] Code review --- .../src/ssa/acir_gen/operations/sort.rs | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs index d7937fb7bdf..ab5b6b09c01 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/sort.rs @@ -60,17 +60,15 @@ fn permutation_layer( return (Vec::new(), in_expr.clone()); } let n1 = n / 2; - let mut conf = Vec::new(); // witness for the input switches - #[allow(clippy::needless_range_loop)] - for i in 0..n1 { + let mut conf = iter_extended::vecmap(0..n1, |i| { if generate_witness { - conf.push(evaluator.add_witness_to_cs()); + evaluator.add_witness_to_cs() } else { - conf.push(bits[i]); + bits[i] } - } + }); // compute expressions after the input switches // If inputs are a1,a2, and the switch value is c, then we compute expressions b1,b2 where From 0c1bc4eaff2a25e07b2265eaeea480dd001027a2 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 28 Feb 2023 16:45:28 +0000 Subject: [PATCH 13/37] MemAddress --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 05b850d2fc0..09635a35903 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -32,13 +32,15 @@ struct MemOp { index: Expression, } +type MemAddress = u32; + #[derive(Default)] pub struct ArrayHeap { // maps memory address to InternalVar - memory_map: BTreeMap, + memory_map: BTreeMap, trace: Vec, // maps memory address to (values,operation) that must be committed to the trace - staged: BTreeMap, + staged: BTreeMap, } impl ArrayHeap { @@ -164,7 +166,7 @@ impl AcirMem { } // Write the value to the array's VM at the specified index - pub fn insert(&mut self, array_id: ArrayId, index: u32, value: InternalVar) { + pub fn insert(&mut self, array_id: ArrayId, index: MemAddress, value: InternalVar) { let heap = self.virtual_memory.entry(array_id).or_default(); let value_expr = value.to_expression(); heap.memory_map.insert(index, value); @@ -213,7 +215,7 @@ impl AcirMem { pub(crate) fn load_array_element_constant_index( &mut self, array: &MemArray, - offset: u32, + offset: MemAddress, ) -> Option { // Check the memory_map to see if the element is there self.array_map_mut(array.id).get(&offset).cloned() From 966b5574bdbada0c6aff5a28d832890f5a8c5148 Mon Sep 17 00:00:00 2001 From: guipublic Date: Fri, 10 Mar 2023 11:00:09 +0000 Subject: [PATCH 14/37] merge from master --- crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs index 597c4afc80d..c38b7506a16 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs @@ -34,7 +34,8 @@ pub(crate) fn evaluate( } else { let pred = var_cache.get_or_compute_internal_var_unwrap(predicate, evaluator, ctx); let dummy_load = - load::evaluate(array_id, index, acir_mem, var_cache, evaluator, ctx).unwrap(); + load::evaluate(array_id, index, acir_mem, var_cache, None, evaluator, ctx) + .unwrap(); let result = condition::evaluate_expression( pred.expression(), value_var.expression(), From cb93f6e8cbaf6c364ffc3ec2f0ed4639865f660b Mon Sep 17 00:00:00 2001 From: guipublic Date: Fri, 10 Mar 2023 11:30:14 +0000 Subject: [PATCH 15/37] Remove ilog2 because it is tagged as unstable --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 2baed927466..5c525273930 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -194,12 +194,13 @@ impl AcirMem { } // number of bits required to store the input - fn bits(t: usize) -> u32 { - if t > 0 { - t.ilog2() + 1 - } else { - 1 + fn bits(mut t: usize) -> u32 { + let mut r = 0; + while t != 0 { + t >>= 1; + r += 1; } + r } // Loads the associated `InternalVar` for the element From c79e9dc815dfeaacd2d7648dddc2e1799644293c Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 14 Mar 2023 14:18:26 +0000 Subject: [PATCH 16/37] clippy --- crates/noirc_evaluator/src/ssa/acir_gen.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 9a7adba209b..3cb0308789b 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -30,7 +30,7 @@ pub(crate) struct Acir { } impl Acir { - pub fn acir_gen( + pub(crate) fn acir_gen( &mut self, evaluator: &mut Evaluator, ctx: &SsaContext, From 1aa52fee141592177d742dc9a063a467d272b2a4 Mon Sep 17 00:00:00 2001 From: guipublic Date: Thu, 16 Mar 2023 09:13:12 +0000 Subject: [PATCH 17/37] *WIP* handle block opcode --- crates/noirc_evaluator/src/ssa/acir_gen.rs | 2 +- .../src/ssa/acir_gen/acir_mem.rs | 30 ++++++++++++------- crates/noirc_evaluator/src/ssa/mem.rs | 4 +++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 3cb0308789b..0050101ebf8 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -46,7 +46,7 @@ impl Acir { //TODO we should rather follow the jumps current_block = block.left.map(|block_id| &ctx[block_id]); } - self.memory.acir_gen(evaluator); + self.memory.acir_gen(evaluator, ctx); Ok(()) } diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 279d86f8b5d..ba06f377f28 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -8,7 +8,7 @@ use crate::{ }; use acvm::{ acir::{ - circuit::{directives::Directive, opcodes::Opcode as AcirOpcode}, + circuit::{directives::Directive, opcodes::{Opcode as AcirOpcode, MemoryBlock, BlockId as AcirBlockId, MemOp}}, native_types::{Expression, Witness}, }, FieldElement, @@ -24,12 +24,12 @@ use super::{ /// Represent a memory operation on the ArrayHeap, at the specified index /// Operation is one for a store and 0 for a load -#[derive(Clone, Debug)] -struct MemOp { - operation: Expression, - value: Expression, - index: Expression, -} +// #[derive(Clone, Debug)] +// struct MemOp { +// operation: Expression, +// value: Expression, +// index: Expression, +// } type MemAddress = u32; @@ -77,7 +77,7 @@ impl ArrayHeap { } outputs } - pub(crate) fn acir_gen(&self, evaluator: &mut Evaluator) { + pub(crate) fn acir_gen(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { let len = self.trace.len(); if len == 0 { return; @@ -141,6 +141,15 @@ impl ArrayHeap { evaluator.opcodes.push(AcirOpcode::Arithmetic(store_on_new_adr)); evaluator.opcodes.push(AcirOpcode::Arithmetic(load_on_same_adr)); } + + let id = array_id.as_u32(); + evaluator.opcodes.push(AcirOpcode::Block(MemoryBlock { + id: AcirBlockId(id), + len: array_len, + trace: self.trace.clone(), + init: 0, + })); + } } @@ -238,9 +247,10 @@ impl AcirMem { self.commit(array_id, op != Expression::zero()); self.array_heap_mut(*array_id).push(index, value, op); } - pub(crate) fn acir_gen(&self, evaluator: &mut Evaluator) { + pub(crate) fn acir_gen(&self, evaluator: &mut Evaluator, ctx: &SsaContext) { for mem in &self.virtual_memory { - mem.1.acir_gen(evaluator); + let array = ctx.mem[*mem.0]; + mem.1.acir_gen(evaluator, array.id, array.len); } } } diff --git a/crates/noirc_evaluator/src/ssa/mem.rs b/crates/noirc_evaluator/src/ssa/mem.rs index 6ab42d05f6e..1217bbc3956 100644 --- a/crates/noirc_evaluator/src/ssa/mem.rs +++ b/crates/noirc_evaluator/src/ssa/mem.rs @@ -23,6 +23,10 @@ impl ArrayId { pub(crate) fn dummy() -> ArrayId { ArrayId(std::u32::MAX) } + + pub(crate) fn as_u32(&self) -> u32 { + self.0 + } } #[derive(Debug, Clone)] From 713ebc325e8564c330bd2fa7cf6d2bb472c59dd9 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 21 Mar 2023 10:18:25 +0000 Subject: [PATCH 18/37] **WIP** support RAM/ROM/BLOCK opcodes --- crates/noirc_evaluator/src/lib.rs | 5 +- crates/noirc_evaluator/src/ssa/acir_gen.rs | 1 + .../src/ssa/acir_gen/acir_mem.rs | 78 ++++++++++++++++++- crates/noirc_evaluator/src/ssa/context.rs | 3 +- crates/noirc_evaluator/src/ssa/ssa_gen.rs | 2 +- 5 files changed, 84 insertions(+), 5 deletions(-) diff --git a/crates/noirc_evaluator/src/lib.rs b/crates/noirc_evaluator/src/lib.rs index 99db5fe7766..7999206e411 100644 --- a/crates/noirc_evaluator/src/lib.rs +++ b/crates/noirc_evaluator/src/lib.rs @@ -60,7 +60,7 @@ pub fn create_circuit( let mut evaluator = Evaluator::default(); // First evaluate the main function - evaluator.evaluate_main_alt(program.clone(), enable_logging, show_output)?; + evaluator.evaluate_main_alt(program.clone(), is_blackbox_supported, enable_logging, show_output)?; let witness_index = evaluator.current_witness_index(); @@ -118,6 +118,7 @@ impl Evaluator { pub fn evaluate_main_alt( &mut self, program: Program, + is_opcode_supported: IsOpcodeSupported, enable_logging: bool, show_output: bool, ) -> Result<(), RuntimeError> { @@ -128,7 +129,7 @@ impl Evaluator { ir_gen.ssa_gen_main()?; //Generates ACIR representation: - ir_gen.context.ir_to_acir(self, enable_logging, show_output)?; + ir_gen.context.ir_to_acir(self, is_opcode_supported, enable_logging, show_output)?; Ok(()) } diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 0050101ebf8..77e6961d66c 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -35,6 +35,7 @@ impl Acir { evaluator: &mut Evaluator, ctx: &SsaContext, root: &BasicBlock, + is_opcode_supported: IsOpcodeSupported, show_output: bool, ) -> Result<(), RuntimeError> { let mut current_block = Some(root); diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index ba06f377f28..6515525a3e0 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -64,6 +64,82 @@ impl ArrayHeap { self.staged.insert(index, (value, op)); } + + /// This helper function transforms an expression into a linear expression, by generating a witness if the input expression is not linear nor constant + fn normalize_expression(expr: &mut Expression, evaluator: &mut Evaluator) -> Expression { + if !expr.is_linear() || expr.linear_combinations.len() > 1 { + let w = evaluator.create_intermediate_variable(expr); + Expression::from(w) + } else { + expr.clone() + } + } + + /// Decide which opcode to use, depending on the backend support + fn acir_gen(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32, is_opcde_supported: IsOpcodeSupported) { + let (block,ram,rom) = (IsOpcodeSupported(AcirOpcode::Block),IsOpcodeSupported(AcirOpcode::RAM),IsOpcodeSupported(AcirOpcode::ROM)); + if rom + { + todo!("Check if the array is read-only and add the rom opcode if it is"); //TODO we need the R-O arrays PR + self.add_rom_opcode(evaluator,array_id, array_len); + return; + } + + match (block,ram) { + (false, false) => self.generate_permutation_constraints(evaluator, array_id, array_len), + (false, true) => self.add_ram_opcode(evaluator,array_id, array_len), + (true, _) => + { + evaluator.opcodes.push(AcirOpcode::Block(MemoryBlock { + id: AcirBlockId(id), + len: array_len, + trace: self.trace.clone(), + })); + }, + + } + } + + fn add_rom_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { + let mut trace = Vec::new(); + for op in self.trace { + let index = Self::normalize_expression(&mut op.index, evaluator); + let value = Self::normalize_expression(&mut op.value, evaluator); + trace.push(MemOp { + operation: op.operation, + index, + value, + }); + } + evaluator.opcodes.push(AcirOpcode::ROM(MemoryBlock { + id: AcirBlockId(id), + len: array_len, + trace, + })); + } + + fn add_ram_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { + todo!("Check there is an initialization phase"); //TODO we need the R-O array PR for this + let mut trace = Vec::new(); + for op in self.trace { + //TODO - after the init, we need a witness per-index but this will be managed by BB - we need to wait for the BB ram PR + let index = Self::normalize_expression(&mut op.index, evaluator); + let value = Self::normalize_expression(&mut op.value, evaluator); + trace.push(MemOp { + operation: op.operation, + index, + value, + }); + } + evaluator.opcodes.push(AcirOpcode::ROM(MemoryBlock { + id: AcirBlockId(id), + len: array_len, + trace, + })); + } + + + fn generate_outputs( inputs: Vec, bits: &mut Vec, @@ -77,7 +153,7 @@ impl ArrayHeap { } outputs } - pub(crate) fn acir_gen(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { + pub(crate) fn generate_permutation_constraints(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { let len = self.trace.len(); if len == 0 { return; diff --git a/crates/noirc_evaluator/src/ssa/context.rs b/crates/noirc_evaluator/src/ssa/context.rs index a4ba605e623..283b0fc7aef 100644 --- a/crates/noirc_evaluator/src/ssa/context.rs +++ b/crates/noirc_evaluator/src/ssa/context.rs @@ -694,6 +694,7 @@ impl SsaContext { pub(crate) fn ir_to_acir( &mut self, evaluator: &mut Evaluator, + is_opcode_supported: IsOpcodeSupported, enable_logging: bool, show_output: bool, ) -> Result<(), RuntimeError> { @@ -742,7 +743,7 @@ impl SsaContext { self.log(enable_logging, "\noverflow:", ""); //ACIR let mut acir = Acir::default(); - acir.acir_gen(evaluator, self, &self[self.first_block], show_output)?; + acir.acir_gen(evaluator, self, &self[self.first_block], is_opcode_supported, show_output)?; if enable_logging { print_acir_circuit(&evaluator.opcodes); println!("DONE"); diff --git a/crates/noirc_evaluator/src/ssa/ssa_gen.rs b/crates/noirc_evaluator/src/ssa/ssa_gen.rs index ac4b9b297b7..67fe20e5d57 100644 --- a/crates/noirc_evaluator/src/ssa/ssa_gen.rs +++ b/crates/noirc_evaluator/src/ssa/ssa_gen.rs @@ -10,7 +10,7 @@ use crate::{ {block, builtin, node, ssa_form}, }, }; -use acvm::FieldElement; +use acvm::{FieldElement, compiler::transformers::IsOpcodeSupported}; use iter_extended::vecmap; use noirc_errors::Location; use noirc_frontend::{ From 9830b47323fdea2ff5199ee85ce975a139d62c6a Mon Sep 17 00:00:00 2001 From: guipublic Date: Wed, 3 May 2023 11:51:13 +0000 Subject: [PATCH 19/37] fikx the build after merge --- crates/noirc_evaluator/src/ssa/acir_gen.rs | 3 +- .../src/ssa/acir_gen/acir_mem.rs | 130 ++++++++++-------- crates/noirc_evaluator/src/ssa/context.rs | 1 + crates/noirc_evaluator/src/ssa/ssa_gen.rs | 2 +- 4 files changed, 75 insertions(+), 61 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 8ff45240ac9..277eb54d356 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -13,6 +13,7 @@ use acvm::acir::native_types::{Expression, Witness}; mod operations; mod internal_var; +use acvm::compiler::transformers::IsOpcodeSupported; pub(crate) use internal_var::InternalVar; mod constraints; mod internal_var_cache; @@ -47,7 +48,7 @@ impl Acir { //TODO we should rather follow the jumps current_block = block.left.map(|block_id| &ctx[block_id]); } - self.memory.acir_gen(evaluator, ctx); + self.memory.acir_gen(evaluator, is_opcode_supported, ctx); Ok(()) } diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index d75295d8840..7342ee92c02 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -8,9 +8,13 @@ use crate::{ }; use acvm::{ acir::{ - circuit::{directives::Directive, opcodes::{Opcode as AcirOpcode, MemoryBlock, BlockId as AcirBlockId, MemOp}}, + circuit::{ + directives::Directive, + opcodes::{BlockId as AcirBlockId, MemOp, MemoryBlock, Opcode as AcirOpcode}, + }, native_types::{Expression, Witness}, }, + compiler::transformers::IsOpcodeSupported, FieldElement, }; @@ -123,11 +127,10 @@ impl ArrayHeap { self.staged.insert(index, (value, op)); } - /// This helper function transforms an expression into a linear expression, by generating a witness if the input expression is not linear nor constant - fn normalize_expression(expr: &mut Expression, evaluator: &mut Evaluator) -> Expression { + fn normalize_expression(expr: &Expression, evaluator: &mut Evaluator) -> Expression { if !expr.is_linear() || expr.linear_combinations.len() > 1 { - let w = evaluator.create_intermediate_variable(expr); + let w = evaluator.create_intermediate_variable(expr.clone()); Expression::from(w) } else { expr.clone() @@ -135,70 +138,72 @@ impl ArrayHeap { } /// Decide which opcode to use, depending on the backend support - fn acir_gen(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32, is_opcde_supported: IsOpcodeSupported) { - let (block,ram,rom) = (IsOpcodeSupported(AcirOpcode::Block),IsOpcodeSupported(AcirOpcode::RAM),IsOpcodeSupported(AcirOpcode::ROM)); - if rom - { - todo!("Check if the array is read-only and add the rom opcode if it is"); //TODO we need the R-O arrays PR - self.add_rom_opcode(evaluator,array_id, array_len); - return; - } - - match (block,ram) { - (false, false) => self.generate_permutation_constraints(evaluator, array_id, array_len), - (false, true) => self.add_ram_opcode(evaluator,array_id, array_len), - (true, _) => - { - evaluator.opcodes.push(AcirOpcode::Block(MemoryBlock { - id: AcirBlockId(id), - len: array_len, - trace: self.trace.clone(), - })); - }, + fn acir_gen( + &self, + evaluator: &mut Evaluator, + array_id: ArrayId, + array_len: u32, + is_opcode_supported: IsOpcodeSupported, + ) { + let dummy = MemoryBlock { id: AcirBlockId(0), len: 0, trace: Vec::new() }; + let dummy2 = dummy.clone(); + let dummy3 = dummy.clone(); + let (block, ram, rom) = ( + is_opcode_supported(&AcirOpcode::Block(dummy)), + is_opcode_supported(&AcirOpcode::RAM(dummy2)), + is_opcode_supported(&AcirOpcode::ROM(dummy3)), + ); + if rom { + // If the backend support ROM and the array is read-only, we generate the ROM opcode + if let ArrayType::ReadOnly(len) = self.typ { + self.add_rom_opcode(evaluator, array_id, len.unwrap() as u32); + return; + } + } + match (block, ram) { + (false, false) => self.generate_permutation_constraints(evaluator, array_id, array_len), + (false, true) => self.add_ram_opcode(evaluator, array_id, array_len), + (true, _) => { + evaluator.opcodes.push(AcirOpcode::Block(MemoryBlock { + id: AcirBlockId(array_id.as_u32()), + len: array_len, + trace: self.trace.clone(), + })); + } } } fn add_rom_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { let mut trace = Vec::new(); - for op in self.trace { - let index = Self::normalize_expression(&mut op.index, evaluator); - let value = Self::normalize_expression(&mut op.value, evaluator); - trace.push(MemOp { - operation: op.operation, - index, - value, - }); + for op in &self.trace { + let index = Self::normalize_expression(&op.index, evaluator); + let value = Self::normalize_expression(&op.value, evaluator); + trace.push(MemOp { operation: op.operation.clone(), index, value }); } evaluator.opcodes.push(AcirOpcode::ROM(MemoryBlock { - id: AcirBlockId(id), + id: AcirBlockId(array_id.as_u32()), len: array_len, trace, })); } fn add_ram_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { - todo!("Check there is an initialization phase"); //TODO we need the R-O array PR for this let mut trace = Vec::new(); - for op in self.trace { + for op in &self.trace { //TODO - after the init, we need a witness per-index but this will be managed by BB - we need to wait for the BB ram PR - let index = Self::normalize_expression(&mut op.index, evaluator); - let value = Self::normalize_expression(&mut op.value, evaluator); - trace.push(MemOp { - operation: op.operation, - index, - value, - }); + let index = Self::normalize_expression(&op.index, evaluator); + let value = Self::normalize_expression(&op.value, evaluator); + debug_assert!(op.operation.is_const()); + trace.push(MemOp { operation: op.operation.clone(), index, value }); } - evaluator.opcodes.push(AcirOpcode::ROM(MemoryBlock { - id: AcirBlockId(id), + evaluator.opcodes.push(AcirOpcode::RAM(MemoryBlock { + id: AcirBlockId(array_id.as_u32()), len: array_len, trace, })); } - - fn generate_outputs( inputs: Vec, bits: &mut Vec, @@ -212,13 +217,17 @@ impl ArrayHeap { } outputs } - pub(crate) fn generate_permutation_constraints(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { - let len = self.trace.len(); - // let (len, read_write) = match self.typ { - // ArrayType::Init(_, _) | ArrayType::WriteOnly => (0, true), - // ArrayType::ReadOnly(last) => (last.unwrap_or(self.trace.len()), false), - // ArrayType::ReadWrite(last) => (last.unwrap_or(self.trace.len()), true), - // }; + pub(crate) fn generate_permutation_constraints( + &self, + evaluator: &mut Evaluator, + array_id: ArrayId, + array_len: u32, + ) { + let (len, read_write) = match self.typ { + ArrayType::Init(_, _) | ArrayType::WriteOnly => (0, true), + ArrayType::ReadOnly(last) => (last.unwrap_or(self.trace.len()), false), + ArrayType::ReadWrite(last) => (last.unwrap_or(self.trace.len()), true), + }; if len == 0 { return; } @@ -296,15 +305,13 @@ impl ArrayHeap { }; evaluator.opcodes.push(AcirOpcode::Arithmetic(load_on_same_adr)); } - + let id = array_id.as_u32(); evaluator.opcodes.push(AcirOpcode::Block(MemoryBlock { id: AcirBlockId(id), len: array_len, trace: self.trace.clone(), - init: 0, })); - } } @@ -403,10 +410,15 @@ impl AcirMem { let item = MemOp { operation: op, value, index }; self.array_heap_mut(*array_id).push(item); } - pub(crate) fn acir_gen(&self, evaluator: &mut Evaluator, ctx: &SsaContext) { + pub(crate) fn acir_gen( + &self, + evaluator: &mut Evaluator, + is_opcode_supported: IsOpcodeSupported, + ctx: &SsaContext, + ) { for mem in &self.virtual_memory { - let array = ctx.mem[*mem.0]; - mem.1.acir_gen(evaluator, array.id, array.len); + let array = &ctx.mem[*mem.0]; + mem.1.acir_gen(evaluator, array.id, array.len, is_opcode_supported); } } } diff --git a/crates/noirc_evaluator/src/ssa/context.rs b/crates/noirc_evaluator/src/ssa/context.rs index 3de512ed36c..327ffc2b222 100644 --- a/crates/noirc_evaluator/src/ssa/context.rs +++ b/crates/noirc_evaluator/src/ssa/context.rs @@ -12,6 +12,7 @@ use crate::ssa::{ {block, builtin, flatten, function, inline, integer, node, optimizations}, }; use crate::Evaluator; +use acvm::compiler::transformers::IsOpcodeSupported; use acvm::FieldElement; use iter_extended::vecmap; use noirc_errors::Location; diff --git a/crates/noirc_evaluator/src/ssa/ssa_gen.rs b/crates/noirc_evaluator/src/ssa/ssa_gen.rs index 27952ecb897..ae35855b5fa 100644 --- a/crates/noirc_evaluator/src/ssa/ssa_gen.rs +++ b/crates/noirc_evaluator/src/ssa/ssa_gen.rs @@ -10,7 +10,7 @@ use crate::{ {block, builtin, node, ssa_form}, }, }; -use acvm::{acir::native_types::Witness, FieldElement, compiler::transformers::IsOpcodeSupported}; +use acvm::{acir::native_types::Witness, FieldElement}; use iter_extended::vecmap; use noirc_errors::Location; use noirc_frontend::{ From 78da4277db2fcf7b7aa61ba69c6d9f4fe55a02c0 Mon Sep 17 00:00:00 2001 From: guipublic Date: Wed, 3 May 2023 12:04:21 +0000 Subject: [PATCH 20/37] clean-up --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 12 ------------ 1 file changed, 12 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 7342ee92c02..0f98e2a768f 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -26,15 +26,6 @@ use super::{ operations::{self}, }; -/// Represent a memory operation on the ArrayHeap, at the specified index -/// Operation is one for a store and 0 for a load -// #[derive(Clone, Debug)] -// struct MemOp { -// operation: Expression, -// value: Expression, -// index: Expression, -// } - type MemAddress = u32; enum ArrayType { @@ -191,10 +182,8 @@ impl ArrayHeap { fn add_ram_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { let mut trace = Vec::new(); for op in &self.trace { - //TODO - after the init, we need a witness per-index but this will be managed by BB - we need to wait for the BB ram PR let index = Self::normalize_expression(&op.index, evaluator); let value = Self::normalize_expression(&op.value, evaluator); - debug_assert!(op.operation.is_const()); trace.push(MemOp { operation: op.operation.clone(), index, value }); } evaluator.opcodes.push(AcirOpcode::RAM(MemoryBlock { @@ -319,7 +308,6 @@ impl ArrayHeap { #[derive(Default)] pub(crate) struct AcirMem { virtual_memory: BTreeMap, - //pub(crate) dummy: Witness, } impl AcirMem { From be1cf689062226c3ad2cc62ada5b686b5f66248d Mon Sep 17 00:00:00 2001 From: guipublic Date: Wed, 3 May 2023 12:05:12 +0000 Subject: [PATCH 21/37] missed this one --- crates/noirc_evaluator/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/crates/noirc_evaluator/src/lib.rs b/crates/noirc_evaluator/src/lib.rs index bfc9b6256a5..efa3da37b8c 100644 --- a/crates/noirc_evaluator/src/lib.rs +++ b/crates/noirc_evaluator/src/lib.rs @@ -76,7 +76,12 @@ pub fn create_circuit( let mut evaluator = Evaluator::default(); // First evaluate the main function - evaluator.evaluate_main_alt(program.clone(), is_blackbox_supported, enable_logging, show_output)?; + evaluator.evaluate_main_alt( + program.clone(), + is_opcode_supported, + enable_logging, + show_output, + )?; let Evaluator { current_witness_index, From f9c2db84e0f5f5303dbc1fa35b6161470dc30343 Mon Sep 17 00:00:00 2001 From: guipublic Date: Wed, 3 May 2023 16:42:01 +0000 Subject: [PATCH 22/37] code review --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 0f98e2a768f..050f5c86f1e 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -166,7 +166,7 @@ impl ArrayHeap { } fn add_rom_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { - let mut trace = Vec::new(); + let mut trace = Vec::with_capacity(self.trace.len()); for op in &self.trace { let index = Self::normalize_expression(&op.index, evaluator); let value = Self::normalize_expression(&op.value, evaluator); @@ -180,7 +180,7 @@ impl ArrayHeap { } fn add_ram_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { - let mut trace = Vec::new(); + let mut trace = Vec::with_capacity(self.trace.len()); for op in &self.trace { let index = Self::normalize_expression(&op.index, evaluator); let value = Self::normalize_expression(&op.value, evaluator); From ad5171562cd3c7f81cacb09eedf3ec3204f7f240 Mon Sep 17 00:00:00 2001 From: guipublic Date: Wed, 3 May 2023 16:48:34 +0000 Subject: [PATCH 23/37] code review --- .../src/ssa/acir_gen/acir_mem.rs | 31 ++++++++----------- 1 file changed, 13 insertions(+), 18 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 050f5c86f1e..c9ca8cb83e5 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -137,31 +137,26 @@ impl ArrayHeap { is_opcode_supported: IsOpcodeSupported, ) { let dummy = MemoryBlock { id: AcirBlockId(0), len: 0, trace: Vec::new() }; - let dummy2 = dummy.clone(); - let dummy3 = dummy.clone(); - let (block, ram, rom) = ( - is_opcode_supported(&AcirOpcode::Block(dummy)), - is_opcode_supported(&AcirOpcode::RAM(dummy2)), - is_opcode_supported(&AcirOpcode::ROM(dummy3)), - ); - if rom { + + if is_opcode_supported(&AcirOpcode::ROM(dummy.clone())) { // If the backend support ROM and the array is read-only, we generate the ROM opcode if let ArrayType::ReadOnly(len) = self.typ { self.add_rom_opcode(evaluator, array_id, len.unwrap() as u32); return; } } - - match (block, ram) { - (false, false) => self.generate_permutation_constraints(evaluator, array_id, array_len), - (false, true) => self.add_ram_opcode(evaluator, array_id, array_len), - (true, _) => { - evaluator.opcodes.push(AcirOpcode::Block(MemoryBlock { - id: AcirBlockId(array_id.as_u32()), - len: array_len, - trace: self.trace.clone(), - })); + if !is_opcode_supported(&AcirOpcode::Block(dummy.clone())) { + if is_opcode_supported(&AcirOpcode::RAM(dummy)) { + self.add_ram_opcode(evaluator, array_id, array_len); + } else { + self.generate_permutation_constraints(evaluator, array_id, array_len); } + } else { + evaluator.opcodes.push(AcirOpcode::Block(MemoryBlock { + id: AcirBlockId(array_id.as_u32()), + len: array_len, + trace: self.trace.clone(), + })); } } From d58de5c1ad2e512ac602e74a33577a020b457986 Mon Sep 17 00:00:00 2001 From: guipublic Date: Thu, 4 May 2023 10:43:02 +0000 Subject: [PATCH 24/37] Fix issue with array_len --- .../src/ssa/acir_gen/acir_mem.rs | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index c9ca8cb83e5..4697635e7ab 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -140,8 +140,8 @@ impl ArrayHeap { if is_opcode_supported(&AcirOpcode::ROM(dummy.clone())) { // If the backend support ROM and the array is read-only, we generate the ROM opcode - if let ArrayType::ReadOnly(len) = self.typ { - self.add_rom_opcode(evaluator, array_id, len.unwrap() as u32); + if matches!(self.typ, ArrayType::ReadOnly(_)) { + self.add_rom_opcode(evaluator, array_id, array_len); return; } } @@ -149,17 +149,22 @@ impl ArrayHeap { if is_opcode_supported(&AcirOpcode::RAM(dummy)) { self.add_ram_opcode(evaluator, array_id, array_len); } else { + self.add_block_opcode(evaluator, array_id, array_len); self.generate_permutation_constraints(evaluator, array_id, array_len); } } else { - evaluator.opcodes.push(AcirOpcode::Block(MemoryBlock { - id: AcirBlockId(array_id.as_u32()), - len: array_len, - trace: self.trace.clone(), - })); + self.add_block_opcode(evaluator, array_id, array_len); } } + fn add_block_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { + evaluator.opcodes.push(AcirOpcode::Block(MemoryBlock { + id: AcirBlockId(array_id.as_u32()), + len: array_len, + trace: self.trace.clone(), + })); + } + fn add_rom_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { let mut trace = Vec::with_capacity(self.trace.len()); for op in &self.trace { From 899df762c198de247bcc2fcdda07ccc8f0555034 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 15 May 2023 10:11:57 +0000 Subject: [PATCH 25/37] clarify comment --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index f6e3197d139..615418ac237 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -118,7 +118,7 @@ impl ArrayHeap { self.staged.insert(index, (value, op)); } - /// This helper function transforms an expression into a linear expression, by generating a witness if the input expression is not linear nor constant + /// This helper function transforms an expression into a (univariate) linear expression, by generating a witness if the input expression is not linear nor constant fn normalize_expression(expr: &Expression, evaluator: &mut Evaluator) -> Expression { if !expr.is_linear() || expr.linear_combinations.len() > 1 { let w = evaluator.create_intermediate_variable(expr.clone()); From dab6bb37a4fea2f47268208e3c6fc20c39538781 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 15 May 2023 10:20:46 +0000 Subject: [PATCH 26/37] code review --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 615418ac237..b04412102a9 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -145,14 +145,12 @@ impl ArrayHeap { return; } } - if !is_opcode_supported(&AcirOpcode::Block(dummy.clone())) { - if is_opcode_supported(&AcirOpcode::RAM(dummy)) { - self.add_ram_opcode(evaluator, array_id, array_len); - } else { - self.generate_permutation_constraints(evaluator, array_id, array_len); - } - } else { + if is_opcode_supported(&AcirOpcode::Block(dummy.clone())) { self.add_block_opcode(evaluator, array_id, array_len); + } else if is_opcode_supported(&AcirOpcode::RAM(dummy)) { + self.add_ram_opcode(evaluator, array_id, array_len); + } else { + self.generate_permutation_constraints(evaluator, array_id, array_len); } } From 7be88eb689e8759ecbe2ddbb0474f3c240606a42 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 15 May 2023 10:25:23 +0000 Subject: [PATCH 27/37] code review --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index b04412102a9..0bbe99fa23d 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -118,13 +118,13 @@ impl ArrayHeap { self.staged.insert(index, (value, op)); } - /// This helper function transforms an expression into a (univariate) linear expression, by generating a witness if the input expression is not linear nor constant + /// This helper function transforms an expression into a (univariate) affine expression, by generating a witness if the input expression is not linear nor constant fn normalize_expression(expr: &Expression, evaluator: &mut Evaluator) -> Expression { - if !expr.is_linear() || expr.linear_combinations.len() > 1 { + if expr.is_linear() && expr.linear_combinations.len() <= 1 { + expr.clone() + } else { let w = evaluator.create_intermediate_variable(expr.clone()); Expression::from(w) - } else { - expr.clone() } } From 075110d1480e26f7e7543afa194f0cfee952f14a Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 15 May 2023 15:41:14 +0000 Subject: [PATCH 28/37] Code review --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 7 ------- 1 file changed, 7 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 0bbe99fa23d..14f084bc947 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -292,13 +292,6 @@ impl ArrayHeap { }; evaluator.opcodes.push(AcirOpcode::Arithmetic(load_on_same_adr)); } - - let id = array_id.as_u32(); - evaluator.opcodes.push(AcirOpcode::Block(MemoryBlock { - id: AcirBlockId(id), - len: array_len, - trace: self.trace.clone(), - })); } } From 6ac418a3e994987838650ea0404d51a5ff3a5e99 Mon Sep 17 00:00:00 2001 From: guipublic Date: Thu, 25 May 2023 10:01:38 +0000 Subject: [PATCH 29/37] Hardcode BB support for memory gates --- crates/noirc_evaluator/src/lib.rs | 10 ++-------- crates/noirc_evaluator/src/ssa/acir_gen.rs | 4 +--- .../noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 16 ++++++++++------ crates/noirc_evaluator/src/ssa/context.rs | 4 +--- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/crates/noirc_evaluator/src/lib.rs b/crates/noirc_evaluator/src/lib.rs index 8dcc25a9866..b044c70570a 100644 --- a/crates/noirc_evaluator/src/lib.rs +++ b/crates/noirc_evaluator/src/lib.rs @@ -73,12 +73,7 @@ pub fn create_circuit( let mut evaluator = Evaluator::default(); // First evaluate the main function - evaluator.evaluate_main_alt( - program.clone(), - is_opcode_supported, - enable_logging, - show_output, - )?; + evaluator.evaluate_main_alt(program.clone(), enable_logging, show_output)?; let Evaluator { current_witness_index, @@ -152,7 +147,6 @@ impl Evaluator { pub fn evaluate_main_alt( &mut self, program: Program, - is_opcode_supported: IsOpcodeSupported, enable_logging: bool, show_output: bool, ) -> Result<(), RuntimeError> { @@ -165,7 +159,7 @@ impl Evaluator { ir_gen.ssa_gen_main()?; //Generates ACIR representation: - ir_gen.context.ir_to_acir(self, is_opcode_supported, enable_logging, show_output)?; + ir_gen.context.ir_to_acir(self, enable_logging, show_output)?; Ok(()) } diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 277eb54d356..22b5390e2fa 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -13,7 +13,6 @@ use acvm::acir::native_types::{Expression, Witness}; mod operations; mod internal_var; -use acvm::compiler::transformers::IsOpcodeSupported; pub(crate) use internal_var::InternalVar; mod constraints; mod internal_var_cache; @@ -36,7 +35,6 @@ impl Acir { evaluator: &mut Evaluator, ctx: &SsaContext, root: &BasicBlock, - is_opcode_supported: IsOpcodeSupported, show_output: bool, ) -> Result<(), RuntimeError> { let mut current_block = Some(root); @@ -48,7 +46,7 @@ impl Acir { //TODO we should rather follow the jumps current_block = block.left.map(|block_id| &ctx[block_id]); } - self.memory.acir_gen(evaluator, is_opcode_supported, ctx); + self.memory.acir_gen(evaluator, ctx); Ok(()) } diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 14f084bc947..397e19c82f6 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -389,15 +389,19 @@ impl AcirMem { let item = MemOp { operation: op, value, index }; self.array_heap_mut(*array_id).push(item); } - pub(crate) fn acir_gen( - &self, - evaluator: &mut Evaluator, - is_opcode_supported: IsOpcodeSupported, - ctx: &SsaContext, - ) { + pub(crate) fn acir_gen(&self, evaluator: &mut Evaluator, ctx: &SsaContext) { + //Temporary hack - We hardcode Barretenberg support here. + //TODO: to remove once opcodesupported usage is clarified + let is_opcode_supported: OpcodeSupported = |o| match o { + AcirOpcode::Block(_) => false, + AcirOpcode::ROM(_) | AcirOpcode::RAM(_) => true, + _ => unreachable!(), + }; for mem in &self.virtual_memory { let array = &ctx.mem[*mem.0]; mem.1.acir_gen(evaluator, array.id, array.len, is_opcode_supported); } } } + +type OpcodeSupported = fn(&AcirOpcode) -> bool; diff --git a/crates/noirc_evaluator/src/ssa/context.rs b/crates/noirc_evaluator/src/ssa/context.rs index 327ffc2b222..2efdd8ff304 100644 --- a/crates/noirc_evaluator/src/ssa/context.rs +++ b/crates/noirc_evaluator/src/ssa/context.rs @@ -12,7 +12,6 @@ use crate::ssa::{ {block, builtin, flatten, function, inline, integer, node, optimizations}, }; use crate::Evaluator; -use acvm::compiler::transformers::IsOpcodeSupported; use acvm::FieldElement; use iter_extended::vecmap; use noirc_errors::Location; @@ -702,7 +701,6 @@ impl SsaContext { pub(crate) fn ir_to_acir( &mut self, evaluator: &mut Evaluator, - is_opcode_supported: IsOpcodeSupported, enable_logging: bool, show_output: bool, ) -> Result<(), RuntimeError> { @@ -749,7 +747,7 @@ impl SsaContext { self.log(enable_logging, "\noverflow:", ""); //ACIR let mut acir = Acir::default(); - acir.acir_gen(evaluator, self, &self[self.first_block], is_opcode_supported, show_output)?; + acir.acir_gen(evaluator, self, &self[self.first_block], show_output)?; if enable_logging { print_acir_circuit(&evaluator.opcodes); println!("DONE"); From dc0cf8f5d5f555b2e3f7bc7cafd3486cdaf4102a Mon Sep 17 00:00:00 2001 From: guipublic Date: Thu, 25 May 2023 10:26:55 +0000 Subject: [PATCH 30/37] Fix clippy error --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 397e19c82f6..016ba41ca83 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -14,7 +14,6 @@ use acvm::{ }, native_types::{Expression, Witness}, }, - compiler::transformers::IsOpcodeSupported, FieldElement, }; @@ -134,7 +133,7 @@ impl ArrayHeap { evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32, - is_opcode_supported: IsOpcodeSupported, + is_opcode_supported: OpcodeSupported, ) { let dummy = MemoryBlock { id: AcirBlockId(0), len: 0, trace: Vec::new() }; From 3337cb59e391f85dd70fdb4913a8340e06c6544f Mon Sep 17 00:00:00 2001 From: guipublic Date: Thu, 25 May 2023 10:41:56 +0000 Subject: [PATCH 31/37] Code review --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 016ba41ca83..123ae673b38 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -202,7 +202,7 @@ impl ArrayHeap { } outputs } - pub(crate) fn generate_permutation_constraints( + fn generate_permutation_constraints( &self, evaluator: &mut Evaluator, array_id: ArrayId, From d88708734b3c84aabed95e4da6ad0baa4d9e973a Mon Sep 17 00:00:00 2001 From: guipublic Date: Fri, 26 May 2023 08:02:35 +0000 Subject: [PATCH 32/37] Check for array length before adding a memory gate --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 123ae673b38..463f6b6fc7d 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -135,6 +135,11 @@ impl ArrayHeap { array_len: u32, is_opcode_supported: OpcodeSupported, ) { + //sanity check + if array_len == 0 { + return; + } + let dummy = MemoryBlock { id: AcirBlockId(0), len: 0, trace: Vec::new() }; if is_opcode_supported(&AcirOpcode::ROM(dummy.clone())) { From 6cd3a709c36c0dc085b0f70beab053e1cf03c150 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 30 May 2023 10:13:41 +0000 Subject: [PATCH 33/37] avoid empty memory constraints --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 463f6b6fc7d..6a1aaac6860 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -136,10 +136,9 @@ impl ArrayHeap { is_opcode_supported: OpcodeSupported, ) { //sanity check - if array_len == 0 { + if array_len == 0 || self.trace.is_empty() { return; } - let dummy = MemoryBlock { id: AcirBlockId(0), len: 0, trace: Vec::new() }; if is_opcode_supported(&AcirOpcode::ROM(dummy.clone())) { From 837798a6e1980a2902ae123ecefdcf2f4c449248 Mon Sep 17 00:00:00 2001 From: guipublic Date: Fri, 2 Jun 2023 16:33:55 +0000 Subject: [PATCH 34/37] Use correct trace length --- .../src/ssa/acir_gen/acir_mem.rs | 43 +++++++++++++++---- .../src/ssa/acir_gen/operations/return.rs | 1 + 2 files changed, 36 insertions(+), 8 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 6a1aaac6860..887274daad4 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -140,18 +140,22 @@ impl ArrayHeap { return; } let dummy = MemoryBlock { id: AcirBlockId(0), len: 0, trace: Vec::new() }; + let trace_len = match self.typ { + ArrayType::ReadOnly(Some(len)) | ArrayType::ReadWrite(Some(len)) => len, + _ => self.trace.len(), + }; if is_opcode_supported(&AcirOpcode::ROM(dummy.clone())) { // If the backend support ROM and the array is read-only, we generate the ROM opcode if matches!(self.typ, ArrayType::ReadOnly(_)) { - self.add_rom_opcode(evaluator, array_id, array_len); + self.add_rom_opcode(evaluator, array_id, array_len, trace_len); return; } } if is_opcode_supported(&AcirOpcode::Block(dummy.clone())) { self.add_block_opcode(evaluator, array_id, array_len); } else if is_opcode_supported(&AcirOpcode::RAM(dummy)) { - self.add_ram_opcode(evaluator, array_id, array_len); + self.add_ram_opcode(evaluator, array_id, array_len, trace_len); } else { self.generate_permutation_constraints(evaluator, array_id, array_len); } @@ -165,9 +169,15 @@ impl ArrayHeap { })); } - fn add_rom_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { - let mut trace = Vec::with_capacity(self.trace.len()); - for op in &self.trace { + fn add_rom_opcode( + &self, + evaluator: &mut Evaluator, + array_id: ArrayId, + array_len: u32, + trace_len: usize, + ) { + let mut trace = Vec::with_capacity(trace_len); + for op in self.trace.iter().take(trace_len) { let index = Self::normalize_expression(&op.index, evaluator); let value = Self::normalize_expression(&op.value, evaluator); trace.push(MemOp { operation: op.operation.clone(), index, value }); @@ -179,9 +189,15 @@ impl ArrayHeap { })); } - fn add_ram_opcode(&self, evaluator: &mut Evaluator, array_id: ArrayId, array_len: u32) { - let mut trace = Vec::with_capacity(self.trace.len()); - for op in &self.trace { + fn add_ram_opcode( + &self, + evaluator: &mut Evaluator, + array_id: ArrayId, + array_len: u32, + trace_len: usize, + ) { + let mut trace = Vec::with_capacity(trace_len); + for op in self.trace.iter().take(trace_len) { let index = Self::normalize_expression(&op.index, evaluator); let value = Self::normalize_expression(&op.value, evaluator); trace.push(MemOp { operation: op.operation.clone(), index, value }); @@ -337,6 +353,17 @@ impl AcirMem { } } + //Ensure we do not optimise writes when the array is returned + pub(crate) fn return_array(&mut self, array_id: ArrayId) { + let heap = self.array_heap_mut(array_id); + match heap.typ { + ArrayType::ReadOnly(_) | ArrayType::ReadWrite(_) => { + heap.typ = ArrayType::ReadWrite(None); + } + _ => (), + } + } + // Load array values into InternalVars // If create_witness is true, we create witnesses for values that do not have witness pub(super) fn load_array(&mut self, array: &MemArray) -> Vec { diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/operations/return.rs b/crates/noirc_evaluator/src/ssa/acir_gen/operations/return.rs index 6aaa3b2fbbd..3a444771616 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/return.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/return.rs @@ -32,6 +32,7 @@ pub(crate) fn evaluate( let objects = match Memory::deref(ctx, *node_id) { Some(a) => { let array = &ctx.mem[a]; + memory_map.return_array(a); memory_map.load_array(array) } None => { From 91e376a19a09346b10c5d73dc63419db27c60c85 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 12 Jun 2023 12:25:14 +0000 Subject: [PATCH 35/37] Create a witness for memory operations --- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs index 3ead1645576..ae0a7277ca0 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -117,14 +117,11 @@ impl ArrayHeap { self.staged.insert(index, (value, op)); } - /// This helper function transforms an expression into a (univariate) affine expression, by generating a witness if the input expression is not linear nor constant + /// This helper function transforms an expression into a single witness representing the expression fn normalize_expression(expr: &Expression, evaluator: &mut Evaluator) -> Expression { - if expr.is_linear() && expr.linear_combinations.len() <= 1 { - expr.clone() - } else { - let w = evaluator.create_intermediate_variable(expr.clone()); - Expression::from(w) - } + expr.to_witness() + .unwrap_or_else(|| evaluator.create_intermediate_variable(expr.clone())) + .into() } /// Decide which opcode to use, depending on the backend support From 01edbc38b6aa65b8a55832ef838399255f20e337 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 13 Jun 2023 16:46:15 +0000 Subject: [PATCH 36/37] use barretenberg with dynamic array fixes --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index c02dbe14542..d56ed2079db 100644 --- a/flake.nix +++ b/flake.nix @@ -38,7 +38,7 @@ }; barretenberg = { - url = "github:AztecProtocol/barretenberg"; + url = "github:AztecProtocol/barretenberg/76482829f72f4cd9c866737c7501f5c58d86bc6e"; # All of these inputs (a.k.a. dependencies) need to align with inputs we # use so they use the `inputs.*.follows` syntax to reference our inputs inputs = { From b9d35b167da70f2619801f2781205349239ebd33 Mon Sep 17 00:00:00 2001 From: guipublic Date: Wed, 14 Jun 2023 14:15:45 +0000 Subject: [PATCH 37/37] Update to last commit of bb noir branch, through flake.lock --- flake.lock | 6 +++--- flake.nix | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/flake.lock b/flake.lock index 10839befbc2..c9047f7d52a 100644 --- a/flake.lock +++ b/flake.lock @@ -10,11 +10,11 @@ ] }, "locked": { - "lastModified": 1685812470, - "narHash": "sha256-sJYVipq1EthnjSxVIZnZF15wy9LDMHNPfIJKRHyZrws=", + "lastModified": 1686677483, + "narHash": "sha256-mpsCXzHMaqSveQcD/SA9k3NH4pF167KqR5/oYJJjKE8=", "owner": "AztecProtocol", "repo": "barretenberg", - "rev": "193ce1a45ef5eab6a8522178cf918e45320f3de8", + "rev": "65e651d04c6092cb5ca079cd9e12ed9b5846fa3a", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index d56ed2079db..c02dbe14542 100644 --- a/flake.nix +++ b/flake.nix @@ -38,7 +38,7 @@ }; barretenberg = { - url = "github:AztecProtocol/barretenberg/76482829f72f4cd9c866737c7501f5c58d86bc6e"; + url = "github:AztecProtocol/barretenberg"; # All of these inputs (a.k.a. dependencies) need to align with inputs we # use so they use the `inputs.*.follows` syntax to reference our inputs inputs = {