Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'master' into tf/constant-range-constraints
Browse files Browse the repository at this point in the history
TomAFrench authored Jan 2, 2024

Verified

This commit was signed with the committer’s verified signature.
AdmiralCurtiss Admiral H. Curtiss
2 parents 5404f90 + f9bfed6 commit c3a7475
Showing 7 changed files with 85 additions and 208 deletions.
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -92,6 +92,10 @@ This strategy avoids scenarios where pull requests grow too large/out-of-scope a

The easiest way to do this is to have multiple Conventional Commits while you work and then you can cherry-pick the smaller changes into separate branches for pull requesting.

### Typos and other small changes

Significant changes, like new features or important bug fixes, typically have a more pronounced impact on the project’s overall development. For smaller fixes, such as typos, we encourage you to report them instead of opening PRs. This approach helps us manage our resources effectively and ensures that every change contributes meaningfully to the project. PRs involving such smaller fixes will likely be closed and incorporated in PRs authored by the core team.

### Reviews

For any repository in the noir-lang organization, we require code review & approval by __one__ Noir team member before the changes are merged, as enforced by GitHub branch protection. Non-breaking pull requests may be merged at any time. Breaking pull requests should only be merged when the team has general agreement of the changes and is preparing a breaking release.
72 changes: 16 additions & 56 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

55 changes: 31 additions & 24 deletions compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs
Original file line number Diff line number Diff line change
@@ -454,14 +454,11 @@ impl AcirContext {
self.sub_var(sum, mul)
} else {
// Implement OR in terms of AND
// max - ((max - a) AND (max -b))
// Subtracting from max flips the bits, so this is effectively:
// (NOT a) NAND (NOT b)
let max = self.add_constant((1_u128 << bit_size) - 1);
let a = self.sub_var(max, lhs)?;
let b = self.sub_var(max, rhs)?;
let a_and_b = self.and_var(a, b, typ)?;
self.sub_var(max, a_and_b)
// (NOT a) NAND (NOT b) => a OR b
let a = self.not_var(lhs, typ.clone())?;
let b = self.not_var(rhs, typ.clone())?;
let a_and_b = self.and_var(a, b, typ.clone())?;
self.not_var(a_and_b, typ)
}
}

@@ -533,8 +530,19 @@ impl AcirContext {
let lhs_data = self.vars[&lhs].clone();
let rhs_data = self.vars[&rhs].clone();
let result = match (lhs_data, rhs_data) {
// (x * 1) == (1 * x) == x
(AcirVarData::Const(constant), _) if constant.is_one() => rhs,
(_, AcirVarData::Const(constant)) if constant.is_one() => lhs,

// (x * 0) == (0 * x) == 0
(AcirVarData::Const(constant), _) | (_, AcirVarData::Const(constant))
if constant.is_zero() =>
{
self.add_constant(FieldElement::zero())
}

(AcirVarData::Const(lhs_constant), AcirVarData::Const(rhs_constant)) => {
self.add_data(AcirVarData::Const(lhs_constant * rhs_constant))
self.add_constant(lhs_constant * rhs_constant)
}
(AcirVarData::Witness(witness), AcirVarData::Const(constant))
| (AcirVarData::Const(constant), AcirVarData::Witness(witness)) => {
@@ -991,23 +999,25 @@ impl AcirContext {
lhs: AcirVar,
rhs: AcirVar,
bit_count: u32,
predicate: AcirVar,
) -> Result<AcirVar, RuntimeError> {
let pow_last = self.add_constant(FieldElement::from(1_u128 << (bit_count - 1)));
let pow = self.add_constant(FieldElement::from(1_u128 << (bit_count)));

// We check whether the inputs have same sign or not by computing the XOR of their bit sign

// Predicate is always active as `pow_last` is known to be non-zero.
let one = self.add_constant(1_u128);
let lhs_sign = self.div_var(
lhs,
pow_last,
AcirType::NumericType(NumericType::Unsigned { bit_size: bit_count }),
predicate,
one,
)?;
let rhs_sign = self.div_var(
rhs,
pow_last,
AcirType::NumericType(NumericType::Unsigned { bit_size: bit_count }),
predicate,
one,
)?;
let same_sign = self.xor_var(
lhs_sign,
@@ -1020,7 +1030,7 @@ impl AcirContext {
let diff = self.sub_var(no_underflow, rhs)?;

// We check the 'bit sign' of the difference
let diff_sign = self.less_than_var(diff, pow, bit_count + 1, predicate)?;
let diff_sign = self.less_than_var(diff, pow, bit_count + 1)?;

// Then the result is simply diff_sign XOR same_sign (can be checked with a truth table)
self.xor_var(
@@ -1037,7 +1047,6 @@ impl AcirContext {
lhs: AcirVar,
rhs: AcirVar,
max_bits: u32,
predicate: AcirVar,
) -> Result<AcirVar, RuntimeError> {
// Returns a `Witness` that is constrained to be:
// - `1` if lhs >= rhs
@@ -1062,6 +1071,7 @@ impl AcirContext {
//
// TODO: perhaps this should be a user error, instead of an assert
assert!(max_bits + 1 < FieldElement::max_num_bits());

let two_max_bits = self
.add_constant(FieldElement::from(2_i128).pow(&FieldElement::from(max_bits as i128)));
let diff = self.sub_var(lhs, rhs)?;
@@ -1091,13 +1101,11 @@ impl AcirContext {
// let k = b - a
// - 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, _) = self.euclidean_division_var(
comparison_evaluation,
two_max_bits,
max_bits + 1,
predicate,
)?;

// Predicate is always active as we know `two_max_bits` is always non-zero.
let one = self.add_constant(1_u128);
let (q, _) =
self.euclidean_division_var(comparison_evaluation, two_max_bits, max_bits + 1, one)?;
Ok(q)
}

@@ -1108,11 +1116,10 @@ impl AcirContext {
lhs: AcirVar,
rhs: AcirVar,
bit_size: u32,
predicate: AcirVar,
) -> Result<AcirVar, RuntimeError> {
// Flip the result of calling more than equal method to
// compute less than.
let comparison = self.more_than_eq_var(lhs, rhs, bit_size, predicate)?;
let comparison = self.more_than_eq_var(lhs, rhs, bit_size)?;

let one = self.add_constant(FieldElement::one());
self.sub_var(one, comparison) // comparison_negated
@@ -1508,7 +1515,7 @@ impl AcirContext {
bit_size: u32,
predicate: AcirVar,
) -> Result<(), RuntimeError> {
let lhs_less_than_rhs = self.more_than_eq_var(rhs, lhs, bit_size, predicate)?;
let lhs_less_than_rhs = self.more_than_eq_var(rhs, lhs, bit_size)?;
self.maybe_eq_predicate(lhs_less_than_rhs, predicate)
}

30 changes: 8 additions & 22 deletions compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs
Original file line number Diff line number Diff line change
@@ -1571,15 +1571,10 @@ impl Context {
// this Eq instruction is being used for a constrain statement
BinaryOp::Eq => self.acir_context.eq_var(lhs, rhs),
BinaryOp::Lt => match binary_type {
AcirType::NumericType(NumericType::Signed { .. }) => self
.acir_context
.less_than_signed(lhs, rhs, bit_count, self.current_side_effects_enabled_var),
_ => self.acir_context.less_than_var(
lhs,
rhs,
bit_count,
self.current_side_effects_enabled_var,
),
AcirType::NumericType(NumericType::Signed { .. }) => {
self.acir_context.less_than_signed(lhs, rhs, bit_count)
}
_ => self.acir_context.less_than_var(lhs, rhs, bit_count),
},
BinaryOp::Xor => self.acir_context.xor_var(lhs, rhs, binary_type),
BinaryOp::And => self.acir_context.and_var(lhs, rhs, binary_type),
@@ -2141,19 +2136,11 @@ impl Context {
let current_index = self.acir_context.add_constant(i);

// Check that we are above the lower bound of the insertion index
let greater_eq_than_idx = self.acir_context.more_than_eq_var(
current_index,
flat_user_index,
64,
self.current_side_effects_enabled_var,
)?;
let greater_eq_than_idx =
self.acir_context.more_than_eq_var(current_index, flat_user_index, 64)?;
// Check that we are below the upper bound of the insertion index
let less_than_idx = self.acir_context.less_than_var(
current_index,
max_flat_user_index,
64,
self.current_side_effects_enabled_var,
)?;
let less_than_idx =
self.acir_context.less_than_var(current_index, max_flat_user_index, 64)?;

// Read from the original slice the value we want to insert into our new slice.
// We need to make sure that we read the previous element when our current index is greater than insertion index.
@@ -2328,7 +2315,6 @@ impl Context {
current_index,
flat_user_index,
64,
self.current_side_effects_enabled_var,
)?;

let shifted_value_pred =
Loading

0 comments on commit c3a7475

Please sign in to comment.