From b003f0a6369b14de34325d7f646b95ff640f1943 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Wed, 10 Jan 2024 18:40:32 +0000 Subject: [PATCH 1/6] chore: add test case showing reexports (#4001) # Description ## Problem\* Resolves ## Summary\* This PR adds a test case to just show the current state of reexports across libraries. ## Additional Context ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --- compiler/noirc_frontend/src/hir/def_map/mod.rs | 1 + .../compile_success_empty/reexports/Nargo.toml | 7 +++++++ .../compile_success_empty/reexports/src/main.nr | 8 ++++++++ test_programs/test_libraries/exporting_lib/Nargo.toml | 6 ++++++ test_programs/test_libraries/exporting_lib/src/lib.nr | 10 ++++++++++ .../test_libraries/reexporting_lib/Nargo.toml | 7 +++++++ .../test_libraries/reexporting_lib/src/lib.nr | 3 +++ 7 files changed, 42 insertions(+) create mode 100644 test_programs/compile_success_empty/reexports/Nargo.toml create mode 100644 test_programs/compile_success_empty/reexports/src/main.nr create mode 100644 test_programs/test_libraries/exporting_lib/Nargo.toml create mode 100644 test_programs/test_libraries/exporting_lib/src/lib.nr create mode 100644 test_programs/test_libraries/reexporting_lib/Nargo.toml create mode 100644 test_programs/test_libraries/reexporting_lib/src/lib.nr diff --git a/compiler/noirc_frontend/src/hir/def_map/mod.rs b/compiler/noirc_frontend/src/hir/def_map/mod.rs index 9c46ef3585..fbf94468c4 100644 --- a/compiler/noirc_frontend/src/hir/def_map/mod.rs +++ b/compiler/noirc_frontend/src/hir/def_map/mod.rs @@ -64,6 +64,7 @@ pub struct CrateDefMap { pub(crate) krate: CrateId, + /// Maps an external dependency's name to its root module id. pub(crate) extern_prelude: BTreeMap, } diff --git a/test_programs/compile_success_empty/reexports/Nargo.toml b/test_programs/compile_success_empty/reexports/Nargo.toml new file mode 100644 index 0000000000..4a87f28fd8 --- /dev/null +++ b/test_programs/compile_success_empty/reexports/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "reexports" +type = "bin" +authors = [""] + +[dependencies] +reexporting_lib = { path = "../../test_libraries/reexporting_lib" } diff --git a/test_programs/compile_success_empty/reexports/src/main.nr b/test_programs/compile_success_empty/reexports/src/main.nr new file mode 100644 index 0000000000..bb94b21b22 --- /dev/null +++ b/test_programs/compile_success_empty/reexports/src/main.nr @@ -0,0 +1,8 @@ +use dep::reexporting_lib::{FooStruct, MyStruct, lib}; + +fn main() { + let x: FooStruct = MyStruct { + inner: 0 + }; + assert(lib::is_struct_zero(x)); +} diff --git a/test_programs/test_libraries/exporting_lib/Nargo.toml b/test_programs/test_libraries/exporting_lib/Nargo.toml new file mode 100644 index 0000000000..628418c060 --- /dev/null +++ b/test_programs/test_libraries/exporting_lib/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "exporting_lib" +type = "lib" +authors = [""] + +[dependencies] diff --git a/test_programs/test_libraries/exporting_lib/src/lib.nr b/test_programs/test_libraries/exporting_lib/src/lib.nr new file mode 100644 index 0000000000..af1fd7a32d --- /dev/null +++ b/test_programs/test_libraries/exporting_lib/src/lib.nr @@ -0,0 +1,10 @@ + +struct MyStruct { + inner: Field +} + +type FooStruct = MyStruct; + +fn is_struct_zero(val: MyStruct) -> bool { + val.inner == 0 +} diff --git a/test_programs/test_libraries/reexporting_lib/Nargo.toml b/test_programs/test_libraries/reexporting_lib/Nargo.toml new file mode 100644 index 0000000000..c26ce501e5 --- /dev/null +++ b/test_programs/test_libraries/reexporting_lib/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "reexporting_lib" +type = "lib" +authors = [""] + +[dependencies] +exporting_lib = { path = "../exporting_lib" } diff --git a/test_programs/test_libraries/reexporting_lib/src/lib.nr b/test_programs/test_libraries/reexporting_lib/src/lib.nr new file mode 100644 index 0000000000..f12dfe01ec --- /dev/null +++ b/test_programs/test_libraries/reexporting_lib/src/lib.nr @@ -0,0 +1,3 @@ +use dep::exporting_lib::{MyStruct, FooStruct}; + +use dep::exporting_lib as lib; From 857ff97b196174a0999f0fe7e387bfca5c3b7cd3 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Wed, 10 Jan 2024 20:12:16 +0000 Subject: [PATCH 2/6] feat: remove truncation from brillig casts (#3997) # Description ## Problem\* Resolves ## Summary\* As part of #3984, I noticed that I forgot to remove the truncation behaviour from casts in brillig. This PR updates them to be a simple `mov` instruction. In order to do this I've added a proper implementation of `Instruction::Truncate`. ## Additional Context ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [x] I have tested the changes locally. - [x] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --- .../src/brillig/brillig_gen/brillig_block.rs | 59 ++++--------------- .../noirc_evaluator/src/brillig/brillig_ir.rs | 55 +++++++---------- .../src/brillig/brillig_ir/debug_show.rs | 4 +- 3 files changed, 37 insertions(+), 81 deletions(-) diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index 0e06a36fd9..db005d9d43 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -521,7 +521,7 @@ impl<'block> BrilligBlock<'block> { unreachable!("unsupported function call type {:?}", dfg[*func]) } }, - Instruction::Truncate { value, .. } => { + Instruction::Truncate { value, bit_size, .. } => { let result_ids = dfg.instruction_results(instruction_id); let destination_register = self.variables.define_register_variable( self.function_context, @@ -530,9 +530,13 @@ impl<'block> BrilligBlock<'block> { dfg, ); let source_register = self.convert_ssa_register_value(*value, dfg); - self.brillig_context.truncate_instruction(destination_register, source_register); + self.brillig_context.truncate_instruction( + destination_register, + source_register, + *bit_size, + ); } - Instruction::Cast(value, target_type) => { + Instruction::Cast(value, _) => { let result_ids = dfg.instruction_results(instruction_id); let destination_register = self.variables.define_register_variable( self.function_context, @@ -541,12 +545,7 @@ impl<'block> BrilligBlock<'block> { dfg, ); let source_register = self.convert_ssa_register_value(*value, dfg); - self.convert_cast( - destination_register, - source_register, - target_type, - &dfg.type_of_value(*value), - ); + self.convert_cast(destination_register, source_register); } Instruction::ArrayGet { array, index } => { let result_ids = dfg.instruction_results(instruction_id); @@ -1092,43 +1091,11 @@ impl<'block> BrilligBlock<'block> { /// Converts an SSA cast to a sequence of Brillig opcodes. /// Casting is only necessary when shrinking the bit size of a numeric value. - fn convert_cast( - &mut self, - destination: RegisterIndex, - source: RegisterIndex, - target_type: &Type, - source_type: &Type, - ) { - fn numeric_to_bit_size(typ: &NumericType) -> u32 { - match typ { - NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => *bit_size, - NumericType::NativeField => FieldElement::max_num_bits(), - } - } - // Casting is only valid for numeric types - // This should be checked by the frontend, so we panic if this is the case - let (source_numeric_type, target_numeric_type) = match (source_type, target_type) { - (Type::Numeric(source_numeric_type), Type::Numeric(target_numeric_type)) => { - (source_numeric_type, target_numeric_type) - } - _ => unimplemented!("The cast operation is only valid for integers."), - }; - let source_bit_size = numeric_to_bit_size(source_numeric_type); - let target_bit_size = numeric_to_bit_size(target_numeric_type); - // Casting from a larger bit size to a smaller bit size (narrowing cast) - // requires a cast instruction. - // If its a widening cast, ie casting from a smaller bit size to a larger bit size - // we simply put a mov instruction as a no-op - // - // Field elements by construction always have the largest bit size - // This means that casting to a Field element, will always be a widening cast - // and therefore a no-op. Conversely, casting from a Field element - // will always be a narrowing cast and therefore a cast instruction - if source_bit_size > target_bit_size { - self.brillig_context.cast_instruction(destination, source, target_bit_size); - } else { - self.brillig_context.mov_instruction(destination, source); - } + fn convert_cast(&mut self, destination: RegisterIndex, source: RegisterIndex) { + // We assume that `source` is a valid `target_type` as it's expected that a truncate instruction was emitted + // to ensure this is the case. + + self.brillig_context.mov_instruction(destination, source); } /// Converts the Binary instruction into a sequence of Brillig opcodes. diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index ff182aaa7d..3c4e77b09e 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -687,10 +687,29 @@ impl BrilligContext { &mut self, destination_of_truncated_value: RegisterIndex, value_to_truncate: RegisterIndex, + bit_size: u32, ) { - // Effectively a no-op because brillig already has implicit truncation on integer - // operations. We need only copy the value to it's destination. - self.mov_instruction(destination_of_truncated_value, value_to_truncate); + self.debug_show.truncate_instruction( + destination_of_truncated_value, + value_to_truncate, + bit_size, + ); + assert!( + bit_size <= BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, + "tried to truncate to a bit size greater than allowed {bit_size}" + ); + + // The brillig VM performs all arithmetic operations modulo 2**bit_size + // So to truncate any value to a target bit size we can just issue a no-op arithmetic operation + // With bit size equal to target_bit_size + let zero_register = self.make_constant(Value::from(FieldElement::zero())); + self.binary_instruction( + value_to_truncate, + zero_register, + destination_of_truncated_value, + BrilligBinaryOp::Integer { op: BinaryIntOp::Add, bit_size }, + ); + self.deallocate_register(zero_register); } /// Emits a stop instruction @@ -761,36 +780,6 @@ impl BrilligContext { self.deallocate_register(scratch_register_j); } - /// Emits a modulo instruction against 2**target_bit_size - /// - /// Integer arithmetic in Brillig is currently constrained to 127 bit integers. - /// We restrict the cast operation, so that integer types over 127 bits - /// cannot be created. - pub(crate) fn cast_instruction( - &mut self, - destination: RegisterIndex, - source: RegisterIndex, - target_bit_size: u32, - ) { - self.debug_show.cast_instruction(destination, source, target_bit_size); - assert!( - target_bit_size <= BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, - "tried to cast to a bit size greater than allowed {target_bit_size}" - ); - - // The brillig VM performs all arithmetic operations modulo 2**bit_size - // So to cast any value to a target bit size we can just issue a no-op arithmetic operation - // With bit size equal to target_bit_size - let zero_register = self.make_constant(Value::from(FieldElement::zero())); - self.binary_instruction( - source, - zero_register, - destination, - BrilligBinaryOp::Integer { op: BinaryIntOp::Add, bit_size: target_bit_size }, - ); - self.deallocate_register(zero_register); - } - /// Adds a unresolved external `Call` instruction to the bytecode. /// This calls into another function compiled into this brillig artifact. pub(crate) fn add_external_call_instruction(&mut self, func_label: T) { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index aae74849b8..74b24b280c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -326,7 +326,7 @@ impl DebugShow { } /// Debug function for cast_instruction - pub(crate) fn cast_instruction( + pub(crate) fn truncate_instruction( &self, destination: RegisterIndex, source: RegisterIndex, @@ -334,7 +334,7 @@ impl DebugShow { ) { debug_println!( self.enable_debug_trace, - " CAST {} FROM {} TO {} BITS", + " TRUNCATE {} FROM {} TO {} BITS", destination, source, target_bit_size From 51cf9d37c8b9fbb14bb54b178d93129a7563e131 Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Wed, 10 Jan 2024 20:14:10 +0000 Subject: [PATCH 3/6] feat: decompose `Instruction::Constrain` into multiple more basic constraints (#3892) # Description ## Problem\* Some experimentation related to #3782. ## Summary\* If we switch to an unary constrain instruction then we will want to be able to decompose an assertion on a composite type to perform assertions directly on its fields. Otherwise we have to create a predicate for each field and then collect these all together before constraining that. For example consider this program which simulates an unary constrain ``` fn main(x: [Field; 2], y: [Field; 2]) { let equal = x == y; assert(equal); } ``` Currently this produces: ``` acir fn main f0 { b0(v0: [Field; 2], v1: [Field; 2]): v66 = array_get v0, index Field 0 v67 = array_get v1, index Field 0 v68 = eq v66, v67 v69 = array_get v0, index Field 1 v70 = array_get v1, index Field 1 v71 = eq v69, v70 v72 = mul v68, v71 constrain v72 == u1 1 return } Compiled ACIR for main (unoptimized): current witness index : 10 public parameters indices : [] return value indices : [] EXPR [ (-1, _1) (1, _3) (-1, _5) 0 ] BRILLIG: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(5))], q_c: 0 })] outputs: [Simple(Witness(6))] [JumpIfNot { condition: RegisterIndex(0), location: 3 }, Const { destination: RegisterIndex(1), value: Value { inner: 1 } }, BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) }, Stop] EXPR [ (1, _5, _6) (1, _7) -1 ] EXPR [ (1, _5, _7) 0 ] EXPR [ (-1, _2) (1, _4) (-1, _8) 0 ] BRILLIG: inputs: [Single(Expression { mul_terms: [], linear_combinations: [(1, Witness(8))], q_c: 0 })] outputs: [Simple(Witness(9))] [JumpIfNot { condition: RegisterIndex(0), location: 3 }, Const { destination: RegisterIndex(1), value: Value { inner: 1 } }, BinaryFieldOp { destination: RegisterIndex(0), op: Div, lhs: RegisterIndex(1), rhs: RegisterIndex(0) }, Stop] EXPR [ (1, _8, _9) (1, _10) -1 ] EXPR [ (1, _8, _10) 0 ] EXPR [ (1, _7, _10) -1 ] ``` After this PR we can recover the current optimisations for `assert(x == y)` ``` acir fn main f0 { b0(v0: [Field; 2], v1: [Field; 2]): v66 = array_get v0, index Field 0 v67 = array_get v1, index Field 0 v68 = array_get v0, index Field 1 v69 = array_get v1, index Field 1 constrain v66 == v67 constrain v68 == v69 return } Compiled ACIR for main (unoptimized): current witness index : 4 public parameters indices : [] return value indices : [] EXPR [ (1, _1) (-1, _3) 0 ] EXPR [ (1, _2) (-1, _4) 0 ] ``` ## Additional Context ## Documentation\* Check one: - [ ] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [ ] I have tested the changes locally. - [ ] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --------- Co-authored-by: jfecher --- compiler/noirc_evaluator/src/ssa/ir/dfg.rs | 30 ++- .../noirc_evaluator/src/ssa/ir/instruction.rs | 202 ++++++++++++------ .../src/ssa/opt/constant_folding.rs | 63 ++++++ 3 files changed, 222 insertions(+), 73 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs index 931aee9d07..98c0253c6e 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/dfg.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/dfg.rs @@ -166,11 +166,31 @@ impl DataFlowGraph { SimplifiedToMultiple(simplification) } SimplifyResult::Remove => InstructionRemoved, - result @ (SimplifyResult::SimplifiedToInstruction(_) | SimplifyResult::None) => { - let instruction = result.instruction().unwrap_or(instruction); - let id = self.make_instruction(instruction, ctrl_typevars); - self.blocks[block].insert_instruction(id); - self.locations.insert(id, call_stack); + result @ (SimplifyResult::SimplifiedToInstruction(_) + | SimplifyResult::SimplifiedToInstructionMultiple(_) + | SimplifyResult::None) => { + let instructions = result.instructions().unwrap_or(vec![instruction]); + + if instructions.len() > 1 { + // There's currently no way to pass results from one instruction in `instructions` on to the next. + // We then restrict this to only support multiple instructions if they're all `Instruction::Constrain` + // as this instruction type does not have any results. + assert!( + instructions.iter().all(|instruction| matches!(instruction, Instruction::Constrain(..))), + "`SimplifyResult::SimplifiedToInstructionMultiple` only supports `Constrain` instructions" + ); + } + + let mut last_id = None; + + for instruction in instructions { + let id = self.make_instruction(instruction, ctrl_typevars.clone()); + self.blocks[block].insert_instruction(id); + self.locations.insert(id, call_stack.clone()); + last_id = Some(id); + } + + let id = last_id.expect("There should be at least 1 simplified instruction"); InsertInstructionResult::Results(id, self.instruction_results(id)) } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs index 25b406dc85..afd182ab2d 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction.rs @@ -432,73 +432,11 @@ impl Instruction { } } Instruction::Constrain(lhs, rhs, msg) => { - if dfg.resolve(*lhs) == dfg.resolve(*rhs) { - // Remove trivial case `assert_eq(x, x)` - SimplifyResult::Remove + let constraints = decompose_constrain(*lhs, *rhs, msg.clone(), dfg); + if constraints.is_empty() { + Remove } else { - match (&dfg[dfg.resolve(*lhs)], &dfg[dfg.resolve(*rhs)]) { - ( - Value::NumericConstant { constant, typ }, - Value::Instruction { instruction, .. }, - ) - | ( - Value::Instruction { instruction, .. }, - Value::NumericConstant { constant, typ }, - ) if *typ == Type::bool() => { - match dfg[*instruction] { - Instruction::Binary(Binary { - lhs, - rhs, - operator: BinaryOp::Eq, - }) if constant.is_one() => { - // Replace an explicit two step equality assertion - // - // v2 = eq v0, u32 v1 - // constrain v2 == u1 1 - // - // with a direct assertion of equality between the two values - // - // v2 = eq v0, u32 v1 - // constrain v0 == v1 - // - // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it - // will likely be removed through dead instruction elimination. - - SimplifiedToInstruction(Instruction::Constrain( - lhs, - rhs, - msg.clone(), - )) - } - Instruction::Not(value) => { - // Replace an assertion that a not instruction is truthy - // - // v1 = not v0 - // constrain v1 == u1 1 - // - // with an assertion that the not instruction input is falsy - // - // v1 = not v0 - // constrain v0 == u1 0 - // - // Note that this doesn't remove the value `v1` as it may be used in other instructions, but it - // will likely be removed through dead instruction elimination. - let reversed_constant = FieldElement::from(!constant.is_one()); - let reversed_constant = - dfg.make_constant(reversed_constant, Type::bool()); - SimplifiedToInstruction(Instruction::Constrain( - value, - reversed_constant, - msg.clone(), - )) - } - - _ => None, - } - } - - _ => None, - } + SimplifiedToInstructionMultiple(constraints) } } Instruction::ArrayGet { array, index } => { @@ -646,6 +584,129 @@ fn simplify_cast(value: ValueId, dst_typ: &Type, dfg: &mut DataFlowGraph) -> Sim } } +/// Try to decompose this constrain instruction. This constraint will be broken down such that it instead constrains +/// all the values which are used to compute the values which were being constrained. +fn decompose_constrain( + lhs: ValueId, + rhs: ValueId, + msg: Option, + dfg: &mut DataFlowGraph, +) -> Vec { + let lhs = dfg.resolve(lhs); + let rhs = dfg.resolve(rhs); + + if lhs == rhs { + // Remove trivial case `assert_eq(x, x)` + Vec::new() + } else { + match (&dfg[lhs], &dfg[rhs]) { + (Value::NumericConstant { constant, typ }, Value::Instruction { instruction, .. }) + | (Value::Instruction { instruction, .. }, Value::NumericConstant { constant, typ }) + if *typ == Type::bool() => + { + match dfg[*instruction] { + Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Eq }) + if constant.is_one() => + { + // Replace an explicit two step equality assertion + // + // v2 = eq v0, u32 v1 + // constrain v2 == u1 1 + // + // with a direct assertion of equality between the two values + // + // v2 = eq v0, u32 v1 + // constrain v0 == v1 + // + // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it + // will likely be removed through dead instruction elimination. + + vec![Instruction::Constrain(lhs, rhs, msg)] + } + + Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Mul }) + if constant.is_one() && dfg.type_of_value(lhs) == Type::bool() => + { + // Replace an equality assertion on a boolean multiplication + // + // v2 = mul v0, v1 + // constrain v2 == u1 1 + // + // with a direct assertion that each value is equal to 1 + // + // v2 = mul v0, v1 + // constrain v0 == 1 + // constrain v1 == 1 + // + // This is due to the fact that for `v2` to be 1 then both `v0` and `v1` are 1. + // + // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it + // will likely be removed through dead instruction elimination. + let one = FieldElement::one(); + let one = dfg.make_constant(one, Type::bool()); + + [ + decompose_constrain(lhs, one, msg.clone(), dfg), + decompose_constrain(rhs, one, msg, dfg), + ] + .concat() + } + + Instruction::Binary(Binary { lhs, rhs, operator: BinaryOp::Or }) + if constant.is_zero() => + { + // Replace an equality assertion on an OR + // + // v2 = or v0, v1 + // constrain v2 == u1 0 + // + // with a direct assertion that each value is equal to 0 + // + // v2 = or v0, v1 + // constrain v0 == 0 + // constrain v1 == 0 + // + // This is due to the fact that for `v2` to be 0 then both `v0` and `v1` are 0. + // + // Note that this doesn't remove the value `v2` as it may be used in other instructions, but it + // will likely be removed through dead instruction elimination. + let zero = FieldElement::zero(); + let zero = dfg.make_constant(zero, dfg.type_of_value(lhs)); + + [ + decompose_constrain(lhs, zero, msg.clone(), dfg), + decompose_constrain(rhs, zero, msg, dfg), + ] + .concat() + } + + Instruction::Not(value) => { + // Replace an assertion that a not instruction is truthy + // + // v1 = not v0 + // constrain v1 == u1 1 + // + // with an assertion that the not instruction input is falsy + // + // v1 = not v0 + // constrain v0 == u1 0 + // + // Note that this doesn't remove the value `v1` as it may be used in other instructions, but it + // will likely be removed through dead instruction elimination. + let reversed_constant = FieldElement::from(!constant.is_one()); + let reversed_constant = dfg.make_constant(reversed_constant, Type::bool()); + decompose_constrain(value, reversed_constant, msg, dfg) + } + + _ => vec![Instruction::Constrain(lhs, rhs, msg)], + } + } + + _ => vec![Instruction::Constrain(lhs, rhs, msg)], + } + } +} + /// The possible return values for Instruction::return_types pub(crate) enum InstructionResultType { /// The result type of this instruction matches that of this operand @@ -1134,6 +1195,10 @@ pub(crate) enum SimplifyResult { /// Replace this function with an simpler but equivalent instruction. SimplifiedToInstruction(Instruction), + /// Replace this function with a set of simpler but equivalent instructions. + /// This is currently only to be used for [`Instruction::Constrain`]. + SimplifiedToInstructionMultiple(Vec), + /// Remove the instruction, it is unnecessary Remove, @@ -1142,9 +1207,10 @@ pub(crate) enum SimplifyResult { } impl SimplifyResult { - pub(crate) fn instruction(self) -> Option { + pub(crate) fn instructions(self) -> Option> { match self { - SimplifyResult::SimplifiedToInstruction(instruction) => Some(instruction), + SimplifyResult::SimplifiedToInstruction(instruction) => Some(vec![instruction]), + SimplifyResult::SimplifiedToInstructionMultiple(instructions) => Some(instructions), _ => None, } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs b/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs index 7e6d841adc..addaee3ba8 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/constant_folding.rs @@ -445,4 +445,67 @@ mod test { assert_eq!(instruction, &Instruction::Cast(v0, Type::unsigned(32))); } + + #[test] + fn constraint_decomposition() { + // fn main f0 { + // b0(v0: u1, v1: u1, v2: u1): + // v3 = mul v0 v1 + // v4 = not v2 + // v5 = mul v3 v4 + // constrain v4 u1 1 + // } + // + // When constructing this IR, we should automatically decompose the constraint to be in terms of `v0`, `v1` and `v2`. + // + // The mul instructions are retained and will be removed in the dead instruction elimination pass. + let main_id = Id::test_new(0); + + // Compiling main + let mut builder = FunctionBuilder::new("main".into(), main_id, RuntimeType::Acir); + let v0 = builder.add_parameter(Type::bool()); + let v1 = builder.add_parameter(Type::bool()); + let v2 = builder.add_parameter(Type::bool()); + + let v3 = builder.insert_binary(v0, BinaryOp::Mul, v1); + let v4 = builder.insert_not(v2); + let v5 = builder.insert_binary(v3, BinaryOp::Mul, v4); + + // This constraint is automatically decomposed when it is inserted. + let v_true = builder.numeric_constant(true, Type::bool()); + builder.insert_constrain(v5, v_true, None); + + let v_false = builder.numeric_constant(false, Type::bool()); + + // Expected output: + // + // fn main f0 { + // b0(v0: u1, v1: u1, v2: u1): + // v3 = mul v0 v1 + // v4 = not v2 + // v5 = mul v3 v4 + // constrain v0 u1 1 + // constrain v1 u1 1 + // constrain v2 u1 0 + // } + + let ssa = builder.finish(); + let main = ssa.main(); + let instructions = main.dfg[main.entry_block()].instructions(); + + assert_eq!(instructions.len(), 6); + + assert_eq!( + main.dfg[instructions[0]], + Instruction::Binary(Binary { lhs: v0, operator: BinaryOp::Mul, rhs: v1 }) + ); + assert_eq!(main.dfg[instructions[1]], Instruction::Not(v2)); + assert_eq!( + main.dfg[instructions[2]], + Instruction::Binary(Binary { lhs: v3, operator: BinaryOp::Mul, rhs: v4 }) + ); + assert_eq!(main.dfg[instructions[3]], Instruction::Constrain(v0, v_true, None)); + assert_eq!(main.dfg[instructions[4]], Instruction::Constrain(v1, v_true, None)); + assert_eq!(main.dfg[instructions[5]], Instruction::Constrain(v2, v_false, None)); + } } From 179c90dc3263c85de105c57925d9c5894427e8e1 Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Wed, 10 Jan 2024 17:36:30 -0600 Subject: [PATCH 4/6] feat: docker testing flow (#3895) ## Summary\* Adds a building / testing flow for CI in docker ## Additional Context ## Documentation\* Check one: - [x] No documentation needed. - [ ] Documentation included in this PR. - [ ] **[Exceptional Case]** Documentation to be submitted in a separate PR. # PR Checklist\* - [ ] I have tested the changes locally. - [ ] I have formatted the changes with [Prettier](https://prettier.io/) and/or `cargo fmt` on default settings. --- .dockerignore | 9 + .github/scripts/acvm_js-build.sh | 5 + .github/scripts/acvm_js-test-browser.sh | 5 + .github/scripts/acvm_js-test.sh | 4 + .github/scripts/backend-barretenberg-build.sh | 4 + .github/scripts/backend-barretenberg-test.sh | 4 + .github/scripts/install_wasm-bindgen.sh | 5 + .github/scripts/integration-test.sh | 6 + .github/scripts/nargo-build.sh | 8 + .github/scripts/nargo-test.sh | 10 + .github/scripts/noir-codegen-build.sh | 4 + .github/scripts/noir-codegen-test.sh | 4 + .github/scripts/noir-js-build.sh | 4 + .github/scripts/noir-js-test.sh | 6 + .github/scripts/noir-js-types-build.sh | 4 + .github/scripts/noir-wasm-build.sh | 5 + .github/scripts/noir-wasm-test-browser.sh | 6 + .github/scripts/noir-wasm-test.sh | 7 + .github/scripts/noirc-abi-build.sh | 5 + .github/scripts/noirc-abi-test-browser.sh | 5 + .github/scripts/noirc-abi-test.sh | 4 + .github/workflows/docker-test-flow.yml | 733 ++++++++++++++++++ Dockerfile.ci | 49 +- .../nargo_compile_noir_codegen_assert_lt.sh | 4 - 24 files changed, 867 insertions(+), 33 deletions(-) create mode 100755 .github/scripts/acvm_js-build.sh create mode 100755 .github/scripts/acvm_js-test-browser.sh create mode 100755 .github/scripts/acvm_js-test.sh create mode 100755 .github/scripts/backend-barretenberg-build.sh create mode 100755 .github/scripts/backend-barretenberg-test.sh create mode 100755 .github/scripts/install_wasm-bindgen.sh create mode 100755 .github/scripts/integration-test.sh create mode 100755 .github/scripts/nargo-build.sh create mode 100755 .github/scripts/nargo-test.sh create mode 100755 .github/scripts/noir-codegen-build.sh create mode 100755 .github/scripts/noir-codegen-test.sh create mode 100755 .github/scripts/noir-js-build.sh create mode 100755 .github/scripts/noir-js-test.sh create mode 100755 .github/scripts/noir-js-types-build.sh create mode 100755 .github/scripts/noir-wasm-build.sh create mode 100755 .github/scripts/noir-wasm-test-browser.sh create mode 100755 .github/scripts/noir-wasm-test.sh create mode 100755 .github/scripts/noirc-abi-build.sh create mode 100755 .github/scripts/noirc-abi-test-browser.sh create mode 100755 .github/scripts/noirc-abi-test.sh create mode 100644 .github/workflows/docker-test-flow.yml delete mode 100755 scripts/nargo_compile_noir_codegen_assert_lt.sh diff --git a/.dockerignore b/.dockerignore index 8bea0aeeb1..559b271bf3 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,6 +1,15 @@ Dockerfile* .dockerignore +# Yarn +.pnp.* +.yarn/* +!.yarn/patches +!.yarn/plugins +!.yarn/releases +!.yarn/sdks +!.yarn/versions + packages **/package.tgz **/target diff --git a/.github/scripts/acvm_js-build.sh b/.github/scripts/acvm_js-build.sh new file mode 100755 index 0000000000..0565a9bb89 --- /dev/null +++ b/.github/scripts/acvm_js-build.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -eu + +.github/scripts/install_wasm-bindgen.sh +yarn workspace @noir-lang/acvm_js build diff --git a/.github/scripts/acvm_js-test-browser.sh b/.github/scripts/acvm_js-test-browser.sh new file mode 100755 index 0000000000..598c98dadf --- /dev/null +++ b/.github/scripts/acvm_js-test-browser.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -eu + +npx playwright install && npx playwright install-deps +yarn workspace @noir-lang/acvm_js test:browser diff --git a/.github/scripts/acvm_js-test.sh b/.github/scripts/acvm_js-test.sh new file mode 100755 index 0000000000..d5519d26cc --- /dev/null +++ b/.github/scripts/acvm_js-test.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -eu + +yarn workspace @noir-lang/acvm_js test diff --git a/.github/scripts/backend-barretenberg-build.sh b/.github/scripts/backend-barretenberg-build.sh new file mode 100755 index 0000000000..d90995397d --- /dev/null +++ b/.github/scripts/backend-barretenberg-build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -eu + +yarn workspace @noir-lang/backend_barretenberg build diff --git a/.github/scripts/backend-barretenberg-test.sh b/.github/scripts/backend-barretenberg-test.sh new file mode 100755 index 0000000000..1bd6f8e410 --- /dev/null +++ b/.github/scripts/backend-barretenberg-test.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -eu + +yarn workspace @noir-lang/backend_barretenberg test diff --git a/.github/scripts/install_wasm-bindgen.sh b/.github/scripts/install_wasm-bindgen.sh new file mode 100755 index 0000000000..b8c41393ab --- /dev/null +++ b/.github/scripts/install_wasm-bindgen.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -eu + +curl -L --proto '=https' --tlsv1.2 -sSf https://raw.githubusercontent.com/cargo-bins/cargo-binstall/main/install-from-binstall-release.sh | bash +cargo-binstall wasm-bindgen-cli --version 0.2.86 -y diff --git a/.github/scripts/integration-test.sh b/.github/scripts/integration-test.sh new file mode 100755 index 0000000000..4e1b52cedf --- /dev/null +++ b/.github/scripts/integration-test.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -eu + +apt-get install libc++-dev -y +npx playwright install && npx playwright install-deps +yarn workspace integration-tests test \ No newline at end of file diff --git a/.github/scripts/nargo-build.sh b/.github/scripts/nargo-build.sh new file mode 100755 index 0000000000..2115732ab7 --- /dev/null +++ b/.github/scripts/nargo-build.sh @@ -0,0 +1,8 @@ +#!/bin/bash +set -eu + +export SOURCE_DATE_EPOCH=$(date +%s) +export GIT_DIRTY=false +export GIT_COMMIT=$(git rev-parse --verify HEAD) + +cargo build --release diff --git a/.github/scripts/nargo-test.sh b/.github/scripts/nargo-test.sh new file mode 100755 index 0000000000..9234df7bf5 --- /dev/null +++ b/.github/scripts/nargo-test.sh @@ -0,0 +1,10 @@ +#!/bin/bash +set -eu + +apt-get install -y curl libc++-dev + +export SOURCE_DATE_EPOCH=$(date +%s) +export GIT_DIRTY=false +export GIT_COMMIT=$(git rev-parse --verify HEAD) + +cargo test --workspace --locked --release \ No newline at end of file diff --git a/.github/scripts/noir-codegen-build.sh b/.github/scripts/noir-codegen-build.sh new file mode 100755 index 0000000000..d42be4d676 --- /dev/null +++ b/.github/scripts/noir-codegen-build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -eu + +yarn workspace @noir-lang/noir_codegen build diff --git a/.github/scripts/noir-codegen-test.sh b/.github/scripts/noir-codegen-test.sh new file mode 100755 index 0000000000..6f603f6550 --- /dev/null +++ b/.github/scripts/noir-codegen-test.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -eu + +yarn workspace @noir-lang/noir_codegen test \ No newline at end of file diff --git a/.github/scripts/noir-js-build.sh b/.github/scripts/noir-js-build.sh new file mode 100755 index 0000000000..04367e4134 --- /dev/null +++ b/.github/scripts/noir-js-build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -eu + +yarn workspace @noir-lang/noir_js build diff --git a/.github/scripts/noir-js-test.sh b/.github/scripts/noir-js-test.sh new file mode 100755 index 0000000000..b5fe34038f --- /dev/null +++ b/.github/scripts/noir-js-test.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -eu + +./scripts/nargo_compile_noir_js_assert_lt.sh +rm -rf /usr/src/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/debug_assert_lt.json +yarn workspace @noir-lang/noir_js test \ No newline at end of file diff --git a/.github/scripts/noir-js-types-build.sh b/.github/scripts/noir-js-types-build.sh new file mode 100755 index 0000000000..77b08651d6 --- /dev/null +++ b/.github/scripts/noir-js-types-build.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -eu + +yarn workspace @noir-lang/types build \ No newline at end of file diff --git a/.github/scripts/noir-wasm-build.sh b/.github/scripts/noir-wasm-build.sh new file mode 100755 index 0000000000..4523751612 --- /dev/null +++ b/.github/scripts/noir-wasm-build.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -eu + +.github/scripts/install_wasm-bindgen.sh +yarn workspace @noir-lang/noir_wasm build \ No newline at end of file diff --git a/.github/scripts/noir-wasm-test-browser.sh b/.github/scripts/noir-wasm-test-browser.sh new file mode 100755 index 0000000000..4b584abce2 --- /dev/null +++ b/.github/scripts/noir-wasm-test-browser.sh @@ -0,0 +1,6 @@ +#!/bin/bash +set -eu + +./scripts/nargo_compile_wasm_fixtures.sh +npx playwright install && npx playwright install-deps +yarn workspace @noir-lang/noir_wasm test:browser \ No newline at end of file diff --git a/.github/scripts/noir-wasm-test.sh b/.github/scripts/noir-wasm-test.sh new file mode 100755 index 0000000000..03e1bac233 --- /dev/null +++ b/.github/scripts/noir-wasm-test.sh @@ -0,0 +1,7 @@ +#!/bin/bash +set -eu + +./scripts/nargo_compile_wasm_fixtures.sh +yarn workspace @noir-lang/noir_wasm test:node +npx playwright install && npx playwright install-deps +yarn workspace @noir-lang/noir_wasm test:browser diff --git a/.github/scripts/noirc-abi-build.sh b/.github/scripts/noirc-abi-build.sh new file mode 100755 index 0000000000..d5da6deaa0 --- /dev/null +++ b/.github/scripts/noirc-abi-build.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -eu + +.github/scripts/install_wasm-bindgen.sh +yarn workspace @noir-lang/noirc_abi build diff --git a/.github/scripts/noirc-abi-test-browser.sh b/.github/scripts/noirc-abi-test-browser.sh new file mode 100755 index 0000000000..7a966cb5e9 --- /dev/null +++ b/.github/scripts/noirc-abi-test-browser.sh @@ -0,0 +1,5 @@ +#!/bin/bash +set -eu + +npx playwright install && npx playwright install-deps +yarn workspace @noir-lang/noirc_abi test:browser diff --git a/.github/scripts/noirc-abi-test.sh b/.github/scripts/noirc-abi-test.sh new file mode 100755 index 0000000000..39ca0a44b0 --- /dev/null +++ b/.github/scripts/noirc-abi-test.sh @@ -0,0 +1,4 @@ +#!/bin/bash +set -eu + +yarn workspace @noir-lang/noirc_abi test diff --git a/.github/workflows/docker-test-flow.yml b/.github/workflows/docker-test-flow.yml new file mode 100644 index 0000000000..0277812f5a --- /dev/null +++ b/.github/workflows/docker-test-flow.yml @@ -0,0 +1,733 @@ +name: Test Nargo and JS packages + +on: + push: + branches: + - 'master' + +concurrency: + group: ${{ github.workflow }}-${{ github.head_ref || github.ref || github.run_id }} + cancel-in-progress: true + +jobs: + build-base-nargo: + name: Build base nargo docker image + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Get current date + id: date + run: echo "date=$(date +'%Y.%m.%d.%H.%M')" >> $GITHUB_STATE + - name: prepare docker images tags + id: prep + run: | + REGISTRY="ghcr.io" + IMG_RAW="${REGISTRY}/${{ github.repository }}" + IMAGE=$(echo "$IMG_RAW" | tr '[:upper:]' '[:lower:]') + TAGS="${IMAGE}:${{ github.sha }}-nargo" + FULL_TAGS="${TAGS},${IMAGE}:latest-nargo,${IMAGE}:v${{ steps.date.outputs.date }}-nargo" + echo "tags=$FULL_TAGS" >> $GITHUB_OUTPUT + echo "image=$IMAGE" >> $GITHUB_OUTPUT + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build nargo base dockerfile + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile.ci + tags: ${{ steps.prep.outputs.tags }} + target: base-nargo + cache-from: type=gha + cache-to: type=gha,mode=max + push: true + + build-base-js: + name: Build base js docker image + runs-on: ubuntu-latest + steps: + - name: Checkout code + uses: actions/checkout@v4 + - name: Get current date + id: date + run: echo "date=$(date +'%Y.%m.%d.%H.%M')" >> $GITHUB_STATE + - name: Prepare docker image tags + id: prep + run: | + REGISTRY="ghcr.io" + IMG_RAW="${REGISTRY}/${{ github.repository }}" + IMAGE=$(echo "$IMG_RAW" | tr '[:upper:]' '[:lower:]') + TAGS="${IMAGE}:${{ github.sha }}-js" + FULL_TAGS="${TAGS},${IMAGE}:latest-js,${IMAGE}:v${{ steps.date.outputs.date }}-js" + echo "tags=$FULL_TAGS" >> $GITHUB_OUTPUT + echo "image=$IMAGE" >> $GITHUB_OUTPUT + - name: Set up Docker Buildx + id: buildx + uses: docker/setup-buildx-action@v3 + - name: Login to GitHub Container Registry + uses: docker/login-action@v3 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + - name: Build js base dockerfile + uses: docker/build-push-action@v5 + with: + context: . + file: Dockerfile.ci + tags: ${{ steps.prep.outputs.tags }} + target: base-js + cache-from: type=gha + cache-to: type=gha,mode=max + push: true + + artifact-nargo: + name: Artifact nargo + runs-on: ubuntu-latest + needs: [build-base-nargo] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-nargo + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Artifact nargo + uses: actions/upload-artifact@v4 + with: + name: nargo + path: /usr/src/noir/target/release/nargo + if-no-files-found: error + compression-level: 0 + + test-nargo: + name: Test nargo + runs-on: ubuntu-latest + needs: [build-base-nargo] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-nargo + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Test + working-directory: /usr/src/noir + run: | + .github/scripts/nargo-test.sh + + build-noir-wasm: + name: Build noir wasm + runs-on: ubuntu-latest + needs: [build-base-js] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Build + working-directory: /usr/src/noir + run: | + ./.github/scripts/noir-wasm-build.sh + - name: Artifact + uses: actions/upload-artifact@v4 + with: + name: noir_wasm + path: /usr/src/noir/compiler/wasm/outputs/out/noir_wasm + retention-days: 10 + + test-noir-wasm: + name: Test noir wasm + runs-on: ubuntu-latest + needs: [build-base-js, artifact-nargo, build-noir-wasm] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download nargo + uses: actions/download-artifact@v4 + with: + name: nargo + path: /usr/src/noir/target/release + - name: Prep downloaded artifact + run: | + chmod +x /usr/src/noir/target/release/nargo + - name: Download noir_wasm artifact + uses: actions/download-artifact@v4 + with: + name: noir_wasm + path: /usr/src/noir/compiler/wasm + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/noir-wasm-test.sh + + test-noir-wasm-browser: + name: Test noir wasm browser + runs-on: ubuntu-latest + needs: [build-base-js, artifact-nargo, build-noir-wasm] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download nargo + uses: actions/download-artifact@v4 + with: + name: nargo + path: /usr/src/noir/target/release + - name: Prep downloaded artifact + run: | + chmod +x /usr/src/noir/target/release/nargo + - name: Download noir_wasm artifact + uses: actions/download-artifact@v4 + with: + name: noir_wasm + path: /usr/src/noir/compiler/wasm + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/noir-wasm-test-browser.sh + + build-acvm_js: + name: Build acvm js + runs-on: ubuntu-latest + needs: [build-base-js] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Build + working-directory: /usr/src/noir + run: | + ./.github/scripts/acvm_js-build.sh + - name: Artifact + uses: actions/upload-artifact@v4 + with: + name: acvm_js + path: + /usr/src/noir/acvm-repo/acvm_js/outputs/out/acvm_js + if-no-files-found: error + compression-level: 0 + + test-acvm_js: + name: Test acvm js + runs-on: ubuntu-latest + needs: [build-base-js, build-acvm_js] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download acvm js + uses: actions/download-artifact@v4 + with: + name: acvm_js + path: | + /usr/src/noir/acvm-repo/acvm_js + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/acvm_js-test.sh + + test-acvm_js-browser: + name: Test acvm js browser + runs-on: ubuntu-latest + needs: [build-base-js, build-acvm_js] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download acvm js + uses: actions/download-artifact@v4 + with: + name: acvm_js + path: | + /usr/src/noir/acvm-repo/acvm_js + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/acvm_js-test-browser.sh + + build-noirc-abi: + name: Build noirc abi + runs-on: ubuntu-latest + needs: [build-base-js] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Build + working-directory: /usr/src/noir + run: | + ./.github/scripts/noirc-abi-build.sh + - name: Artifact + uses: actions/upload-artifact@v4 + with: + name: noirc_abi_wasm + path: + /usr/src/noir/tooling/noirc_abi_wasm/outputs/out/noirc_abi_wasm + if-no-files-found: error + compression-level: 0 + + test-noirc-abi: + name: Test noirc abi + runs-on: ubuntu-latest + needs: [build-base-js, build-noirc-abi] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download noirc abi + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: | + /usr/src/noir/tooling/noirc_abi_wasm + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/noirc-abi-test.sh + + test-noirc-abi-browser: + name: Test noirc abi browser + runs-on: ubuntu-latest + needs: [build-base-js, build-noirc-abi] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download noirc abi + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: | + /usr/src/noir/tooling/noirc_abi_wasm + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/noirc-abi-test-browser.sh + + build-noir-js-types: + name: Build noir js types + runs-on: ubuntu-latest + needs: [build-base-js, build-noirc-abi] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download noirc abi + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: | + /usr/src/noir/tooling/noirc_abi_wasm + - name: Build + working-directory: /usr/src/noir + run: | + ./.github/scripts/noir-js-types-build.sh + - name: Artifact + uses: actions/upload-artifact@v4 + with: + name: noir-js-types + path: | + /usr/src/noir/tooling/noir_js_types/lib + if-no-files-found: error + compression-level: 0 + + build-barretenberg-backend: + name: Build Barretenberg backend + runs-on: ubuntu-latest + needs: [build-base-js, build-noirc-abi, build-noir-js-types] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download noirc abi + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: | + /usr/src/noir/tooling/noirc_abi_wasm + - name: Download noir js types + uses: actions/download-artifact@v4 + with: + name: noir-js-types + path: /usr/src/noir/tooling/noir_js_types/lib/ + - name: Build + working-directory: /usr/src/noir + run: | + ./.github/scripts/backend-barretenberg-build.sh + - name: Artifact + uses: actions/upload-artifact@v4 + with: + name: barretenberg-backend + path: + /usr/src/noir/tooling/noir_js_backend_barretenberg/lib + if-no-files-found: error + compression-level: 0 + + test-barretenberg-backend: + name: Test Barretenberg backend + runs-on: ubuntu-latest + needs: [build-base-js, build-noirc-abi, build-noir-js-types, build-barretenberg-backend] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: | + /usr/src/noir/tooling/noirc_abi_wasm + - name: Download noir js types + uses: actions/download-artifact@v4 + with: + name: noir-js-types + path: /usr/src/noir/tooling/noir_js_types/lib/ + - name: Download Backend barretenberg + uses: actions/download-artifact@v4 + with: + name: barretenberg-backend + path: + /usr/src/noir/tooling/noir_js_backend_barretenberg/lib + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/backend-barretenberg-test.sh + + build-noir_js: + name: Build noirjs + runs-on: ubuntu-latest + needs: [build-base-js, artifact-nargo, build-noirc-abi, build-acvm_js, build-barretenberg-backend, build-noir-js-types] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download nargo + uses: actions/download-artifact@v4 + with: + name: nargo + path: /usr/src/noir/target/release + - name: prep downloaded artifact + run: | + chmod +x /usr/src/noir/target/release/nargo + - name: Download noirc abi + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: | + /usr/src/noir/tooling/noirc_abi_wasm + - name: Download acvm js + uses: actions/download-artifact@v4 + with: + name: acvm_js + path: | + /usr/src/noir/acvm-repo/acvm_js + - name: Download Barretenberg backend + uses: actions/download-artifact@v4 + with: + name: barretenberg-backend + path: + /usr/src/noir/tooling/noir_js_backend_barretenberg/lib + - name: Download noir js types + uses: actions/download-artifact@v4 + with: + name: noir-js-types + path: | + /usr/src/noir/tooling/noir_js_types/lib + - name: Build + working-directory: /usr/src/noir + run: | + ./.github/scripts/noir-js-build.sh + - name: Artifact + uses: actions/upload-artifact@v4 + with: + name: noir_js + path: + /usr/src/noir/tooling/noir_js/lib + + test-noir_js: + name: Test noirjs + runs-on: ubuntu-latest + needs: [ + build-base-js, + build-noirc-abi, + artifact-nargo, + build-acvm_js, + build-barretenberg-backend, + build-noir_js, + build-noir-js-types + ] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download nargo + uses: actions/download-artifact@v4 + with: + name: nargo + path: /usr/src/noir/target/release + - name: Prep downloaded artifact + run: | + chmod +x /usr/src/noir/target/release/nargo + - name: Download noirc abi + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: | + /usr/src/noir/tooling/noirc_abi_wasm + - name: Download acvm js + uses: actions/download-artifact@v4 + with: + name: acvm_js + path: | + /usr/src/noir/acvm-repo/acvm_js + - name: Download Barretenberg backend + uses: actions/download-artifact@v4 + with: + name: barretenberg-backend + path: + /usr/src/noir/tooling/noir_js_backend_barretenberg/lib + - name: Download noir js types + uses: actions/download-artifact@v4 + with: + name: noir-js-types + path: | + /usr/src/noir/tooling/noir_js_types/lib + - name: Download noir js + uses: actions/download-artifact@v4 + with: + name: noir_js + path: + /usr/src/noir/tooling/noir_js/lib + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/noir-js-test.sh + + build-noir_codegen: + name: Build noir codegen + runs-on: ubuntu-latest + needs: [build-base-js, build-noirc-abi, build-acvm_js, build-noir-js-types, build-noir_js] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download nargo + uses: actions/download-artifact@v4 + with: + name: nargo + path: /usr/src/noir/target/release + - name: Prep downloaded artifact + run: | + chmod +x /usr/src/noir/target/release/nargo + - name: Download noirc abi package + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: /usr/src/noir/tooling/noirc_abi_wasm + - name: Download acvm js + uses: actions/download-artifact@v4 + with: + name: acvm_js + path: /usr/src/noir/acvm-repo/acvm_js + - name: Download noir js types + uses: actions/download-artifact@v4 + with: + name: noir-js-types + path: | + /usr/src/noir/tooling/noir_js_types/lib + - name: Download noir js + uses: actions/download-artifact@v4 + with: + name: noir_js + path: + /usr/src/noir/tooling/noir_js/lib + - name: Build + working-directory: /usr/src/noir + run: | + ./.github/scripts/noir-codegen-build.sh + - name: Artifact + uses: actions/upload-artifact@v4 + with: + name: noir_codegen + path: + /usr/src/noir/tooling/noir_codegen/lib + + test-noir_codegen: + name: Test noir codegen + runs-on: ubuntu-latest + needs: [build-base-js, artifact-nargo, build-noirc-abi, build-acvm_js, build-noir-js-types, build-noir_js, build-noir_codegen] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download nargo + uses: actions/download-artifact@v4 + with: + name: nargo + path: /usr/src/noir/target/release + - name: Prep downloaded artifact + run: | + chmod +x /usr/src/noir/target/release/nargo + - name: Download noirc abi + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: /usr/src/noir/tooling/noirc_abi_wasm + - name: Download acvm js + uses: actions/download-artifact@v4 + with: + name: acvm_js + path: /usr/src/noir/acvm-repo/acvm_js + - name: Download noir js types + uses: actions/download-artifact@v4 + with: + name: noir-js-types + path: | + /usr/src/noir/tooling/noir_js_types/lib + - name: Download noir js + uses: actions/download-artifact@v4 + with: + name: noir_js + path: + /usr/src/noir/tooling/noir_js/lib + - name: Download noir codegen + uses: actions/download-artifact@v4 + with: + name: noir_codegen + path: + /usr/src/noir/tooling/noir_codegen/lib + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/noir-codegen-test.sh + + test-integration: + name: Integration test + runs-on: ubuntu-latest + needs: [ + build-base-js, + artifact-nargo, + build-noir-wasm, + build-noirc-abi, + build-acvm_js, + build-noir-js-types, + build-noir_js, + build-barretenberg-backend + ] + container: + image: ghcr.io/noir-lang/noir:${{ github.sha }}-js + credentials: + username: ${{ github.actor }} + password: ${{ secrets.github_token }} + steps: + - name: Download nargo + uses: actions/download-artifact@v4 + with: + name: nargo + path: /usr/src/noir/target/release + - name: Prep downloaded artifact + run: | + chmod +x /usr/src/noir/target/release/nargo + - name: Download noir wasm + uses: actions/download-artifact@v4 + with: + name: noir_wasm + path: /usr/src/noir/compiler/wasm + - name: Download noirc abi + uses: actions/download-artifact@v4 + with: + name: noirc_abi_wasm + path: /usr/src/noir/tooling/noirc_abi_wasm + - name: Download acvm js + uses: actions/download-artifact@v4 + with: + name: acvm_js + path: /usr/src/noir/acvm-repo/acvm_js + - name: Download noir js types + uses: actions/download-artifact@v4 + with: + name: noir-js-types + path: | + /usr/src/noir/tooling/noir_js_types/lib + - name: Download noir js + uses: actions/download-artifact@v4 + with: + name: noir_js + path: + /usr/src/noir/tooling/noir_js/lib + - name: Download Barretenberg backend + uses: actions/download-artifact@v4 + with: + name: barretenberg-backend + path: + /usr/src/noir/tooling/noir_js_backend_barretenberg/lib + - name: Test + working-directory: /usr/src/noir + run: | + ./.github/scripts/integration-test.sh + + tests-end: + name: End + runs-on: ubuntu-latest + if: ${{ always() }} + needs: + - test-nargo + - test-noirc-abi + - test-noirc-abi-browser + - test-noir-wasm + - test-noir-wasm-browser + - test-integration + - test-noir_codegen + - test-acvm_js + - test-acvm_js-browser + - test-barretenberg-backend + - test-noir_js + + steps: + - name: Report overall success + run: | + if [[ $FAIL == true ]]; then + exit 1 + else + exit 0 + fi + env: + FAIL: ${{ contains(needs.*.result, 'failure') || contains(needs.*.result, 'skipped') }} diff --git a/Dockerfile.ci b/Dockerfile.ci index 9ca995fd94..57dcbe9cfe 100644 --- a/Dockerfile.ci +++ b/Dockerfile.ci @@ -1,40 +1,31 @@ -FROM rust:1-slim-bookworm as test-base +FROM rust:1.71.1-slim-bookworm as base RUN apt-get update && apt-get upgrade -y && apt-get install build-essential git -y WORKDIR /usr/src/noir -COPY . . -RUN ./scripts/bootstrap_native.sh -ENV PATH="${PATH}:/usr/src/noir/target/release/" +ENV PATH="${PATH}:/usr/src/noir/target/release" -FROM test-base as test-cargo -RUN apt-get install -y curl libc++-dev -RUN ./scripts/test_native.sh +FROM base as base-nargo +COPY . . +RUN .github/scripts/nargo-build.sh -FROM test-base as test-js -RUN apt-get install pkg-config libssl-dev -y -RUN ./scripts/install_wasm-bindgen.sh +FROM base as base-js RUN apt-get install -y ca-certificates curl gnupg RUN mkdir -p /etc/apt/keyrings RUN curl -fsSL https://deb.nodesource.com/gpgkey/nodesource-repo.gpg.key | gpg --dearmor -o /etc/apt/keyrings/nodesource.gpg RUN echo "deb [signed-by=/etc/apt/keyrings/nodesource.gpg] https://deb.nodesource.com/node_20.x nodistro main" | tee /etc/apt/sources.list.d/nodesource.list RUN apt-get update && apt-get install nodejs -y RUN corepack enable -RUN yarn --immutable RUN apt-get install -y jq -RUN yarn build -RUN yarn workspace @noir-lang/acvm_js test -RUN npx playwright install && npx playwright install-deps -RUN yarn workspace @noir-lang/acvm_js test:browser -RUN yarn workspace @noir-lang/noirc_abi test -RUN yarn workspace @noir-lang/noirc_abi test:browser -RUN yarn workspace @noir-lang/backend_barretenberg test -RUN ./scripts/nargo_compile_noir_js_assert_lt.sh -RUN rm -rf /usr/src/noir/tooling/noir_js/test/noir_compiled_examples/assert_lt/target/debug_assert_lt.json -RUN yarn workspace @noir-lang/noir_js test -RUN ./scripts/nargo_compile_wasm_fixtures.sh -RUN yarn workspace @noir-lang/noir_wasm test:node -RUN yarn workspace @noir-lang/noir_wasm test:browser -RUN ./scripts/nargo_compile_noir_codegen_assert_lt.sh -RUN rm -rf /usr/src/noir/tooling/noir_codegen/test/assert_lt/target/debug_assert_lt.json -RUN yarn workspace @noir-lang/noir_codegen test -RUN apt-get install -y libc++-dev -RUN yarn test:integration +COPY yarn.lock package.json .yarnrc.yml ./ +COPY .yarn/ ./.yarn/ +COPY ./acvm-repo/acvm_js/package.json ./acvm-repo/acvm_js/ +COPY ./tooling/noirc_abi_wasm/package.json ./tooling/noirc_abi_wasm/ +COPY ./compiler/wasm/package.json ./compiler/wasm/ +COPY ./tooling/noir_js_types/package.json ./tooling/noir_js_types/ +COPY ./tooling/noir_js_backend_barretenberg/package.json ./tooling/noir_js_backend_barretenberg/ +COPY ./tooling/noir_js/package.json ./tooling/noir_js/ +COPY ./tooling/noir_codegen/package.json ./tooling/noir_codegen/ +COPY ./compiler/integration-tests/package.json ./compiler/integration-tests/ +COPY ./release-tests/package.json ./release-tests/ +COPY ./docs/package.json ./docs/ +RUN yarn --immutable +COPY . . diff --git a/scripts/nargo_compile_noir_codegen_assert_lt.sh b/scripts/nargo_compile_noir_codegen_assert_lt.sh deleted file mode 100755 index 858a16cf51..0000000000 --- a/scripts/nargo_compile_noir_codegen_assert_lt.sh +++ /dev/null @@ -1,4 +0,0 @@ -#!/bin/bash - -cd ./tooling/noir_codegen/test/assert_lt -nargo compile \ No newline at end of file From e37798cb333226173a2bf1b16249337bbfff3589 Mon Sep 17 00:00:00 2001 From: Gregorio Juliana Date: Thu, 11 Jan 2024 10:48:12 +0100 Subject: [PATCH 5/6] chore: force public functions for trait implementation (#3986) Resolves https://github.com/noir-lang/noir/issues/3948 Functions implemented in Traits weren't being treated as public, which resulted in `...is private and not visible from the current module` warnings This PR simply forces the creation of public functions in the AST at the parser level. --------- Co-authored-by: jfecher Co-authored-by: Tom French --- compiler/noirc_frontend/src/parser/errors.rs | 7 +++++++ compiler/noirc_frontend/src/parser/parser.rs | 13 ++++++++++++- 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/compiler/noirc_frontend/src/parser/errors.rs b/compiler/noirc_frontend/src/parser/errors.rs index 09dc6dfff8..5c869ff471 100644 --- a/compiler/noirc_frontend/src/parser/errors.rs +++ b/compiler/noirc_frontend/src/parser/errors.rs @@ -26,6 +26,8 @@ pub enum ParserErrorReason { EarlyReturn, #[error("Patterns aren't allowed in a trait's function declarations")] PatternInTraitFunctionParameter, + #[error("Modifiers are ignored on a trait impl method")] + TraitImplFunctionModifiers, #[error("comptime keyword is deprecated")] ComptimeDeprecated, #[error("{0} are experimental and aren't fully supported yet")] @@ -148,6 +150,11 @@ impl From for Diagnostic { "".into(), error.span, ), + ParserErrorReason::TraitImplFunctionModifiers => Diagnostic::simple_warning( + reason.to_string(), + "".into(), + error.span, + ), ParserErrorReason::ExpectedPatternButFoundType(ty) => { Diagnostic::simple_error("Expected a ; separating these two statements".into(), format!("{ty} is a type and cannot be used as a variable name"), error.span) } diff --git a/compiler/noirc_frontend/src/parser/parser.rs b/compiler/noirc_frontend/src/parser/parser.rs index b149eb24f0..954b531abf 100644 --- a/compiler/noirc_frontend/src/parser/parser.rs +++ b/compiler/noirc_frontend/src/parser/parser.rs @@ -613,7 +613,18 @@ fn trait_implementation() -> impl NoirParser { } fn trait_implementation_body() -> impl NoirParser> { - let function = function_definition(true).map(TraitImplItem::Function); + let function = function_definition(true).validate(|mut f, span, emit| { + if f.def().is_internal + || f.def().is_unconstrained + || f.def().is_open + || f.def().visibility != FunctionVisibility::Private + { + emit(ParserError::with_reason(ParserErrorReason::TraitImplFunctionModifiers, span)); + } + // Trait impl functions are always public + f.def_mut().visibility = FunctionVisibility::Public; + TraitImplItem::Function(f) + }); let alias = keyword(Keyword::Type) .ignore_then(ident()) From 3decf8d2f35b1ec8531f24119b3526b80395e284 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Thu, 11 Jan 2024 05:16:43 -0500 Subject: [PATCH 6/6] chore: quiet down aztec-bot! (#4006) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Development from Aztec. --------- Co-authored-by: ludamad Co-authored-by: ludamad Co-authored-by: kevaundray Co-authored-by: sirasistant Co-authored-by: Gregorio Juliana Co-authored-by: Tom French Co-authored-by: Maxim Vezenov Co-authored-by: Jan Beneš Co-authored-by: Charlie Lye Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com>