1
0
Fork 0
mirror of synced 2025-09-24 04:40:05 +00:00

Merge branch 'develop' of github.com:Zokrates/ZoKrates into dummy-contraint

This commit is contained in:
dark64 2020-11-25 11:55:56 +01:00
commit 760bd7085a
29 changed files with 455 additions and 30 deletions

View file

@ -5,7 +5,7 @@ The following table lists the precedence and associativity of all available oper
| Operator | Description | Associativity | Remarks |
|------------------------------|--------------------------------------------------------------|------------------------------------|---------|
| ** <br> | Power | Left | [^1] |
| * <br> /<br> | Multiplication <br> Division <br> | Left <br> Left | |
| *<br> /<br> %<br> | Multiplication <br> Division <br> Remainder | Left <br> Left <br>Left | |
| + <br> - <br> | Addition <br> Subtraction <br> | Left <br> Left | |
| << <br> >> <br> | Left shift <br> Right shift <br> | Left <br> Left | [^2] |
| & | Bitwise AND | Left <br> Left | |
@ -22,4 +22,4 @@ The following table lists the precedence and associativity of all available oper
[^2]: The right operand must be a compile time constant
[^3]: Both operands are be asserted to be strictly lower than the biggest power of 2 lower than `p/2`
[^3]: Both operands are asserted to be strictly lower than the biggest power of 2 lower than `p/2`

View file

@ -16,6 +16,8 @@ While `field` values mostly behave like unsigned integers, one should keep in mi
{{#include ../../../zokrates_cli/examples/book/field_overflow.zok}}
```
Note that for field elements, the division operation multiplies the numerator with the denominator's inverse field element. The results coincide with integer divisions for cases with remainder 0, but differ otherwise.
### `bool`
Booleans are available in ZoKrates. When a boolean is used as a parameter of the main function, the program is constrained to only accept `0` or `1` for that parameter. A boolean can be asserted to be true using an `assert(bool)` statement.
@ -28,6 +30,8 @@ Internally, they use a binary encoding, which makes them particularly efficient
Similarly to booleans, unsigned integer inputs of the main function only accept values of the appropriate range.
The division operation calculates the standard floor division for integers. The `%` operand can be used to obtain the remainder.
## Complex Types
ZoKrates provides two complex types: arrays and structs.

View file

@ -0,0 +1,3 @@
def main(field x):
field y = 1 / x
return

View file

@ -0,0 +1,3 @@
def main(u8 x):
u8 y = 0x01 / x
return

View file

@ -320,6 +320,10 @@ impl<'ast> From<pest::BinaryExpression<'ast>> for absy::ExpressionNode<'ast> {
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Rem => absy::Expression::Rem(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
pest::BinaryOperator::Eq => absy::Expression::Eq(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),

View file

@ -482,6 +482,7 @@ pub enum Expression<'ast> {
Sub(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Mult(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Div(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Rem(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
Pow(Box<ExpressionNode<'ast>>, Box<ExpressionNode<'ast>>),
IfElse(
Box<ExpressionNode<'ast>>,
@ -522,6 +523,7 @@ impl<'ast> fmt::Display for Expression<'ast> {
Expression::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs),
Expression::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs),
Expression::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs),
Expression::Rem(ref lhs, ref rhs) => write!(f, "({} % {})", lhs, rhs),
Expression::Pow(ref lhs, ref rhs) => write!(f, "({}**{})", lhs, rhs),
Expression::BooleanConstant(b) => write!(f, "{}", b),
Expression::IfElse(ref condition, ref consequent, ref alternative) => write!(
@ -590,6 +592,7 @@ impl<'ast> fmt::Debug for Expression<'ast> {
Expression::Sub(ref lhs, ref rhs) => write!(f, "Sub({:?}, {:?})", lhs, rhs),
Expression::Mult(ref lhs, ref rhs) => write!(f, "Mult({:?}, {:?})", lhs, rhs),
Expression::Div(ref lhs, ref rhs) => write!(f, "Div({:?}, {:?})", lhs, rhs),
Expression::Rem(ref lhs, ref rhs) => write!(f, "Rem({:?}, {:?})", lhs, rhs),
Expression::Pow(ref lhs, ref rhs) => write!(f, "Pow({:?}, {:?})", lhs, rhs),
Expression::BooleanConstant(b) => write!(f, "{}", b),
Expression::IfElse(ref condition, ref consequent, ref alternative) => write!(

View file

@ -1012,6 +1012,97 @@ impl<'ast, T: Field> Flattener<'ast, T> {
FlatUExpression::with_bits(xor)
}
fn euclidean_division(
&mut self,
symbols: &ZirFunctionSymbols<'ast, T>,
statements_flattened: &mut FlatStatements<T>,
target_bitwidth: UBitwidth,
left: UExpression<'ast, T>,
right: UExpression<'ast, T>,
) -> (FlatExpression<T>, FlatExpression<T>) {
let left_flattened = self
.flatten_uint_expression(symbols, statements_flattened, left)
.get_field_unchecked();
let right_flattened = self
.flatten_uint_expression(symbols, statements_flattened, right)
.get_field_unchecked();
let n = if left_flattened.is_linear() {
left_flattened
} else {
let id = self.use_sym();
statements_flattened.push(FlatStatement::Definition(id, left_flattened));
FlatExpression::Identifier(id)
};
let d = if right_flattened.is_linear() {
right_flattened
} else {
let id = self.use_sym();
statements_flattened.push(FlatStatement::Definition(id, right_flattened));
FlatExpression::Identifier(id)
};
// first check that the d is not 0 by giving its inverse
let invd = self.use_sym();
// # invd = 1/d
statements_flattened.push(FlatStatement::Directive(FlatDirective::new(
vec![invd],
Solver::Div,
vec![FlatExpression::Number(T::one()), d.clone()],
)));
// assert(invd * d == 1)
statements_flattened.push(FlatStatement::Condition(
FlatExpression::Number(T::one()),
FlatExpression::Mult(box invd.into(), box d.clone().into()),
));
// now introduce the quotient and remainder
let q = self.use_sym();
let r = self.use_sym();
statements_flattened.push(FlatStatement::Directive(FlatDirective {
inputs: vec![n.clone(), d.clone()],
outputs: vec![q.clone(), r.clone()],
solver: Solver::EuclideanDiv,
}));
// q in range
let _ = self.get_bits(
FlatUExpression::with_field(FlatExpression::from(q)),
target_bitwidth.to_usize(),
target_bitwidth,
statements_flattened,
);
// r in range
let _ = self.get_bits(
FlatUExpression::with_field(FlatExpression::from(r)),
target_bitwidth.to_usize(),
target_bitwidth,
statements_flattened,
);
// r < d <=> r - d + 2**w < 2**w
let _ = self.get_bits(
FlatUExpression::with_field(FlatExpression::Add(
box FlatExpression::Sub(box r.into(), box d.clone().into()),
box FlatExpression::Number(T::from(2usize.pow(target_bitwidth.to_usize() as u32))),
)),
target_bitwidth.to_usize(),
target_bitwidth,
statements_flattened,
);
// q*d == n - r
statements_flattened.push(FlatStatement::Condition(
FlatExpression::Sub(box n, box r.into()),
FlatExpression::Mult(box q.into(), box d),
));
(q.into(), r.into())
}
/// Flattens a uint expression
///
/// # Arguments
@ -1208,6 +1299,28 @@ impl<'ast, T: Field> Flattener<'ast, T> {
FlatUExpression::with_field(FlatExpression::Identifier(res))
}
UExpressionInner::Div(box left, box right) => {
let (q, _) = self.euclidean_division(
symbols,
statements_flattened,
target_bitwidth,
left,
right,
);
FlatUExpression::with_field(q)
}
UExpressionInner::Rem(box left, box right) => {
let (_, r) = self.euclidean_division(
symbols,
statements_flattened,
target_bitwidth,
left,
right,
);
FlatUExpression::with_field(r)
}
UExpressionInner::IfElse(box condition, box consequence, box alternative) => self
.flatten_if_else_expression(
symbols,
@ -1533,10 +1646,10 @@ impl<'ast, T: Field> Flattener<'ast, T> {
assert!(to < T::get_required_bits());
// constants do not require directives
match e.field.clone() {
Some(FlatExpression::Number(x)) => {
match e.field {
Some(FlatExpression::Number(ref x)) => {
let bits: Vec<_> = ir::Interpreter::default()
.execute_solver(&Solver::bits(to), &vec![x])
.execute_solver(&Solver::bits(to), &vec![x.clone()])
.unwrap()
.into_iter()
.map(|x| FlatExpression::Number(x))
@ -1981,7 +2094,7 @@ impl<'ast, T: Field> Flattener<'ast, T> {
// push parameters
let arguments_flattened = funct
.arguments
.iter()
.into_iter()
.map(|p| self.use_parameter(&p, &mut statements_flattened))
.collect();
@ -2079,7 +2192,7 @@ impl<'ast, T: Field> Flattener<'ast, T> {
if parameter.private {
// we insert dummy condition statement for private field elements
// to avoid unconstrained variables
// translates to y = x * x
// translates to y == x * x
statements_flattened.push(FlatStatement::Condition(
self.use_sym().into(),
FlatExpression::Mult(box variable.into(), box variable.into()),

View file

@ -263,7 +263,7 @@ impl<T: Field> Div<&T> for LinComb<T> {
type Output = LinComb<T>;
fn div(self, scalar: &T) -> LinComb<T> {
self * &scalar.inverse_mul()
self * &scalar.inverse_mul().unwrap()
}
}

View file

@ -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].clone()],
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,20 @@ 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;
let n = inputs[0].clone().to_biguint();
let d = inputs[1].clone().to_biguint();
let q = n.checked_div(&d).unwrap_or(0u32.into());
let r = n - d * &q;
vec![T::try_from(q).unwrap(), T::try_from(r).unwrap()]
}
};
assert_eq!(res.len(), expected_output_count);

View file

@ -1243,7 +1243,7 @@ impl<'ast> Checker<'ast> {
pos: Some(pos),
message: format!(
"Cannot apply `+` to {:?}, {:?}",
"Cannot apply `+` to {}, {}",
e1.get_type(),
e2.get_type()
),
@ -1254,7 +1254,7 @@ impl<'ast> Checker<'ast> {
pos: Some(pos),
message: format!(
"Cannot apply `+` to {:?}, {:?}",
"Cannot apply `+` to {}, {}",
t1.get_type(),
t2.get_type()
),
@ -1277,7 +1277,7 @@ impl<'ast> Checker<'ast> {
pos: Some(pos),
message: format!(
"Cannot apply `+` to {:?}, {:?}",
"Cannot apply `+` to {}, {}",
e1.get_type(),
e2.get_type()
),
@ -1288,7 +1288,7 @@ impl<'ast> Checker<'ast> {
pos: Some(pos),
message: format!(
"Expected only field elements, found {:?}, {:?}",
"Expected only field elements, found {}, {}",
t1.get_type(),
t2.get_type()
),
@ -1311,7 +1311,7 @@ impl<'ast> Checker<'ast> {
pos: Some(pos),
message: format!(
"Cannot apply `*` to {:?}, {:?}",
"Cannot apply `*` to {}, {}",
e1.get_type(),
e2.get_type()
),
@ -1322,7 +1322,7 @@ impl<'ast> Checker<'ast> {
pos: Some(pos),
message: format!(
"Cannot apply `*` to {:?}, {:?}",
"Cannot apply `*` to {}, {}",
t1.get_type(),
t2.get_type()
),
@ -1337,11 +1337,57 @@ impl<'ast> Checker<'ast> {
(TypedExpression::FieldElement(e1), TypedExpression::FieldElement(e2)) => {
Ok(FieldElementExpression::Div(box e1, box e2).into())
}
(TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => {
if e1.get_type() == e2.get_type() {
Ok(UExpression::div(e1, e2).into())
} else {
Err(ErrorInner {
pos: Some(pos),
message: format!(
"Cannot apply `/` to {}, {}",
e1.get_type(),
e2.get_type()
),
})
}
}
(t1, t2) => Err(ErrorInner {
pos: Some(pos),
message: format!(
"Expected only field elements, found {:?}, {:?}",
"Cannot apply `/` to {}, {}",
t1.get_type(),
t2.get_type()
),
}),
}
}
Expression::Rem(box e1, box e2) => {
let e1_checked = self.check_expression(e1, module_id, &types)?;
let e2_checked = self.check_expression(e2, module_id, &types)?;
match (e1_checked, e2_checked) {
(TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => {
if e1.get_type() == e2.get_type() {
Ok(UExpression::rem(e1, e2).into())
} else {
Err(ErrorInner {
pos: Some(pos),
message: format!(
"Cannot apply `%` to {}, {}",
e1.get_type(),
e2.get_type()
),
})
}
}
(t1, t2) => Err(ErrorInner {
pos: Some(pos),
message: format!(
"Cannot apply `%` to {}, {}",
t1.get_type(),
t2.get_type()
),
@ -1360,7 +1406,7 @@ impl<'ast> Checker<'ast> {
pos: Some(pos),
message: format!(
"Expected only field elements, found {:?}, {:?}",
"Expected only field elements, found {}, {}",
t1.get_type(),
t2.get_type()
),

View file

@ -10,6 +10,7 @@ pub enum Solver {
Or,
ShaAndXorAndXorAnd,
ShaCh,
EuclideanDiv,
}
impl fmt::Display for Solver {
@ -28,6 +29,7 @@ impl Solver {
Solver::Or => (2, 1),
Solver::ShaAndXorAndXorAnd => (3, 1),
Solver::ShaCh => (3, 1),
Solver::EuclideanDiv => (2, 2),
}
}
}

View file

@ -724,6 +724,18 @@ pub fn fold_uint_expression_inner<'ast, T: Field>(
zir::UExpressionInner::Mult(box left, box right)
}
typed_absy::UExpressionInner::Div(box left, box right) => {
let left = f.fold_uint_expression(left);
let right = f.fold_uint_expression(right);
zir::UExpressionInner::Div(box left, box right)
}
typed_absy::UExpressionInner::Rem(box left, box right) => {
let left = f.fold_uint_expression(left);
let right = f.fold_uint_expression(right);
zir::UExpressionInner::Rem(box left, box right)
}
typed_absy::UExpressionInner::Xor(box left, box right) => {
let left = f.fold_uint_expression(left);
let right = f.fold_uint_expression(right);

View file

@ -420,6 +420,48 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
UExpressionInner::Mult(box e1.annotate(bitwidth), box e2.annotate(bitwidth))
}
},
UExpressionInner::Div(box e1, box e2) => match (
self.fold_uint_expression(e1).into_inner(),
self.fold_uint_expression(e2).into_inner(),
) {
(UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => {
use std::convert::TryInto;
UExpressionInner::Value(
(v1 / v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()),
)
}
(e, UExpressionInner::Value(v)) => match v {
1 => e,
_ => UExpressionInner::Div(
box e.annotate(bitwidth),
box UExpressionInner::Value(v).annotate(bitwidth),
),
},
(e1, e2) => {
UExpressionInner::Div(box e1.annotate(bitwidth), box e2.annotate(bitwidth))
}
},
UExpressionInner::Rem(box e1, box e2) => match (
self.fold_uint_expression(e1).into_inner(),
self.fold_uint_expression(e2).into_inner(),
) {
(UExpressionInner::Value(v1), UExpressionInner::Value(v2)) => {
use std::convert::TryInto;
UExpressionInner::Value(
(v1 % v2) % 2_u128.pow(bitwidth.to_usize().try_into().unwrap()),
)
}
(e, UExpressionInner::Value(v)) => match v {
1 => UExpressionInner::Value(0),
_ => UExpressionInner::Rem(
box e.annotate(bitwidth),
box UExpressionInner::Value(v).annotate(bitwidth),
),
},
(e1, e2) => {
UExpressionInner::Rem(box e1.annotate(bitwidth), box e2.annotate(bitwidth))
}
},
UExpressionInner::RightShift(box e, box by) => {
let e = self.fold_uint_expression(e);
let by = self.fold_field_expression(by);

View file

@ -258,6 +258,20 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> {
UExpression::mult(left, right).with_max(max)
}
Div(box left, box right) => {
// reduce the two terms
let left = self.fold_uint_expression(left);
let right = self.fold_uint_expression(right);
UExpression::div(force_reduce(left), force_reduce(right)).with_max(range_max)
}
Rem(box left, box right) => {
// reduce the two terms
let left = self.fold_uint_expression(left);
let right = self.fold_uint_expression(right);
UExpression::rem(force_reduce(left), force_reduce(right)).with_max(range_max)
}
Not(box e) => {
let e = self.fold_uint_expression(e);

View file

@ -430,6 +430,18 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
UExpressionInner::Mult(box left, box right)
}
UExpressionInner::Div(box left, box right) => {
let left = f.fold_uint_expression(left);
let right = f.fold_uint_expression(right);
UExpressionInner::Div(box left, box right)
}
UExpressionInner::Rem(box left, box right) => {
let left = f.fold_uint_expression(left);
let right = f.fold_uint_expression(right);
UExpressionInner::Rem(box left, box right)
}
UExpressionInner::Xor(box left, box right) => {
let left = f.fold_uint_expression(left);
let right = f.fold_uint_expression(right);

View file

@ -890,6 +890,8 @@ impl<'ast, T: fmt::Display> fmt::Display for UExpression<'ast, T> {
UExpressionInner::Xor(ref lhs, ref rhs) => write!(f, "({} ^ {})", lhs, rhs),
UExpressionInner::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs),
UExpressionInner::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs),
UExpressionInner::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs),
UExpressionInner::Rem(ref lhs, ref rhs) => write!(f, "({} % {})", lhs, rhs),
UExpressionInner::RightShift(ref e, ref by) => write!(f, "({} >> {})", e, by),
UExpressionInner::LeftShift(ref e, ref by) => write!(f, "({} << {})", e, by),
UExpressionInner::Not(ref e) => write!(f, "!{}", e),

View file

@ -23,6 +23,18 @@ impl<'ast, T: Field> UExpression<'ast, T> {
UExpressionInner::Mult(box self, box other).annotate(bitwidth)
}
pub fn div(self, other: Self) -> UExpression<'ast, T> {
let bitwidth = self.bitwidth;
assert_eq!(bitwidth, other.bitwidth);
UExpressionInner::Div(box self, box other).annotate(bitwidth)
}
pub fn rem(self, other: Self) -> UExpression<'ast, T> {
let bitwidth = self.bitwidth;
assert_eq!(bitwidth, other.bitwidth);
UExpressionInner::Rem(box self, box other).annotate(bitwidth)
}
pub fn xor(self, other: Self) -> UExpression<'ast, T> {
let bitwidth = self.bitwidth;
assert_eq!(bitwidth, other.bitwidth);
@ -89,6 +101,8 @@ pub enum UExpressionInner<'ast, T> {
Add(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Sub(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Mult(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Div(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Rem(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Xor(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
And(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Or(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),

View file

@ -283,6 +283,18 @@ pub fn fold_uint_expression_inner<'ast, T: Field, F: Folder<'ast, T>>(
UExpressionInner::Mult(box left, box right)
}
UExpressionInner::Div(box left, box right) => {
let left = f.fold_uint_expression(left);
let right = f.fold_uint_expression(right);
UExpressionInner::Div(box left, box right)
}
UExpressionInner::Rem(box left, box right) => {
let left = f.fold_uint_expression(left);
let right = f.fold_uint_expression(right);
UExpressionInner::Rem(box left, box right)
}
UExpressionInner::Xor(box left, box right) => {
let left = f.fold_uint_expression(left);
let right = f.fold_uint_expression(right);

View file

@ -487,6 +487,8 @@ impl<'ast, T: fmt::Display> fmt::Display for UExpression<'ast, T> {
UExpressionInner::Add(ref lhs, ref rhs) => write!(f, "({} + {})", lhs, rhs),
UExpressionInner::Sub(ref lhs, ref rhs) => write!(f, "({} - {})", lhs, rhs),
UExpressionInner::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs),
UExpressionInner::Div(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs),
UExpressionInner::Rem(ref lhs, ref rhs) => write!(f, "({} % {})", lhs, rhs),
UExpressionInner::Xor(ref lhs, ref rhs) => write!(f, "({} ^ {})", lhs, rhs),
UExpressionInner::And(ref lhs, ref rhs) => write!(f, "({} & {})", lhs, rhs),
UExpressionInner::Or(ref lhs, ref rhs) => write!(f, "({} | {})", lhs, rhs),

View file

@ -22,6 +22,18 @@ impl<'ast, T: Field> UExpression<'ast, T> {
UExpressionInner::Mult(box self, box other).annotate(bitwidth)
}
pub fn div(self, other: Self) -> UExpression<'ast, T> {
let bitwidth = self.bitwidth;
assert_eq!(bitwidth, other.bitwidth);
UExpressionInner::Div(box self, box other).annotate(bitwidth)
}
pub fn rem(self, other: Self) -> UExpression<'ast, T> {
let bitwidth = self.bitwidth;
assert_eq!(bitwidth, other.bitwidth);
UExpressionInner::Rem(box self, box other).annotate(bitwidth)
}
pub fn xor(self, other: Self) -> UExpression<'ast, T> {
let bitwidth = self.bitwidth;
assert_eq!(bitwidth, other.bitwidth);
@ -148,6 +160,8 @@ pub enum UExpressionInner<'ast, T> {
Add(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Sub(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Mult(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Div(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Rem(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Xor(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
And(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Or(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),

View file

@ -0,0 +1,26 @@
{
"entry_point": "./tests/tests/uint/div.zok",
"max_constraint_count": 43,
"tests": [
{
"input": {
"values": ["255", "1"]
},
"output": {
"Ok": {
"values": ["255"]
}
}
},
{
"input": {
"values": ["42", "10"]
},
"output": {
"Ok": {
"values": ["4"]
}
}
}
]
}

View file

@ -0,0 +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

View file

@ -0,0 +1,26 @@
{
"entry_point": "./tests/tests/uint/div_rem.zok",
"max_constraint_count": 43,
"tests": [
{
"input": {
"values": ["255", "1"]
},
"output": {
"Ok": {
"values": ["255", "0"]
}
}
},
{
"input": {
"values": ["42", "10"]
},
"output": {
"Ok": {
"values": ["4", "2"]
}
}
}
]
}

View file

@ -0,0 +1,2 @@
def main(u8 n, u8 d) -> (u8, u8):
return n / d, n % d

View file

@ -0,0 +1,26 @@
{
"entry_point": "./tests/tests/uint/rem.zok",
"max_constraint_count": 43,
"tests": [
{
"input": {
"values": ["255", "1"]
},
"output": {
"Ok": {
"values": ["0"]
}
}
},
{
"input": {
"values": ["42", "10"]
},
"output": {
"Ok": {
"values": ["2"]
}
}
}
]
}

View file

@ -0,0 +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

View file

@ -12,7 +12,7 @@ use ark_ec::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};
@ -63,8 +63,8 @@ pub trait Field:
+ for<'a> Sub<&'a Self, Output = Self>
+ Mul<Self, Output = Self>
+ for<'a> Mul<&'a Self, Output = Self>
+ CheckedDiv
+ Div<Self, Output = Self>
+ for<'a> Div<&'a Self, Output = Self>
+ Pow<usize, Output = Self>
+ Pow<Self, Output = Self>
+ for<'a> Pow<&'a Self, Output = Self>
@ -80,7 +80,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<Self>;
/// 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.
@ -131,7 +131,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;
@ -175,11 +175,14 @@ mod prime_field {
self.value.to_str_radix(10)
}
fn inverse_mul(&self) -> FieldPrime {
fn inverse_mul(&self) -> Option<FieldPrime> {
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 {
@ -389,11 +392,17 @@ mod prime_field {
}
}
impl CheckedDiv for FieldPrime {
fn checked_div(&self, other: &FieldPrime) -> Option<FieldPrime> {
other.inverse_mul().map(|inv| inv * self)
}
}
impl Div<FieldPrime> for FieldPrime {
type Output = FieldPrime;
fn div(self, other: FieldPrime) -> FieldPrime {
self * other.inverse_mul()
self.checked_div(&other).unwrap()
}
}
@ -401,7 +410,7 @@ mod prime_field {
type Output = FieldPrime;
fn div(self, other: &FieldPrime) -> FieldPrime {
self / other.clone()
self.checked_div(&other).unwrap()
}
}

View file

@ -114,11 +114,12 @@ op_add = {"+"}
op_sub = {"-"}
op_mul = {"*"}
op_div = {"/"}
op_rem = {"%"}
op_pow = @{"**"}
op_not = {"!"}
op_left_shift = @{"<<"}
op_right_shift = @{">>"}
op_binary = _ { op_pow | op_or | op_and | op_bit_xor | op_bit_and | op_bit_or | op_left_shift | op_right_shift | op_equal | op_not_equal | op_lte | op_lt | op_gte | op_gt | op_add | op_sub | op_mul | op_div }
op_binary = _ { op_pow | op_or | op_and | op_bit_xor | op_bit_and | op_bit_or | op_left_shift | op_right_shift | op_equal | op_not_equal | op_lte | op_lt | op_gte | op_gt | op_add | op_sub | op_mul | op_div | op_rem }
op_unary = { op_not }

View file

@ -49,7 +49,9 @@ mod ast {
Operator::new(Rule::op_left_shift, Assoc::Left)
| Operator::new(Rule::op_right_shift, Assoc::Left),
Operator::new(Rule::op_add, Assoc::Left) | Operator::new(Rule::op_sub, Assoc::Left),
Operator::new(Rule::op_mul, Assoc::Left) | Operator::new(Rule::op_div, Assoc::Left),
Operator::new(Rule::op_mul, Assoc::Left)
| Operator::new(Rule::op_div, Assoc::Left)
| Operator::new(Rule::op_rem, Assoc::Left),
Operator::new(Rule::op_pow, Assoc::Left),
])
}
@ -71,6 +73,7 @@ mod ast {
Rule::op_sub => Expression::binary(BinaryOperator::Sub, lhs, rhs, span),
Rule::op_mul => Expression::binary(BinaryOperator::Mul, lhs, rhs, span),
Rule::op_div => Expression::binary(BinaryOperator::Div, lhs, rhs, span),
Rule::op_rem => Expression::binary(BinaryOperator::Rem, lhs, rhs, span),
Rule::op_pow => Expression::binary(BinaryOperator::Pow, lhs, rhs, span),
Rule::op_equal => Expression::binary(BinaryOperator::Eq, lhs, rhs, span),
Rule::op_not_equal => Expression::binary(BinaryOperator::NotEq, lhs, rhs, span),
@ -418,6 +421,7 @@ mod ast {
Sub,
Mul,
Div,
Rem,
Eq,
NotEq,
Lt,