From 58baa9ef4245e63aafb3538cdd84e10996942cde Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 20 Jun 2023 14:03:33 +0000 Subject: [PATCH 01/11] Use brillig instead of inverse directive --- .../src/brillig/brillig_gen.rs | 1 + .../brillig/brillig_gen/brillig_directive.rs | 16 ++++++++++++ .../acir_gen/acir_ir/acir_variable.rs | 22 ++++++++++++++-- .../acir_gen/acir_ir/generated_acir.rs | 25 ++++++++----------- 4 files changed, 48 insertions(+), 16 deletions(-) create mode 100644 crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen.rs b/crates/noirc_evaluator/src/brillig/brillig_gen.rs index 00d26f6c7fd..84a353ce1ac 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen.rs @@ -1,4 +1,5 @@ pub(crate) mod brillig_block; +pub(crate) mod brillig_directive; pub(crate) mod brillig_fn; use crate::ssa_refactor::ir::{function::Function, post_order::PostOrder}; diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs new file mode 100644 index 00000000000..5d6dd838cc3 --- /dev/null +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -0,0 +1,16 @@ +use acvm::acir::brillig_vm::{BinaryFieldOp, Opcode as BrilligOpcode, RegisterIndex, Value}; + +/// Generates brillig bytecode which computes the inverse of its input if not null, and zero else. +pub(crate) fn directive_invert() -> Vec { + vec![ + BrilligOpcode::JumpIfNot { condition: RegisterIndex::from(0), location: 3 }, + BrilligOpcode::Const { destination: RegisterIndex::from(1), value: Value::from(1_usize) }, + BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::Div, + lhs: RegisterIndex::from(1), + rhs: RegisterIndex::from(0), + destination: RegisterIndex::from(0), + }, + BrilligOpcode::Stop, + ] +} diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs index 7b9ac3a720c..faa35421011 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/acir_variable.rs @@ -1,4 +1,5 @@ use super::{errors::AcirGenError, generated_acir::GeneratedAcir}; +use crate::brillig::brillig_gen::brillig_directive; use crate::ssa_refactor::acir_gen::AcirValue; use crate::ssa_refactor::ir::types::Type as SsaType; use crate::ssa_refactor::ir::{instruction::Endian, map::TwoWayMap, types::NumericType}; @@ -143,8 +144,16 @@ impl AcirContext { let result_var = self.add_data(AcirVarData::Const(constant.inverse())); return Ok(result_var); } - let inverted_witness = self.acir_ir.directive_inverse(&var_data.to_expression()); - let inverted_var = self.add_data(AcirVarData::Witness(inverted_witness)); + + // Compute the inverse with brillig code + let inverse_code = brillig_directive::directive_invert(); + let field_type = AcirType::NumericType(NumericType::NativeField); + let results = self.brillig( + inverse_code, + vec![AcirValue::Var(var, field_type.clone())], + vec![field_type], + ); + let inverted_var = Self::expect_one_var(results); let should_be_one = self.mul_var(inverted_var, var)?; self.assert_eq_one(should_be_one)?; @@ -158,6 +167,15 @@ impl AcirContext { self.assert_eq_var(var, one_var) } + // Returns the variable from the results, assuming it is the only result + fn expect_one_var(results: Vec) -> AcirVar { + assert_eq!(results.len(), 1); + match results[0] { + AcirValue::Var(var, _) => var, + AcirValue::Array(_) => unreachable!("ICE - expected a variable"), + } + } + /// Returns an `AcirVar` that is `1` if `lhs` equals `rhs` and /// 0 otherwise. pub(crate) fn eq_var(&mut self, lhs: AcirVar, rhs: AcirVar) -> Result { diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs index 34abedd9af3..00a19560cf1 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs @@ -1,5 +1,7 @@ //! `GeneratedAcir` is constructed as part of the `acir_gen` pass to accumulate all of the ACIR //! program as it is being converted from SSA form. +use crate::brillig::brillig_gen::brillig_directive; + use super::errors::AcirGenError; use acvm::acir::{ brillig_vm::Opcode as BrilligOpcode, @@ -467,28 +469,23 @@ impl GeneratedAcir { self.push_opcode(AcirOpcode::Directive(Directive::Log(LogInfo::WitnessOutput(witnesses)))); } - /// Adds an inversion directive. + /// Adds an inversion brillig opcode. /// - /// This directive will invert `expr` without applying constraints + /// This code will invert `expr` without applying constraints /// and return a `Witness` which may or may not be the result of /// inverting `expr`. /// /// Safety: It is the callers responsibility to ensure that the /// resulting `Witness` is constrained to be the inverse. - pub(crate) fn directive_inverse(&mut self, expr: &Expression) -> Witness { - // The inversion directive requires that - // the inputs be Witness, so we need this potential extra - // reduction constraint. - // Note: changing this in ACIR would allow us to remove it - let witness = self.get_or_create_witness(expr); - + pub(crate) fn brillig_inverse(&mut self, expr: &Expression) -> Witness { // Create the witness for the result let inverted_witness = self.next_witness_index(); - self.push_opcode(AcirOpcode::Directive(Directive::Invert { - x: witness, - result: inverted_witness, - })); + // Compute the inverse with brillig code + let inverse_code = brillig_directive::directive_invert(); + let inputs = vec![BrilligInputs::Single(expr.clone())]; + let outputs = vec![BrilligOutputs::Simple(inverted_witness)]; + self.brillig(inverse_code, inputs, outputs); inverted_witness } @@ -572,7 +569,7 @@ impl GeneratedAcir { // Call the inversion directive, since we do not apply a constraint // the prover can choose anything here. - let z = self.directive_inverse(&Expression::from(t_witness)); + let z = self.brillig_inverse(&Expression::from(t_witness)); let y = self.next_witness_index(); From 30ec7e6cf14ac7ddd1f52f86d7095a0806dfb2fa Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 20 Jun 2023 15:59:36 +0000 Subject: [PATCH 02/11] *wip* --- .../brillig/brillig_gen/brillig_directive.rs | 52 ++++++++++++++++++- .../acir_gen/acir_ir/generated_acir.rs | 36 ++++++------- 2 files changed, 68 insertions(+), 20 deletions(-) diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index 5d6dd838cc3..e70ffc78a02 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -1,4 +1,6 @@ -use acvm::acir::brillig_vm::{BinaryFieldOp, Opcode as BrilligOpcode, RegisterIndex, Value}; +use acvm::acir::brillig_vm::{ + BinaryFieldOp, BinaryIntOp, Opcode as BrilligOpcode, RegisterIndex, Value, +}; /// Generates brillig bytecode which computes the inverse of its input if not null, and zero else. pub(crate) fn directive_invert() -> Vec { @@ -14,3 +16,51 @@ pub(crate) fn directive_invert() -> Vec { BrilligOpcode::Stop, ] } + +/// Generates brillig bytecode which computes the a / b and returns the quotient and remainder. +/// It returns (0,0) if the predicate is null +pub(crate) fn directive_quotient(bit_size: u32) -> Vec { + // We generate the following code: + // fn quotient(a : Int, b: Int, predicate: bool) -> (Int,Int) { + // if predicate != 0 { + // (a/b, a-a/b*b) + // } else { + // (0,0) + // } + // } + vec![ + // If the predicate is zero, we jump to the exit segment + BrilligOpcode::JumpIfNot { condition: RegisterIndex::from(2), location: 6 }, + //q = a/b + BrilligOpcode::BinaryIntOp { + op: BinaryIntOp::UnsignedDiv, + lhs: RegisterIndex::from(0), + rhs: RegisterIndex::from(1), + destination: RegisterIndex::from(3), + bit_size, + }, + //(1)= q*b + BrilligOpcode::BinaryIntOp { + op: BinaryIntOp::Mul, + lhs: RegisterIndex::from(3), + rhs: RegisterIndex::from(1), + destination: RegisterIndex::from(1), + bit_size, + }, + //(1) = a-q*b + BrilligOpcode::BinaryIntOp { + op: BinaryIntOp::Sub, + lhs: RegisterIndex::from(0), + rhs: RegisterIndex::from(1), + destination: RegisterIndex::from(1), + bit_size, + }, + //(0) = q + BrilligOpcode::Mov { destination: RegisterIndex::from(0), source: RegisterIndex::from(3) }, + BrilligOpcode::Stop, + // Exit segment: we return 0,0 + BrilligOpcode::Const { destination: RegisterIndex::from(0), value: Value::from(0_usize) }, + BrilligOpcode::Const { destination: RegisterIndex::from(1), value: Value::from(0_usize) }, + BrilligOpcode::Stop, + ] +} diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs index 00a19560cf1..af4ff245644 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs @@ -318,19 +318,10 @@ impl GeneratedAcir { max_bit_size: u32, predicate: &Expression, ) -> Result<(Witness, Witness), AcirGenError> { - let q_witness = self.next_witness_index(); - let r_witness = self.next_witness_index(); - // lhs = rhs * q + r // // If predicate is zero, `q_witness` and `r_witness` will be 0 - self.push_opcode(AcirOpcode::Directive(Directive::Quotient(QuotientDirective { - a: lhs.clone(), - b: rhs.clone(), - q: q_witness, - r: r_witness, - predicate: Some(predicate.clone()), - }))); + let (q_witness, r_witness) = self.brillig_quotient(lhs, rhs, predicate, max_bit_size); // Constrain r to be 0 <= r < 2^{max_bit_size} let r_expr = Expression::from(r_witness); @@ -357,6 +348,20 @@ impl GeneratedAcir { Ok((q_witness, r_witness)) } + + pub(crate) fn brillig_quotient(&mut self, lhs: &Expression, rhs: &Expression, predicate: &Expression, max_bit_size: u32) -> (Witness, Witness) { + // Create the witness for the result + let q_witness = self.next_witness_index(); + let r_witness = self.next_witness_index(); + + let quotient_code = brillig_directive::directive_quotient(max_bit_size); + let inputs = vec![BrilligInputs::Single(lhs.clone()), BrilligInputs::Single(rhs.clone()), BrilligInputs::Single(predicate.clone())]; + let outputs = vec![BrilligOutputs::Simple(q_witness), BrilligOutputs::Simple(r_witness)]; + self.brillig(quotient_code, inputs, outputs); + + (q_witness, r_witness) + } + /// Generate constraints that are satisfied iff /// a < b , when offset is 1, or /// a <= b, when offset is 0 @@ -639,8 +644,6 @@ impl GeneratedAcir { let two_max_bits = two.pow(&FieldElement::from(max_bits as i128)); comparison_evaluation.q_c += two_max_bits; - let q_witness = self.next_witness_index(); - let r_witness = self.next_witness_index(); // Add constraint : 2^{max_bits} + a - b = q * 2^{max_bits} + r // @@ -667,13 +670,8 @@ impl GeneratedAcir { expr.push_addition_term(FieldElement::one(), r_witness); self.push_opcode(AcirOpcode::Arithmetic(&comparison_evaluation - &expr)); - self.push_opcode(AcirOpcode::Directive(Directive::Quotient(QuotientDirective { - a: comparison_evaluation, - b: Expression::from_field(two_max_bits), - q: q_witness, - r: r_witness, - predicate, - }))); + let (q_witness, r_witness) = self.brillig_quotient(comparison_evaluation, &Expression::from_field(two_max_bits), &predicate, max_bits + 1); + // Add constraint to ensure `r` is correctly bounded // between [0, 2^{max_bits}-1] From 7314bb3dc710ce50be0d595ea9b0d0dc3400db24 Mon Sep 17 00:00:00 2001 From: guipublic Date: Tue, 20 Jun 2023 16:19:40 +0000 Subject: [PATCH 03/11] Remove usage of quotient directive in favor of brillig --- .../brillig/brillig_gen/brillig_directive.rs | 6 +++- .../acir_gen/acir_ir/generated_acir.rs | 28 +++++++++++++------ 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index e70ffc78a02..49139d43e7a 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -28,10 +28,14 @@ pub(crate) fn directive_quotient(bit_size: u32) -> Vec { // (0,0) // } // } + + //a is (0) (i.e register index 0) + //b is (1) + //predicate is (2) vec![ // If the predicate is zero, we jump to the exit segment BrilligOpcode::JumpIfNot { condition: RegisterIndex::from(2), location: 6 }, - //q = a/b + //q = a/b is set into register (3) BrilligOpcode::BinaryIntOp { op: BinaryIntOp::UnsignedDiv, lhs: RegisterIndex::from(0), diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs index af4ff245644..4df2d732fc3 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs @@ -321,7 +321,7 @@ impl GeneratedAcir { // lhs = rhs * q + r // // If predicate is zero, `q_witness` and `r_witness` will be 0 - let (q_witness, r_witness) = self.brillig_quotient(lhs, rhs, predicate, max_bit_size); + let (q_witness, r_witness) = self.brillig_quotient(lhs, rhs, predicate, max_bit_size); // Constrain r to be 0 <= r < 2^{max_bit_size} let r_expr = Expression::from(r_witness); @@ -348,14 +348,23 @@ impl GeneratedAcir { Ok((q_witness, r_witness)) } - - pub(crate) fn brillig_quotient(&mut self, lhs: &Expression, rhs: &Expression, predicate: &Expression, max_bit_size: u32) -> (Witness, Witness) { + pub(crate) fn brillig_quotient( + &mut self, + lhs: &Expression, + rhs: &Expression, + predicate: &Expression, + max_bit_size: u32, + ) -> (Witness, Witness) { // Create the witness for the result let q_witness = self.next_witness_index(); let r_witness = self.next_witness_index(); let quotient_code = brillig_directive::directive_quotient(max_bit_size); - let inputs = vec![BrilligInputs::Single(lhs.clone()), BrilligInputs::Single(rhs.clone()), BrilligInputs::Single(predicate.clone())]; + let inputs = vec![ + BrilligInputs::Single(lhs.clone()), + BrilligInputs::Single(rhs.clone()), + BrilligInputs::Single(predicate.clone()), + ]; let outputs = vec![BrilligOutputs::Simple(q_witness), BrilligOutputs::Simple(r_witness)]; self.brillig(quotient_code, inputs, outputs); @@ -644,7 +653,7 @@ impl GeneratedAcir { let two_max_bits = two.pow(&FieldElement::from(max_bits as i128)); comparison_evaluation.q_c += two_max_bits; - + let predicate = predicate.unwrap_or_else(Expression::one); // Add constraint : 2^{max_bits} + a - b = q * 2^{max_bits} + r // // case: a == b @@ -665,14 +674,17 @@ impl GeneratedAcir { // - 2^{max_bits} - k == q * 2^{max_bits} + r // - This is only the case when q == 0 and r == 2^{max_bits} - k // + let (q_witness, r_witness) = self.brillig_quotient( + &comparison_evaluation, + &Expression::from_field(two_max_bits), + &predicate, + max_bits + 1, + ); let mut expr = Expression::default(); expr.push_addition_term(two_max_bits, q_witness); expr.push_addition_term(FieldElement::one(), r_witness); self.push_opcode(AcirOpcode::Arithmetic(&comparison_evaluation - &expr)); - let (q_witness, r_witness) = self.brillig_quotient(comparison_evaluation, &Expression::from_field(two_max_bits), &predicate, max_bits + 1); - - // Add constraint to ensure `r` is correctly bounded // between [0, 2^{max_bits}-1] self.range_constraint(r_witness, max_bits)?; From b5c9c2d6648e2f064a18433541dc5a033ac39148 Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Tue, 25 Jul 2023 21:39:30 +0000 Subject: [PATCH 04/11] chore: improve import --- .../src/brillig/brillig_gen/brillig_directive.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index 50ae89ed401..66021a663ca 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -1,4 +1,6 @@ -use acvm::{acir::brillig::{BinaryFieldOp, Opcode as BrilligOpcode, RegisterIndex, Value}, brillig_vm::brillig::BinaryIntOp}; +use acvm::acir::brillig::{ + BinaryFieldOp, BinaryIntOp, Opcode as BrilligOpcode, RegisterIndex, Value, +}; /// Generates brillig bytecode which computes the inverse of its input if not null, and zero else. pub(crate) fn directive_invert() -> Vec { From 15070157b3fe0bac3201f5745bfb60c7c1cfe967 Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Tue, 25 Jul 2023 21:41:20 +0000 Subject: [PATCH 05/11] chore: remove unnecessary brillig quotient --- .../acir_gen/acir_ir/generated_acir.rs | 14 -------------- 1 file changed, 14 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs index 05a52fd6b54..c66c8bee77f 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs @@ -693,20 +693,6 @@ impl GeneratedAcir { // Euclidian division by 2^{max_bits} : 2^{max_bits} + a - b = q * 2^{max_bits} + r // - // In the document linked above, they mention negating the value of `q` - // which would tell us whether a < b. Since we do not negate `q` - // what we get is a boolean indicating whether a >= b. - let (q_witness, r_witness) = self.brillig_quotient( - &comparison_evaluation, - &Expression::from_field(two_max_bits), - &predicate, - max_bits + 1, - ); - self.range_constraint(r_witness, max_bits)?; - self.range_constraint(q_witness, 1)?; - - // Add constraint : 2^{max_bits} + a - b = q * 2^{max_bits} + r - // // If a>b, then a-b is less than 2^{max_bits} - 1, so 2^{max_bits} + a - b is less than 2^{max_bits} + 2^{max_bits} - 1 = 2^{max_bits+1} - // If a <= b, then 2^{max_bits} + a - b is less than 2^{max_bits} <= 2^{max_bits+1} - 1 // This means that both operands of the division have at most max_bits+1 bit size. From 31fc82b93e3ca1781fe611b5637f114b32129cad Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Tue, 25 Jul 2023 21:42:37 +0000 Subject: [PATCH 06/11] chore: remove unnecessary comment change --- .../src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs index c66c8bee77f..465333b6219 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs @@ -693,8 +693,8 @@ impl GeneratedAcir { // Euclidian division by 2^{max_bits} : 2^{max_bits} + a - b = q * 2^{max_bits} + r // - // If a>b, then a-b is less than 2^{max_bits} - 1, so 2^{max_bits} + a - b is less than 2^{max_bits} + 2^{max_bits} - 1 = 2^{max_bits+1} - - // If a <= b, then 2^{max_bits} + a - b is less than 2^{max_bits} <= 2^{max_bits+1} - 1 + // 2^{max_bits} is of max_bits+1 bit size + // If a>b, then a-b is less than 2^{max_bits} - 1, so 2^{max_bits} + a - b is less than 2^{max_bits} + 2^{max_bits} - 1 = 2^{max_bits+1} - 1 // This means that both operands of the division have at most max_bits+1 bit size. // // case: a == b From 50aa90cc2ba55fdb5f44cfc2d1478bdb4bf6c99e Mon Sep 17 00:00:00 2001 From: TomAFrench Date: Tue, 25 Jul 2023 21:43:20 +0000 Subject: [PATCH 07/11] chore: comment change --- .../src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs index 465333b6219..cc9e563ee19 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs @@ -695,6 +695,7 @@ impl GeneratedAcir { // // 2^{max_bits} is of max_bits+1 bit size // If a>b, then a-b is less than 2^{max_bits} - 1, so 2^{max_bits} + a - b is less than 2^{max_bits} + 2^{max_bits} - 1 = 2^{max_bits+1} - 1 + // If a <= b, then 2^{max_bits} + a - b is less than 2^{max_bits} <= 2^{max_bits+1} - 1 // This means that both operands of the division have at most max_bits+1 bit size. // // case: a == b From 03a402e984bc18a434465a5b43b9dfecf4179fbc Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 2 Aug 2023 18:48:08 +0100 Subject: [PATCH 08/11] chore: push clone further up call stack --- .../acir_gen/acir_ir/generated_acir.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs index 611048a5fbb..5a2c7a9ea8a 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs @@ -432,7 +432,8 @@ impl GeneratedAcir { } } - let (q_witness, r_witness) = self.brillig_quotient(lhs, rhs, predicate, max_bit_size + 1); + let (q_witness, r_witness) = + self.brillig_quotient(lhs.clone(), rhs.clone(), predicate.clone(), max_bit_size + 1); // Apply range constraints to injected witness values. // Constrains `q` to be 0 <= q < 2^{q_max_bits}, etc. @@ -461,9 +462,9 @@ impl GeneratedAcir { /// Suitable range constraints are also applied to `q` and `r`. pub(crate) fn brillig_quotient( &mut self, - lhs: &Expression, - rhs: &Expression, - predicate: &Expression, + lhs: Expression, + rhs: Expression, + predicate: Expression, max_bit_size: u32, ) -> (Witness, Witness) { // Create the witness for the result @@ -472,12 +473,12 @@ impl GeneratedAcir { let quotient_code = brillig_directive::directive_quotient(max_bit_size); let inputs = vec![ - BrilligInputs::Single(lhs.clone()), - BrilligInputs::Single(rhs.clone()), + BrilligInputs::Single(lhs), + BrilligInputs::Single(rhs), BrilligInputs::Single(predicate.clone()), ]; let outputs = vec![BrilligOutputs::Simple(q_witness), BrilligOutputs::Simple(r_witness)]; - self.brillig(Some(predicate.clone()), quotient_code, inputs, outputs); + self.brillig(Some(predicate), quotient_code, inputs, outputs); (q_witness, r_witness) } From 438be3c47ece2d2c0061102f551b3b35045e17b7 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 2 Aug 2023 18:50:45 +0100 Subject: [PATCH 09/11] chore: correct comment on `brillig_quotient` --- .../src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs index 5a2c7a9ea8a..b425eab42d3 100644 --- a/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs +++ b/crates/noirc_evaluator/src/ssa_refactor/acir_gen/acir_ir/generated_acir.rs @@ -459,7 +459,7 @@ impl GeneratedAcir { /// Adds a brillig opcode which injects witnesses with values `q = a / b` and `r = a % b`. /// - /// Suitable range constraints are also applied to `q` and `r`. + /// Suitable range constraints for `q` and `r` must be applied externally. pub(crate) fn brillig_quotient( &mut self, lhs: Expression, From a1640768c195e2b931ca7767a99039bd9639f7a1 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 2 Aug 2023 18:56:41 +0100 Subject: [PATCH 10/11] chore: improve docs for `directive_quotient` --- .../brillig/brillig_gen/brillig_directive.rs | 32 +++++++++++-------- 1 file changed, 18 insertions(+), 14 deletions(-) diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index 66021a663ca..e4e91a9cfdc 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -32,21 +32,25 @@ pub(crate) fn directive_invert() -> Vec { ] } -/// Generates brillig bytecode which computes the a / b and returns the quotient and remainder. -/// It returns (0,0) if the predicate is null +/// Generates brillig bytecode which computes `a / b` and returns the quotient and remainder. +/// It returns `(0,0)` if the predicate is null +/// +/// +/// This is equivalent to the Noir (psuedo)code +/// +/// ```no_run +/// fn quotient(a: T, b: T, predicate: bool) -> (T,T) { +/// if predicate != 0 { +/// (a/b, a-a/b*b) +/// } else { +/// (0,0) +/// } +/// } +/// ``` pub(crate) fn directive_quotient(bit_size: u32) -> Vec { - // We generate the following code: - // fn quotient(a : Int, b: Int, predicate: bool) -> (Int,Int) { - // if predicate != 0 { - // (a/b, a-a/b*b) - // } else { - // (0,0) - // } - // } - - //a is (0) (i.e register index 0) - //b is (1) - //predicate is (2) + // `a` is (0) (i.e register index 0) + // `b` is (1) + // `predicate` is (2) vec![ // If the predicate is zero, we jump to the exit segment BrilligOpcode::JumpIfNot { condition: RegisterIndex::from(2), location: 6 }, From 8c075821f645027bf0391768dd320f1929b3b704 Mon Sep 17 00:00:00 2001 From: Tom French Date: Wed, 2 Aug 2023 19:19:59 +0100 Subject: [PATCH 11/11] chore: ignore pseudocode entirely --- .../src/brillig/brillig_gen/brillig_directive.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index e4e91a9cfdc..93e760f9737 100644 --- a/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/crates/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -33,12 +33,12 @@ pub(crate) fn directive_invert() -> Vec { } /// Generates brillig bytecode which computes `a / b` and returns the quotient and remainder. -/// It returns `(0,0)` if the predicate is null +/// It returns `(0,0)` if the predicate is null. /// /// /// This is equivalent to the Noir (psuedo)code /// -/// ```no_run +/// ```ignore /// fn quotient(a: T, b: T, predicate: bool) -> (T,T) { /// if predicate != 0 { /// (a/b, a-a/b*b)