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

clean, add boolean check to all boolean user input

This commit is contained in:
schaeff 2019-09-23 18:33:08 +02:00
parent a0c2663471
commit 79fea57be8
10 changed files with 211 additions and 51 deletions

16
t.code
View file

@ -1,16 +0,0 @@
from "./u.code" import Fooo
struct Bar {
a: field,
a: field,
c: field,
}
struct Baz {
a: Bar
}
def main(Bar a, Bar b, bool c) -> (Bar):
Bar bar = Bar { a: 1, b: 1, c: 1 }
return if false then a else bar fi

4
u.code
View file

@ -1,4 +0,0 @@
struct Foo {
a: field,
b: field[2],
}

View file

@ -138,8 +138,6 @@ pub fn compile<T: Field, R: BufRead, S: BufRead, E: Into<imports::Error>>(
let source = arena.alloc(source);
println!("{:?}", source);
let compiled = compile_program(source, location.clone(), resolve_option, &arena)?;
// check semantics

View file

@ -1548,7 +1548,7 @@ impl<'ast, T: Field> Flattener<'ast, T> {
let arguments_flattened = funct
.arguments
.into_iter()
.flat_map(|p| self.use_parameter(&p, &mut statements_flattened))
.flat_map(|p| self.use_parameter(&p))
.collect();
// flatten statements in functions and apply substitution
@ -1602,19 +1602,8 @@ impl<'ast, T: Field> Flattener<'ast, T> {
vars
}
fn use_parameter(
&mut self,
parameter: &Parameter<'ast>,
statements: &mut Vec<FlatStatement<T>>,
) -> Vec<FlatParameter> {
fn use_parameter(&mut self, parameter: &Parameter<'ast>) -> Vec<FlatParameter> {
let variables = self.use_variable(&parameter.id);
match parameter.id.get_type() {
Type::Boolean => statements.extend(Self::boolean_constraint(&variables)),
Type::Array(box Type::Boolean, _) => {
statements.extend(Self::boolean_constraint(&variables))
}
_ => {}
};
variables
.into_iter()
@ -1635,21 +1624,6 @@ impl<'ast, T: Field> Flattener<'ast, T> {
(0..count).map(|_| self.issue_new_variable()).collect()
}
fn boolean_constraint(variables: &Vec<FlatVariable>) -> Vec<FlatStatement<T>> {
variables
.iter()
.map(|v| {
FlatStatement::Condition(
FlatExpression::Identifier(*v),
FlatExpression::Mult(
box FlatExpression::Identifier(*v),
box FlatExpression::Identifier(*v),
),
)
})
.collect()
}
// create an internal variable. We do not register it in the layout
fn use_sym(&mut self) -> FlatVariable {
self.issue_new_variable()

View file

@ -0,0 +1,120 @@
//! Add runtime boolean checks on user inputs
//! Example:
//! ```
//! struct Foo {
//! bar: bool
//! }
//!
//! def main(Foo f) -> ():
//! f.bar == f.bar && f.bar
//! return
//! ```
//! @file unroll.rs
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
//! @date 2018
use crate::typed_absy::folder::Folder;
use crate::typed_absy::types::Type;
use crate::typed_absy::*;
use zokrates_field::field::Field;
pub struct InputConstrainer<'ast, T: Field> {
constraints: Vec<TypedStatement<'ast, T>>,
}
impl<'ast, T: Field> InputConstrainer<'ast, T> {
fn new() -> Self {
InputConstrainer {
constraints: vec![],
}
}
pub fn constrain(p: TypedProgram<T>) -> TypedProgram<T> {
InputConstrainer::new().fold_program(p)
}
fn constrain_expression(&mut self, e: TypedExpression<'ast, T>) {
match e {
TypedExpression::FieldElement(_) => {}
TypedExpression::Boolean(b) => self.constraints.push(TypedStatement::Condition(
b.clone().into(),
BooleanExpression::And(box b.clone(), box b).into(),
)),
TypedExpression::Array(a) => {
for i in 0..a.size() {
let e = match a.inner_type() {
Type::FieldElement => FieldElementExpression::select(
a.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
Type::Boolean => BooleanExpression::select(
a.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
Type::Array(..) => ArrayExpression::select(
a.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
Type::Struct(..) => StructExpression::select(
a.clone(),
FieldElementExpression::Number(T::from(i)),
)
.into(),
};
self.constrain_expression(e);
}
}
TypedExpression::Struct(s) => {
for (id, ty) in s.ty() {
let e = match ty {
Type::FieldElement => {
FieldElementExpression::member(s.clone(), id.clone()).into()
}
Type::Boolean => BooleanExpression::member(s.clone(), id.clone()).into(),
Type::Array(..) => ArrayExpression::member(s.clone(), id.clone()).into(),
Type::Struct(..) => StructExpression::member(s.clone(), id.clone()).into(),
};
self.constrain_expression(e);
}
}
}
}
}
impl<'ast, T: Field> Folder<'ast, T> for InputConstrainer<'ast, T> {
fn fold_parameter(&mut self, p: Parameter<'ast>) -> Parameter<'ast> {
let v = p.id.clone();
let e = match v.get_type() {
Type::FieldElement => FieldElementExpression::Identifier(v.id).into(),
Type::Boolean => BooleanExpression::Identifier(v.id).into(),
Type::Struct(members) => StructExpressionInner::Identifier(v.id)
.annotate(members)
.into(),
Type::Array(box ty, size) => ArrayExpressionInner::Identifier(v.id)
.annotate(ty, size)
.into(),
};
self.constrain_expression(e);
p
}
fn fold_function(&mut self, f: TypedFunction<'ast, T>) -> TypedFunction<'ast, T> {
TypedFunction {
arguments: f
.arguments
.into_iter()
.map(|a| self.fold_parameter(a))
.collect(),
statements: self.constraints.drain(..).chain(f.statements).collect(),
..f
}
}
}

View file

@ -4,11 +4,13 @@
//! @author Thibaut Schaeffer <thibaut@schaeff.fr>
//! @date 2018
mod constrain_inputs;
mod flat_propagation;
mod inline;
mod propagation;
mod unroll;
use self::constrain_inputs::InputConstrainer;
use self::inline::Inliner;
use self::propagation::Propagator;
use self::unroll::Unroller;
@ -24,11 +26,12 @@ impl<'ast, T: Field> Analyse for TypedProgram<'ast, T> {
fn analyse(self) -> Self {
// unroll
let r = Unroller::unroll(self);
println!("{}", r);
// inline
let r = Inliner::inline(r);
// propagate
let r = Propagator::propagate(r);
// constrain inputs
let r = InputConstrainer::constrain(r);
r
}
}

View file

@ -0,0 +1,2 @@
def main(bool[3] a) -> (bool[3]):
return a

View file

@ -0,0 +1,38 @@
{
"entry_point": "./tests/tests/arrays/identity.code",
"tests": [
{
"input": {
"values": ["0", "0", "0"]
},
"output": {
"Ok": {
"values": ["0", "0", "0"]
}
}
},
{
"input": {
"values": ["1", "0", "1"]
},
"output": {
"Ok": {
"values": ["1", "0", "1"]
}
}
},
{
"input": {
"values": ["2", "1", "1"]
},
"output": {
"Err": {
"UnsatisfiedConstraint": {
"left": "4",
"right": "2"
}
}
}
}
]
}

View file

@ -0,0 +1,7 @@
struct A {
a: field,
b: bool
}
def main(A a) -> (A):
return a

View file

@ -0,0 +1,38 @@
{
"entry_point": "./tests/tests/structs/identity.code",
"tests": [
{
"input": {
"values": ["42", "0"]
},
"output": {
"Ok": {
"values": ["42", "0"]
}
}
},
{
"input": {
"values": ["42", "1"]
},
"output": {
"Ok": {
"values": ["42", "1"]
}
}
},
{
"input": {
"values": ["42", "3"]
},
"output": {
"Err": {
"UnsatisfiedConstraint": {
"left": "9",
"right": "3"
}
}
}
}
]
}