Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: wrapping in signed division #5134

Merged
merged 5 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -979,6 +979,7 @@ impl AcirContext {
let max_power_of_two = self.add_constant(
FieldElement::from(2_i128).pow(&FieldElement::from(bit_size as i128 - 1)),
);
let zero = self.add_constant(FieldElement::zero());
let one = self.add_constant(FieldElement::one());

// Get the sign bit of rhs by computing rhs / max_power_of_two
Expand All @@ -998,10 +999,19 @@ impl AcirContext {
// Unsigned to signed: derive q and r from q1,r1 and the signs of lhs and rhs
// Quotient sign is lhs sign * rhs sign, whose resulting sign bit is the XOR of the sign bits
let q_sign = self.xor_var(lhs_leading, rhs_leading, AcirType::unsigned(1))?;

let quotient = self.two_complement(q1, q_sign, bit_size)?;
let remainder = self.two_complement(r1, lhs_leading, bit_size)?;

// Issue #5129 - When q1 is zero and quotient sign is -1, we compute -0=2^{bit_size},
// which is not valid because we do not wrap integer operations
// Similar case can happen with the remainder.
let q_is_0 = self.eq_var(q1, zero)?;
let q_is_not_0 = self.not_var(q_is_0, AcirType::unsigned(1))?;
let quotient = self.mul_var(quotient, q_is_not_0)?;
let r_is_0 = self.eq_var(r1, zero)?;
let r_is_not_0 = self.not_var(r_is_0, AcirType::unsigned(1))?;
let remainder = self.mul_var(remainder, r_is_not_0)?;

Ok((quotient, remainder))
}

Expand Down
2 changes: 1 addition & 1 deletion test_programs/execution_success/signed_div/src/main.nr
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ struct SignedDivOp {
result: i8,
}

unconstrained fn main(ops: [SignedDivOp; 15]) {
fn main(ops: [SignedDivOp; 15]) {
for i in 0..15 {
assert_eq(ops[i].lhs / ops[i].rhs, ops[i].result);
}
Expand Down
Loading