diff --git a/zokrates_analysis/src/assembly_transformer.rs b/zokrates_analysis/src/assembly_transformer.rs index eb4b8ef5..3d1e9567 100644 --- a/zokrates_analysis/src/assembly_transformer.rs +++ b/zokrates_analysis/src/assembly_transformer.rs @@ -1,3 +1,7 @@ +// A static analyser pass to transform user-defined constraints to the form `lin_comb === quad_comb` +// This pass can fail if a non-quadratic constraint is found which cannot be transformed to the expected form + +use crate::ZirPropagator; use std::fmt; use zokrates_ast::zir::lqc::LinQuadComb; use zokrates_ast::zir::result_folder::{fold_field_expression, ResultFolder}; @@ -17,8 +21,7 @@ pub struct AssemblyTransformer; impl AssemblyTransformer { pub fn transform(p: ZirProgram) -> Result, Error> { - let mut f = AssemblyTransformer; - f.fold_program(p) + AssemblyTransformer.fold_program(p) } } @@ -52,7 +55,7 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for AssemblyTransformer { match is_quadratic { true => Ok(ZirAssemblyStatement::Constraint(lhs, rhs)), false => { - let sub = FieldElementExpression::Sub(box lhs.clone(), box rhs.clone()); + let sub = FieldElementExpression::Sub(box lhs, box rhs); let mut lqc = LinQuadComb::try_from(sub.clone()).map_err(|_| { Error("Non-quadratic constraints are not allowed".to_string()) })?; @@ -60,72 +63,72 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for AssemblyTransformer { let linear = lqc .linear .into_iter() - .filter_map(|(c, i)| match c { - c if c == T::from(0) => None, - c if c == T::from(1) => Some(FieldElementExpression::identifier(i)), - _ => Some(FieldElementExpression::Mult( + .map(|(c, i)| { + FieldElementExpression::Mult( box FieldElementExpression::Number(c), box FieldElementExpression::identifier(i), - )), + ) }) - .reduce(|p, n| FieldElementExpression::Add(box p, box n)) - .unwrap_or_else(|| FieldElementExpression::Number(T::from(0))); + .fold(FieldElementExpression::Number(T::from(0)), |acc, e| { + FieldElementExpression::Add(box acc, box e) + }); - let lhs = match lqc.constant { - c if c == T::from(0) => linear, - c => FieldElementExpression::Add( - box FieldElementExpression::Number(c), - box linear, - ), - }; + let lhs = FieldElementExpression::Add( + box FieldElementExpression::Number(lqc.constant), + box linear, + ); let rhs: FieldElementExpression<'ast, T> = if lqc.quadratic.len() > 1 { - let is_common_factor = |id: &Identifier<'ast>, - q: &Vec<( - T, - Identifier<'ast>, - Identifier<'ast>, - )>| { - q.iter().all(|(_, i0, i1)| i0.eq(id) || i1.eq(id)) - }; + let common_factors = lqc.quadratic.iter().fold( + None, + |acc: Option>, (_, a, b)| { + Some( + acc.map(|factors| { + factors + .into_iter() + .filter(|f| f == a || f == b) + .collect() + }) + .unwrap_or_else(|| vec![a.clone(), b.clone()]), + ) + }, + ); - let common_factor: Option> = - lqc.quadratic.iter().find_map(|(_, i0, i1)| { - if is_common_factor(i0, &lqc.quadratic) { - Some(i0.clone()) - } else if is_common_factor(i1, &lqc.quadratic) { - Some(i1.clone()) - } else { - None - } - }); - - match common_factor { - Some(id) => Ok(FieldElementExpression::Mult( + match common_factors { + Some(factors) => Ok(FieldElementExpression::Mult( box lqc .quadratic .into_iter() - .filter_map(|(c, i0, i1)| { + .map(|(c, i0, i1)| { let c = T::zero() - c; - let id = if id.eq(&i0) { i1 } else { i0 }; - match c { - c if c == T::from(0) => None, - c if c == T::from(1) => { - Some(FieldElementExpression::identifier(id)) - } - _ => Some(FieldElementExpression::Mult( - box FieldElementExpression::Number(c), - box FieldElementExpression::identifier(id), - )), - } + let i0 = match factors.contains(&i0) { + true => FieldElementExpression::Number(T::from(1)), + false => FieldElementExpression::identifier(i0), + }; + let i1 = match factors.contains(&i1) { + true => FieldElementExpression::Number(T::from(1)), + false => FieldElementExpression::identifier(i1), + }; + FieldElementExpression::Mult( + box FieldElementExpression::Number(c), + box FieldElementExpression::Mult(box i0, box i1), + ) }) - .reduce(|p, n| FieldElementExpression::Add(box p, box n)) - .unwrap_or_else(|| { - FieldElementExpression::Number(T::from(0)) - }), - box FieldElementExpression::identifier(id), + .fold( + FieldElementExpression::Number(T::from(0)), + |acc, e| FieldElementExpression::Add(box acc, box e), + ), + box factors.into_iter().fold( + FieldElementExpression::Number(T::from(1)), + |acc, id| { + FieldElementExpression::Mult( + box acc, + box FieldElementExpression::identifier(id), + ) + }, + ), )), - _ => Err(Error( + None => Err(Error( "Non-quadratic constraints are not allowed".to_string(), )), }? @@ -144,6 +147,15 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for AssemblyTransformer { .unwrap_or_else(|| FieldElementExpression::Number(T::from(0))) }; + let mut propagator = ZirPropagator::default(); + let lhs = propagator + .fold_field_expression(lhs) + .map_err(|e| Error(e.to_string()))?; + + let rhs = propagator + .fold_field_expression(rhs) + .map_err(|e| Error(e.to_string()))?; + Ok(ZirAssemblyStatement::Constraint(lhs, rhs)) } } diff --git a/zokrates_analysis/src/flatten_complex_types.rs b/zokrates_analysis/src/flatten_complex_types.rs index 2d17575e..56bb55c9 100644 --- a/zokrates_analysis/src/flatten_complex_types.rs +++ b/zokrates_analysis/src/flatten_complex_types.rs @@ -458,6 +458,27 @@ impl<'ast, T: Field> Flattener { } } +// This finder looks for identifiers that were not defined in some block of statements +// These identifiers are used as function arguments when moving witness assignment expression +// to a zir function. +// +// Example: +// def main(field a, field mut b) -> field { +// asm { +// b <== a * a; +// } +// return b; +// } +// is turned into +// def main(field a, field mut b) -> field { +// asm { +// b <-- (field a) -> field { +// return a * a; +// } +// b == a * a; +// } +// return b; +// } #[derive(Default)] pub struct ArgumentFinder<'ast, T> { pub identifiers: HashMap, zir::Type>, diff --git a/zokrates_analysis/src/propagation.rs b/zokrates_analysis/src/propagation.rs index a1c1764f..e8022ed6 100644 --- a/zokrates_analysis/src/propagation.rs +++ b/zokrates_analysis/src/propagation.rs @@ -12,7 +12,7 @@ use num_bigint::BigUint; use std::collections::HashMap; use std::convert::{TryFrom, TryInto}; use std::fmt; -use std::ops::{BitAnd, BitOr, BitXor, Mul, Shr, Sub}; +use std::ops::{BitAnd, BitOr, BitXor, Shl, Shr, Sub}; use zokrates_ast::common::FlatEmbed; use zokrates_ast::typed::result_folder::*; use zokrates_ast::typed::types::Type; @@ -402,7 +402,6 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { true => { let r: Option> = match embed_call.embed { FlatEmbed::FieldToBoolUnsafe => Ok(None), // todo - FlatEmbed::BoolToField => Ok(None), // todo FlatEmbed::BitArrayLe => Ok(None), // todo FlatEmbed::U64FromBits => Ok(Some(process_u_from_bits( &embed_call.arguments, @@ -874,6 +873,12 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { T::try_from(n1.to_biguint().bitxor(n2.to_biguint())).unwrap(), )) } + (FieldElementExpression::Number(n), e) + | (e, FieldElementExpression::Number(n)) + if n == T::from(0) => + { + Ok(e) + } (e1, e2) if e1.eq(&e2) => Ok(FieldElementExpression::Number(T::from(0))), (e1, e2) => Ok(FieldElementExpression::Xor(box e1, box e2)), } @@ -948,8 +953,7 @@ impl<'ast, 'a, T: Field> ResultFolder<'ast, T> for Propagator<'ast, 'a, T> { let mask: BigUint = two.pow(T::get_required_bits()).sub(1usize); Ok(FieldElementExpression::Number( - T::try_from(n.to_biguint().mul(two.pow(by as usize)).bitand(mask)) - .unwrap(), + T::try_from(n.to_biguint().shl(by as usize).bitand(mask)).unwrap(), )) } (e, by) => Ok(FieldElementExpression::LeftShift(box e, box by)), diff --git a/zokrates_analysis/src/zir_propagation.rs b/zokrates_analysis/src/zir_propagation.rs index 1a026b17..298166bf 100644 --- a/zokrates_analysis/src/zir_propagation.rs +++ b/zokrates_analysis/src/zir_propagation.rs @@ -2,7 +2,7 @@ use num::traits::Pow; use num_bigint::BigUint; use std::collections::HashMap; use std::fmt; -use std::ops::{BitAnd, BitOr, BitXor, Mul, Shr, Sub}; +use std::ops::{BitAnd, BitOr, BitXor, Shl, Shr, Sub}; use zokrates_ast::zir::types::UBitwidth; use zokrates_ast::zir::{ result_folder::*, Conditional, ConditionalExpression, ConditionalOrExpression, Expr, Id, @@ -334,8 +334,7 @@ impl<'ast, T: Field> ResultFolder<'ast, T> for ZirPropagator<'ast, T> { let mask: BigUint = two.pow(T::get_required_bits()).sub(1usize); Ok(FieldElementExpression::Number( - T::try_from(n.to_biguint().mul(two.pow(by as usize)).bitand(mask)) - .unwrap(), + T::try_from(n.to_biguint().shl(by as usize).bitand(mask)).unwrap(), )) } (e, by) => Ok(FieldElementExpression::LeftShift(box e, box by)), diff --git a/zokrates_ast/src/common/embed.rs b/zokrates_ast/src/common/embed.rs index 3f961cd9..58294142 100644 --- a/zokrates_ast/src/common/embed.rs +++ b/zokrates_ast/src/common/embed.rs @@ -32,7 +32,6 @@ cfg_if::cfg_if! { #[derive(Debug, Clone, PartialEq, Eq, Hash, Copy, PartialOrd, Ord, Serialize, Deserialize)] pub enum FlatEmbed { FieldToBoolUnsafe, - BoolToField, BitArrayLe, Unpack, U8ToBits, @@ -55,9 +54,6 @@ impl FlatEmbed { FlatEmbed::FieldToBoolUnsafe => UnresolvedSignature::new() .inputs(vec![UnresolvedType::FieldElement.into()]) .output(UnresolvedType::Boolean.into()), - FlatEmbed::BoolToField => UnresolvedSignature::new() - .inputs(vec![UnresolvedType::Boolean.into()]) - .output(UnresolvedType::FieldElement.into()), FlatEmbed::BitArrayLe => UnresolvedSignature::new() .generics(vec![ConstantGenericNode::mock("N")]) .inputs(vec![ @@ -197,9 +193,6 @@ impl FlatEmbed { FlatEmbed::FieldToBoolUnsafe => DeclarationSignature::new() .inputs(vec![DeclarationType::FieldElement]) .output(DeclarationType::Boolean), - FlatEmbed::BoolToField => DeclarationSignature::new() - .inputs(vec![DeclarationType::Boolean]) - .output(DeclarationType::FieldElement), FlatEmbed::BitArrayLe => DeclarationSignature::new() .generics(vec![Some(DeclarationConstant::Generic( GenericIdentifier::with_name("N").with_index(0), @@ -307,7 +300,6 @@ impl FlatEmbed { pub fn id(&self) -> &'static str { match self { FlatEmbed::FieldToBoolUnsafe => "_FIELD_TO_BOOL_UNSAFE", - FlatEmbed::BoolToField => "_BOOL_TO_FIELD", FlatEmbed::BitArrayLe => "_BIT_ARRAY_LT", FlatEmbed::Unpack => "_UNPACK", FlatEmbed::U8ToBits => "_U8_TO_BITS", diff --git a/zokrates_ast/src/common/error.rs b/zokrates_ast/src/common/error.rs index 28c209f4..499ac97d 100644 --- a/zokrates_ast/src/common/error.rs +++ b/zokrates_ast/src/common/error.rs @@ -3,7 +3,7 @@ use std::fmt; #[derive(Debug, Clone, Serialize, Deserialize, Hash, PartialEq, Eq)] pub enum RuntimeError { - UserConstraint, + SourceAssemblyConstraint, BellmanConstraint, BellmanOneBinding, BellmanInputBinding, @@ -50,7 +50,7 @@ impl RuntimeError { !matches!( self, - UserConstraint + SourceAssemblyConstraint | SourceAssertion(_) | Inverse | SelectRangeCheck @@ -65,7 +65,7 @@ impl fmt::Display for RuntimeError { use RuntimeError::*; let msg = match self { - UserConstraint => "User constraint is unsatisfied", + SourceAssemblyConstraint => "Source constraint is unsatisfied", BellmanConstraint => "Bellman constraint is unsatisfied", BellmanOneBinding => "Bellman ~one binding is unsatisfied", BellmanInputBinding => "Bellman input binding is unsatisfied", diff --git a/zokrates_ast/src/common/solvers.rs b/zokrates_ast/src/common/solvers.rs index 26247f59..915d9ceb 100644 --- a/zokrates_ast/src/common/solvers.rs +++ b/zokrates_ast/src/common/solvers.rs @@ -20,7 +20,7 @@ pub enum Solver<'ast, T> { SnarkVerifyBls12377(usize), } -impl<'ast, T: fmt::Debug + fmt::Display> fmt::Display for Solver<'ast, T> { +impl<'ast, T: fmt::Debug> fmt::Display for Solver<'ast, T> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { Solver::Zir(_) => write!(f, "Zir(..)"), diff --git a/zokrates_ast/src/zir/lqc.rs b/zokrates_ast/src/zir/lqc.rs index 746bdc31..98b1c30e 100644 --- a/zokrates_ast/src/zir/lqc.rs +++ b/zokrates_ast/src/zir/lqc.rs @@ -1,14 +1,17 @@ use crate::zir::{FieldElementExpression, Identifier}; use zokrates_field::Field; +pub type LinearTerm<'ast, T> = (T, Identifier<'ast>); +pub type QuadraticTerm<'ast, T> = (T, Identifier<'ast>, Identifier<'ast>); + #[derive(Clone, PartialEq, Hash, Eq, Debug, Default)] pub struct LinQuadComb<'ast, T> { // the constant terms pub constant: T, // the linear terms - pub linear: Vec<(T, Identifier<'ast>)>, + pub linear: Vec>, // the quadratic terms - pub quadratic: Vec<(T, Identifier<'ast>, Identifier<'ast>)>, + pub quadratic: Vec>, } impl<'ast, T: Field> std::ops::Add for LinQuadComb<'ast, T> { diff --git a/zokrates_ast/src/zir/mod.rs b/zokrates_ast/src/zir/mod.rs index b793e4d6..ba7a0e3e 100644 --- a/zokrates_ast/src/zir/mod.rs +++ b/zokrates_ast/src/zir/mod.rs @@ -166,7 +166,8 @@ pub enum ZirStatement<'ast, T> { FormatString, Vec<(ConcreteType, Vec>)>, ), - Assembly(#[serde(borrow)] Vec>), + #[serde(borrow)] + Assembly(Vec>), } impl<'ast, T: fmt::Display> fmt::Display for ZirStatement<'ast, T> { diff --git a/zokrates_cli/examples/book/assembly/bool_to_field.zok b/zokrates_cli/examples/book/assembly/bool_to_field.zok index 4c1284b0..48f0e017 100644 --- a/zokrates_cli/examples/book/assembly/bool_to_field.zok +++ b/zokrates_cli/examples/book/assembly/bool_to_field.zok @@ -1,8 +1,6 @@ -from "EMBED" import bool_to_field; - def main(bool x) -> field { // `x` is constrained by the compiler automatically so we can safely - // treat it as `field` with no extra cost - field out = bool_to_field(x); + // convert to `field` with no extra cost + field out = x ? 1 : 0; return out; } \ No newline at end of file diff --git a/zokrates_cli/examples/book/assembly/division.zok b/zokrates_cli/examples/book/assembly/division.zok index c38e18ee..b9f65af2 100644 --- a/zokrates_cli/examples/book/assembly/division.zok +++ b/zokrates_cli/examples/book/assembly/division.zok @@ -1,7 +1,11 @@ -def main(field a, field b) { +def main(field a, field b) -> field { field mut c = 0; + field mut invb = 0; asm { - c <-- a / b; + invb <-- b == 0 ? 0 : 1 / b; + invb * b === 1; + c <-- invb * a; a === b * c; } + return c; } \ No newline at end of file diff --git a/zokrates_cli/examples/book/assembly/field_to_bool.zok b/zokrates_cli/examples/book/assembly/field_to_bool.zok index b213b346..2e9f0552 100644 --- a/zokrates_cli/examples/book/assembly/field_to_bool.zok +++ b/zokrates_cli/examples/book/assembly/field_to_bool.zok @@ -5,7 +5,8 @@ def main(field x) -> bool { asm { x * (x - 1) === 0; } - // we can treat `x` as `bool` afterwards, as we constrained it properly + // we can convert `x` to `bool` afterwards, as we constrained it properly + // if we failed to constrain `x` to `0` or `1`, the call to `field_to_bool_unsafe` introduces undefined behavior // `field_to_bool_unsafe` call does not produce any extra constraints bool out = field_to_bool_unsafe(x); return out; diff --git a/zokrates_cli/src/bin.rs b/zokrates_cli/src/bin.rs index a2b857a9..a5f8a31f 100644 --- a/zokrates_cli/src/bin.rs +++ b/zokrates_cli/src/bin.rs @@ -259,7 +259,7 @@ mod tests { let interpreter = zokrates_interpreter::Interpreter::default(); - let res = interpreter.execute(artifacts.prog(), &[Bn128Field::from(0u32)]); + let res = interpreter.execute(artifacts.prog(), &[Bn128Field::from(0)]); assert!(res.is_err()); } diff --git a/zokrates_codegen/src/lib.rs b/zokrates_codegen/src/lib.rs index 25317391..ba3b92da 100644 --- a/zokrates_codegen/src/lib.rs +++ b/zokrates_codegen/src/lib.rs @@ -1050,7 +1050,6 @@ impl<'ast, T: Field> Flattener<'ast, T> { match embed { FlatEmbed::FieldToBoolUnsafe => vec![params.pop().unwrap()], - FlatEmbed::BoolToField => vec![params.pop().unwrap()], FlatEmbed::U8ToBits => self.u_to_bits(params.pop().unwrap(), 8.into()), FlatEmbed::U16ToBits => self.u_to_bits(params.pop().unwrap(), 16.into()), FlatEmbed::U32ToBits => self.u_to_bits(params.pop().unwrap(), 32.into()), @@ -2255,7 +2254,7 @@ impl<'ast, T: Field> Flattener<'ast, T> { statements_flattened.push_back(FlatStatement::Condition( lhs, rhs, - RuntimeError::UserConstraint, + RuntimeError::SourceAssemblyConstraint, )); } } diff --git a/zokrates_core/src/imports.rs b/zokrates_core/src/imports.rs index 4bdf4940..f7fa95f1 100644 --- a/zokrates_core/src/imports.rs +++ b/zokrates_core/src/imports.rs @@ -151,10 +151,6 @@ impl Importer { id: symbol.get_alias(), symbol: Symbol::Flat(FlatEmbed::FieldToBoolUnsafe), }, - "bool_to_field" => SymbolDeclaration { - id: symbol.get_alias(), - symbol: Symbol::Flat(FlatEmbed::BoolToField), - }, "bit_array_le" => SymbolDeclaration { id: symbol.get_alias(), symbol: Symbol::Flat(FlatEmbed::BitArrayLe), diff --git a/zokrates_core/src/semantics.rs b/zokrates_core/src/semantics.rs index b1ef9286..70bde599 100644 --- a/zokrates_core/src/semantics.rs +++ b/zokrates_core/src/semantics.rs @@ -1804,10 +1804,9 @@ impl<'ast, T: Field> Checker<'ast, T> { let e = match checked_e { TypedExpression::FieldElement(e) => Ok(e), TypedExpression::Int(e) => Ok(FieldElementExpression::try_from_int(e).unwrap()), - _ => Err(ErrorInner { + e => Err(ErrorInner { pos: Some(pos), - message: "Only field element expressions are allowed in the assembly block" - .to_string(), + message: format!("The right hand side of an assembly assignment must be of type field, found {}", e.get_type()) }), }?; @@ -1819,9 +1818,9 @@ impl<'ast, T: Field> Checker<'ast, T> { TypedAssemblyStatement::Assignment(assignee.clone(), e.clone()), TypedAssemblyStatement::Constraint(assignee.into(), e), ]), - _ => Err(ErrorInner { + ty => Err(ErrorInner { pos: Some(pos), - message: "Assignee must be of type `field`".to_string(), + message: format!("Assignee must be of type field, found {}", ty), }), } } @@ -1849,10 +1848,13 @@ impl<'ast, T: Field> Checker<'ast, T> { FieldElementExpression::try_from_int(lhs).unwrap(), FieldElementExpression::try_from_int(rhs).unwrap(), )), - _ => Err(ErrorInner { + (e1, e2) => Err(ErrorInner { pos: Some(pos), - message: "Only field element expressions are allowed in the assembly block" - .to_string(), + message: format!( + "Assembly constraint expected expressions of type field, found {}, {}", + e1.get_type(), + e2.get_type() + ), }), }?; @@ -1873,14 +1875,12 @@ impl<'ast, T: Field> Checker<'ast, T> { Statement::Assembly(statements) => { let mut checked_statements = vec![]; for s in statements { - checked_statements.push( + checked_statements.extend( self.check_assembly_statement(s, module_id, types) .map_err(|e| vec![e])?, ); } - Ok(TypedStatement::Assembly( - checked_statements.into_iter().flatten().collect(), - )) + Ok(TypedStatement::Assembly(checked_statements)) } Statement::Log(l, expressions) => { let l = FormatString::from(l); diff --git a/zokrates_core_test/tests/tests/assembly/binary_check.json b/zokrates_core_test/tests/tests/assembly/binary_check.json index 53912338..0973db36 100644 --- a/zokrates_core_test/tests/tests/assembly/binary_check.json +++ b/zokrates_core_test/tests/tests/assembly/binary_check.json @@ -29,7 +29,7 @@ "output": { "Err": { "UnsatisfiedConstraint": { - "error": "UserConstraint" + "error": "SourceAssemblyConstraint" } } } diff --git a/zokrates_core_test/tests/tests/assembly/bitify.json b/zokrates_core_test/tests/tests/assembly/bitify.json index ba04a1e6..19beb2bd 100644 --- a/zokrates_core_test/tests/tests/assembly/bitify.json +++ b/zokrates_core_test/tests/tests/assembly/bitify.json @@ -48,7 +48,7 @@ "output": { "Err": { "UnsatisfiedConstraint": { - "error": "UserConstraint" + "error": "SourceAssemblyConstraint" } } } diff --git a/zokrates_core_test/tests/tests/assembly/division.json b/zokrates_core_test/tests/tests/assembly/division.json index 7478326f..9e3e511a 100644 --- a/zokrates_core_test/tests/tests/assembly/division.json +++ b/zokrates_core_test/tests/tests/assembly/division.json @@ -1,6 +1,6 @@ { "curves": ["Bn128"], - "max_constraint_count": 2, + "max_constraint_count": 3, "tests": [ { "input": { @@ -14,11 +14,13 @@ }, { "input": { - "values": ["4", "0"] + "values": ["0", "0"] }, "output": { "Err": { - "Solver": "Assertion failed: `Division by zero`" + "UnsatisfiedConstraint": { + "error": "SourceAssemblyConstraint" + } } } } diff --git a/zokrates_core_test/tests/tests/assembly/division.zok b/zokrates_core_test/tests/tests/assembly/division.zok index 35669ffd..b9f65af2 100644 --- a/zokrates_core_test/tests/tests/assembly/division.zok +++ b/zokrates_core_test/tests/tests/assembly/division.zok @@ -1,8 +1,11 @@ -def main(field x, field y) -> field { - field mut z = 0; +def main(field a, field b) -> field { + field mut c = 0; + field mut invb = 0; asm { - z <-- x / y; - z * y === x; + invb <-- b == 0 ? 0 : 1 / b; + invb * b === 1; + c <-- invb * a; + a === b * c; } - return z; + return c; } \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/embed/bool_to_field.json b/zokrates_core_test/tests/tests/embed/bool_to_field.json deleted file mode 100644 index 5e78b298..00000000 --- a/zokrates_core_test/tests/tests/embed/bool_to_field.json +++ /dev/null @@ -1,26 +0,0 @@ -{ - "curves": ["Bn128"], - "max_constraint_count": 2, - "tests": [ - { - "input": { - "values": [false] - }, - "output": { - "Ok": { - "value": "0" - } - } - }, - { - "input": { - "values": [true] - }, - "output": { - "Ok": { - "value": "1" - } - } - } - ] -} diff --git a/zokrates_core_test/tests/tests/embed/bool_to_field.zok b/zokrates_core_test/tests/tests/embed/bool_to_field.zok deleted file mode 100644 index 457ac06d..00000000 --- a/zokrates_core_test/tests/tests/embed/bool_to_field.zok +++ /dev/null @@ -1,6 +0,0 @@ -from "EMBED" import bool_to_field; - -def main(bool x) -> field { - field out = bool_to_field(x); - return out; -} \ No newline at end of file diff --git a/zokrates_core_test/tests/tests/embed/field_to_bool.json b/zokrates_core_test/tests/tests/embed/field_to_bool.json index d24af7e0..b8357755 100644 --- a/zokrates_core_test/tests/tests/embed/field_to_bool.json +++ b/zokrates_core_test/tests/tests/embed/field_to_bool.json @@ -29,7 +29,7 @@ "output": { "Err": { "UnsatisfiedConstraint": { - "error": "UserConstraint" + "error": "SourceAssemblyConstraint" } } } diff --git a/zokrates_test/tests/out_of_range.rs b/zokrates_test/tests/out_of_range.rs index 781bae76..ea280025 100644 --- a/zokrates_test/tests/out_of_range.rs +++ b/zokrates_test/tests/out_of_range.rs @@ -42,7 +42,7 @@ fn lt_field() { assert!(interpreter .execute( res.prog(), - &[Bn128Field::from(10000u32), Bn128Field::from(5555u32)] + &[Bn128Field::from(10000), Bn128Field::from(5555)] ) .is_err()); } @@ -78,7 +78,7 @@ fn lt_uint() { assert!(interpreter .execute( res.prog(), - &[Bn128Field::from(10000u32), Bn128Field::from(5555u32)] + &[Bn128Field::from(10000), Bn128Field::from(5555)] ) .is_err()); } @@ -123,7 +123,7 @@ fn unpack256() { let interpreter = Interpreter::try_out_of_range(); assert!(interpreter - .execute(res.prog(), &[Bn128Field::from(0u32)]) + .execute(res.prog(), &[Bn128Field::from(0)]) .is_err()); } @@ -167,6 +167,6 @@ fn unpack256_unchecked() { let interpreter = Interpreter::try_out_of_range(); assert!(interpreter - .execute(res.prog(), &[Bn128Field::from(0u32)]) + .execute(res.prog(), &[Bn128Field::from(0)]) .is_ok()); }