diff --git a/zokrates_cli/examples/runtime_errors/div_zero_field.zok b/zokrates_cli/examples/runtime_errors/div_zero_field.zok new file mode 100644 index 00000000..dd0668f3 --- /dev/null +++ b/zokrates_cli/examples/runtime_errors/div_zero_field.zok @@ -0,0 +1,3 @@ +def main(field x): + field y = 1 / x + return \ No newline at end of file diff --git a/zokrates_cli/examples/runtime_errors/div_zero_uint.zok b/zokrates_cli/examples/runtime_errors/div_zero_uint.zok new file mode 100644 index 00000000..b307a5c9 --- /dev/null +++ b/zokrates_cli/examples/runtime_errors/div_zero_uint.zok @@ -0,0 +1,3 @@ +def main(u8 x): + u8 y = 0x01 / x + return \ No newline at end of file diff --git a/zokrates_core/src/ir/expression.rs b/zokrates_core/src/ir/expression.rs index 48054660..e64f59d4 100644 --- a/zokrates_core/src/ir/expression.rs +++ b/zokrates_core/src/ir/expression.rs @@ -263,7 +263,7 @@ impl Div<&T> for LinComb { type Output = LinComb; fn div(self, scalar: &T) -> LinComb { - self * &scalar.inverse_mul() + self * &scalar.inverse_mul().unwrap() } } diff --git a/zokrates_core/src/ir/interpreter.rs b/zokrates_core/src/ir/interpreter.rs index cf61dff6..da4d97ac 100644 --- a/zokrates_core/src/ir/interpreter.rs +++ b/zokrates_core/src/ir/interpreter.rs @@ -141,7 +141,10 @@ impl Interpreter { let res = match s { Solver::ConditionEq => match inputs[0].is_zero() { true => vec![T::zero(), T::one()], - false => vec![T::one(), T::one() / &inputs[0]], + false => vec![ + T::one(), + T::one().checked_div(&inputs[0]).unwrap_or(T::one()), + ], }, Solver::Bits(bit_width) => { let mut num = inputs[0].clone(); @@ -183,7 +186,10 @@ impl Interpreter { let c = inputs[2].clone(); vec![a * (b - c.clone()) + c] } - Solver::Div => vec![inputs[0].clone() / inputs[1].clone()], + Solver::Div => vec![inputs[0] + .clone() + .checked_div(&inputs[1]) + .unwrap_or(T::one())], Solver::EuclideanDiv => { use num::CheckedDiv; diff --git a/zokrates_core_test/tests/tests/uint/div.zok b/zokrates_core_test/tests/tests/uint/div.zok index 0ac951ed..730ce4b2 100644 --- a/zokrates_core_test/tests/tests/uint/div.zok +++ b/zokrates_core_test/tests/tests/uint/div.zok @@ -1,2 +1,6 @@ def main(u8 x, u8 y) -> u8: + assert(0x02 / 0x02 == 0x01) + assert(0x04 / 0x02 == 0x02) + assert(0x05 / 0x02 == 0x02) + assert(0xff / 0x03 == 0x55) return x / y \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/uint/rem.zok b/zokrates_core_test/tests/tests/uint/rem.zok index f7097d68..c72401dc 100644 --- a/zokrates_core_test/tests/tests/uint/rem.zok +++ b/zokrates_core_test/tests/tests/uint/rem.zok @@ -1,2 +1,7 @@ def main(u8 x, u8 y) -> u8: + assert(0x02 % 0x02 == 0x00) + assert(0x04 % 0x02 == 0x00) + assert(0x05 % 0x02 == 0x01) + assert(0xff % 0x03 == 0x00) + assert(0xff % 0x01 == 0x00) return x % y \ No newline at end of file diff --git a/zokrates_field/src/lib.rs b/zokrates_field/src/lib.rs index 3a1b5f3a..e69769dc 100644 --- a/zokrates_field/src/lib.rs +++ b/zokrates_field/src/lib.rs @@ -10,7 +10,7 @@ use algebra_core::PairingEngine; use bellman_ce::pairing::ff::ScalarEngine; use bellman_ce::pairing::Engine; use num_bigint::BigUint; -use num_traits::{One, Zero}; +use num_traits::{CheckedDiv, One, Zero}; use serde::{Deserialize, Serialize}; use std::convert::{From, TryFrom}; use std::fmt::{Debug, Display}; @@ -61,8 +61,8 @@ pub trait Field: + for<'a> Sub<&'a Self, Output = Self> + Mul + for<'a> Mul<&'a Self, Output = Self> + + CheckedDiv + Div - + for<'a> Div<&'a Self, Output = Self> + Pow + Pow + for<'a> Pow<&'a Self, Output = Self> @@ -78,7 +78,7 @@ pub trait Field: /// Returns this `Field`'s contents as decimal string fn to_dec_string(&self) -> String; /// Returns the multiplicative inverse, i.e.: self * self.inverse_mul() = Self::one() - fn inverse_mul(&self) -> Self; + fn inverse_mul(&self) -> Option; /// Returns the smallest value that can be represented by this field type. fn min_value() -> Self; /// Returns the largest value that can be represented by this field type. @@ -129,7 +129,7 @@ mod prime_field { use lazy_static::lazy_static; use num_bigint::{BigInt, BigUint, Sign, ToBigInt}; use num_integer::Integer; - use num_traits::{One, Zero}; + use num_traits::{CheckedDiv, One, Zero}; use serde_derive::{Deserialize, Serialize}; use std::convert::From; use std::convert::TryFrom; @@ -173,11 +173,14 @@ mod prime_field { self.value.to_str_radix(10) } - fn inverse_mul(&self) -> FieldPrime { + fn inverse_mul(&self) -> Option { let (b, s, _) = extended_euclid(&self.value, &*P); - assert_eq!(b, BigInt::one()); - FieldPrime { - value: &s - s.div_floor(&*P) * &*P, + if b == BigInt::one() { + Some(FieldPrime { + value: &s - s.div_floor(&*P) * &*P, + }) + } else { + None } } fn min_value() -> FieldPrime { @@ -387,11 +390,17 @@ mod prime_field { } } + impl CheckedDiv for FieldPrime { + fn checked_div(&self, other: &FieldPrime) -> Option { + other.inverse_mul().map(|inv| inv * self) + } + } + impl Div for FieldPrime { type Output = FieldPrime; fn div(self, other: FieldPrime) -> FieldPrime { - self * other.inverse_mul() + self.checked_div(&other).unwrap() } } @@ -399,7 +408,7 @@ mod prime_field { type Output = FieldPrime; fn div(self, other: &FieldPrime) -> FieldPrime { - self / other.clone() + self.checked_div(&other).unwrap() } }