From 47012e3f861be81d4f0ff1cf1a506b4dc52f4f17 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 28 Aug 2024 19:43:32 +0100 Subject: [PATCH 01/15] feat!: return arrays instead of slices from `to_be_radix` functions --- .../src/brillig/brillig_gen/brillig_block.rs | 77 ++++--------------- .../brillig/brillig_ir/codegen_intrinsic.rs | 28 +++---- .../src/brillig/brillig_ir/codegen_memory.rs | 16 ++-- .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 25 ++---- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 36 +++++++-- .../src/ssa/ir/instruction/call.rs | 39 ++++++---- .../ssa/opt/flatten_cfg/capacity_tracker.rs | 1 - .../src/ssa/opt/remove_bit_shifts.rs | 8 +- .../src/ssa/opt/remove_if_else.rs | 16 +--- noir_stdlib/src/ec/mod.nr | 9 +-- noir_stdlib/src/ec/swcurve.nr | 4 +- noir_stdlib/src/ec/tecurve.nr | 4 +- noir_stdlib/src/field/bn254.nr | 6 +- noir_stdlib/src/field/mod.nr | 60 ++++++--------- noir_stdlib/src/hash/keccak.nr | 2 +- noir_stdlib/src/hash/mod.nr | 2 +- noir_stdlib/src/hash/sha256.nr | 6 +- noir_stdlib/src/hash/sha512.nr | 4 +- noir_stdlib/src/merkle.nr | 5 +- noir_stdlib/src/uint128.nr | 20 ++--- temp/Nargo.toml | 7 ++ temp/src/main.nr | 4 + .../compile_success_empty/to_bits/src/main.nr | 8 +- .../execution_success/to_be_bytes/src/main.nr | 2 +- 24 files changed, 167 insertions(+), 222 deletions(-) create mode 100644 temp/Nargo.toml create mode 100644 temp/src/main.nr 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 a9801c8904e..a02667ab022 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -492,6 +492,8 @@ impl<'block> BrilligBlock<'block> { ); } Value::Intrinsic(Intrinsic::ToRadix(endianness)) => { + let results = dfg.instruction_results(instruction_id); + let source = self.convert_ssa_single_addr_value(arguments[0], dfg); let radix: u32 = dfg @@ -502,88 +504,43 @@ impl<'block> BrilligBlock<'block> { .try_into() .expect("Radix should be u32"); - let limb_count: usize = dfg - .get_numeric_constant(arguments[2]) - .expect("Limb count should be known") - .try_to_u64() - .expect("Limb count should fit in u64") - .try_into() - .expect("Limb count should fit in usize"); - - let results = dfg.instruction_results(instruction_id); - - let target_len = self.variables.define_single_addr_variable( - self.function_context, - self.brillig_context, - results[0], - dfg, - ); - - let target_vector = self + let target_array = self .variables .define_variable( self.function_context, self.brillig_context, - results[1], + results[0], dfg, ) - .extract_vector(); - - // Update the user-facing slice length - self.brillig_context - .usize_const_instruction(target_len.address, limb_count.into()); + .extract_array(); self.brillig_context.codegen_to_radix( source, - target_vector, + target_array, radix, - limb_count, matches!(endianness, Endian::Big), 8, ); } Value::Intrinsic(Intrinsic::ToBits(endianness)) => { - let source = self.convert_ssa_single_addr_value(arguments[0], dfg); - let limb_count: usize = dfg - .get_numeric_constant(arguments[1]) - .expect("Limb count should be known") - .try_to_u64() - .expect("Limb count should fit in u64") - .try_into() - .expect("Limb count should fit in usize"); - let results = dfg.instruction_results(instruction_id); - let target_len_variable = self.variables.define_variable( - self.function_context, - self.brillig_context, - results[0], - dfg, - ); - let target_len = target_len_variable.extract_single_addr(); - - let target_vector = match self.variables.define_variable( - self.function_context, - self.brillig_context, - results[1], - dfg, - ) { - BrilligVariable::BrilligArray(array) => { - self.brillig_context.array_to_vector_instruction(&array) - } - BrilligVariable::BrilligVector(vector) => vector, - BrilligVariable::SingleAddr(..) => unreachable!("ICE: ToBits on non-array"), - }; + let source = self.convert_ssa_single_addr_value(arguments[0], dfg); - // Update the user-facing slice length - self.brillig_context - .usize_const_instruction(target_len.address, limb_count.into()); + let target_array = self + .variables + .define_variable( + self.function_context, + self.brillig_context, + results[0], + dfg, + ) + .extract_array(); self.brillig_context.codegen_to_radix( source, - target_vector, + target_array, 2, - limb_count, matches!(endianness, Endian::Big), 1, ); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs index d07b411f5a1..8066b1d77cb 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs @@ -1,12 +1,12 @@ use acvm::acir::{ - brillig::{BlackBoxOp, HeapArray, IntegerBitSize}, + brillig::{BlackBoxOp, IntegerBitSize}, AcirField, }; use crate::brillig::brillig_ir::BrilligBinaryOp; use super::{ - brillig_variable::{BrilligVector, SingleAddrVariable}, + brillig_variable::{BrilligArray, SingleAddrVariable}, debug_show::DebugToString, BrilligContext, }; @@ -66,40 +66,34 @@ impl BrilligContext { pub(crate) fn codegen_to_radix( &mut self, source_field: SingleAddrVariable, - target_vector: BrilligVector, + target_array: BrilligArray, radix: u32, - limb_count: usize, big_endian: bool, limb_bit_size: u32, ) { assert!(source_field.bit_size == F::max_num_bits()); - self.usize_const_instruction(target_vector.size, limb_count.into()); - self.usize_const_instruction(target_vector.rc, 1_usize.into()); - self.codegen_allocate_array(target_vector.pointer, target_vector.size); - self.black_box_op_instruction(BlackBoxOp::ToRadix { input: source_field.address, radix, - output: HeapArray { pointer: target_vector.pointer, size: limb_count }, + output: target_array.to_heap_array(), }); let limb_field = SingleAddrVariable::new(self.allocate_register(), F::max_num_bits()); let limb_casted = SingleAddrVariable::new(self.allocate_register(), limb_bit_size); if limb_bit_size != F::max_num_bits() { - self.codegen_loop(target_vector.size, |ctx, iterator_register| { + let size = self.allocate_register(); + self.usize_const_instruction(size, target_array.size.into()); + self.codegen_loop(size, |ctx, iterator_register| { // Read the limb - ctx.codegen_array_get(target_vector.pointer, iterator_register, limb_field.address); + ctx.codegen_array_get(target_array.pointer, iterator_register, limb_field.address); // Cast it ctx.cast_instruction(limb_casted, limb_field); // Write it - ctx.codegen_array_set( - target_vector.pointer, - iterator_register, - limb_casted.address, - ); + ctx.codegen_array_set(target_array.pointer, iterator_register, limb_casted.address); }); + self.deallocate_register(size); } // Deallocate our temporary registers @@ -107,7 +101,7 @@ impl BrilligContext { self.deallocate_single_addr(limb_casted); if big_endian { - self.codegen_reverse_vector_in_place(target_vector); + self.codegen_reverse_array_in_place(target_array); } } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs index d20f736ee6d..dc72db247d5 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs @@ -254,10 +254,10 @@ impl BrilligContext { } } - /// This instruction will reverse the order of the elements in a vector. - pub(crate) fn codegen_reverse_vector_in_place(&mut self, vector: BrilligVector) { + /// This instruction will reverse the order of the elements in a array. + pub(crate) fn codegen_reverse_array_in_place(&mut self, array: BrilligArray) { let iteration_count = self.allocate_register(); - self.codegen_usize_op(vector.size, iteration_count, BrilligBinaryOp::UnsignedDiv, 2); + self.usize_const_instruction(iteration_count, array.size.into()); let start_value_register = self.allocate_register(); let index_at_end_of_array = self.allocate_register(); @@ -265,10 +265,10 @@ impl BrilligContext { self.codegen_loop(iteration_count, |ctx, iterator_register| { // Load both values - ctx.codegen_array_get(vector.pointer, iterator_register, start_value_register); + ctx.codegen_array_get(array.pointer, iterator_register, start_value_register); // The index at the end of array is size - 1 - iterator - ctx.mov_instruction(index_at_end_of_array, vector.size); + ctx.usize_const_instruction(index_at_end_of_array, array.size.into()); ctx.codegen_usize_op_in_place(index_at_end_of_array, BrilligBinaryOp::Sub, 1); ctx.memory_op_instruction( index_at_end_of_array, @@ -278,15 +278,15 @@ impl BrilligContext { ); ctx.codegen_array_get( - vector.pointer, + array.pointer, SingleAddrVariable::new_usize(index_at_end_of_array), end_value_register, ); // Write both values - ctx.codegen_array_set(vector.pointer, iterator_register, end_value_register); + ctx.codegen_array_set(array.pointer, iterator_register, end_value_register); ctx.codegen_array_set( - vector.pointer, + array.pointer, SingleAddrVariable::new_usize(index_at_end_of_array), start_value_register, ); diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 6d17484ee95..efd6983df14 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -1504,9 +1504,9 @@ impl AcirContext { endian: Endian, input_var: AcirVar, radix_var: AcirVar, - limb_count_var: AcirVar, + limb_count: u32, result_element_type: AcirType, - ) -> Result, RuntimeError> { + ) -> Result { let radix = match self.vars[&radix_var].as_constant() { Some(radix) => radix.to_u128() as u32, None => { @@ -1517,16 +1517,6 @@ impl AcirContext { } }; - let limb_count = match self.vars[&limb_count_var].as_constant() { - Some(limb_count) => limb_count.to_u128() as u32, - None => { - return Err(RuntimeError::InternalError(InternalError::NotAConstant { - name: "limb_size".to_string(), - call_stack: self.get_call_stack(), - })); - } - }; - let input_expr = self.var_to_expression(input_var)?; let bit_size = u32::BITS - (radix - 1).leading_zeros(); @@ -1543,10 +1533,7 @@ impl AcirContext { // `Intrinsic::ToRadix` returns slices which are represented // by tuples with the structure (length, slice contents) - Ok(vec![ - AcirValue::Var(self.add_constant(limb_vars.len()), AcirType::field()), - AcirValue::Array(limb_vars.into()), - ]) + Ok(AcirValue::Array(limb_vars.into())) } /// Returns `AcirVar`s constrained to be the bit decomposition of the provided input @@ -1554,11 +1541,11 @@ impl AcirContext { &mut self, endian: Endian, input_var: AcirVar, - limb_count_var: AcirVar, + limb_count: u32, result_element_type: AcirType, - ) -> Result, RuntimeError> { + ) -> Result { let two_var = self.add_constant(2_u128); - self.radix_decompose(endian, input_var, two_var, limb_count_var, result_element_type) + self.radix_decompose(endian, input_var, two_var, limb_count, result_element_type) } /// Recursive helper to flatten a single AcirValue into the result vector. diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 0a81990ab10..bbf379ee0e5 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -1073,6 +1073,7 @@ impl<'a> Context<'a> { match self.convert_value(array_id, dfg) { AcirValue::Var(acir_var, _) => { + println!("{array}[{index}]"); Err(RuntimeError::InternalError(InternalError::Unexpected { expected: "an array value".to_string(), found: format!("{acir_var:?}"), @@ -2177,19 +2178,42 @@ impl<'a> Context<'a> { Intrinsic::ToRadix(endian) => { let field = self.convert_value(arguments[0], dfg).into_var()?; let radix = self.convert_value(arguments[1], dfg).into_var()?; - let limb_size = self.convert_value(arguments[2], dfg).into_var()?; - let result_type = Self::array_element_type(dfg, result_ids[1]); + let Type::Array(result_type, array_length) = dfg.type_of_value(result_ids[0]) + else { + unreachable!("ICE: ToRadix result must be an array"); + }; - self.acir_context.radix_decompose(endian, field, radix, limb_size, result_type) + self.acir_context + .radix_decompose( + endian, + field, + radix, + array_length as u32, + result_type[0].clone().into(), + ) + .map(|array| vec![array]) } Intrinsic::ToBits(endian) => { let field = self.convert_value(arguments[0], dfg).into_var()?; - let bit_size = self.convert_value(arguments[1], dfg).into_var()?; - let result_type = Self::array_element_type(dfg, result_ids[1]); + let Type::Array(result_type, array_length) = dfg.type_of_value(result_ids[0]) + else { + println!("{:?}", result_ids); + println!("{:?}", dfg.type_of_value(result_ids[0])); + println!("{:?}", dfg.type_of_value(result_ids[1])); - self.acir_context.bit_decompose(endian, field, bit_size, result_type) + unreachable!("ICE: ToRadix result must be an array"); + }; + + self.acir_context + .bit_decompose( + endian, + field, + array_length as u32, + result_type[0].clone().into(), + ) + .map(|array| vec![array]) } Intrinsic::ArrayLen => { let len = match self.convert_value(arguments[0], dfg) { diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index de7ab6e532d..926046ed10b 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -50,32 +50,37 @@ pub(super) fn simplify_call( match intrinsic { Intrinsic::ToBits(endian) => { - if let Some(constant_args) = constant_args { + if let (Some(constant_args), Some(return_type)) = + (constant_args, ctrl_typevars.map(|return_types| return_types.first().cloned())) + { let field = constant_args[0]; - let limb_count = constant_args[1].to_u128() as u32; - - let (len_value, result_slice) = - constant_to_radix(endian, field, 2, limb_count, dfg); + let limb_count = if let Some(Type::Array(_, array_len)) = return_type { + array_len as u32 + } else { + unreachable!("ICE: Intrinsic::ToRadix return type must be array") + }; + let result_array = constant_to_radix(endian, field, 2, limb_count, dfg); - // `Intrinsic::ToBits` returns slices which are represented - // by tuples with the structure (length, slice contents) - SimplifyResult::SimplifiedToMultiple(vec![len_value, result_slice]) + SimplifyResult::SimplifiedTo(result_array) } else { SimplifyResult::None } } Intrinsic::ToRadix(endian) => { - if let Some(constant_args) = constant_args { + if let (Some(constant_args), Some(return_type)) = + (constant_args, ctrl_typevars.map(|return_types| return_types.first().cloned())) + { let field = constant_args[0]; let radix = constant_args[1].to_u128() as u32; - let limb_count = constant_args[2].to_u128() as u32; + let limb_count = if let Some(Type::Array(_, array_len)) = return_type { + array_len as u32 + } else { + unreachable!("ICE: Intrinsic::ToRadix return type must be array") + }; - let (len_value, result_slice) = - constant_to_radix(endian, field, radix, limb_count, dfg); + let result_array = constant_to_radix(endian, field, radix, limb_count, dfg); - // `Intrinsic::ToRadix` returns slices which are represented - // by tuples with the structure (length, slice contents) - SimplifyResult::SimplifiedToMultiple(vec![len_value, result_slice]) + SimplifyResult::SimplifiedTo(result_array) } else { SimplifyResult::None } @@ -584,7 +589,7 @@ fn constant_to_radix( radix: u32, limb_count: u32, dfg: &mut DataFlowGraph, -) -> (ValueId, ValueId) { +) -> ValueId { let bit_size = u32::BITS - (radix - 1).leading_zeros(); let radix_big = BigUint::from(radix); assert_eq!(BigUint::from(2u128).pow(bit_size), radix_big, "ICE: Radix must be a power of 2"); @@ -599,7 +604,7 @@ fn constant_to_radix( if endian == Endian::Big { limbs.reverse(); } - make_constant_slice(dfg, limbs, Type::unsigned(bit_size)) + make_constant_array(dfg, limbs, Type::unsigned(bit_size)) } fn to_u8_vec(dfg: &DataFlowGraph, values: im::Vector>) -> Vec { diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs index f0760f29006..9c8d7fb1ad7 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs @@ -72,7 +72,6 @@ impl<'a> SliceCapacityTracker<'a> { // where v7 is the slice length and v8 is the popped slice itself. Intrinsic::SlicePopFront => (Some(1), results.len() - 1), // The slice capacity of these intrinsics is not determined by the arguments of the function. - Intrinsic::ToBits(_) | Intrinsic::ToRadix(_) => (None, 1), Intrinsic::AsSlice => (Some(0), 1), _ => return, }; diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs index 628e1bd7410..0840113e69c 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs @@ -172,12 +172,10 @@ impl Context<'_> { let typ = self.function.dfg.type_of_value(rhs); if let Type::Numeric(NumericType::Unsigned { bit_size }) = typ { let to_bits = self.function.dfg.import_intrinsic(Intrinsic::ToBits(Endian::Little)); - let length = self.field_constant(FieldElement::from(bit_size as i128)); - let result_types = - vec![Type::field(), Type::Array(Rc::new(vec![Type::bool()]), bit_size as usize)]; - let rhs_bits = self.insert_call(to_bits, vec![rhs, length], result_types); + let result_types = vec![Type::Array(Rc::new(vec![Type::bool()]), bit_size as usize)]; + let rhs_bits = self.insert_call(to_bits, vec![rhs], result_types); - let rhs_bits = rhs_bits[1]; + let rhs_bits = rhs_bits[0]; let one = self.field_constant(FieldElement::one()); let mut r = one; for i in 1..bit_size + 1 { diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs index cc02faeb3df..8d6225afabf 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs @@ -203,18 +203,6 @@ fn slice_capacity_change( SizeChange::Dec { old, new } } - Intrinsic::ToBits(_) => { - assert_eq!(results.len(), 2); - // Some tests fail this check, returning an array instead somehow: - // assert!(matches!(dfg.type_of_value(results[1]), Type::Slice(_))); - SizeChange::SetTo(results[1], FieldElement::max_num_bits() as usize) - } - // ToRadix seems to assume it is to bytes - Intrinsic::ToRadix(_) => { - assert_eq!(results.len(), 2); - assert!(matches!(dfg.type_of_value(results[1]), Type::Slice(_))); - SizeChange::SetTo(results[1], FieldElement::max_num_bytes() as usize) - } Intrinsic::AsSlice => { assert_eq!(arguments.len(), 1); assert_eq!(results.len(), 2); @@ -238,6 +226,8 @@ fn slice_capacity_change( | Intrinsic::AsField | Intrinsic::AsWitness | Intrinsic::IsUnconstrained - | Intrinsic::DerivePedersenGenerators => SizeChange::None, + | Intrinsic::DerivePedersenGenerators + | Intrinsic::ToBits(_) + | Intrinsic::ToRadix(_) => SizeChange::None, } } diff --git a/noir_stdlib/src/ec/mod.nr b/noir_stdlib/src/ec/mod.nr index 86fb201408f..093852acc79 100644 --- a/noir_stdlib/src/ec/mod.nr +++ b/noir_stdlib/src/ec/mod.nr @@ -155,15 +155,12 @@ pub fn is_square(x: Field) -> bool { // Power function of two Field arguments of arbitrary size. // Adapted from std::field::pow_32. pub fn pow(x: Field, y: Field) -> Field { - // As in tests with minor modifications - let N_BITS = crate::field::modulus_num_bits(); - let mut r = 1 as Field; - let b = y.to_le_bits(N_BITS as u32); + let b: [u1; 254] = y.to_le_bits(); - for i in 0..N_BITS { + for i in 0..254 { r *= r; - r *= (b[N_BITS - 1 - i] as Field)*x + (1-b[N_BITS - 1 - i] as Field); + r *= (b[254 - 1 - i] as Field)*x + (1-b[254 - 1 - i] as Field); } r diff --git a/noir_stdlib/src/ec/swcurve.nr b/noir_stdlib/src/ec/swcurve.nr index 3ad3af41cff..4139492af63 100644 --- a/noir_stdlib/src/ec/swcurve.nr +++ b/noir_stdlib/src/ec/swcurve.nr @@ -350,11 +350,9 @@ mod curvegroup { // Scalar multiplication (p + ... + p n times) pub fn mul(self, n: Field, p: Point) -> Point { - let N_BITS = crate::field::modulus_num_bits(); - // TODO: temporary workaround until issue 1354 is solved let mut n_as_bits: [u1; 254] = [0; 254]; - let tmp = n.to_le_bits(N_BITS as u32); + let tmp: [u1; 254] = n.to_le_bits(); for i in 0..254 { n_as_bits[i] = tmp[i]; } diff --git a/noir_stdlib/src/ec/tecurve.nr b/noir_stdlib/src/ec/tecurve.nr index aaf66f903cc..2ba3fd4401c 100644 --- a/noir_stdlib/src/ec/tecurve.nr +++ b/noir_stdlib/src/ec/tecurve.nr @@ -354,11 +354,9 @@ mod curvegroup { // Scalar multiplication (p + ... + p n times) pub fn mul(self, n: Field, p: Point) -> Point { - let N_BITS = crate::field::modulus_num_bits(); - // TODO: temporary workaround until issue 1354 is solved let mut n_as_bits: [u1; 254] = [0; 254]; - let tmp = n.to_le_bits(N_BITS as u32); + let tmp: [u1; 254] = n.to_le_bits(); for i in 0..254 { n_as_bits[i] = tmp[i]; } diff --git a/noir_stdlib/src/field/bn254.nr b/noir_stdlib/src/field/bn254.nr index ed0053694c7..d7b9cf8fb80 100644 --- a/noir_stdlib/src/field/bn254.nr +++ b/noir_stdlib/src/field/bn254.nr @@ -8,7 +8,7 @@ global TWO_POW_128: Field = 0x100000000000000000000000000000000; // Decomposes a single field into two 16 byte fields. fn compute_decomposition(x: Field) -> (Field, Field) { - let x_bytes = x.to_le_bytes(32); + let x_bytes: [u8; 32] = x.to_le_bytes(); let mut low: Field = 0; let mut high: Field = 0; @@ -28,8 +28,8 @@ unconstrained pub(crate) fn decompose_hint(x: Field) -> (Field, Field) { } fn compute_lt(x: Field, y: Field, num_bytes: u32) -> bool { - let x_bytes = x.to_le_radix(256, num_bytes); - let y_bytes = y.to_le_radix(256, num_bytes); + let x_bytes: [u8; 254] = x.to_le_bytes(); + let y_bytes: [u8; 254] = y.to_le_bytes(); let mut x_is_lt = false; let mut done = false; for i in 0..num_bytes { diff --git a/noir_stdlib/src/field/mod.nr b/noir_stdlib/src/field/mod.nr index 534ac012beb..df84c6b544c 100644 --- a/noir_stdlib/src/field/mod.nr +++ b/noir_stdlib/src/field/mod.nr @@ -15,45 +15,33 @@ impl Field { #[builtin(apply_range_constraint)] fn __assert_max_bit_size(self, bit_size: u32) {} - /// Decomposes `self` into its little endian bit decomposition as a `[u1]` slice of length `bit_size`. + /// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array. /// This slice will be zero padded should not all bits be necessary to represent `self`. /// /// # Failures - /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}` as the resulting slice will not + /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not /// be able to represent the original `Field`. /// /// # Safety - /// Values of `bit_size` equal to or greater than the number of bits necessary to represent the `Field` modulus + /// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus /// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will /// wrap around due to overflow when verifying the decomposition. - pub fn to_le_bits(self: Self, bit_size: u32) -> [u1] { - crate::assert_constant(bit_size); - self.__to_le_bits(bit_size) - } + #[builtin(to_le_bits)] + pub fn to_le_bits(self: Self) -> [u1; N] {} - /// Decomposes `self` into its big endian bit decomposition as a `[u1]` slice of length `bit_size`. - /// This slice will be zero padded should not all bits be necessary to represent `self`. + /// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array. + /// This array will be zero padded should not all bits be necessary to represent `self`. /// /// # Failures - /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}` as the resulting slice will not + /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not /// be able to represent the original `Field`. /// /// # Safety - /// Values of `bit_size` equal to or greater than the number of bits necessary to represent the `Field` modulus + /// Values of `N` equal to or greater than the number of bits necessary to represent the `Field` modulus /// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will /// wrap around due to overflow when verifying the decomposition. - pub fn to_be_bits(self: Self, bit_size: u32) -> [u1] { - crate::assert_constant(bit_size); - self.__to_be_bits(bit_size) - } - - /// See `Field.to_be_bits` - #[builtin(to_le_bits)] - fn __to_le_bits(self, _bit_size: u32) -> [u1] {} - - /// See `Field.to_le_bits` #[builtin(to_be_bits)] - fn __to_be_bits(self, bit_size: u32) -> [u1] {} + pub fn to_be_bits(self: Self) -> [u1; N] {} /// Decomposes `self` into its little endian byte decomposition as a `[u8]` slice of length `byte_size`. /// This slice will be zero padded should not all bytes be necessary to represent `self`. @@ -66,8 +54,8 @@ impl Field { /// Values of `byte_size` equal to or greater than the number of bytes necessary to represent the `Field` modulus /// (e.g. 32 for the BN254 field) allow for multiple byte decompositions. This is due to how the `Field` will /// wrap around due to overflow when verifying the decomposition. - pub fn to_le_bytes(self: Self, byte_size: u32) -> [u8] { - self.to_le_radix(256, byte_size) + pub fn to_le_bytes(self: Self) -> [u8; N] { + self.to_le_radix(256) } /// Decomposes `self` into its big endian byte decomposition as a `[u8]` slice of length `byte_size`. @@ -81,35 +69,33 @@ impl Field { /// Values of `byte_size` equal to or greater than the number of bytes necessary to represent the `Field` modulus /// (e.g. 32 for the BN254 field) allow for multiple byte decompositions. This is due to how the `Field` will /// wrap around due to overflow when verifying the decomposition. - pub fn to_be_bytes(self: Self, byte_size: u32) -> [u8] { - self.to_be_radix(256, byte_size) + pub fn to_be_bytes(self: Self) -> [u8; N] { + self.to_be_radix(256) } - pub fn to_le_radix(self: Self, radix: u32, result_len: u32) -> [u8] { + pub fn to_le_radix(self: Self, radix: u32) -> [u8; N] { crate::assert_constant(radix); - crate::assert_constant(result_len); - self.__to_le_radix(radix, result_len) + self.__to_le_radix(radix) } - pub fn to_be_radix(self: Self, radix: u32, result_len: u32) -> [u8] { + pub fn to_be_radix(self: Self, radix: u32) -> [u8; N] { crate::assert_constant(radix); - crate::assert_constant(result_len); - self.__to_be_radix(radix, result_len) + self.__to_be_radix(radix) } // `_radix` must be less than 256 #[builtin(to_le_radix)] - fn __to_le_radix(self, radix: u32, result_len: u32) -> [u8] {} + fn __to_le_radix(self, radix: u32) -> [u8; N] {} #[builtin(to_be_radix)] - fn __to_be_radix(self, radix: u32, result_len: u32) -> [u8] {} + fn __to_be_radix(self, radix: u32) -> [u8; N] {} // Returns self to the power of the given exponent value. // Caution: we assume the exponent fits into 32 bits // using a bigger bit size impacts negatively the performance and should be done only if the exponent does not fit in 32 bits pub fn pow_32(self, exponent: Field) -> Field { let mut r: Field = 1; - let b = exponent.to_le_bits(32); + let b: [u1; 32] = exponent.to_le_bits(); for i in 1..33 { r *= r; @@ -165,8 +151,8 @@ pub fn bytes32_to_field(bytes32: [u8; 32]) -> Field { fn lt_fallback(x: Field, y: Field) -> bool { let num_bytes = (modulus_num_bits() as u32 + 7) / 8; - let x_bytes = x.to_le_bytes(num_bytes); - let y_bytes = y.to_le_bytes(num_bytes); + let x_bytes = x.to_le_bytes(); + let y_bytes = y.to_le_bytes(); let mut x_is_lt = false; let mut done = false; for i in 0..num_bytes { diff --git a/noir_stdlib/src/hash/keccak.nr b/noir_stdlib/src/hash/keccak.nr index 0c31d238f66..36787c7b4af 100644 --- a/noir_stdlib/src/hash/keccak.nr +++ b/noir_stdlib/src/hash/keccak.nr @@ -115,7 +115,7 @@ pub(crate) fn keccak256(input: [u8; N], message_size: u32) -> [u8; 3 let mut result = [0; 32]; for i in 0..4 { let lane = state[i] as Field; - let lane_le = lane.to_le_bytes(8); + let lane_le: [u8; 8] = lane.to_le_bytes(); for j in 0..8 { result[8*i+j] = lane_le[j]; } diff --git a/noir_stdlib/src/hash/mod.nr b/noir_stdlib/src/hash/mod.nr index 657e1cd8309..33be56cdc3d 100644 --- a/noir_stdlib/src/hash/mod.nr +++ b/noir_stdlib/src/hash/mod.nr @@ -118,7 +118,7 @@ pub fn hash_to_field(inputs: [Field]) -> Field { let mut sum = 0; for input in inputs { - let input_bytes: [u8; 32] = input.to_le_bytes(32).as_array(); + let input_bytes: [u8; 32] = input.to_le_bytes(); sum += crate::field::bytes32_to_field(blake2s(input_bytes)); } diff --git a/noir_stdlib/src/hash/sha256.nr b/noir_stdlib/src/hash/sha256.nr index 352df656068..3b4823c9f7c 100644 --- a/noir_stdlib/src/hash/sha256.nr +++ b/noir_stdlib/src/hash/sha256.nr @@ -169,7 +169,7 @@ pub fn sha256_var(msg: [u8; N], message_size: u64) -> [u8; 32] { } let len = 8 * message_size; - let len_bytes = (len as Field).to_le_bytes(8); + let len_bytes: [u8; 8] = (len as Field).to_le_bytes(); // In any case, fill blocks up with zeros until the last 64 (i.e. until msg_byte_ptr = 56). for _ in 0..64 { if msg_byte_ptr < 56 { @@ -211,7 +211,7 @@ unconstrained fn attach_len_to_msg_block( message_size: u64 ) -> [u8; 64] { let len = 8 * message_size; - let len_bytes = (len as Field).to_le_bytes(8); + let len_bytes: [u8; 8] = (len as Field).to_le_bytes(); for _i in 0..64 { // In any case, fill blocks up with zeros until the last 64 (i.e. until msg_byte_ptr = 56). if msg_byte_ptr < 56 { @@ -235,7 +235,7 @@ fn hash_final_block(msg_block: [u8; 64], mut state: [u32; 8]) -> [u8; 32] { // Return final hash as byte array for j in 0..8 { - let h_bytes = (state[7 - j] as Field).to_le_bytes(4); + let h_bytes: [u8; 4] = (state[7 - j] as Field).to_le_bytes(); for k in 0..4 { out_h[31 - 4*j - k] = h_bytes[k]; } diff --git a/noir_stdlib/src/hash/sha512.nr b/noir_stdlib/src/hash/sha512.nr index be255a594af..09de174103f 100644 --- a/noir_stdlib/src/hash/sha512.nr +++ b/noir_stdlib/src/hash/sha512.nr @@ -135,7 +135,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 64] { } let len = 8 * msg.len(); - let len_bytes = (len as Field).to_le_bytes(16); + let len_bytes: [u8; 16] = (len as Field).to_le_bytes(); for _i in 0..128 { // In any case, fill blocks up with zeros until the last 128 (i.e. until i = 112). if i < 112 { @@ -155,7 +155,7 @@ pub fn digest(msg: [u8; N]) -> [u8; 64] { } // Return final hash as byte array for j in 0..8 { - let h_bytes = (h[7 - j] as Field).to_le_bytes(8); + let h_bytes: [u8; 8] = (h[7 - j] as Field).to_le_bytes(); for k in 0..8 { out_h[63 - 8*j - k] = h_bytes[k]; } diff --git a/noir_stdlib/src/merkle.nr b/noir_stdlib/src/merkle.nr index 17e539ab9b7..f6806874444 100644 --- a/noir_stdlib/src/merkle.nr +++ b/noir_stdlib/src/merkle.nr @@ -3,10 +3,9 @@ // XXX: In the future we can add an arity parameter // Returns the merkle root of the tree from the provided leaf, its hashpath, using a pedersen hash function. pub fn compute_merkle_root(leaf: Field, index: Field, hash_path: [Field; N]) -> Field { - let n = hash_path.len(); - let index_bits = index.to_le_bits(n as u32); + let index_bits: [u1; N] = index.to_le_bits(); let mut current = leaf; - for i in 0..n { + for i in 0..N { let path_bit = index_bits[i] as bool; let (hash_left, hash_right) = if path_bit { (hash_path[i], current) diff --git a/noir_stdlib/src/uint128.nr b/noir_stdlib/src/uint128.nr index a6d980c7f33..6b2e78f33d6 100644 --- a/noir_stdlib/src/uint128.nr +++ b/noir_stdlib/src/uint128.nr @@ -45,8 +45,8 @@ impl U128 { } pub fn to_be_bytes(self: Self) -> [u8; 16] { - let lo = self.lo.to_be_bytes(8); - let hi = self.hi.to_be_bytes(8); + let lo: [u8; 8] = self.lo.to_be_bytes(); + let hi: [u8; 8] = self.hi.to_be_bytes(); let mut bytes = [0; 16]; for i in 0..8 { bytes[i] = hi[i]; @@ -56,8 +56,8 @@ impl U128 { } pub fn to_le_bytes(self: Self) -> [u8; 16] { - let lo = self.lo.to_le_bytes(8); - let hi = self.hi.to_le_bytes(8); + let lo: [u8; 8] = self.lo.to_le_bytes(); + let hi: [u8; 8] = self.hi.to_le_bytes(); let mut bytes = [0; 16]; for i in 0..8 { bytes[i] = lo[i]; @@ -295,12 +295,13 @@ impl BitXor for U128 { impl Shl for U128 { fn shl(self, other: u8) -> U128 { assert(other < 128, "attempt to shift left with overflow"); - let exp_bits = (other as Field).to_be_bits(7); + let exp_bits: [u1; 7] = (other as Field).to_be_bits(); let mut r: Field = 2; let mut y: Field = 1; for i in 1..8 { - y = (exp_bits[7-i] as Field) * (r * y) + (1 - exp_bits[7-i] as Field) * y; + let bit = exp_bits[7-i] as Field; + y = bit * (r * y) + (1 - bit) * y; r *= r; } self.wrapping_mul(U128::from_integer(y)) @@ -310,12 +311,13 @@ impl Shl for U128 { impl Shr for U128 { fn shr(self, other: u8) -> U128 { assert(other < 128, "attempt to shift right with overflow"); - let exp_bits = (other as Field).to_be_bits(7); + let exp_bits: [u1; 7] = (other as Field).to_be_bits(); let mut r: Field = 2; let mut y: Field = 1; for i in 1..8 { - y = (exp_bits[7-i] as Field) * (r * y) + (1 - exp_bits[7-i] as Field) * y; + let bit = exp_bits[7-i] as Field; + y = bit * (r * y) + (1 - bit) * y; r *= r; } self / U128::from_integer(y) @@ -435,7 +437,7 @@ mod tests { // but in the past it was possible to create a value > (1<<128) let a = U128::from_hex("0x~fffffffffffffffffffffffffffffff"); let b:Field= a.to_integer(); - let c= b.to_le_bytes(17); + let c: [u8; 17]= b.to_le_bytes(); assert(c[16] != 0); } diff --git a/temp/Nargo.toml b/temp/Nargo.toml new file mode 100644 index 00000000000..2d63990947f --- /dev/null +++ b/temp/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "temp" +type = "bin" +authors = [""] +compiler_version = ">=0.33.0" + +[dependencies] \ No newline at end of file diff --git a/temp/src/main.nr b/temp/src/main.nr new file mode 100644 index 00000000000..ab5737d8371 --- /dev/null +++ b/temp/src/main.nr @@ -0,0 +1,4 @@ +fn main(x: Field) -> pub [u8; 4] { + x.to_be_bytes() +} + diff --git a/test_programs/compile_success_empty/to_bits/src/main.nr b/test_programs/compile_success_empty/to_bits/src/main.nr index 84ace83903a..918a2fad036 100644 --- a/test_programs/compile_success_empty/to_bits/src/main.nr +++ b/test_programs/compile_success_empty/to_bits/src/main.nr @@ -1,7 +1,7 @@ fn main() { let field = 1000; - let be_bits = field.to_be_bits(16); - let le_bits = field.to_le_bits(16); + let be_bits:[u1; 16] = field.to_be_bits(); + let le_bits:[u1; 16] = field.to_le_bits(); for i in 0..16 { let x = be_bits[i]; @@ -10,8 +10,8 @@ fn main() { } let x = 3; - let be_bits_x = x.to_be_bits(4); - let le_bits_x = x.to_le_bits(4); + let be_bits_x: [u1; 4] = x.to_be_bits(); + let le_bits_x: [u1; 4] = x.to_le_bits(); for i in 0..4 { let be_bit = be_bits_x[i]; diff --git a/test_programs/execution_success/to_be_bytes/src/main.nr b/test_programs/execution_success/to_be_bytes/src/main.nr index 64d54ddff66..809d8ad4563 100644 --- a/test_programs/execution_success/to_be_bytes/src/main.nr +++ b/test_programs/execution_success/to_be_bytes/src/main.nr @@ -1,6 +1,6 @@ fn main(x: Field) -> pub [u8; 31] { // The result of this byte array will be big-endian - let byte_array = x.to_be_bytes(31); + let byte_array: [u8; 31] = x.to_be_bytes(); let mut bytes = [0; 31]; for i in 0..31 { bytes[i] = byte_array[i]; From 96a24b4ab0914d6f9e815f0d8cf2985bbb364b1e Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Wed, 28 Aug 2024 19:45:39 +0100 Subject: [PATCH 02/15] Update compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs --- compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index bbf379ee0e5..6b7eaef6e18 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -2199,9 +2199,6 @@ impl<'a> Context<'a> { let Type::Array(result_type, array_length) = dfg.type_of_value(result_ids[0]) else { - println!("{:?}", result_ids); - println!("{:?}", dfg.type_of_value(result_ids[0])); - println!("{:?}", dfg.type_of_value(result_ids[1])); unreachable!("ICE: ToRadix result must be an array"); }; From dcd72f05ff56a26560b8b3cab82b45fb876acb76 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 28 Aug 2024 19:46:48 +0100 Subject: [PATCH 03/15] . --- compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs | 2 -- temp/Nargo.toml | 7 ------- temp/src/main.nr | 4 ---- 3 files changed, 13 deletions(-) delete mode 100644 temp/Nargo.toml delete mode 100644 temp/src/main.nr diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index 6b7eaef6e18..3aa2ff4d3ef 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -1073,7 +1073,6 @@ impl<'a> Context<'a> { match self.convert_value(array_id, dfg) { AcirValue::Var(acir_var, _) => { - println!("{array}[{index}]"); Err(RuntimeError::InternalError(InternalError::Unexpected { expected: "an array value".to_string(), found: format!("{acir_var:?}"), @@ -2199,7 +2198,6 @@ impl<'a> Context<'a> { let Type::Array(result_type, array_length) = dfg.type_of_value(result_ids[0]) else { - unreachable!("ICE: ToRadix result must be an array"); }; diff --git a/temp/Nargo.toml b/temp/Nargo.toml deleted file mode 100644 index 2d63990947f..00000000000 --- a/temp/Nargo.toml +++ /dev/null @@ -1,7 +0,0 @@ -[package] -name = "temp" -type = "bin" -authors = [""] -compiler_version = ">=0.33.0" - -[dependencies] \ No newline at end of file diff --git a/temp/src/main.nr b/temp/src/main.nr deleted file mode 100644 index ab5737d8371..00000000000 --- a/temp/src/main.nr +++ /dev/null @@ -1,4 +0,0 @@ -fn main(x: Field) -> pub [u8; 4] { - x.to_be_bytes() -} - From c07e5562226a24ea56489f7778fad112bb56ca00 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 28 Aug 2024 19:56:42 +0100 Subject: [PATCH 04/15] . --- noir_stdlib/src/field/mod.nr | 11 +++++------ .../builtin_function_declaration/src/main.nr | 6 +++--- .../radix_non_constant_length/Nargo.toml | 6 ------ .../radix_non_constant_length/src/main.nr | 4 ---- .../conditional_regression_to_bits/src/main.nr | 2 +- .../execution_success/7_function/src/main.nr | 2 +- test_programs/execution_success/array_len/src/main.nr | 2 +- test_programs/execution_success/bigint/src/main.nr | 2 +- .../brillig_cow_regression/src/main.nr | 4 ++-- test_programs/execution_success/schnorr/src/main.nr | 6 +++--- .../execution_success/simple_radix/src/main.nr | 2 +- test_programs/execution_success/slices/src/main.nr | 2 +- test_programs/execution_success/to_bits/src/main.nr | 8 ++++---- .../execution_success/to_bytes_consistent/src/main.nr | 4 ++-- .../to_bytes_integration/src/main.nr | 10 +++++----- .../execution_success/to_le_bytes/src/main.nr | 4 ++-- 16 files changed, 32 insertions(+), 43 deletions(-) delete mode 100644 test_programs/compile_failure/radix_non_constant_length/Nargo.toml delete mode 100644 test_programs/compile_failure/radix_non_constant_length/src/main.nr diff --git a/noir_stdlib/src/field/mod.nr b/noir_stdlib/src/field/mod.nr index df84c6b544c..4472aa95e91 100644 --- a/noir_stdlib/src/field/mod.nr +++ b/noir_stdlib/src/field/mod.nr @@ -150,15 +150,14 @@ pub fn bytes32_to_field(bytes32: [u8; 32]) -> Field { } fn lt_fallback(x: Field, y: Field) -> bool { - let num_bytes = (modulus_num_bits() as u32 + 7) / 8; - let x_bytes = x.to_le_bytes(); - let y_bytes = y.to_le_bytes(); + let x_bytes: [u8; 32] = x.to_le_bytes(); + let y_bytes: [u8; 32] = y.to_le_bytes(); let mut x_is_lt = false; let mut done = false; - for i in 0..num_bytes { + for i in 0..32 { if (!done) { - let x_byte = x_bytes[num_bytes - 1 - i] as u8; - let y_byte = y_bytes[num_bytes - 1 - i] as u8; + let x_byte = x_bytes[32 - 1 - i] as u8; + let y_byte = y_bytes[32 - 1 - i] as u8; let bytes_match = x_byte == y_byte; if !bytes_match { x_is_lt = x_byte < y_byte; diff --git a/test_programs/compile_failure/builtin_function_declaration/src/main.nr b/test_programs/compile_failure/builtin_function_declaration/src/main.nr index 473b5405691..1f0af24a243 100644 --- a/test_programs/compile_failure/builtin_function_declaration/src/main.nr +++ b/test_programs/compile_failure/builtin_function_declaration/src/main.nr @@ -2,9 +2,9 @@ // This would otherwise be a perfectly valid declaration of the `to_le_bits` builtin function #[builtin(to_le_bits)] -fn to_le_bits(_x: Field, _bit_size: u32) -> [u1] {} +fn to_le_bits(_x: Field) -> [u1: N] {} fn main(x: Field) -> pub u1 { - let bits = to_le_bits(x, 100); + let bits: [u1; 100] = to_le_bits(x); bits[0] -} \ No newline at end of file +} diff --git a/test_programs/compile_failure/radix_non_constant_length/Nargo.toml b/test_programs/compile_failure/radix_non_constant_length/Nargo.toml deleted file mode 100644 index 349698cc32d..00000000000 --- a/test_programs/compile_failure/radix_non_constant_length/Nargo.toml +++ /dev/null @@ -1,6 +0,0 @@ -[package] -name = "radix_non_constant_length" -type = "bin" -authors = [""] - -[dependencies] diff --git a/test_programs/compile_failure/radix_non_constant_length/src/main.nr b/test_programs/compile_failure/radix_non_constant_length/src/main.nr deleted file mode 100644 index c6dd68d925c..00000000000 --- a/test_programs/compile_failure/radix_non_constant_length/src/main.nr +++ /dev/null @@ -1,4 +0,0 @@ -fn main(x: Field, y: pub u32) { - let bytes = x.to_be_bytes(y); - assert(bytes[0] == 0); -} diff --git a/test_programs/compile_success_empty/conditional_regression_to_bits/src/main.nr b/test_programs/compile_success_empty/conditional_regression_to_bits/src/main.nr index 9b5d95c11bc..5205e2bff73 100644 --- a/test_programs/compile_success_empty/conditional_regression_to_bits/src/main.nr +++ b/test_programs/compile_success_empty/conditional_regression_to_bits/src/main.nr @@ -5,7 +5,7 @@ fn main() { let as_bits_hardcode_1 = [1, 0]; let mut c1 = 0; for i in 0..2 { - let mut as_bits = (arr[i] as Field).to_le_bits(2); + let mut as_bits: [u1; 2] = (arr[i] as Field).to_le_bits(); c1 = c1 + as_bits[0] as Field; if i == 0 { diff --git a/test_programs/execution_success/7_function/src/main.nr b/test_programs/execution_success/7_function/src/main.nr index 95568dd4ccd..dc56f2bea4f 100644 --- a/test_programs/execution_success/7_function/src/main.nr +++ b/test_programs/execution_success/7_function/src/main.nr @@ -29,7 +29,7 @@ fn test2(z: Field, t: u32) { fn pow(base: Field, exponent: Field) -> Field { let mut r = 1 as Field; - let b = exponent.to_le_bits(32 as u32); + let b: [u1; 32] = exponent.to_le_bits(); for i in 1..33 { r = r*r; r = (b[32-i] as Field) * (r * base) + (1 - b[32-i] as Field) * r; diff --git a/test_programs/execution_success/array_len/src/main.nr b/test_programs/execution_success/array_len/src/main.nr index 45c09b8a282..126fcd18d3f 100644 --- a/test_programs/execution_success/array_len/src/main.nr +++ b/test_programs/execution_success/array_len/src/main.nr @@ -20,5 +20,5 @@ fn main(x: Field, len3: [u8; 3], len4: [Field; 4]) { // Regression for #1023, ensure .len still works after calling to_le_bytes on a witness. // This was needed because normally .len is evaluated before acir-gen where to_le_bytes // on a witness is only evaluated during/after acir-gen. - assert(x.to_le_bytes(8).len() != 0); + assert(x.to_le_bytes::<8>().len() != 0); } diff --git a/test_programs/execution_success/bigint/src/main.nr b/test_programs/execution_success/bigint/src/main.nr index 188ccd01131..8592e6fb230 100644 --- a/test_programs/execution_success/bigint/src/main.nr +++ b/test_programs/execution_success/bigint/src/main.nr @@ -35,7 +35,7 @@ fn main(mut x: [u8; 5], y: [u8; 5]) { let d = d - b; let mut result = [0; 32]; - let result_slice = (a_field * b_field - b_field).to_le_bytes(32); + let result_slice: [u8; 32] = (a_field * b_field - b_field).to_le_bytes(); for i in 0..32 { result[i] = result_slice[i]; } diff --git a/test_programs/execution_success/brillig_cow_regression/src/main.nr b/test_programs/execution_success/brillig_cow_regression/src/main.nr index ae3adf6425c..adeadfc9f20 100644 --- a/test_programs/execution_success/brillig_cow_regression/src/main.nr +++ b/test_programs/execution_success/brillig_cow_regression/src/main.nr @@ -160,14 +160,14 @@ unconstrained fn main(kernel_data: DataToHash) -> pub [Field; NUM_FIELDS_PER_SHA let mut hash_input_flattened = [0; TX_EFFECT_HASH_FULL_FIELDS * 32 + TX_EFFECT_HASH_LOG_FIELDS * 16]; for offset in 0..TX_EFFECT_HASH_FULL_FIELDS { - let input_as_bytes = tx_effects_hash_inputs[offset].to_be_bytes(32); + let input_as_bytes: [u8; 32] = tx_effects_hash_inputs[offset].to_be_bytes(); for byte_index in 0..32 { hash_input_flattened[offset * 32 + byte_index] = input_as_bytes[byte_index]; } } for log_field_index in 0..TX_EFFECT_HASH_LOG_FIELDS { - let input_as_bytes = tx_effects_hash_inputs[TX_EFFECT_HASH_FULL_FIELDS + log_field_index].to_be_bytes(16); + let input_as_bytes: [u8; 16] = tx_effects_hash_inputs[TX_EFFECT_HASH_FULL_FIELDS + log_field_index].to_be_bytes(); for byte_index in 0..16 { hash_input_flattened[TX_EFFECT_HASH_FULL_FIELDS * 32 + log_field_index * 16 + byte_index] = input_as_bytes[byte_index]; } diff --git a/test_programs/execution_success/schnorr/src/main.nr b/test_programs/execution_success/schnorr/src/main.nr index cf22fd371d1..8b3b4735145 100644 --- a/test_programs/execution_success/schnorr/src/main.nr +++ b/test_programs/execution_success/schnorr/src/main.nr @@ -11,7 +11,7 @@ fn main( ) { // Regression for issue #2421 // We want to make sure that we can accurately verify a signature whose message is a slice vs. an array - let message_field_bytes = message_field.to_be_bytes(10); + let message_field_bytes: [u8; 10] = message_field.to_be_bytes(); let mut message2 = [0; 42]; for i in 0..10 { assert(message[i] == message_field_bytes[i]); @@ -52,7 +52,7 @@ pub fn verify_signature_noir(public_key: embedded_curve_ops::EmbeddedCurvePoi // compare the _hashes_ rather than field elements modulo r let pedersen_hash = std::hash::pedersen_hash([r.x, public_key.x, public_key.y]); let mut hash_input = [0; M]; - let pde = pedersen_hash.to_be_bytes(32); + let pde: [u8; 32] = pedersen_hash.to_be_bytes(); for i in 0..32 { hash_input[i] = pde[i]; @@ -103,7 +103,7 @@ pub fn assert_valid_signature(public_key: embedded_curve_ops::EmbeddedCurvePo // compare the _hashes_ rather than field elements modulo r let pedersen_hash = std::hash::pedersen_hash([r.x, public_key.x, public_key.y]); let mut hash_input = [0; M]; - let pde = pedersen_hash.to_be_bytes(32); + let pde: [u8; 32] = pedersen_hash.to_be_bytes(); for i in 0..32 { hash_input[i] = pde[i]; diff --git a/test_programs/execution_success/simple_radix/src/main.nr b/test_programs/execution_success/simple_radix/src/main.nr index 4a335e1bade..b905d2e533e 100644 --- a/test_programs/execution_success/simple_radix/src/main.nr +++ b/test_programs/execution_success/simple_radix/src/main.nr @@ -1,6 +1,6 @@ // Simple program to test to_radix fn main(x: Field) { - let bits = x.to_le_bits(3); + let bits: [u1; 3] = x.to_le_bits(); assert(bits[0] == 0); assert(bits[1] == 1); assert(bits[2] == 0); diff --git a/test_programs/execution_success/slices/src/main.nr b/test_programs/execution_success/slices/src/main.nr index 2bd4dbd97b0..47272869b04 100644 --- a/test_programs/execution_success/slices/src/main.nr +++ b/test_programs/execution_success/slices/src/main.nr @@ -315,7 +315,7 @@ fn regression_2370() { } fn regression_4418(x: Field) { - let mut crash = x.to_be_bytes(32); + let mut crash: [u8; 32] = x.to_be_bytes(); if x != 0 { crash[0] = 10; diff --git a/test_programs/execution_success/to_bits/src/main.nr b/test_programs/execution_success/to_bits/src/main.nr index 84ace83903a..dc2ff4be394 100644 --- a/test_programs/execution_success/to_bits/src/main.nr +++ b/test_programs/execution_success/to_bits/src/main.nr @@ -1,7 +1,7 @@ fn main() { let field = 1000; - let be_bits = field.to_be_bits(16); - let le_bits = field.to_le_bits(16); + let be_bits: [u1; 16] = field.to_be_bits(); + let le_bits: [u1; 16] = field.to_le_bits(); for i in 0..16 { let x = be_bits[i]; @@ -10,8 +10,8 @@ fn main() { } let x = 3; - let be_bits_x = x.to_be_bits(4); - let le_bits_x = x.to_le_bits(4); + let be_bits_x: [u1; 4] = x.to_be_bits(); + let le_bits_x: [u1; 4] = x.to_le_bits(); for i in 0..4 { let be_bit = be_bits_x[i]; diff --git a/test_programs/execution_success/to_bytes_consistent/src/main.nr b/test_programs/execution_success/to_bytes_consistent/src/main.nr index 638b34c9bab..a51d52da855 100644 --- a/test_programs/execution_success/to_bytes_consistent/src/main.nr +++ b/test_programs/execution_success/to_bytes_consistent/src/main.nr @@ -3,9 +3,9 @@ // with constant inputs or with witness inputs. // x = 2040124 fn main(x: Field) { - let byte_array = x.to_be_bytes(31); + let byte_array: [u8; 31] = x.to_be_bytes(); let x_as_constant = 2040124; - let constant_byte_array = x_as_constant.to_be_bytes(31); + let constant_byte_array: [u8; 31] = x_as_constant.to_be_bytes(); assert(constant_byte_array.len() == byte_array.len()); for i in 0..constant_byte_array.len() { assert(constant_byte_array[i] == byte_array[i]); diff --git a/test_programs/execution_success/to_bytes_integration/src/main.nr b/test_programs/execution_success/to_bytes_integration/src/main.nr index 21c4ad90bfe..21245378971 100644 --- a/test_programs/execution_success/to_bytes_integration/src/main.nr +++ b/test_programs/execution_success/to_bytes_integration/src/main.nr @@ -1,7 +1,7 @@ fn main(x: Field, a: Field) { let y: Field = 2040124; - let be_byte_array = y.to_be_bytes(31); - let le_byte_array = x.to_le_bytes(31); + let be_byte_array: [u8; 31] = y.to_be_bytes(); + let le_byte_array: [u8; 31] = x.to_le_bytes(); assert(le_byte_array[0] == 60); assert(le_byte_array[0] == be_byte_array[30]); @@ -10,14 +10,14 @@ fn main(x: Field, a: Field) { let z = 0 - 1; let p_bytes = std::field::modulus_le_bytes(); - let z_bytes = z.to_le_bytes(32); + let z_bytes: [u8; 32] = z.to_le_bytes(); assert(p_bytes[10] == z_bytes[10]); assert(p_bytes[0] == z_bytes[0] as u8 + 1 as u8); let p_bits = std::field::modulus_le_bits(); - let z_bits = z.to_le_bits(std::field::modulus_num_bits() as u32); + let z_bits: [u1; 254] = z.to_le_bits(); assert(z_bits[0] == 0); assert(p_bits[100] == z_bits[100]); - a.to_le_bits(std::field::modulus_num_bits() as u32); + let _: [u1; 254] = a.to_le_bits(); } diff --git a/test_programs/execution_success/to_le_bytes/src/main.nr b/test_programs/execution_success/to_le_bytes/src/main.nr index a0b48efe528..4e232b025aa 100644 --- a/test_programs/execution_success/to_le_bytes/src/main.nr +++ b/test_programs/execution_success/to_le_bytes/src/main.nr @@ -1,6 +1,6 @@ fn main(x: Field, cond: bool) -> pub [u8; 31] { // The result of this byte array will be little-endian - let byte_array = x.to_le_bytes(31); + let byte_array: [u8; 31] = x.to_le_bytes(); assert(byte_array.len() == 31); let mut bytes = [0; 31]; @@ -10,7 +10,7 @@ fn main(x: Field, cond: bool) -> pub [u8; 31] { if cond { // We've set x = "2040124" so we shouldn't be able to represent this as a single byte. - let bad_byte_array = x.to_le_bytes(1); + let bad_byte_array: [u8; 1] = x.to_le_bytes(); assert_eq(bad_byte_array.len(), 1); } From 6d31164d15125b738358b311c14e85aa248280bc Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 28 Aug 2024 19:59:00 +0100 Subject: [PATCH 05/15] fix: re-add division by 2 --- .../noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs index dc72db247d5..78962211e23 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_memory.rs @@ -257,7 +257,7 @@ impl BrilligContext { /// This instruction will reverse the order of the elements in a array. pub(crate) fn codegen_reverse_array_in_place(&mut self, array: BrilligArray) { let iteration_count = self.allocate_register(); - self.usize_const_instruction(iteration_count, array.size.into()); + self.usize_const_instruction(iteration_count, (array.size / 2).into()); let start_value_register = self.allocate_register(); let index_at_end_of_array = self.allocate_register(); From 225eb1e16035191e2cfd8f77cab5ff00c2969796 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 28 Aug 2024 20:58:02 +0100 Subject: [PATCH 06/15] . --- .../src/brillig/brillig_ir/codegen_intrinsic.rs | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs index 8066b1d77cb..63dce824943 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs @@ -73,19 +73,22 @@ impl BrilligContext { ) { assert!(source_field.bit_size == F::max_num_bits()); + let size = SingleAddrVariable::new_usize(self.allocate_register()); + self.usize_const_instruction(size.address, target_array.size.into()); + self.usize_const_instruction(target_array.rc, 1_usize.into()); + self.codegen_allocate_array(target_array.pointer, size.address); + self.black_box_op_instruction(BlackBoxOp::ToRadix { input: source_field.address, radix, output: target_array.to_heap_array(), }); - let limb_field = SingleAddrVariable::new(self.allocate_register(), F::max_num_bits()); + let limb_field = SingleAddrVariable::new_field(self.allocate_register()); let limb_casted = SingleAddrVariable::new(self.allocate_register(), limb_bit_size); if limb_bit_size != F::max_num_bits() { - let size = self.allocate_register(); - self.usize_const_instruction(size, target_array.size.into()); - self.codegen_loop(size, |ctx, iterator_register| { + self.codegen_loop(size.address, |ctx, iterator_register| { // Read the limb ctx.codegen_array_get(target_array.pointer, iterator_register, limb_field.address); // Cast it @@ -93,10 +96,10 @@ impl BrilligContext { // Write it ctx.codegen_array_set(target_array.pointer, iterator_register, limb_casted.address); }); - self.deallocate_register(size); } // Deallocate our temporary registers + self.deallocate_single_addr(size); self.deallocate_single_addr(limb_field); self.deallocate_single_addr(limb_casted); From 38d41855b05d53b3975c506291836759470b19e0 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 28 Aug 2024 21:13:56 +0100 Subject: [PATCH 07/15] fix test --- .../noirc_evaluator/src/ssa/function_builder/mod.rs | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index 8cc42241d92..7845003e332 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -533,7 +533,7 @@ mod tests { fn insert_constant_call() { // `bits` should be an array of constants [1, 1, 1, 0...] of length 8: // let x = 7; - // let bits = x.to_le_bits(8); + // let bits: [u1; 8] = x.to_le_bits(); let func_id = Id::test_new(0); let mut builder = FunctionBuilder::new("func".into(), func_id); let one = builder.numeric_constant(FieldElement::one(), Type::bool()); @@ -546,13 +546,7 @@ mod tests { let call_results = builder.insert_call(to_bits_id, vec![input, length], result_types).into_owned(); - let slice_len = match &builder.current_function.dfg[call_results[0]] { - Value::NumericConstant { constant, .. } => *constant, - _ => panic!(), - }; - assert_eq!(slice_len, FieldElement::from(8_u128)); - - let slice = match &builder.current_function.dfg[call_results[1]] { + let slice = match &builder.current_function.dfg[call_results[0]] { Value::Array { array, .. } => array, _ => panic!(), }; From 9d3a23e16686e2b2691b74e31fa13b0af9bd3b22 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 28 Aug 2024 23:43:50 +0100 Subject: [PATCH 08/15] chore: update comptime `to_le_radix` --- .../src/hir/comptime/interpreter/builtin.rs | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 852733b6ca8..d859e94a2ec 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -117,7 +117,7 @@ impl<'local, 'context> Interpreter<'local, 'context> { "struct_def_as_type" => struct_def_as_type(interner, arguments, location), "struct_def_fields" => struct_def_fields(interner, arguments, location), "struct_def_generics" => struct_def_generics(interner, arguments, location), - "to_le_radix" => to_le_radix(arguments, location), + "to_le_radix" => to_le_radix(arguments, return_type, location), "trait_constraint_eq" => trait_constraint_eq(interner, arguments, location), "trait_constraint_hash" => trait_constraint_hash(interner, arguments, location), "trait_def_as_trait_constraint" => { @@ -429,12 +429,24 @@ fn quoted_as_type( Ok(Value::Type(typ)) } -fn to_le_radix(arguments: Vec<(Value, Location)>, location: Location) -> IResult { - let (value, radix, limb_count) = check_three_arguments(arguments, location)?; +fn to_le_radix( + arguments: Vec<(Value, Location)>, + return_type: Type, + location: Location, +) -> IResult { + let (value, radix) = check_two_arguments(arguments, location)?; let value = get_field(value)?; let radix = get_u32(radix)?; - let limb_count = get_u32(limb_count)?; + let limb_count = if let Type::Array(length, _) = return_type { + if let Type::Constant(limb_count) = *length { + limb_count + } else { + return Err(InterpreterError::TypeAnnotationsNeededForMethodCall { location }); + } + } else { + return Err(InterpreterError::TypeAnnotationsNeededForMethodCall { location }); + }; // Decompose the integer into its radix digits in little endian form. let decomposed_integer = compute_to_radix(value, radix); From b11de8e77506a18bbf139c8855621ff8e3fa0579 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 28 Aug 2024 23:48:23 +0100 Subject: [PATCH 09/15] . --- .../noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs index 9c8d7fb1ad7..97b75967892 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs @@ -71,7 +71,6 @@ impl<'a> SliceCapacityTracker<'a> { // v3, v4, v5, v6, v7, v8 = call slice_pop_front(v1, v2) // where v7 is the slice length and v8 is the popped slice itself. Intrinsic::SlicePopFront => (Some(1), results.len() - 1), - // The slice capacity of these intrinsics is not determined by the arguments of the function. Intrinsic::AsSlice => (Some(0), 1), _ => return, }; From 19aeae731acb4714fdf6134d019f770a9e64946e Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 28 Aug 2024 23:54:00 +0100 Subject: [PATCH 10/15] . --- .../src/ssa/opt/flatten_cfg/capacity_tracker.rs | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs index 97b75967892..836c812843e 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg/capacity_tracker.rs @@ -63,15 +63,15 @@ impl<'a> SliceCapacityTracker<'a> { | Intrinsic::SlicePushFront | Intrinsic::SlicePopBack | Intrinsic::SliceInsert - | Intrinsic::SliceRemove => (Some(1), 1), + | Intrinsic::SliceRemove => (1, 1), // `pop_front` returns the popped element, and then the respective slice. // This means in the case of a slice with structs, the result index of the popped slice // will change depending on the number of elements in the struct. // For example, a slice with four elements will look as such in SSA: // v3, v4, v5, v6, v7, v8 = call slice_pop_front(v1, v2) // where v7 is the slice length and v8 is the popped slice itself. - Intrinsic::SlicePopFront => (Some(1), results.len() - 1), - Intrinsic::AsSlice => (Some(0), 1), + Intrinsic::SlicePopFront => (1, results.len() - 1), + Intrinsic::AsSlice => (0, 1), _ => return, }; let result_slice = results[result_index]; @@ -79,8 +79,6 @@ impl<'a> SliceCapacityTracker<'a> { Intrinsic::SlicePushBack | Intrinsic::SlicePushFront | Intrinsic::SliceInsert => { - let argument_index = argument_index - .expect("ICE: Should have an argument index for slice intrinsics"); let slice_contents = arguments[argument_index]; for arg in &arguments[(argument_index + 1)..] { @@ -98,8 +96,6 @@ impl<'a> SliceCapacityTracker<'a> { Intrinsic::SlicePopBack | Intrinsic::SliceRemove | Intrinsic::SlicePopFront => { - let argument_index = argument_index - .expect("ICE: Should have an argument index for slice intrinsics"); let slice_contents = arguments[argument_index]; if let Some(contents_capacity) = slice_sizes.get(&slice_contents) { @@ -119,8 +115,6 @@ impl<'a> SliceCapacityTracker<'a> { .insert(result_slice, FieldElement::max_num_bytes() as usize); } Intrinsic::AsSlice => { - let argument_index = argument_index - .expect("ICE: Should have an argument index for AsSlice builtin"); let array_size = self .dfg .try_get_array_length(arguments[argument_index]) From bbaa87c9471be48f870d17ed7c43849ff8535539 Mon Sep 17 00:00:00 2001 From: Tom French Date: Fri, 30 Aug 2024 17:31:14 +0100 Subject: [PATCH 11/15] chore: remove external repo checks --- .github/workflows/test-js-packages.yml | 53 -------------------------- 1 file changed, 53 deletions(-) diff --git a/.github/workflows/test-js-packages.yml b/.github/workflows/test-js-packages.yml index 5a09a0cf444..9f46e6f98e8 100644 --- a/.github/workflows/test-js-packages.yml +++ b/.github/workflows/test-js-packages.yml @@ -509,59 +509,6 @@ jobs: working-directory: ./examples/codegen_verifier run: ./test.sh - external-repo-checks: - needs: [build-nargo] - runs-on: ubuntu-22.04 - timeout-minutes: 30 - strategy: - fail-fast: false - matrix: - project: - # - { repo: AztecProtocol/aztec-nr, path: ./ } - # - { repo: AztecProtocol/aztec-packages, path: ./noir-projects/noir-contracts } - # Disabled as aztec-packages requires a setup-step in order to generate a `Nargo.toml` - #- { repo: AztecProtocol/aztec-packages, path: ./noir-projects/noir-protocol-circuits } - - { repo: zac-williamson/noir-edwards, path: ./, ref: 0016ce82cd58b6ebb0c43c271725590bcff4e755 } - # TODO: Enable these once they're passing against master again. - # - { repo: zac-williamson/noir-bignum, path: ./, ref: 030c2acce1e6b97c44a3bbbf3429ed96f20d72d3 } - # - { repo: vlayer-xyz/monorepo, path: ./, ref: ee46af88c025863872234eb05d890e1e447907cb } - # - { repo: hashcloak/noir-bigint, path: ./, ref: 940ddba3a5201b508e7b37a2ef643551afcf5ed8 } - - name: Check external repo - ${{ matrix.project.repo }} - - steps: - - name: Checkout - uses: actions/checkout@v4 - with: - repository: ${{ matrix.project.repo }} - path: test-repo - ref: ${{ matrix.project.ref }} - - - name: Download nargo binary - uses: actions/download-artifact@v4 - with: - name: nargo - path: ./nargo - - - name: Set nargo on PATH - run: | - nargo_binary="${{ github.workspace }}/nargo/nargo" - chmod +x $nargo_binary - echo "$(dirname $nargo_binary)" >> $GITHUB_PATH - export PATH="$PATH:$(dirname $nargo_binary)" - nargo -V - - - name: Remove requirements on compiler version - working-directory: ./test-repo - run: | - # Github actions seems to not expand "**" in globs by default. - shopt -s globstar - sed -i '/^compiler_version/d' ./**/Nargo.toml - - - name: Run nargo check - working-directory: ./test-repo/${{ matrix.project.path }} - run: nargo check - # This is a job which depends on all test jobs and reports the overall status. # This allows us to add/remove test jobs without having to update the required workflows. tests-end: From d045193c9b7b70da82f5ff7dffa44f2da279dd87 Mon Sep 17 00:00:00 2001 From: Tom French Date: Fri, 30 Aug 2024 23:49:22 +0100 Subject: [PATCH 12/15] . --- compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index e5f5497baf1..d3e5acb467b 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -50,6 +50,7 @@ pub(super) fn simplify_call( match intrinsic { Intrinsic::ToBits(endian) => { + // TODO: simplify to a range constraint if `limb_count == 1` if let (Some(constant_args), Some(return_type)) = (constant_args, ctrl_typevars.map(|return_types| return_types.first().cloned())) { @@ -67,6 +68,7 @@ pub(super) fn simplify_call( } } Intrinsic::ToRadix(endian) => { + // TODO: simplify to a range constraint if `limb_count == 1` if let (Some(constant_args), Some(return_type)) = (constant_args, ctrl_typevars.map(|return_types| return_types.first().cloned())) { From f07e529c1d6dbcf082892d0746ce00b9812b77f8 Mon Sep 17 00:00:00 2001 From: Tom French Date: Mon, 2 Sep 2024 10:37:20 +0100 Subject: [PATCH 13/15] chore: update docs --- docs/docs/noir/concepts/data_types/fields.md | 80 +++++--------------- noir_stdlib/src/field/mod.nr | 69 +++++++++++++++++ 2 files changed, 90 insertions(+), 59 deletions(-) diff --git a/docs/docs/noir/concepts/data_types/fields.md b/docs/docs/noir/concepts/data_types/fields.md index a10a4810788..b5af20f7d7e 100644 --- a/docs/docs/noir/concepts/data_types/fields.md +++ b/docs/docs/noir/concepts/data_types/fields.md @@ -41,103 +41,67 @@ After declaring a Field, you can use these common methods on it: Transforms the field into an array of bits, Little Endian. -```rust -fn to_le_bits(_x : Field, _bit_size: u32) -> [u1] -``` +#include_code to_le_bits noir_stdlib/src/field/mod.nr rust example: -```rust -fn main() { - let field = 2; - let bits = field.to_le_bits(32); -} -``` +#include_code to_le_bits_example noir_stdlib/src/field/mod.nr rust + ### to_be_bits Transforms the field into an array of bits, Big Endian. -```rust -fn to_be_bits(_x : Field, _bit_size: u32) -> [u1] -``` +#include_code to_be_bits noir_stdlib/src/field/mod.nr rust example: -```rust -fn main() { - let field = 2; - let bits = field.to_be_bits(32); -} -``` +#include_code to_be_bits_example noir_stdlib/src/field/mod.nr rust + ### to_le_bytes Transforms into an array of bytes, Little Endian -```rust -fn to_le_bytes(_x : Field, byte_size: u32) -> [u8] -``` +#include_code to_le_bytes noir_stdlib/src/field/mod.nr rust example: -```rust -fn main() { - let field = 2; - let bytes = field.to_le_bytes(4); -} -``` +#include_code to_le_bytes_example noir_stdlib/src/field/mod.nr rust ### to_be_bytes Transforms into an array of bytes, Big Endian -```rust -fn to_be_bytes(_x : Field, byte_size: u32) -> [u8] -``` +#include_code to_be_bytes noir_stdlib/src/field/mod.nr rust example: -```rust -fn main() { - let field = 2; - let bytes = field.to_be_bytes(4); -} -``` +#include_code to_be_bytes_example noir_stdlib/src/field/mod.nr rust + ### to_le_radix -Decomposes into a vector over the specified base, Little Endian +Decomposes into an array over the specified base, Little Endian + +#include_code to_le_radix noir_stdlib/src/field/mod.nr rust -```rust -fn to_le_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] -``` example: -```rust -fn main() { - let field = 2; - let radix = field.to_le_radix(256, 4); -} -``` +#include_code to_le_radix_example noir_stdlib/src/field/mod.nr rust + ### to_be_radix -Decomposes into a vector over the specified base, Big Endian +Decomposes into an array over the specified base, Big Endian -```rust -fn to_be_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] -``` +#include_code to_be_radix noir_stdlib/src/field/mod.nr rust example: -```rust -fn main() { - let field = 2; - let radix = field.to_be_radix(256, 4); -} -``` +#include_code to_be_radix_example noir_stdlib/src/field/mod.nr rust + ### pow_32 @@ -161,9 +125,7 @@ fn main() { Adds a constraint to specify that the field can be represented with `bit_size` number of bits -```rust -fn assert_max_bit_size(self, bit_size: u32) -``` +#include_code assert_max_bit_size noir_stdlib/src/field/mod.nr rust example: diff --git a/noir_stdlib/src/field/mod.nr b/noir_stdlib/src/field/mod.nr index 4472aa95e91..81aa9a23bb0 100644 --- a/noir_stdlib/src/field/mod.nr +++ b/noir_stdlib/src/field/mod.nr @@ -6,7 +6,9 @@ impl Field { /// /// # Failures /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`. + // docs:start:assert_max_bit_size pub fn assert_max_bit_size(self, bit_size: u32) { + // docs:end:assert_max_bit_size crate::assert_constant(bit_size); assert(bit_size < modulus_num_bits() as u32); self.__assert_max_bit_size(bit_size); @@ -27,7 +29,9 @@ impl Field { /// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will /// wrap around due to overflow when verifying the decomposition. #[builtin(to_le_bits)] + // docs:start:to_le_bits pub fn to_le_bits(self: Self) -> [u1; N] {} + // docs:end:to_le_bits /// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array. /// This array will be zero padded should not all bits be necessary to represent `self`. @@ -41,7 +45,9 @@ impl Field { /// (e.g. 254 for the BN254 field) allow for multiple bit decompositions. This is due to how the `Field` will /// wrap around due to overflow when verifying the decomposition. #[builtin(to_be_bits)] + // docs:start:to_be_bits pub fn to_be_bits(self: Self) -> [u1; N] {} + // docs:end:to_be_bits /// Decomposes `self` into its little endian byte decomposition as a `[u8]` slice of length `byte_size`. /// This slice will be zero padded should not all bytes be necessary to represent `self`. @@ -54,9 +60,11 @@ impl Field { /// Values of `byte_size` equal to or greater than the number of bytes necessary to represent the `Field` modulus /// (e.g. 32 for the BN254 field) allow for multiple byte decompositions. This is due to how the `Field` will /// wrap around due to overflow when verifying the decomposition. + // docs:start:to_le_bytes pub fn to_le_bytes(self: Self) -> [u8; N] { self.to_le_radix(256) } + // docs:end:to_le_bytes /// Decomposes `self` into its big endian byte decomposition as a `[u8]` slice of length `byte_size`. /// This slice will be zero padded should not all bytes be necessary to represent `self`. @@ -69,19 +77,25 @@ impl Field { /// Values of `byte_size` equal to or greater than the number of bytes necessary to represent the `Field` modulus /// (e.g. 32 for the BN254 field) allow for multiple byte decompositions. This is due to how the `Field` will /// wrap around due to overflow when verifying the decomposition. + // docs:start:to_be_bytes pub fn to_be_bytes(self: Self) -> [u8; N] { self.to_be_radix(256) } + // docs:end:to_be_bytes + // docs:start:to_le_radix pub fn to_le_radix(self: Self, radix: u32) -> [u8; N] { crate::assert_constant(radix); self.__to_le_radix(radix) } + // docs:end:to_le_radix + // docs:start:to_be_radix pub fn to_be_radix(self: Self, radix: u32) -> [u8; N] { crate::assert_constant(radix); self.__to_be_radix(radix) } + // docs:end:to_be_radix // `_radix` must be less than 256 #[builtin(to_le_radix)] @@ -168,3 +182,58 @@ fn lt_fallback(x: Field, y: Field) -> bool { x_is_lt } +mod tests { + #[test] + // docs:start:to_be_bits_example + fn test_to_be_bits() { + let field = 2; + let bits: [u1; 8] = field.to_be_bits(); + assert_eq(bits, [0, 0, 0, 0, 0, 0, 1, 0]); + } + // docs:end:to_be_radix_example + + #[test] + // docs:start:to_le_bits_example + fn test_to_le_bits() { + let field = 2; + let bits: [u1; 8] = field.to_le_bits(); + assert_eq(bits, [0, 1, 0, 0, 0, 0, 0, 0]); + } + // docs:end:to_le_bits_example + + #[test] + // docs:start:to_be_bytes_example + fn test_to_be_bytes() { + let field = 2; + let bits: [u8; 8] = field.to_be_bytes(); + assert_eq(bits, [0, 0, 0, 0, 0, 0, 0, 2]); + } + // docs:end:to_be_bytes_example + + #[test] + // docs:start:to_le_bytes_example + fn test_to_le_bytes() { + let field = 2; + let bits: [u8; 8] = field.to_le_bytes(); + assert_eq(bits, [2, 0, 0, 0, 0, 0, 0, 0]); + } + // docs:end:to_le_bytes_example + + #[test] + // docs:start:to_be_radix_example + fn test_to_be_radix() { + let field = 2; + let bits: [u8; 8] = field.to_be_radix(256); + assert_eq(bits, [0, 0, 0, 0, 0, 0, 0, 2]); + } + // docs:end:to_be_radix_example + + #[test] + // docs:start:to_le_radix_example + fn test_to_le_radix() { + let field = 2; + let bits: [u8; 8] = field.to_le_radix(256); + assert_eq(bits, [2, 0, 0, 0, 0, 0, 0, 0]); + } + // docs:end:to_le_radix_example +} From 9fbcdc01ccc2f40a9fe296ea436c5639efcc958d Mon Sep 17 00:00:00 2001 From: Tom French Date: Mon, 2 Sep 2024 10:49:27 +0100 Subject: [PATCH 14/15] . --- noir_stdlib/src/field/mod.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/noir_stdlib/src/field/mod.nr b/noir_stdlib/src/field/mod.nr index 81aa9a23bb0..176f102321d 100644 --- a/noir_stdlib/src/field/mod.nr +++ b/noir_stdlib/src/field/mod.nr @@ -190,7 +190,7 @@ mod tests { let bits: [u1; 8] = field.to_be_bits(); assert_eq(bits, [0, 0, 0, 0, 0, 0, 1, 0]); } - // docs:end:to_be_radix_example + // docs:end:to_be_bits_example #[test] // docs:start:to_le_bits_example From e9899dd1f0c35a337d332713796490579d31316e Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Mon, 2 Sep 2024 10:52:29 +0100 Subject: [PATCH 15/15] Update noir_stdlib/src/field/bn254.nr --- noir_stdlib/src/field/bn254.nr | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/noir_stdlib/src/field/bn254.nr b/noir_stdlib/src/field/bn254.nr index d7b9cf8fb80..19a49402642 100644 --- a/noir_stdlib/src/field/bn254.nr +++ b/noir_stdlib/src/field/bn254.nr @@ -28,8 +28,8 @@ unconstrained pub(crate) fn decompose_hint(x: Field) -> (Field, Field) { } fn compute_lt(x: Field, y: Field, num_bytes: u32) -> bool { - let x_bytes: [u8; 254] = x.to_le_bytes(); - let y_bytes: [u8; 254] = y.to_le_bytes(); + let x_bytes: [u8; 32] = x.to_le_bytes(); + let y_bytes: [u8; 32] = y.to_le_bytes(); let mut x_is_lt = false; let mut done = false; for i in 0..num_bytes {