From bcb631dbfe39f9d8069d0b2dfd9a2754b2b86f40 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 13 Feb 2023 17:15:43 +0000 Subject: [PATCH 01/20] 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 52fe4de857..80008275e8 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 5e91ad52aa..d3106a0642 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 57bc0782d1..286ba988ee 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 7a282fdf0f..86e5c0211d 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 8beed8119c..ccd1ce15ea 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 b12e9c487b..c28e77e822 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 2fc08cdf48..96b637d99c 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 1fd72793eb..329513f06a 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 bf1d1ddfcf..155288203d 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/20] 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 2891f1ad4b..3bf4db01f6 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/20] 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 d3106a0642..29aa254f52 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 86e5c0211d..fdf411acb7 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 3bf4db01f6..942a00f013 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 329513f06a..ead9429f64 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/20] 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 80008275e8..6ac54ef7af 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/20] 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 aade42f6e6..69e07a39db 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 4fcd1c6f2c..2ff8503dbc 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 d15dcfd20d..c606068dae 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 44d00763d7..004d41beb4 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 6078bef79d..ba16681767 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 7e1b507887..55a192faf7 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 2e72fb8ac7..632d769fd7 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 1af21131ee..a62cdecdc5 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 286ba988ee..2b339ec161 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 c28e77e822..c46cb013d7 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 eab75742ab..a6b5534e7b 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 250a8a64be..462e7be772 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 0784a19e51..5dd83af2c5 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 88f768a71a..8bc17b8fcd 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 f79df00dbe..1c1e027bbe 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 10b70ad2db..d17f9832f7 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/20] 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 632d769fd7..ee4d507abc 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/20] 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 c606068dae..d15dcfd20d 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 004d41beb4..909fc1bbf6 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 ba16681767..26405d9991 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/20] 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 26405d9991..c1752cf327 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/20] restore bad commit --- Cargo.lock | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 69e07a39db..aade42f6e6 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/20] 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 ee4d507abc..3c9cab707d 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 a6b5534e7b..745cdd5883 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 8bc17b8fcd..9b3675b69e 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 1c1e027bbe..bfbbd48f42 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 d17f9832f7..10b70ad2db 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/20] 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 3c9cab707d..05b850d2fc 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 745cdd5883..9c80446b26 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/20] 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 d7937fb7bd..ab5b6b09c0 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/20] 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 05b850d2fc..09635a3590 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/20] 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 597c4afc80..c38b7506a1 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/20] 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 2baed92746..5c52527393 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/20] 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 9a7adba209..3cb0308789 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 e406af79193467b6cfc16d2255b452d885dc625c Mon Sep 17 00:00:00 2001 From: guipublic Date: Fri, 17 Mar 2023 10:26:28 +0000 Subject: [PATCH 17/20] de-activate dynamic arrays --- .../nargo/tests/test_data/6_array/src/main.nr | 32 +++++++++---------- .../noirc_frontend/src/hir/type_check/expr.rs | 28 +++++++++++++--- .../noirc_frontend/src/hir/type_check/stmt.rs | 12 +++++-- 3 files changed, 49 insertions(+), 23 deletions(-) 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 2ff8503dbc..3537740f1e 100644 --- a/crates/nargo/tests/test_data/6_array/src/main.nr +++ b/crates/nargo/tests/test_data/6_array/src/main.nr @@ -1,7 +1,7 @@ //Basic tests for arrays fn main(x: [u32; 5], y: [u32; 5], mut z: u32, t: u32) { let mut c = 2301; - let idx = (z - 5*t - 5) as Field; + let _idx = (z - 5*t - 5) as Field; z = y[4]; //Test 1: for i in 0..5 { @@ -52,20 +52,20 @@ fn main(x: [u32; 5], y: [u32; 5], mut z: u32, t: u32) { } } - //dynamic array test - dyn_array(x, idx, idx - 3); + //dynamic array test - TODO uncomment the call below when activating dynamic arrays + //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 +// 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/noirc_frontend/src/hir/type_check/expr.rs b/crates/noirc_frontend/src/hir/type_check/expr.rs index eea64bd0ef..e3381f2fe6 100644 --- a/crates/noirc_frontend/src/hir/type_check/expr.rs +++ b/crates/noirc_frontend/src/hir/type_check/expr.rs @@ -264,13 +264,31 @@ 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.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, + + 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, + } } }); + // TODO: replace the above by the below in order to activate dynamic arrays + // 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 249c84fcce..ef5bbfa892 100644 --- a/crates/noirc_frontend/src/hir/type_check/stmt.rs +++ b/crates/noirc_frontend/src/hir/type_check/stmt.rs @@ -189,13 +189,21 @@ fn type_check_lvalue( let index_type = type_check_expression(interner, &index, errors); let expr_span = interner.expr_span(&index); - index_type.make_subtype_of(&Type::field(Some(expr_span)), expr_span, errors, || { + index_type.unify(&Type::comp_time(Some(expr_span)), expr_span, errors, || { TypeCheckError::TypeMismatch { - expected_typ: "Field".to_owned(), + expected_typ: "comptime Field".to_owned(), expr_typ: index_type.to_string(), expr_span, } }); + //TODO replace the above by the below in order to activate dynamic arrays + // 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); From 023ab4e1c3298f8115afa29e9698cf9b554fa713 Mon Sep 17 00:00:00 2001 From: guipublic Date: Fri, 17 Mar 2023 10:27:04 +0000 Subject: [PATCH 18/20] cargo fmt --- crates/noirc_frontend/src/hir/type_check/expr.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/crates/noirc_frontend/src/hir/type_check/expr.rs b/crates/noirc_frontend/src/hir/type_check/expr.rs index e3381f2fe6..f4c5d4b82c 100644 --- a/crates/noirc_frontend/src/hir/type_check/expr.rs +++ b/crates/noirc_frontend/src/hir/type_check/expr.rs @@ -288,7 +288,6 @@ fn type_check_index_expression( // expr_span: span, // } // }); - let lhs_type = type_check_expression(interner, &index_expr.collection, errors); match lhs_type { From 61c24ad7b82a0a93e09cc9947bd5cc33ae9fe62b Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 20 Mar 2023 17:23:17 +0000 Subject: [PATCH 19/20] Code review --- crates/noirc_evaluator/src/ssa/acir_gen.rs | 2 +- crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs | 3 +-- .../src/ssa/acir_gen/operations/store.rs | 11 +++++------ 3 files changed, 7 insertions(+), 9 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 3cb0308789..22d183698f 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -101,7 +101,7 @@ impl Acir { *array_id, *index, acir_mem, var_cache, *location, evaluator, ctx, )?), Operation::Store { .. } => { - store::evaluate(&ins.operation, acir_mem, var_cache, evaluator, ctx) + store::evaluate(&ins.operation, acir_mem, var_cache, evaluator, ctx)? } Operation::Nop => None, i @ Operation::Jne(..) 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 279d86f8b5..12c85fe1d4 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/acir_mem.rs @@ -148,7 +148,6 @@ impl ArrayHeap { #[derive(Default)] pub(crate) struct AcirMem { virtual_memory: BTreeMap, - //pub(crate) dummy: Witness, } impl AcirMem { @@ -193,7 +192,7 @@ impl AcirMem { }) } - // number of bits required to store the input + // Number of bits required to store the input fn bits(mut t: usize) -> u32 { let mut r = 0; while t != 0 { 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 c38b7506a1..8fe4ebb6f1 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen/operations/store.rs @@ -12,7 +12,7 @@ use crate::{ mem, node::Operation, }, - Evaluator, + Evaluator, errors::RuntimeError, }; pub(crate) fn evaluate( @@ -21,7 +21,7 @@ pub(crate) fn evaluate( var_cache: &mut InternalVarCache, evaluator: &mut Evaluator, ctx: &SsaContext, -) -> Option { +) -> Result, RuntimeError> { 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 = var_cache.get_or_compute_internal_var_unwrap(index, evaluator, ctx); @@ -30,12 +30,11 @@ pub(crate) fn evaluate( if predicate.is_dummy() || ctx.is_one(predicate) { value_var } else if ctx.is_zero(predicate) { - return None; + return Ok(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, None, evaluator, ctx) - .unwrap(); + load::evaluate(array_id, index, acir_mem, var_cache, None, evaluator, ctx)?; let result = condition::evaluate_expression( pred.expression(), value_var.expression(), @@ -66,5 +65,5 @@ pub(crate) fn evaluate( unreachable!("Expected store, got {:?}", store.opcode()); } //we do not generate constraint, so no output. - None + Ok(None) } From f4e590fc63f3aeaacc03b0da869c5ad332cfafbb Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 20 Mar 2023 17:42:23 +0000 Subject: [PATCH 20/20] format --- 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 8fe4ebb6f1..b6733ef522 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,7 @@ use acvm::acir::native_types::Expression; use crate::{ + errors::RuntimeError, ssa::{ acir_gen::{ acir_mem::AcirMem, @@ -12,7 +13,7 @@ use crate::{ mem, node::Operation, }, - Evaluator, errors::RuntimeError, + Evaluator, }; pub(crate) fn evaluate(