Skip to content

Commit

Permalink
feat: implement euclidean division and signed division in terms of `A…
Browse files Browse the repository at this point in the history
…cirVar`s (#3230)
  • Loading branch information
TomAFrench authored and guipublic committed Oct 30, 2023
1 parent 84f408e commit 66a8453
Show file tree
Hide file tree
Showing 70 changed files with 292 additions and 342 deletions.
24 changes: 18 additions & 6 deletions acvm-repo/brillig_vm/src/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,18 +25,28 @@ pub(crate) fn evaluate_binary_bigint_op(
a: BigUint,
b: BigUint,
bit_size: u32,
) -> BigUint {
) -> Result<BigUint, String> {
let bit_modulo = &(BigUint::one() << bit_size);
match op {
let result = match op {
// Perform addition, subtraction, and multiplication, applying a modulo operation to keep the result within the bit size.
BinaryIntOp::Add => (a + b) % bit_modulo,
BinaryIntOp::Sub => (bit_modulo + a - b) % bit_modulo,
BinaryIntOp::Mul => (a * b) % bit_modulo,
// Perform unsigned division using the modulo operation on a and b.
BinaryIntOp::UnsignedDiv => (a % bit_modulo) / (b % bit_modulo),
BinaryIntOp::UnsignedDiv => {
let b_mod = b % bit_modulo;
if b_mod.is_zero() {
return Err("Division by zero".to_owned());
}
(a % bit_modulo) / b_mod
}
// Perform signed division by first converting a and b to signed integers and then back to unsigned after the operation.
BinaryIntOp::SignedDiv => {
let signed_div = to_big_signed(a, bit_size) / to_big_signed(b, bit_size);
let b_signed = to_big_signed(b, bit_size);
if b_signed.is_zero() {
return Err("Division by zero".to_owned());
}
let signed_div = to_big_signed(a, bit_size) / b_signed;
to_big_unsigned(signed_div, bit_size)
}
// Perform a == operation, returning 0 or 1
Expand Down Expand Up @@ -77,7 +87,9 @@ pub(crate) fn evaluate_binary_bigint_op(
let b = b.to_u128().unwrap();
(a >> b) % bit_modulo
}
}
};

Ok(result)
}

fn to_big_signed(a: BigUint, bit_size: u32) -> BigInt {
Expand Down Expand Up @@ -111,7 +123,7 @@ mod tests {
// Convert to big integers
let lhs_big = BigUint::from(a);
let rhs_big = BigUint::from(b);
let result_value = evaluate_binary_bigint_op(op, lhs_big, rhs_big, bit_size);
let result_value = evaluate_binary_bigint_op(op, lhs_big, rhs_big, bit_size).unwrap();
// Convert back to u128
result_value.to_u128().unwrap()
}
Expand Down
13 changes: 9 additions & 4 deletions acvm-repo/brillig_vm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,8 +177,12 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> {
self.increment_program_counter()
}
Opcode::BinaryIntOp { op, bit_size, lhs, rhs, destination: result } => {
self.process_binary_int_op(*op, *bit_size, *lhs, *rhs, *result);
self.increment_program_counter()
if let Err(error) = self.process_binary_int_op(*op, *bit_size, *lhs, *rhs, *result)
{
self.fail(error)
} else {
self.increment_program_counter()
}
}
Opcode::Jump { location: destination } => self.set_program_counter(*destination),
Opcode::JumpIf { condition, location: destination } => {
Expand Down Expand Up @@ -391,17 +395,18 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> {
lhs: RegisterIndex,
rhs: RegisterIndex,
result: RegisterIndex,
) {
) -> Result<(), String> {
let lhs_value = self.registers.get(lhs);
let rhs_value = self.registers.get(rhs);

// Convert to big integers
let lhs_big = BigUint::from_bytes_be(&lhs_value.to_field().to_be_bytes());
let rhs_big = BigUint::from_bytes_be(&rhs_value.to_field().to_be_bytes());
let result_value = evaluate_binary_bigint_op(&op, lhs_big, rhs_big, bit_size);
let result_value = evaluate_binary_bigint_op(&op, lhs_big, rhs_big, bit_size)?;
// Convert back to field element
self.registers
.set(result, FieldElement::from_be_bytes_reduce(&result_value.to_bytes_be()).into());
Ok(())
}
}

Expand Down
Loading

0 comments on commit 66a8453

Please sign in to comment.