From 17bd75e153dd44b1ef822cefcf6c01f5e461e9a8 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 19 Dec 2022 14:08:51 +0000 Subject: [PATCH 01/11] implement to_radix --- crates/acir/src/circuit/gate.rs | 36 +-- crates/acir/src/fallback/mod.rs | 6 +- crates/acir/src/opcode.rs | 18 -- crates/acvm/src/lib.rs | 72 ++--- crates/noirc_evaluator/src/ssa/acir_gen.rs | 335 +++++++++++++-------- crates/noirc_evaluator/src/ssa/builtin.rs | 75 +++++ crates/noirc_evaluator/src/ssa/code_gen.rs | 3 +- crates/noirc_evaluator/src/ssa/function.rs | 24 +- crates/noirc_evaluator/src/ssa/integer.rs | 17 +- crates/noirc_evaluator/src/ssa/mod.rs | 1 + crates/noirc_evaluator/src/ssa/node.rs | 9 +- crates/noirc_evaluator/src/ssa/optim.rs | 5 +- noir_stdlib/src/lib.nr | 16 +- 13 files changed, 359 insertions(+), 258 deletions(-) create mode 100644 crates/noirc_evaluator/src/ssa/builtin.rs diff --git a/crates/acir/src/circuit/gate.rs b/crates/acir/src/circuit/gate.rs index c44cb6ccb2c..2b6ff67d7db 100644 --- a/crates/acir/src/circuit/gate.rs +++ b/crates/acir/src/circuit/gate.rs @@ -41,8 +41,7 @@ impl Gate { Gate::Directive(Directive::Truncate { .. }) => "truncate", Gate::Directive(Directive::Quotient { .. }) => "quotient", Gate::Directive(Directive::Oddrange { .. }) => "odd_range", - Gate::Directive(Directive::Split { .. }) => "split", - Gate::Directive(Directive::ToBytes { .. }) => "to_bytes", + Gate::Directive(Directive::ToRadix { .. }) => "to_radix", Gate::GadgetCall(g) => g.name.name(), } } @@ -78,9 +77,9 @@ impl std::fmt::Debug for Gate { Gate::Directive(Directive::Truncate { a, b, c: _c, bit_size }) => { write!( f, - "Truncate: x{} is x{} truncated to {} bits", + "Truncate: x{} is {} truncated to {} bits", b.witness_index(), - a.witness_index(), + a, bit_size ) } @@ -120,20 +119,12 @@ impl std::fmt::Debug for Gate { Gate::And(g) => write!(f, "{:?}", g), Gate::Xor(g) => write!(f, "{:?}", g), Gate::GadgetCall(g) => write!(f, "{:?}", g), - Gate::Directive(Directive::Split { a, b, bit_size: _ }) => { - write!( - f, - "Split: {} into x{}...x{}", - a, - b.first().unwrap().witness_index(), - b.last().unwrap().witness_index(), - ) - } - Gate::Directive(Directive::ToBytes { a, b, byte_size: _ }) => { + Gate::Directive(Directive::ToRadix { a, b, radix }) => { write!( f, - "To Bytes: {} into x{}...x{}", + "To Radix: {} into base {}; x{}...x{}", a, + radix, b.first().unwrap().witness_index(), b.last().unwrap().witness_index(), ) @@ -162,7 +153,7 @@ pub enum Directive { //Reduces the value of a modulo 2^bit_size and stores the result in b: a= c*2^bit_size + b Truncate { - a: Witness, + a: Expression, b: Witness, c: Witness, bit_size: u32, @@ -176,18 +167,11 @@ pub enum Directive { bit_size: u32, }, - //bit decomposition of a: a=\sum b[i]*2^i - Split { - a: Expression, - b: Vec, - bit_size: u32, - }, - - //byte decomposition of a: a=\sum b[i]*2^i where b is a byte array - ToBytes { + //decomposition of a: a=\sum b[i]*radix^i where b is an array of witnesses < radix + ToRadix { a: Expression, b: Vec, - byte_size: u32, + radix: u32, }, } diff --git a/crates/acir/src/fallback/mod.rs b/crates/acir/src/fallback/mod.rs index c4a788074ee..92b429344bd 100644 --- a/crates/acir/src/fallback/mod.rs +++ b/crates/acir/src/fallback/mod.rs @@ -29,7 +29,11 @@ pub fn split( g.linear_combinations.push((-two_pow, w)); two_pow = FieldElement::from(2_i128) * two_pow; } - new_gates.push(Gate::Directive(Directive::Split { a: gate, b: bit_vector.clone(), bit_size })); + new_gates.push(Gate::Directive(Directive::ToRadix { + a: gate, + b: bit_vector.clone(), + radix: 2, + })); new_gates.extend(intermediate_gates); g.sort(); new_gates.push(Gate::Arithmetic(g)); diff --git a/crates/acir/src/opcode.rs b/crates/acir/src/opcode.rs index 4c0708251f5..51fd1eb1423 100644 --- a/crates/acir/src/opcode.rs +++ b/crates/acir/src/opcode.rs @@ -13,8 +13,6 @@ pub enum OPCODE { HashToField, EcdsaSecp256k1, FixedBaseScalarMul, - ToBits, - ToBytes, } impl std::fmt::Display for OPCODE { @@ -35,8 +33,6 @@ impl OPCODE { OPCODE::HashToField => 6, OPCODE::EcdsaSecp256k1 => 7, OPCODE::FixedBaseScalarMul => 8, - OPCODE::ToBits => 9, - OPCODE::ToBytes => 10, } } pub fn name(&self) -> &str { @@ -50,8 +46,6 @@ impl OPCODE { OPCODE::HashToField => "hash_to_field", OPCODE::EcdsaSecp256k1 => "ecdsa_secp256k1", OPCODE::FixedBaseScalarMul => "fixed_base_scalar_mul", - OPCODE::ToBits => "to_bits", - OPCODE::ToBytes => "to_bytes", } } pub fn lookup(op_name: &str) -> Option { @@ -64,8 +58,6 @@ impl OPCODE { "hash_to_field" => Some(OPCODE::HashToField), "ecdsa_secp256k1" => Some(OPCODE::EcdsaSecp256k1), "fixed_base_scalar_mul" => Some(OPCODE::FixedBaseScalarMul), - "to_bits" => Some(OPCODE::ToBits), - "to_bytes" => Some(OPCODE::ToBytes), _ => None, } } @@ -118,16 +110,6 @@ impl OPCODE { input_size: InputSize::Fixed(1), output_size: OutputSize(2), }, - OPCODE::ToBits => GadgetDefinition { - name: self.name().into(), - input_size: InputSize::Fixed(2), - output_size: OutputSize(1), - }, - OPCODE::ToBytes => GadgetDefinition { - name: self.name().into(), - input_size: InputSize::Fixed(2), - output_size: OutputSize(1), - }, } } } diff --git a/crates/acvm/src/lib.rs b/crates/acvm/src/lib.rs index cd561f623a2..598f9e67e06 100644 --- a/crates/acvm/src/lib.rs +++ b/crates/acvm/src/lib.rs @@ -133,61 +133,43 @@ pub trait PartialWitnessGenerator { _ => true, } } - Directive::Truncate { a, b, c, bit_size } => match initial_witness.get(a) { - Some(val_a) => { - let pow: BigUint = BigUint::one() << bit_size; - - let int_a = BigUint::from_bytes_be(&val_a.to_bytes()); - let int_b: BigUint = &int_a % &pow; - let int_c: BigUint = (&int_a - &int_b) / &pow; - - initial_witness.insert( - *b, - FieldElement::from_be_bytes_reduce(&int_b.to_bytes_be()), - ); - initial_witness.insert( - *c, - FieldElement::from_be_bytes_reduce(&int_c.to_bytes_be()), - ); - false - } - _ => true, - }, - Directive::Split { a, b, bit_size } => { + Directive::Truncate { a, b, c, bit_size } => { match Self::get_value(a, initial_witness) { Some(val_a) => { - let a_big = BigUint::from_bytes_be(&val_a.to_bytes()); - for i in 0..*bit_size { - let j = i as usize; - let v = if a_big.bit(j as u64) { - FieldElement::one() - } else { - FieldElement::zero() - }; - match initial_witness.entry(b[j]) { - std::collections::btree_map::Entry::Vacant(e) => { - e.insert(v); - } - std::collections::btree_map::Entry::Occupied(e) => { - if e.get() != &v { - return GateResolution::UnsatisfiedConstrain; - } - } - } - } + let pow: BigUint = BigUint::one() << bit_size; + + let int_a = BigUint::from_bytes_be(&val_a.to_bytes()); + let int_b: BigUint = &int_a % &pow; + let int_c: BigUint = (&int_a - &int_b) / &pow; + + initial_witness.insert( + *b, + FieldElement::from_be_bytes_reduce(&int_b.to_bytes_be()), + ); + initial_witness.insert( + *c, + FieldElement::from_be_bytes_reduce(&int_c.to_bytes_be()), + ); false } _ => true, } } - Directive::ToBytes { a, b, byte_size } => { + Directive::ToRadix { a, b, radix } => { match Self::get_value(a, initial_witness) { Some(val_a) => { - let mut a_bytes = val_a.to_bytes(); - a_bytes.reverse(); - for i in 0..*byte_size { + let a_big = BigUint::from_bytes_be(&val_a.to_bytes()); + let a_dec = a_big.to_radix_le(*radix); + if b.len() < a_dec.len() { + return GateResolution::UnsatisfiedConstrain; + } + for i in 0..b.len() { let i_usize = i as usize; - let v = FieldElement::from_be_bytes_reduce(&[a_bytes[i_usize]]); + let v = if i_usize < a_dec.len() { + FieldElement::from_be_bytes_reduce(&[a_dec[i_usize]]) + } else { + FieldElement::zero() + }; match initial_witness.entry(b[i_usize]) { std::collections::btree_map::Entry::Vacant(e) => { e.insert(v); diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index c9924b2ba06..1b4d126cb2a 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -1,6 +1,6 @@ +use super::builtin::{self, Opcode}; use super::mem::{ArrayId, MemArray, Memory}; use super::node::{BinaryOp, Instruction, ObjectType, Operation}; -use acvm::acir::OPCODE; use acvm::FieldElement; use super::node::NodeId; @@ -46,8 +46,28 @@ impl InternalVar { None } - pub fn get_or_generate_witness(&self, evaluator: &mut Evaluator) -> Witness { - self.witness.unwrap_or_else(|| generate_witness(self, evaluator)) + pub fn generate_witness(&mut self, evaluator: &mut Evaluator) -> Witness { + if let Some(witness) = self.witness { + return witness; + } + + if self.expression.is_const() { + todo!("Panic"); + } + let witness = InternalVar::expression_to_witness(self.expression.clone(), evaluator); + self.witness = Some(witness); + witness + } + + pub fn expression_to_witness(expr: Expression, evaluator: &mut Evaluator) -> Witness { + if expr.mul_terms.is_empty() + && expr.linear_combinations.len() == 1 + && expr.q_c == FieldElement::zero() + && expr.linear_combinations[0].0 == FieldElement::one() + { + return expr.linear_combinations[0].1; + } + evaluator.create_intermediate_variable(expr) } } @@ -314,13 +334,8 @@ impl Acir { } BinaryOp::Ule => { let size = ctx[binary.lhs].get_type().bits(); - let w = evaluate_cmp(&r_c, &l_c, size, false, evaluator); - Expression { - mul_terms: Vec::new(), - linear_combinations: vec![(-FieldElement::one(), w)], - q_c: FieldElement::one(), - } - .into() + let e = evaluate_cmp(&r_c, &l_c, size, false, evaluator); + subtract(&Expression::one(), FieldElement::one(), &e).into() } BinaryOp::Slt => { let s = ctx[binary.lhs].get_type().bits(); @@ -328,13 +343,8 @@ impl Acir { } BinaryOp::Sle => { let s = ctx[binary.lhs].get_type().bits(); - let w = evaluate_cmp(&r_c, &l_c, s, true, evaluator); - Expression { - mul_terms: Vec::new(), - linear_combinations: vec![(-FieldElement::one(), w)], - q_c: FieldElement::one(), - } - .into() + let e = evaluate_cmp(&r_c, &l_c, s, true, evaluator); + subtract(&Expression::one(), FieldElement::one(), &e).into() } BinaryOp::Lt => unimplemented!( "Field comparison is not implemented yet, try to cast arguments to integer type" @@ -404,7 +414,7 @@ impl Acir { if array_a.len == array_b.len { let mut x = InternalVar::from(self.zero_eq_array_sum(array_a, array_b, evaluator)); - x.witness = Some(generate_witness(&x, evaluator)); + x.generate_witness(evaluator); from_witness(evaluate_zero_equality(&x, evaluator)) } else { //If length are different, then the arrays are different @@ -420,7 +430,8 @@ impl Acir { } let mut x = InternalVar::from(subtract(&l_c.expression, FieldElement::one(), &r_c.expression)); - x.witness = Some(generate_witness(&x, evaluator)); + dbg!(&x); + x.generate_witness(evaluator); from_witness(evaluate_zero_equality(&x, evaluator)) } } @@ -525,9 +536,9 @@ impl Acir { } _ => { if self.arith_cache.contains_key(a) { - let var = self.arith_cache[a].clone(); + let mut var = self.arith_cache[a].clone(); let witness = - var.witness.unwrap_or_else(|| generate_witness(&var, evaluator)); + var.witness.unwrap_or_else(|| var.generate_witness(evaluator)); inputs.push(GadgetInput { witness, num_bits: l_obj.size_in_bits() }); } else { dbg!(&l_obj); @@ -542,7 +553,7 @@ impl Acir { pub fn evaluate_opcode( &mut self, instruction_id: NodeId, - opcode: OPCODE, + opcode: builtin::Opcode, args: &[NodeId], res_type: ObjectType, ctx: &SsaContext, @@ -550,29 +561,30 @@ impl Acir { ) -> Expression { let outputs; match opcode { - OPCODE::ToBits => { + Opcode::ToBits => { let bit_size = ctx.get_as_constant(args[1]).unwrap().to_u128() as u32; let l_c = self.substitute(args[0], evaluator, ctx); - outputs = split(&l_c, bit_size, evaluator); + outputs = to_radix_base(&l_c, 2, bit_size, evaluator); if let node::ObjectType::Pointer(a) = res_type { self.map_array(a, &outputs, ctx); } } - OPCODE::ToBytes => { - let byte_size = ctx.get_as_constant(args[1]).unwrap().to_u128() as u32; + Opcode::ToRadix => { + let radix = ctx.get_as_constant(args[1]).unwrap().to_u128() as u32; + let limb_size = ctx.get_as_constant(args[2]).unwrap().to_u128() as u32; let l_c = self.substitute(args[0], evaluator, ctx); - outputs = to_bytes(&l_c, byte_size, evaluator); + outputs = to_radix_base(&l_c, radix, limb_size, evaluator); //TODO !! if let node::ObjectType::Pointer(a) = res_type { self.map_array(a, &outputs, ctx); } } - _ => { + Opcode::LowLevel(op) => { let inputs = self.prepare_inputs(args, ctx, evaluator); - let output_count = opcode.definition().output_size.0 as u32; + let output_count = op.definition().output_size.0 as u32; outputs = self.prepare_outputs(instruction_id, output_count, ctx, evaluator); let call_gate = GadgetCall { - name: opcode, + name: op, inputs, //witness + bit size outputs: outputs.clone(), //witness }; @@ -625,52 +637,86 @@ pub fn evaluate_cmp( bit_size: u32, signed: bool, evaluator: &mut Evaluator, -) -> Witness { - //TODO use quad_decomposition gate for barretenberg - let mut sub_expr = subtract(&lhs.expression, FieldElement::one(), &rhs.expression); - let two_pow = BigUint::one() << (bit_size + 1); - sub_expr.q_c += FieldElement::from_be_bytes_reduce(&two_pow.to_bytes_be()); - let bits = split(&sub_expr.into(), bit_size + 2, evaluator); +) -> Expression { if signed { - bits[(bit_size - 1) as usize] + //TODO use range_constraints instead of bit decomposition, like in the unsigned case + let mut sub_expr = subtract(&lhs.expression, FieldElement::one(), &rhs.expression); + let two_pow = BigUint::one() << (bit_size + 1); + sub_expr.q_c += FieldElement::from_be_bytes_reduce(&two_pow.to_bytes_be()); + let bits = to_radix_base(&sub_expr.into(), 2, bit_size + 2, evaluator); + from_witness(bits[(bit_size - 1) as usize]) } else { - bits[(bit_size) as usize] + let is_greater = + from_witness(bound_check(&lhs.expression, &rhs.expression, bit_size, evaluator)); + subtract(&Expression::one(), FieldElement::one(), &is_greater) } } -//Decomposition into a list of unsigned integers based on a base2 radix (bits - u1, bytes - u8, etc) -pub fn to_base2_decomposition( - pow: u32, +const fn num_bits() -> usize { + std::mem::size_of::() * 8 +} +pub fn bit_size_u32(a: u32) -> u32 where { + num_bits::() as u32 - a.leading_zeros() +} + +pub fn bit_size_u128(a: u128) -> u32 where { + num_bits::() as u32 - a.leading_zeros() +} + +//Decomposition into b-base: \sum ai b^i, where 0<=ai (Vec, Expression) { let mut digits = Expression::default(); - let mut two_pow = FieldElement::one(); - let base: i32 = 2; - let radix_base = base.pow(pow); - let shift = FieldElement::from(radix_base as i128); + let mut radix_pow = FieldElement::one(); + + let shift = FieldElement::from(radix as i128); let mut result = Vec::new(); + let bit_size = bit_size_u32(radix); for _ in 0..num_limbs { - let radix_witness = evaluator.add_witness_to_cs(); - result.push(radix_witness); - let radix_expr = from_witness(radix_witness); - digits = add(&digits, two_pow, &radix_expr); - two_pow = two_pow.mul(shift); - - range_constraint(radix_witness, pow, evaluator).unwrap(); + let limb_witness = evaluator.add_witness_to_cs(); + result.push(limb_witness); + let limb_expr = from_witness(limb_witness); + digits = add(&digits, radix_pow, &limb_expr); + radix_pow = radix_pow.mul(shift); + + if 1_u128 << (bit_size - 1) != radix as u128 { + range_constraint(limb_witness, bit_size, evaluator).unwrap(); + } + bound_constraint_with_offset( + &from_witness(limb_witness), + &Expression::from_field(shift), + &Expression::one(), + bit_size, + evaluator, + ); } (result, digits) } -//Performs byte decomposition -pub fn to_bytes(lhs: &InternalVar, byte_size: u32, evaluator: &mut Evaluator) -> Vec { - assert!(byte_size < FieldElement::max_num_bytes()); - let (result, bytes) = to_base2_decomposition(8, byte_size, evaluator); - evaluator.gates.push(Gate::Directive(Directive::ToBytes { +//decompose lhs onto radix-base with limb_size limbs +pub fn to_radix_base( + lhs: &InternalVar, + radix: u32, + limb_size: u32, + evaluator: &mut Evaluator, +) -> Vec { + // ensure there is no overflow + let mut max = BigUint::from(radix); + max = max.pow(limb_size) - BigUint::one(); + assert!(max < FieldElement::modulus()); + + let (result, bytes) = to_radix(radix, limb_size, evaluator); + evaluator.gates.push(Gate::Directive(Directive::ToRadix { a: lhs.expression.clone(), b: result.clone(), - byte_size, + radix, })); evaluator.gates.push(Gate::Arithmetic(subtract(&lhs.expression, FieldElement::one(), &bytes))); @@ -678,28 +724,13 @@ pub fn to_bytes(lhs: &InternalVar, byte_size: u32, evaluator: &mut Evaluator) -> result } -//Performs bit decomposition -pub fn split(lhs: &InternalVar, bit_size: u32, evaluator: &mut Evaluator) -> Vec { - assert!(bit_size < FieldElement::max_num_bits()); - let (result, bits) = to_base2_decomposition(1, bit_size, evaluator); - evaluator.gates.push(Gate::Directive(Directive::Split { - a: lhs.expression.clone(), - b: result.clone(), - bit_size, - })); - - evaluator.gates.push(Gate::Arithmetic(subtract(&lhs.expression, FieldElement::one(), &bits))); - - result -} - fn const_and( var: InternalVar, b: FieldElement, bit_size: u32, evaluator: &mut Evaluator, ) -> Expression { - let a_bits = split(&var, bit_size, evaluator); + let a_bits = to_radix_base(&var, 2, bit_size, evaluator); let mut result = Expression::default(); let mut k = FieldElement::one(); let two = FieldElement::from(2_i128); @@ -718,7 +749,7 @@ fn const_xor( bit_size: u32, evaluator: &mut Evaluator, ) -> Expression { - let a_bits = split(&var, bit_size, evaluator); + let a_bits = to_radix_base(&var, 2, bit_size, evaluator); let mut result = Expression::default(); let mut k = FieldElement::one(); let two = FieldElement::from(2_i128); @@ -747,7 +778,7 @@ fn const_or( q_c: (l_c.to_u128() | b.to_u128()).into(), }; } - let a_bits = split(&var, bit_size, evaluator); + let a_bits = to_radix_base(&var, 2, bit_size, evaluator); let mut result = Expression::default(); let mut k = FieldElement::one(); let two = FieldElement::from(2_i128); @@ -765,8 +796,8 @@ fn const_or( } pub fn evaluate_and( - lhs: InternalVar, - rhs: InternalVar, + mut lhs: InternalVar, + mut rhs: InternalVar, bit_size: u32, evaluator: &mut Evaluator, ) -> Expression { @@ -777,8 +808,8 @@ pub fn evaluate_and( return const_and(rhs, l_c, bit_size, evaluator); } - let a_witness = generate_witness(&lhs, evaluator); - let b_witness = generate_witness(&rhs, evaluator); + let a_witness = lhs.generate_witness(evaluator); + let b_witness = rhs.generate_witness(evaluator); //TODO checks the cost of the gate vs bit_size (cf. #164) if bit_size == 1 { return Expression { @@ -800,8 +831,8 @@ pub fn evaluate_and( } pub fn evaluate_xor( - lhs: InternalVar, - rhs: InternalVar, + mut lhs: InternalVar, + mut rhs: InternalVar, bit_size: u32, evaluator: &mut Evaluator, ) -> Expression { @@ -819,8 +850,8 @@ pub fn evaluate_xor( return subtract(&sum, FieldElement::from(2_i128), &mul); } let result = evaluator.add_witness_to_cs(); - let a_witness = generate_witness(&lhs, evaluator); - let b_witness = generate_witness(&rhs, evaluator); + let a_witness = lhs.generate_witness(evaluator); + let b_witness = rhs.generate_witness(evaluator); let bsize = if bit_size % 2 == 1 { bit_size + 1 } else { bit_size }; assert!(bsize < FieldElement::max_num_bits() - 1); evaluator.gates.push(Gate::Xor(acvm::acir::circuit::gate::XorGate { @@ -851,8 +882,8 @@ pub fn evaluate_or( return subtract(&sum, FieldElement::one(), &mul); } - let lhs_bits = split(&lhs, bit_size, evaluator); - let rhs_bits = split(&rhs, bit_size, evaluator); + let lhs_bits = to_radix_base(&lhs, 2, bit_size, evaluator); + let rhs_bits = to_radix_base(&rhs, 2, bit_size, evaluator); let mut result = Expression::default(); let mut k = FieldElement::one(); let two = FieldElement::from(2_i128); @@ -881,17 +912,8 @@ pub fn evaluate_truncate( return InternalVar::from(FieldElement::from_be_bytes_reduce(&a_big.to_bytes_be())); } //1. Generate witnesses a,b,c - //TODO: we should truncate the arithmetic expression (and so avoid having to create a witness) - // if lhs is not a witness, but this requires a new truncate directive...TODO - let a_witness = generate_witness(&lhs, evaluator); let b_witness = evaluator.add_witness_to_cs(); let c_witness = evaluator.add_witness_to_cs(); - evaluator.gates.push(Gate::Directive(Directive::Truncate { - a: a_witness, - b: b_witness, - c: c_witness, - bit_size: rhs, - })); range_constraint(b_witness, rhs, evaluator).unwrap_or_else(|err| { dbg!(err); @@ -906,27 +928,17 @@ pub fn evaluate_truncate( let b_arith = from_witness(b_witness); let c_arith = from_witness(c_witness); let res = add(&b_arith, f, &c_arith); //b+2^Nc - let a = &Expression::from(Linear::from_witness(a_witness)); - let my_constraint = add(&res, -FieldElement::one(), a); + let my_constraint = add(&res, -FieldElement::one(), &lhs.expression); + evaluator.gates.push(Gate::Directive(Directive::Truncate { + a: lhs.expression, + b: b_witness, + c: c_witness, + bit_size: rhs, + })); evaluator.gates.push(Gate::Arithmetic(my_constraint)); InternalVar::from(b_witness) } -pub fn generate_witness(lhs: &InternalVar, evaluator: &mut Evaluator) -> Witness { - if let Some(witness) = lhs.witness { - return witness; - } - - if lhs.expression.is_const() { - todo!("Panic"); - } - if lhs.expression.mul_terms.is_empty() && lhs.expression.linear_combinations.len() == 1 { - //TODO check if this case can be optimised - } - //TODO set lhs.witness = the next line - evaluator.create_intermediate_variable(lhs.expression.clone()) -} - pub fn evaluate_udiv( lhs: &InternalVar, rhs: &InternalVar, @@ -947,7 +959,14 @@ pub fn evaluate_udiv( //r Wit } /// Creates a new witness and constrains it to be the inverse of x -fn evaluate_inverse(x: InternalVar, predicate: &InternalVar, evaluator: &mut Evaluator) -> Witness { +fn evaluate_inverse( + mut x: InternalVar, + predicate: &InternalVar, + evaluator: &mut Evaluator, +) -> Witness { // Create a fresh witness - n.b we could check if x is constant or not let inverse_witness = evaluator.add_witness_to_cs(); let inverse_expr = from_witness(inverse_witness); - let x_witness = x.get_or_generate_witness(evaluator); //TODO avoid creating witnesses here. + let x_witness = x.generate_witness(evaluator); //TODO avoid creating witnesses here. evaluator .gates .push(Gate::Directive(Directive::Invert { x: x_witness, result: inverse_witness })); @@ -1213,6 +1236,10 @@ pub fn boolean(witness: Witness) -> Expression { } } +pub fn boolean_expr(expr: &Expression, evaluator: &mut Evaluator) -> Expression { + subtract(&mul_with_witness(evaluator, expr, expr), FieldElement::one(), expr) +} + //contrain witness a to be num_bits-size integer, i.e between 0 and 2^num_bits-1 pub fn range_constraint( witness: Witness, @@ -1260,6 +1287,34 @@ pub fn range_constraint( Ok(()) } +// returns a witness of a>=b +fn bound_check( + a: &Expression, + b: &Expression, + max_bits: u32, + evaluator: &mut Evaluator, +) -> Witness { + assert!(max_bits + 1 < FieldElement::max_num_bits()); //n.b what we really need is 2^{max_bits+1}

b, b-a = p+b-a > p-2^bits >= 2^bits (if log(p) >= bits + 1) // n.b: we do NOT check here that a and b are indeed 'bits' size // a < b <=> a+1<=b -fn bound_check_with_offset( +fn bound_constraint_with_offset( a: &Expression, b: &Expression, offset: &Expression, @@ -1281,10 +1336,52 @@ fn bound_check_with_offset( bits < FieldElement::max_num_bits(), "range check with bit size of the prime field is not implemented yet" ); - let aof = add(a, FieldElement::one(), offset); + + let mut aof = add(a, FieldElement::one(), offset); + + if b.is_const() && b.q_c.fits_in_u128() { + let f = if *offset == Expression::one() { + aof = a.clone(); + assert!(b.q_c.to_u128() >= 1); + b.q_c.to_u128() - 1 + } else { + b.q_c.to_u128() + }; + + if f < 3 { + match f { + 0 => evaluator.gates.push(Gate::Arithmetic(aof)), + 1 => { + let expr = boolean_expr(&aof, evaluator); + evaluator.gates.push(Gate::Arithmetic(expr)) + } + 2 => { + let y = InternalVar::expression_to_witness( + boolean_expr(&aof, evaluator), + evaluator, + ); + let two = FieldElement::from(2_i128); + let y_expr = from_witness(y); + let eee = subtract(&mul_with_witness(evaluator, &aof, &y_expr), two, &y_expr); + evaluator.gates.push(Gate::Arithmetic(eee)); + } + _ => unreachable!(), + } + return; + } + let bit_size = bit_size_u128(f); + if bit_size < 128 { + let r = (1_u128 << bit_size) - f - 1; + assert!(bits + bit_size < FieldElement::max_num_bits()); //we need to ensure a+r does not overflow + let aor = add(&aof, FieldElement::from(r), &Expression::one()); + let witness = InternalVar::expression_to_witness(aor, evaluator); + range_constraint(witness, bit_size, evaluator).unwrap(); + return; + } + } + let sub_expression = subtract(b, FieldElement::one(), &aof); //b-(a+offset) - let w = evaluator.add_witness_to_cs(); //range_check requires a witness - TODO: it should be created inside range_constraint(..) - evaluator.gates.push(Gate::Arithmetic(&sub_expression - &Expression::from(&w))); + let w = InternalVar::expression_to_witness(sub_expression, evaluator); range_constraint(w, bits, evaluator).unwrap_or_else(|err| { dbg!(err); }); diff --git a/crates/noirc_evaluator/src/ssa/builtin.rs b/crates/noirc_evaluator/src/ssa/builtin.rs new file mode 100644 index 00000000000..8eb89e5364c --- /dev/null +++ b/crates/noirc_evaluator/src/ssa/builtin.rs @@ -0,0 +1,75 @@ +use acvm::{acir::OPCODE, FieldElement}; +use num_bigint::BigUint; +use num_traits::{One, Zero}; + +use super::node::ObjectType; + +#[derive(Clone, Debug, Hash, Copy, PartialEq, Eq)] +pub enum Opcode { + LowLevel(OPCODE), + ToBits, + ToRadix, +} + +impl std::fmt::Display for Opcode { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.name()) + } +} + +impl Opcode { + pub fn lookup(op_name: &str) -> Option { + match op_name { + "to_bits" => Some(Opcode::ToBits), + "to_radix" => Some(Opcode::ToRadix), + _ => OPCODE::lookup(op_name).map(Opcode::LowLevel), + } + } + + pub fn name(&self) -> &str { + match self { + Opcode::LowLevel(op) => op.name(), + Opcode::ToBits => "to_bits", + Opcode::ToRadix => "to_radix", + } + } + + pub fn get_max_value(&self) -> BigUint { + match self { + Opcode::LowLevel(op) => { + match op { + OPCODE::SHA256 + | OPCODE::Blake2s + | OPCODE::Pedersen + | OPCODE::FixedBaseScalarMul => BigUint::zero(), //pointers do not overflow + OPCODE::SchnorrVerify | OPCODE::EcdsaSecp256k1 | OPCODE::MerkleMembership => { + BigUint::one() + } //verify returns 0 or 1 + _ => todo!("max value must be implemented for opcode {} ", op), + } + } + Opcode::ToBits | Opcode::ToRadix => BigUint::zero(), //pointers do not overflow + } + } + + //Returns the number of elements and their type, of the output result corresponding to the OPCODE function. + pub fn get_result_type(&self) -> (u32, ObjectType) { + match self { + Opcode::LowLevel(op) => { + match op { + OPCODE::AES => (0, ObjectType::NotAnObject), //Not implemented + OPCODE::SHA256 => (32, ObjectType::Unsigned(8)), + OPCODE::Blake2s => (32, ObjectType::Unsigned(8)), + OPCODE::HashToField => (1, ObjectType::NativeField), + OPCODE::MerkleMembership => (1, ObjectType::NativeField), //or bool? + OPCODE::SchnorrVerify => (1, ObjectType::NativeField), //or bool? + OPCODE::Pedersen => (2, ObjectType::NativeField), + OPCODE::EcdsaSecp256k1 => (1, ObjectType::NativeField), //field? + OPCODE::FixedBaseScalarMul => (2, ObjectType::NativeField), + } + } + Opcode::ToBits => (FieldElement::max_num_bits(), ObjectType::Boolean), + Opcode::ToRadix => (FieldElement::max_num_bits(), ObjectType::NativeField), + } + } +} diff --git a/crates/noirc_evaluator/src/ssa/code_gen.rs b/crates/noirc_evaluator/src/ssa/code_gen.rs index 857439445ff..2ff06063000 100644 --- a/crates/noirc_evaluator/src/ssa/code_gen.rs +++ b/crates/noirc_evaluator/src/ssa/code_gen.rs @@ -11,7 +11,6 @@ use super::super::errors::RuntimeError; use crate::errors; use crate::ssa::block::BlockType; use crate::ssa::function; -use acvm::acir::OPCODE; use acvm::FieldElement; use iter_extended::vecmap; use noirc_frontend::monomorphisation::ast::*; @@ -606,7 +605,7 @@ impl IRGenerator { } fn codegen_lowlevel(&mut self, call: &CallLowLevel) -> Result { - match OPCODE::lookup(&call.opcode) { + match super::builtin::Opcode::lookup(&call.opcode) { Some(func) => self.call_low_level(func, call), None => { unreachable!( diff --git a/crates/noirc_evaluator/src/ssa/function.rs b/crates/noirc_evaluator/src/ssa/function.rs index 6e36eccc36b..fcfb15bea55 100644 --- a/crates/noirc_evaluator/src/ssa/function.rs +++ b/crates/noirc_evaluator/src/ssa/function.rs @@ -2,10 +2,9 @@ use std::collections::{HashMap, VecDeque}; use crate::errors::RuntimeError; use crate::ssa::node::Opcode; -use acvm::acir::OPCODE; -use acvm::FieldElement; use noirc_frontend::monomorphisation::ast::{self, Call, DefinitionId, FuncId, Type}; +use super::builtin; use super::conditional::{AssumptionId, DecisionTree, TreeBuilder}; use super::node::Node; use super::{ @@ -142,23 +141,6 @@ impl SSAFunction { } } -//Returns the number of elements and their type, of the output result corresponding to the OPCODE function. -pub fn get_result_type(op: OPCODE) -> (u32, ObjectType) { - match op { - OPCODE::AES => (0, ObjectType::NotAnObject), //Not implemented - OPCODE::SHA256 => (32, ObjectType::Unsigned(8)), - OPCODE::Blake2s => (32, ObjectType::Unsigned(8)), - OPCODE::HashToField => (1, ObjectType::NativeField), - OPCODE::MerkleMembership => (1, ObjectType::NativeField), //or bool? - OPCODE::SchnorrVerify => (1, ObjectType::NativeField), //or bool? - OPCODE::Pedersen => (2, ObjectType::NativeField), - OPCODE::EcdsaSecp256k1 => (1, ObjectType::NativeField), //field? - OPCODE::FixedBaseScalarMul => (2, ObjectType::NativeField), - OPCODE::ToBits => (FieldElement::max_num_bits(), ObjectType::Boolean), - OPCODE::ToBytes => (FieldElement::max_num_bytes(), ObjectType::Boolean), - } -} - impl IRGenerator { pub fn create_function( &mut self, @@ -278,7 +260,7 @@ impl IRGenerator { //Lowlevel functions with no more than 2 arguments pub fn call_low_level( &mut self, - op: OPCODE, + op: builtin::Opcode, call: &ast::CallLowLevel, ) -> Result { //Inputs @@ -294,7 +276,7 @@ impl IRGenerator { //REM: we do not check that the nb of inputs correspond to the function signature, it is done in the frontend //Output: - let (len, elem_type) = get_result_type(op); + let (len, elem_type) = op.get_result_type(); let result_type = if len > 1 { //We create an array that will contain the result and set the res_type to point to that array let result_index = self.new_array(&format!("{}_result", op), elem_type, len, None).1; diff --git a/crates/noirc_evaluator/src/ssa/integer.rs b/crates/noirc_evaluator/src/ssa/integer.rs index 06266c183fb..3efd00e8047 100644 --- a/crates/noirc_evaluator/src/ssa/integer.rs +++ b/crates/noirc_evaluator/src/ssa/integer.rs @@ -8,7 +8,7 @@ use super::{ node::{self, BinaryOp, Instruction, Mark, Node, NodeId, NodeObj, ObjectType, Operation}, optim, }; -use acvm::{acir::OPCODE, FieldElement}; +use acvm::FieldElement; use iter_extended::vecmap; use num_bigint::BigUint; use num_traits::{One, Zero}; @@ -481,20 +481,7 @@ fn get_max_value(ins: &Instruction, max_map: &mut HashMap) -> B Operation::Result { .. } => { unreachable!("Functions must have been inlined before checking for overflows") } - Operation::Intrinsic(opcode, _) => { - match opcode { - OPCODE::SHA256 - | OPCODE::Blake2s - | OPCODE::Pedersen - | OPCODE::FixedBaseScalarMul - | OPCODE::ToBits - | OPCODE::ToBytes => BigUint::zero(), //pointers do not overflow - OPCODE::SchnorrVerify - | OPCODE::EcdsaSecp256k1 - | acvm::acir::OPCODE::MerkleMembership => BigUint::one(), //verify returns 0 or 1 - _ => todo!("max value must be implemented for opcode {} ", opcode), - } - } + Operation::Intrinsic(opcode, _) => opcode.get_max_value(), }; if ins.res_type == ObjectType::NativeField { diff --git a/crates/noirc_evaluator/src/ssa/mod.rs b/crates/noirc_evaluator/src/ssa/mod.rs index ff6cb088052..8c464fe9a6d 100644 --- a/crates/noirc_evaluator/src/ssa/mod.rs +++ b/crates/noirc_evaluator/src/ssa/mod.rs @@ -1,6 +1,7 @@ pub mod acir_gen; pub mod anchor; pub mod block; +pub mod builtin; pub mod code_gen; pub mod conditional; pub mod context; diff --git a/crates/noirc_evaluator/src/ssa/node.rs b/crates/noirc_evaluator/src/ssa/node.rs index c3caccbfd3c..ca02f944434 100644 --- a/crates/noirc_evaluator/src/ssa/node.rs +++ b/crates/noirc_evaluator/src/ssa/node.rs @@ -2,7 +2,6 @@ use std::convert::TryInto; use crate::errors::{RuntimeError, RuntimeErrorKind}; use acvm::acir::native_types::Witness; -use acvm::acir::OPCODE; use acvm::FieldElement; use arena; use iter_extended::vecmap; @@ -15,9 +14,9 @@ use std::ops::{Add, Mul, Sub}; use std::ops::{BitAnd, BitOr, BitXor, Shl, Shr}; use super::block::BlockId; -use super::conditional; use super::context::SsaContext; use super::mem::ArrayId; +use super::{builtin, conditional}; pub trait Node: std::fmt::Display { fn get_type(&self) -> ObjectType; @@ -548,7 +547,7 @@ pub enum Operation { value: NodeId, }, - Intrinsic(OPCODE, Vec), //Custom implementation of usefull primitives which are more performant with Aztec backend + Intrinsic(builtin::Opcode, Vec), //Custom implementation of usefull primitives which are more performant with Aztec backend Nop, // no op } @@ -599,8 +598,8 @@ pub enum Opcode { //memory Load(ArrayId), Store(ArrayId), - Intrinsic(OPCODE), //Custom implementation of usefull primitives which are more performant with Aztec backend - Nop, // no op + Intrinsic(builtin::Opcode), //Custom implementation of usefull primitives which are more performant with Aztec backend + Nop, // no op } #[derive(Debug, PartialEq, Eq, Hash, Clone)] diff --git a/crates/noirc_evaluator/src/ssa/optim.rs b/crates/noirc_evaluator/src/ssa/optim.rs index 7a6d60bf29f..07e6b481a2d 100644 --- a/crates/noirc_evaluator/src/ssa/optim.rs +++ b/crates/noirc_evaluator/src/ssa/optim.rs @@ -5,6 +5,7 @@ use crate::errors::RuntimeError; use super::{ anchor::{Anchor, CseAction}, block::BlockId, + builtin, context::SsaContext, node::{Binary, BinaryOp, Instruction, Mark, Node, NodeEval, NodeId, ObjectType, Operation}, }; @@ -61,13 +62,13 @@ pub fn simplify(ctx: &mut SsaContext, ins: &mut Instruction) -> Result<(), Runti fn evaluate_intrinsic( ctx: &mut SsaContext, - op: acvm::acir::OPCODE, + op: builtin::Opcode, args: Vec, res_type: &ObjectType, block_id: BlockId, ) -> Vec { match op { - acvm::acir::OPCODE::ToBits => { + builtin::Opcode::ToBits => { let bit_count = args[1] as u32; let mut result = Vec::new(); diff --git a/noir_stdlib/src/lib.nr b/noir_stdlib/src/lib.nr index 740c7a14344..828a8f39ee4 100644 --- a/noir_stdlib/src/lib.nr +++ b/noir_stdlib/src/lib.nr @@ -8,11 +8,19 @@ mod sha256; mod sha512; -#[builtin(to_bits)] -fn to_bits(_x : Field, _bit_size: u32) -> [u1; 256] {} + #[builtin(to_bits)] +fn to_bits(_x : Field, _bit_size: u32) -> [u1] {} + +fn to_bytes(x : Field, byte_size: u32) -> [u8] { + to_radix(x, 256, byte_size) +} + +#[builtin(to_radix)] +//decompose _x into a _result_len vector over the _radix basis +//_radix must be less than 256 +fn to_radix(_x : Field, _radix: u32, _result_len: u32) -> [u8] {} + -#[builtin(to_bytes)] -fn to_bytes(_x : Field, _byte_size: u32) -> [u8; 32] {} // Returns base^exponent. // ^ means to the power of and not xor From dccfc1a261415ecee2c58f81adf937ced38cf146 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 19 Dec 2022 14:27:27 +0000 Subject: [PATCH 02/11] fix clippy --- crates/acir/src/circuit/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/acir/src/circuit/mod.rs b/crates/acir/src/circuit/mod.rs index 73846863d2e..38b4d14d33d 100644 --- a/crates/acir/src/circuit/mod.rs +++ b/crates/acir/src/circuit/mod.rs @@ -45,7 +45,7 @@ pub struct PublicInputs(pub Vec); impl PublicInputs { /// Returns the witness index of each public input pub fn indices(&self) -> Vec { - self.0.iter().map(|witness| witness.witness_index() as u32).collect() + self.0.iter().map(|witness| witness.witness_index()).collect() } pub fn contains(&self, index: usize) -> bool { From d69244204168188e396b652651d64ee0727c926b Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 19 Dec 2022 15:08:27 +0000 Subject: [PATCH 03/11] clippy fix --- crates/acvm/src/lib.rs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/crates/acvm/src/lib.rs b/crates/acvm/src/lib.rs index 598f9e67e06..32718372703 100644 --- a/crates/acvm/src/lib.rs +++ b/crates/acvm/src/lib.rs @@ -164,13 +164,12 @@ pub trait PartialWitnessGenerator { return GateResolution::UnsatisfiedConstrain; } for i in 0..b.len() { - let i_usize = i as usize; - let v = if i_usize < a_dec.len() { - FieldElement::from_be_bytes_reduce(&[a_dec[i_usize]]) + let v = if i < a_dec.len() { + FieldElement::from_be_bytes_reduce(&[a_dec[i]]) } else { FieldElement::zero() }; - match initial_witness.entry(b[i_usize]) { + match initial_witness.entry(b[i]) { std::collections::btree_map::Entry::Vacant(e) => { e.insert(v); } From 73b8a046579aa18c600e10dfaa9d259cb48d02cf Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 19 Dec 2022 16:14:59 +0000 Subject: [PATCH 04/11] clippy fix... --- crates/fm/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/fm/src/lib.rs b/crates/fm/src/lib.rs index d292548f356..b3f016a9dfc 100644 --- a/crates/fm/src/lib.rs +++ b/crates/fm/src/lib.rs @@ -85,7 +85,7 @@ impl FileManager { let dir = self.path(anchor).to_path_buf(); - candidate_files.push(dir.join(&format!("{}.{}", mod_name, FILE_EXTENSION))); + candidate_files.push(dir.join(format!("{}.{}", mod_name, FILE_EXTENSION))); for candidate in candidate_files.iter() { if let Some(file_id) = self.add_file(candidate, FileType::Normal) { From ee2537474cd168911429ac538e2da9cec8f876f4 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 19 Dec 2022 17:27:51 +0000 Subject: [PATCH 05/11] clippy fix.... --- crates/noirc_frontend/src/hir_def/types.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/noirc_frontend/src/hir_def/types.rs b/crates/noirc_frontend/src/hir_def/types.rs index 39f166768ca..b294e92f7eb 100644 --- a/crates/noirc_frontend/src/hir_def/types.rs +++ b/crates/noirc_frontend/src/hir_def/types.rs @@ -959,7 +959,7 @@ impl Type { Signedness::Signed => noirc_abi::Sign::Signed, }; - AbiType::Integer { sign, width: *bit_width as u32, visibility: fe_type } + AbiType::Integer { sign, width: *bit_width, visibility: fe_type } } Type::PolymorphicInteger(_, binding) => match &*binding.borrow() { TypeBinding::Bound(typ) => typ.as_abi_type(fe_type), From 64ed07da4a717dfbd02a90afe2bd631ff36170a5 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 19 Dec 2022 17:49:33 +0000 Subject: [PATCH 06/11] clippy fix..... --- crates/nargo/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/nargo/build.rs b/crates/nargo/build.rs index 45967cf719a..a6d8bfc6226 100644 --- a/crates/nargo/build.rs +++ b/crates/nargo/build.rs @@ -66,5 +66,5 @@ fn main() { let stdlib_src_dir = Path::new("../../noir_stdlib/"); rerun_if_stdlib_changes(stdlib_src_dir); let target = dirs::config_dir().unwrap().join("noir-lang").join("std"); - copy(stdlib_src_dir, &target).unwrap(); + copy(stdlib_src_dir, target).unwrap(); } From 23966630b73890eae4e73fd5c500e80c9aa6f7ce Mon Sep 17 00:00:00 2001 From: kevaundray Date: Wed, 21 Dec 2022 18:16:49 +0000 Subject: [PATCH 07/11] update backend commit --- crates/nargo/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/nargo/Cargo.toml b/crates/nargo/Cargo.toml index 9cf40face11..00c10513522 100644 --- a/crates/nargo/Cargo.toml +++ b/crates/nargo/Cargo.toml @@ -28,7 +28,7 @@ hex = "0.4.2" tempdir = "0.3.7" # Backends -aztec_backend = { optional = true, package = "barretenberg_static_lib", git = "https://github.com/noir-lang/aztec_backend", rev = "ef6cdb1e26bff1c8dd9aea811e97b008f7e6651e" } +aztec_backend = { optional = true, package = "barretenberg_static_lib", git = "https://github.com/noir-lang/aztec_backend", rev = "5daca1378dff32bbfff001378b36504b11c4e5da" } marlin_arkworks_backend = { optional = true, git = "https://github.com/noir-lang/marlin_arkworks_backend", rev = "601e24dcb5dcbe72e3de7a33879aaf84e171d541" } [features] From a4c5f33668d8927d777edb7cc431be1c9b97b61d Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 9 Jan 2023 13:28:08 +0000 Subject: [PATCH 08/11] Code review --- crates/noirc_evaluator/src/ssa/acir_gen.rs | 3 +-- crates/noirc_evaluator/src/ssa/node.rs | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 1b4d126cb2a..61a38a0e8a3 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -430,7 +430,6 @@ impl Acir { } let mut x = InternalVar::from(subtract(&l_c.expression, FieldElement::one(), &r_c.expression)); - dbg!(&x); x.generate_witness(evaluator); from_witness(evaluate_zero_equality(&x, evaluator)) } @@ -573,7 +572,7 @@ impl Acir { let radix = ctx.get_as_constant(args[1]).unwrap().to_u128() as u32; let limb_size = ctx.get_as_constant(args[2]).unwrap().to_u128() as u32; let l_c = self.substitute(args[0], evaluator, ctx); - outputs = to_radix_base(&l_c, radix, limb_size, evaluator); //TODO !! + outputs = to_radix_base(&l_c, radix, limb_size, evaluator); if let node::ObjectType::Pointer(a) = res_type { self.map_array(a, &outputs, ctx); } diff --git a/crates/noirc_evaluator/src/ssa/node.rs b/crates/noirc_evaluator/src/ssa/node.rs index ca02f944434..13f743fb25d 100644 --- a/crates/noirc_evaluator/src/ssa/node.rs +++ b/crates/noirc_evaluator/src/ssa/node.rs @@ -598,7 +598,7 @@ pub enum Opcode { //memory Load(ArrayId), Store(ArrayId), - Intrinsic(builtin::Opcode), //Custom implementation of usefull primitives which are more performant with Aztec backend + Intrinsic(builtin::Opcode), //Custom implementation of useful primitives Nop, // no op } From 6e185252d2563c1fc0ae3a837ce2a61fa2d81561 Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 9 Jan 2023 13:51:37 +0000 Subject: [PATCH 09/11] merge from master --- crates/noirc_evaluator/src/ssa/builtin.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/noirc_evaluator/src/ssa/builtin.rs b/crates/noirc_evaluator/src/ssa/builtin.rs index 8eb89e5364c..ef94800e90b 100644 --- a/crates/noirc_evaluator/src/ssa/builtin.rs +++ b/crates/noirc_evaluator/src/ssa/builtin.rs @@ -45,6 +45,7 @@ impl Opcode { OPCODE::SchnorrVerify | OPCODE::EcdsaSecp256k1 | OPCODE::MerkleMembership => { BigUint::one() } //verify returns 0 or 1 + OPCODE::HashToField => ins.res_type.max_size(), _ => todo!("max value must be implemented for opcode {} ", op), } } From ac4bf0a45457c2745a27aaea36a5a0d177a7d1eb Mon Sep 17 00:00:00 2001 From: guipublic Date: Mon, 9 Jan 2023 14:02:43 +0000 Subject: [PATCH 10/11] Fix the build --- crates/noirc_evaluator/src/ssa/builtin.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/noirc_evaluator/src/ssa/builtin.rs b/crates/noirc_evaluator/src/ssa/builtin.rs index ef94800e90b..41f7a7ca1d7 100644 --- a/crates/noirc_evaluator/src/ssa/builtin.rs +++ b/crates/noirc_evaluator/src/ssa/builtin.rs @@ -45,7 +45,7 @@ impl Opcode { OPCODE::SchnorrVerify | OPCODE::EcdsaSecp256k1 | OPCODE::MerkleMembership => { BigUint::one() } //verify returns 0 or 1 - OPCODE::HashToField => ins.res_type.max_size(), + OPCODE::HashToField => ObjectType::NativeField.max_size(), _ => todo!("max value must be implemented for opcode {} ", op), } } From fa0dcdf40d7dd2fc552b8b626e991681d4016e40 Mon Sep 17 00:00:00 2001 From: guipublic Date: Wed, 11 Jan 2023 11:19:59 +0000 Subject: [PATCH 11/11] try_range_constraint --- crates/noirc_evaluator/src/ssa/acir_gen.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa/acir_gen.rs b/crates/noirc_evaluator/src/ssa/acir_gen.rs index 03356cb189c..b3ed514b1b5 100644 --- a/crates/noirc_evaluator/src/ssa/acir_gen.rs +++ b/crates/noirc_evaluator/src/ssa/acir_gen.rs @@ -959,7 +959,7 @@ pub fn evaluate_udiv( //r