1
0
Fork 0
mirror of synced 2025-09-23 04:08:33 +00:00

fix conflicts

This commit is contained in:
schaeff 2020-07-16 00:12:39 +02:00
commit a983f1e145
136 changed files with 1176 additions and 1988 deletions

View file

@ -130,7 +130,7 @@ jobs:
command: cd zokrates_js && npm run build
zokrates_js_test:
docker:
- image: circleci/node
- image: dark64/rust-wasm-env:latest
steps:
- checkout
- run:

View file

@ -5,5 +5,5 @@ def foo(field[3] a) -> (field):
def main() -> (field, field):
field[3] a = [0, 0, 0]
field res = foo(a)
a[1] == 0
assert(a[1] == 0)
return res, a[1]

View file

@ -5,5 +5,5 @@ def main(field a) -> (field, field):
field[2] result = [0, 0]
field r = foo(a)
result[1] = r
result[1] == r
assert(result[1] == r)
return result[1], r

View file

@ -1,3 +1,2 @@
def main(private field a, field b) -> (field):
field result = if a * a == b then 1 else 0 fi
return result
def main(private field a, field b) -> (bool):
return a * a == b

View file

@ -1,4 +1,4 @@
def main() -> (field):
def main() -> ():
field pMinusOne = 21888242871839275222246405745257275088548364400416034343698204186575808495616
0 - 1 == pMinusOne
return 1
assert(0 - 1 == pMinusOne)
return

View file

@ -1,7 +1,7 @@
import "hashes/sha256/512bitPacked" as sha256packed
def main(private field a, private field b, private field c, private field d) -> (field):
def main(private field a, private field b, private field c, private field d) -> ():
field[2] h = sha256packed([a, b, c, d])
h[0] == 263561599766550617289250058199814760685
h[1] == 65303172752238645975888084098459749904
return 1
assert(h[0] == 263561599766550617289250058199814760685)
assert(h[1] == 65303172752238645975888084098459749904)
return

View file

@ -2,8 +2,8 @@ def incr(field a) -> (field):
a = a + 1
return a
def main() -> (field):
def main() -> ():
field x = 1
field res = incr(x)
x == 1 // x has not changed
return 1
assert(x == 1) // x has not changed
return

View file

@ -4,6 +4,6 @@ def foo() -> (field, field[3]):
def foo() -> (field, field):
return 1, 2
def main() -> (field):
def main() -> ():
field a, field[3] b = foo()
return 1
return

View file

@ -3,5 +3,5 @@
def main(field a, field b) -> (field):
field y = if a + 2 == 3 && a * 2 == 2 then 1 else 0 fi
field z = if y == 1 && 1-y == 0 then y else 1 fi
b == 1
assert(b == 1)
return a

View file

@ -2,6 +2,6 @@
def main(field a, field b) -> (field):
field y = if a + 2 == 4 || b * 2 == 2 then 1 else 0 fi
field z = if y == 1 || y == 0 then y else 1 fi
z == 1
assert(z == 1)
return z

View file

@ -2,6 +2,6 @@
def main(field a) -> (field): // a needs to be 1
field b = a + 5 // inline comment
field c = a + b + a + 4
a == 1 // another inline comment
assert(a == 1) // another inline comment
field d = a + c + a + b
return b + c + d

View file

@ -1,6 +1,19 @@
struct Foo {
field a
}
struct Bar {
Foo[1] foo
}
def isEqual(field a, field b) -> (bool):
return a == b
def main(field a) -> (field):
field b = (a + 5) * 6
2 * b == a * 12 + 60
assert(2 * b == a * 12 + 60)
field c = 7 * (b + a)
c == 7 * b + 7 * a
return b + c
assert(isEqual(c, 7 * b + 7 * a))
field k = if [1, 2] == [3, 4] then 1 else 3 fi
assert([Bar { foo : [Foo { a: 42 }]}] == [Bar { foo : [Foo { a: 42 }]}])
return b + c

View file

@ -0,0 +1,5 @@
def assert() -> ():
return
def main() -> ():
return

View file

@ -1,5 +1,5 @@
// a and b are factorization of c
def main(field c, private field a, private field b) -> (field):
def main(field c, private field a, private field b) -> ():
field d = a * b
c == d
return 1
assert(c == d)
return

View file

@ -1,23 +1,17 @@
def lt(field a,field b) -> (field):
return if a < b then 1 else 0 fi
def lt(field a,field b) -> (bool):
return a < b
def cutoff() -> (field):
return 31337
def getThing(field index) -> (field):
field result = 3
result = if index == 0 then 13 else result fi
result = if index == 1 then 23 else result fi
result = if index == 2 then 43 else result fi
result = if index == 3 then 53 else result fi
result = if index == 4 then 73 else result fi
result = if index == 5 then 83 else result fi
return result
field[6] a = [13, 23, 43, 53, 73, 83]
return a[index]
def cubeThing(field thing) -> (field):
return thing**3
def main(field index) -> (field):
def main(field index) -> (bool):
field thing = getThing(index)
thing = cubeThing(thing)
return lt(cutoff(), thing)

View file

@ -7,5 +7,5 @@ import "./bar"
def main() -> (field):
MyBar my_bar = MyBar {}
Bar bar = Bar {}
my_bar == bar
assert(my_bar == bar)
return foo() + bar()

View file

@ -1,6 +1,6 @@
def foo() -> (field):
return 1
def main() -> (field):
foo() + (1 + 44*3) == 1
return 1
def main() -> ():
assert(foo() + (1 + 44*3) == 1)
return

View file

@ -6,7 +6,11 @@ import "hashes/utils/256bitsDirectionHelper" as multiplex
// Merke-Tree inclusion proof for tree depth 3 using SNARK efficient pedersen hashes
// directionSelector=> 1/true if current digest is on the rhs of the hash
<<<<<<< HEAD
def main(u32[8] rootDigest, private u32[8] leafDigest, private bool[3] directionSelector, u32[8] PathDigest0, private u32[8] PathDigest1, private u32[8] PathDigest2) -> (field):
=======
def main(bool[256] rootDigest, private bool[256] leafDigest, private bool[3] directionSelector, bool[256] PathDigest0, private bool[256] PathDigest1, private bool[256] PathDigest2) -> ():
>>>>>>> 26f4d72ee6e0c802823cf145fbd11a372586eb28
BabyJubJubParams context = context()
//Setup
@ -22,7 +26,7 @@ def main(u32[8] rootDigest, private u32[8] leafDigest, private bool[3] direction
preimage = multiplex(directionSelector[2], currentDigest, PathDigest2)
currentDigest = hash(preimage)
rootDigest == currentDigest
return 1 //return true in success
assert(rootDigest == currentDigest)
return

View file

@ -3,7 +3,11 @@ import "utils/multiplexer/256bit" as multiplex
// Merkle-Tree inclusion proof for tree depth 3
<<<<<<< HEAD
def main(field treeDepth, u32[8] rootDigest, private u32[8] leafDigest, private bool[2] directionSelector, u32[8] PathDigest0, private u32[8] PathDigest1) -> (field):
=======
def main(field treeDepth, bool[256] rootDigest, private bool[256] leafDigest, private bool[2] directionSelector, bool[256] PathDigest0, private bool[256] PathDigest1) -> ():
>>>>>>> 26f4d72ee6e0c802823cf145fbd11a372586eb28
//Setup
u32[8] currentDigest = leafDigest
@ -23,8 +27,7 @@ def main(field treeDepth, u32[8] rootDigest, private u32[8] leafDigest, private
currentDigest = sha256(lhs, rhs)
counter = counter + 1
//Asserts
counter == treeDepth
rootDigest == currentDigest
assert(counter == treeDepth)
assert(rootDigest == currentDigest)
return 1 //return true in success
return

View file

@ -2,6 +2,6 @@ def foo(field a) -> (field, field, field, field):
field b = 12*a
return a, 2*a, 5*b, a*b
def main(field i) -> (field):
def main(field i) -> ():
field x, field y, field z, field t = foo(i)
return 1
return

View file

@ -1,4 +1,4 @@
// this code does not need to be flattened
def main(field x, field a, field b) -> (field):
a == b * 7
assert(a == b * 7)
return x + a + b

View file

@ -1,6 +1,6 @@
// this code does not need to be flattened
def main(field x, field y, field z) -> (field):
field a = x + 3*y - z *2 - x * 12
3*y - z *2 - x * 12 == a - x
(x + y) - ((z + 3*x) - y) == (x - y) + ((2*x - 4*y) + (4*y - 2*z))
assert(3*y - z *2 - x * 12 == a - x)
assert((x + y) - ((z + 3*x) - y) == (x - y) + ((2*x - 4*y) + (4*y - 2*z)))
return x

View file

@ -1,16 +1,16 @@
def main() -> (field):
def main() -> ():
field x = 2**4
x == 16
assert(x == 16)
x = x**2
x == 256
assert(x == 256)
field y = 3**3
y == 27
assert(y == 27)
field z = y**2
z == 729
assert(z == 729)
field a = 5**2
a == 25
assert(a == 25)
a = a**2
a == 625
assert(a == 625)
a = 5**5
a == 3125
return 1
assert(a == 3125)
return

View file

@ -1,5 +1,5 @@
def foo(field a, field b) -> (field, field):
a == b + 2
assert(a == b + 2)
return a, b
def main() -> (field):

View file

@ -4,9 +4,9 @@
// It should not work for the maxvalue = 2^(pbits - 2) - 1 augmented by one
// /!\ should be called with a = 0
def main(field a) -> (field):
def main(field a) -> (bool):
field pbits = 254
// maxvalue = 2**252 - 1
field maxvalue = a + 7237005577332262213973186563042994240829374041602535252466099000494570602496 - 1
// we added a = 0 to prevent the condition to be evaluated at compile time
return if 0 < (maxvalue + 1) then 1 else 0 fi
return 0 < (maxvalue + 1)

View file

@ -1,7 +1,7 @@
// as p - 1 is greater than p/2, comparing to it should fail
// /!\ should be called with a = 0
def main(field a) -> (field):
def main(field a) -> (bool):
field p = 21888242871839275222246405745257275088548364400416034343698204186575808495617 + a
// we added a = 0 to prevent the condition to be evaluated at compile time
return if 0 < p - 1 then 1 else 0 fi
return 0 < p - 1

View file

@ -0,0 +1,58 @@
// Sudoku of format
// | a11 | a12 || b11 | b12 |
// --------------------------
// | a21 | a22 || b21 | b22 |
// ==========================
// | c11 | c12 || d11 | d12 |
// --------------------------
// | c21 | c22 || d21 | d22 |
// We encode values in the following way:
// 1 -> 2
// 2 -> 3
// 3 -> 5
// 4 -> 7
// returns true if there are no duplicates
// assumption: `a, b, c, d` are all in `{ 2, 3, 5, 7 }`
def checkNoDuplicates(field a, field b, field c, field d) -> (bool):
// as `{ 2, 3, 5, 7 }` are primes, the set `{ a, b, c, d }` is equal to the set `{ 2, 3, 5, 7}` if and only if the products match
return a * b * c * d == 2 * 3 * 5 * 7
// returns `0` if and only if `x` in `{ 2, 3, 5, 7 }`
def validateInput(field x) -> (bool):
return (x-2) * (x-3) * (x-5) * (x-7) == 0
// variables naming: box'row''column'
def main(field a21, field b11, field b22, field c11, field c22, field d21, private field a11, private field a12, private field a22, private field b12, private field b21, private field c12, private field c21, private field d11, private field d12, private field d22) -> (bool):
field[4][4] a = [[a11, a12, b11, b12], [a21, a22, b21, b22], [c11, c12, d11, d12], [c21, c22, d21, d22]]
bool res = true
// go through the whole grid and check that all elements are valid
for field i in 0..4 do
for field j in 0..4 do
res = res && validateInput(a[i][j])
endfor
endfor
// go through the 4 2x2 boxes and check that they do not contain duplicates
for field i in 0..1 do
for field j in 0..1 do
res = res && checkNoDuplicates(a[2*i][2*i], a[2*i][2*i + 1], a[2*i + 1][2*i], a[2*i + 1][2*i + 1])
endfor
endfor
// go through the 4 rows and check that they do not contain duplicates
for field i in 0..4 do
res = res && checkNoDuplicates(a[i][0], a[i][1], a[i][2], a[i][3])
endfor
// go through the 4 columns and check that they do not contain duplicates
for field j in 0..4 do
res = res && checkNoDuplicates(a[0][j], a[1][j], a[2][j], a[3][j])
endfor
return res

View file

@ -0,0 +1,75 @@
// Sudoku of format
// | a11 | a12 || b11 | b12 |
// --------------------------
// | a21 | a22 || b21 | b22 |
// ==========================
// | c11 | c12 || d11 | d12 |
// --------------------------
// | c21 | c22 || d21 | d22 |
// We use a naive encoding of the values as `[1, 2, 3, 4]` and rely on if-else statements to detect duplicates
def countDuplicates(field e11,field e12,field e21,field e22) -> (field):
field duplicates = if e11 == e12 then 1 else 0 fi
duplicates = duplicates + if e11 == e21 then 1 else 0 fi
duplicates = duplicates + if e11 == e22 then 1 else 0 fi
duplicates = duplicates + if e12 == e21 then 1 else 0 fi
duplicates = duplicates + if e12 == e21 then 1 else 0 fi
duplicates = duplicates + if e21 == e22 then 1 else 0 fi
return duplicates
// returns 0 for x in (1..4)
def validateInput(field x) -> (bool):
return (x-1)*(x-2)*(x-3)*(x-4) == 0
// variables naming: box'row''column'
def main(field a21, field b11, field b22, field c11, field c22, field d21, private field a11, private field a12, private field a22, private field b12, private field b21, private field c12, private field c21, private field d11, private field d12, private field d22) -> (bool):
// validate inputs
assert(validateInput(a11))
assert(validateInput(a12))
assert(validateInput(a21))
assert(validateInput(a22))
assert(validateInput(b11))
assert(validateInput(b12))
assert(validateInput(b21))
assert(validateInput(b22))
assert(validateInput(c11))
assert(validateInput(c12))
assert(validateInput(c21))
assert(validateInput(c22))
assert(validateInput(d11))
assert(validateInput(d12))
assert(validateInput(d21))
assert(validateInput(d22))
field duplicates = 0 // globally counts duplicate entries in boxes, rows and columns
// check box correctness
// no duplicates
duplicates = duplicates + countDuplicates(a11,a12,a21,a22)
duplicates = duplicates + countDuplicates(b11,b12,b21,b22)
duplicates = duplicates + countDuplicates(c11,c12,c21,c22)
duplicates = duplicates + countDuplicates(d11,d12,d21,d22)
// check row correctness
duplicates = duplicates + countDuplicates(a11,a12,b11,b12)
duplicates = duplicates + countDuplicates(a21,a22,b21,b22)
duplicates = duplicates + countDuplicates(c11,c12,d11,d12)
duplicates = duplicates + countDuplicates(c21,c22,d21,d22)
// check column correctness
duplicates = duplicates + countDuplicates(a11,a21,c11,c21)
duplicates = duplicates + countDuplicates(a12,a22,c12,c22)
duplicates = duplicates + countDuplicates(b11,b21,d11,d21)
duplicates = duplicates + countDuplicates(b12,b22,d12,d22)
// the solution is correct if and only if there are no duplicates
return duplicates == 0

View file

@ -1,75 +0,0 @@
// Sudoku of format
// | a11 | a12 || b11 | b12 |
// --------------------------
// | a21 | a22 || b21 | b22 |
// ==========================
// | c11 | c12 || d11 | d12 |
// --------------------------
// | c21 | c22 || d21 | d22 |
def checkEquality(field e11,field e12,field e21,field e22) -> (field):
field counter = if e11 == e12 then 1 else 0 fi
counter = counter + if e11 == e21 then 1 else 0 fi
counter = counter + if e11 == e22 then 1 else 0 fi
counter = counter + if e12 == e21 then 1 else 0 fi
counter = counter + if e12 == e21 then 1 else 0 fi
counter = counter + if e21 == e22 then 1 else 0 fi
return counter
// returns 0 for x in (1..4)
def validateInput(field x) -> (field):
return (x-1)*(x-2)*(x-3)*(x-4)
// variables naming: box'row''column'
def main(field a21, field b11, field b22, field c11, field c22, field d21, private field a11, private field a12, private field a22, private field b12, private field b21, private field c12, private field c21, private field d11, private field d12, private field d22) -> (field):
// validate inputs
0 == validateInput(a11)
0 == validateInput(a12)
0 == validateInput(a21)
0 == validateInput(a22)
0 == validateInput(b11)
0 == validateInput(b12)
0 == validateInput(b21)
0 == validateInput(b22)
0 == validateInput(c11)
0 == validateInput(c12)
0 == validateInput(c21)
0 == validateInput(c22)
0 == validateInput(d11)
0 == validateInput(d12)
0 == validateInput(d21)
0 == validateInput(d22)
field counter = 0 // globally counts duplicate entries in boxes, rows and columns
// check box correctness
// no duplicates
counter = counter + checkEquality(a11,a12,a21,a22)
counter = counter + checkEquality(b11,b12,b21,b22)
counter = counter + checkEquality(c11,c12,c21,c22)
counter = counter + checkEquality(d11,d12,d21,d22)
// check row correctness
counter = counter + checkEquality(a11,a12,b11,b12)
counter = counter + checkEquality(a21,a22,b21,b22)
counter = counter + checkEquality(c11,c12,d11,d12)
counter = counter + checkEquality(c21,c22,d21,d22)
// check column correctness
counter = counter + checkEquality(a11,a21,c11,c21)
counter = counter + checkEquality(a12,a22,c12,c22)
counter = counter + checkEquality(b11,b21,d11,d21)
counter = counter + checkEquality(b12,b22,d12,d22)
// assert counter is 0
counter == 0
return 1

View file

@ -3,11 +3,11 @@ def main(field x) -> (field):
field a = 5
field b = 7
field c = if a == b then 4 else 3 fi
c == 3
assert(c == 3)
field d = if a == 5 then 1 else 2 fi
d == 1
assert(d == 1)
field e = if a < b then 5 else 6 fi
e == 5
assert(e == 5)
field f = if b < a then 7 else 8 fi
f == 8
assert(f == 8)
return x

View file

@ -3,8 +3,8 @@
// we can compare numbers up to 2^(pbits - 2) - 1, ie any number which fits in (pbits - 2) bits
// lt should work for the maxvalue = 2^(pbits - 2) - 1
def main(field a) -> (field):
def main(field a) -> (bool):
field pbits = 254
// maxvalue = 2**252 - 1
field maxvalue = 7237005577332262213973186563042994240829374041602535252466099000494570602496 - 1
return if 0 < maxvalue then 1 else 0 fi
return 0 < maxvalue

View file

@ -2,24 +2,14 @@
// In this example, the crowd is a series of numbers, ideally* all prime but one, and Waldo is a non-prime number
// * we don't enforce only one number being non-prime, so there could be multiple Waldos
def isWaldo(field a, field p, field q) -> (field):
// make sure that p and q are both non zero
// we can't check inequalities, so let's create binary
// variables
field p1 = if p == 1 then 0 else 1 fi // "p != 1"
field q1 = if q == 1 then 0 else 1 fi // "q != 1"
q1 * p1 == 1 // "p1 and q1"
def isWaldo(field a, field p, field q) -> (bool):
// make sure that p and q are both not one
assert(p != 1 && q != 1)
// we know how to factor a
a == p * q
return 1
return a == p * q
// define all
def main(field a0, field a1, field a2, field a3, private field index, private field p, private field q) -> (field):
def main(field[3] a, private field index, private field p, private field q) -> (bool):
// prover provides the index of Waldo
field waldo = if index == 0 then a0 else 0 fi
waldo = waldo + if index == 1 then a1 else 0 fi
waldo = waldo + if index == 2 then a2 else 0 fi
waldo = waldo + if index == 3 then a3 else 0 fi
return isWaldo(waldo, p, q)
return isWaldo(a[index], p, q)

View file

@ -1,3 +1,3 @@
def main(field a, field b) -> ():
a==b
assert(a == b)
return

View file

@ -7,7 +7,7 @@ readme = "README.md"
build = "build.rs"
[features]
default = []
default = ["bellman_ce/nolog"]
libsnark = ["cc", "cmake", "git2"]
wasm = ["bellman_ce/wasm"]
multicore = ["bellman_ce/multicore"]

View file

@ -44,6 +44,7 @@ fn main() {
.define("USE_PT_COMPRESSION", "OFF")
.define("MONTGOMERY_OUTPUT", "ON")
.define("BINARY_OUTPUT", "ON")
.define("DMULTICORE", "ON")
.build();
// build backends

View file

@ -262,23 +262,8 @@ impl<'ast, T: Field> From<pest::AssertionStatement<'ast>> for absy::StatementNod
fn from(statement: pest::AssertionStatement<'ast>) -> absy::StatementNode<T> {
use absy::NodeValue;
match statement.expression {
pest::Expression::Binary(e) => match e.op {
pest::BinaryOperator::Eq => absy::Statement::Condition(
absy::ExpressionNode::from(*e.left),
absy::ExpressionNode::from(*e.right),
),
_ => unimplemented!(
"Assertion statements should be an equality check, found {}",
statement.span.as_str()
),
},
_ => unimplemented!(
"Assertion statements should be an equality check, found {}",
statement.span.as_str()
),
}
.span(statement.span)
absy::Statement::Assertion(absy::ExpressionNode::from(statement.expression))
.span(statement.span)
}
}
@ -389,7 +374,14 @@ impl<'ast, T: Field> From<pest::BinaryExpression<'ast>> for absy::ExpressionNode
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
),
o => unimplemented!("Operator {:?} not implemented", o),
// rewrite (a != b)` as `!(a == b)`
pest::BinaryOperator::NotEq => absy::Expression::Not(
box absy::Expression::Eq(
box absy::ExpressionNode::from(*expression.left),
box absy::ExpressionNode::from(*expression.right),
)
.span(expression.span.clone()),
),
}
.span(expression.span)
}

View file

@ -299,7 +299,7 @@ pub enum Statement<'ast, T> {
Return(ExpressionListNode<'ast, T>),
Declaration(VariableNode<'ast>),
Definition(AssigneeNode<'ast, T>, ExpressionNode<'ast, T>),
Condition(ExpressionNode<'ast, T>, ExpressionNode<'ast, T>),
Assertion(ExpressionNode<'ast, T>),
For(
VariableNode<'ast>,
ExpressionNode<'ast, T>,
@ -317,7 +317,7 @@ impl<'ast, T: fmt::Display> fmt::Display for Statement<'ast, T> {
Statement::Return(ref expr) => write!(f, "return {}", expr),
Statement::Declaration(ref var) => write!(f, "{}", var),
Statement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs),
Statement::Condition(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
Statement::Assertion(ref e) => write!(f, "assert({})", e),
Statement::For(ref var, ref start, ref stop, ref list) => {
write!(f, "for {} in {}..{} do\n", var, start, stop)?;
for l in list {
@ -346,7 +346,7 @@ impl<'ast, T: fmt::Debug> fmt::Debug for Statement<'ast, T> {
Statement::Definition(ref lhs, ref rhs) => {
write!(f, "Definition({:?}, {:?})", lhs, rhs)
}
Statement::Condition(ref lhs, ref rhs) => write!(f, "Condition({:?}, {:?})", lhs, rhs),
Statement::Assertion(ref e) => write!(f, "Assertion({:?})", e),
Statement::For(ref var, ref start, ref stop, ref list) => {
write!(f, "for {:?} in {:?}..{:?} do\n", var, start, stop)?;
for l in list {

View file

@ -140,7 +140,7 @@ impl fmt::Display for CompileErrorInner {
}
}
#[derive(Debug, Default)]
#[derive(Debug, Default, Serialize, Deserialize)]
pub struct CompileConfig {
is_release: bool,
}

View file

@ -575,9 +575,6 @@ impl<'ast, T: Field> Flattener<'ast, T> {
)
}
BooleanExpression::FieldEq(box lhs, box rhs) => {
// We know from semantic checking that lhs and rhs have the same type
// What the expression will flatten to depends on that type
// Wanted: (Y = (X != 0) ? 1 : 0)
// X = a - b
// # Y = if X == 0 then 0 else 1 fi
@ -616,6 +613,53 @@ impl<'ast, T: Field> Flattener<'ast, T> {
res
}
BooleanExpression::UintEq(box lhs, box rhs) => {
// We reduce each side into range and apply the same approach as for field elements
// Wanted: (Y = (X != 0) ? 1 : 0)
// X = a - b
// # Y = if X == 0 then 0 else 1 fi
// # M = if X == 0 then 1 else 1/X fi
// Y == X * M
// 0 == (1-Y) * X
let name_y = self.use_sym();
let name_m = self.use_sym();
assert!(lhs.metadata.clone().unwrap().should_reduce.to_bool());
assert!(rhs.metadata.clone().unwrap().should_reduce.to_bool());
let lhs = self
.flatten_uint_expression(symbols, statements_flattened, lhs)
.get_field_unchecked();
let rhs = self
.flatten_uint_expression(symbols, statements_flattened, rhs)
.get_field_unchecked();
let x = FlatExpression::Sub(box lhs, box rhs);
statements_flattened.push(FlatStatement::Directive(FlatDirective::new(
vec![name_y, name_m],
Solver::ConditionEq,
vec![x.clone()],
)));
statements_flattened.push(FlatStatement::Condition(
FlatExpression::Identifier(name_y),
FlatExpression::Mult(box x.clone(), box FlatExpression::Identifier(name_m)),
));
let res = FlatExpression::Sub(
box FlatExpression::Number(T::one()),
box FlatExpression::Identifier(name_y),
);
statements_flattened.push(FlatStatement::Condition(
FlatExpression::Number(T::zero()),
FlatExpression::Mult(box res.clone(), box x),
));
res
}
BooleanExpression::Le(box lhs, box rhs) => {
let lt = self.flatten_boolean_expression(
symbols,
@ -1851,24 +1895,22 @@ impl<'ast, T: Field> Flattener<'ast, T> {
None => {}
}
}
ZirStatement::Condition(lhs, rhs) => {
// flatten expr1 and expr2 to n flattened expressions with n the number of primitive types for expr1
// add n conditions to check equality of the n expressions
ZirStatement::Assertion(e) => {
// naive approach: flatten the boolean to a single field element and constrain it to 1
let lhs = self
.flatten_expression(symbols, statements_flattened, lhs)
.get_field_unchecked();
let rhs = self
.flatten_expression(symbols, statements_flattened, rhs)
.get_field_unchecked();
let e = self.flatten_boolean_expression(symbols, statements_flattened, e);
if lhs.is_linear() {
statements_flattened.push(FlatStatement::Condition(lhs, rhs));
} else if rhs.is_linear() {
// swap so that left side is linear
statements_flattened.push(FlatStatement::Condition(rhs, lhs));
if e.is_linear() {
statements_flattened.push(FlatStatement::Condition(
e,
FlatExpression::Number(T::from(1)),
));
} else {
unreachable!()
// swap so that left side is linear
statements_flattened.push(FlatStatement::Condition(
FlatExpression::Number(T::from(1)),
e,
));
}
}
ZirStatement::MultipleDefinition(vars, rhs) => {

View file

@ -875,27 +875,21 @@ impl<'ast> Checker<'ast> {
}
.map_err(|e| vec![e])
}
Statement::Condition(lhs, rhs) => {
let checked_lhs = self
.check_expression(lhs, module_id, &types)
.map_err(|e| vec![e])?;
let checked_rhs = self
.check_expression(rhs, module_id, &types)
Statement::Assertion(e) => {
let e = self
.check_expression(e, module_id, &types)
.map_err(|e| vec![e])?;
if checked_lhs.get_type() == checked_rhs.get_type() {
Ok(TypedStatement::Condition(checked_lhs, checked_rhs))
} else {
Err(ErrorInner {
match e {
TypedExpression::Boolean(e) => Ok(TypedStatement::Assertion(e)),
e => Err(ErrorInner {
pos: Some(pos),
message: format!(
"Cannot compare {} of type {:?} to {} of type {:?}",
checked_lhs,
checked_lhs.get_type(),
checked_rhs,
checked_rhs.get_type(),
"Expected {} to be of type bool, found {}",
e,
e.get_type(),
),
})
}),
}
.map_err(|e| vec![e])
}
@ -1543,6 +1537,54 @@ impl<'ast> Checker<'ast> {
(TypedExpression::Boolean(e1), TypedExpression::Boolean(e2)) => {
Ok(BooleanExpression::BoolEq(box e1, box e2).into())
}
(TypedExpression::Array(e1), TypedExpression::Array(e2)) => {
if e1.get_type() == e2.get_type() {
Ok(BooleanExpression::ArrayEq(box e1, box e2).into())
} else {
Err(ErrorInner {
pos: Some(pos),
message: format!(
"Cannot compare {} of type {} to {} of type {}",
e1,
e1.get_type(),
e2,
e2.get_type()
),
})
}
}
(TypedExpression::Struct(e1), TypedExpression::Struct(e2)) => {
if e1.get_type() == e2.get_type() {
Ok(BooleanExpression::StructEq(box e1, box e2).into())
} else {
Err(ErrorInner {
pos: Some(pos),
message: format!(
"Cannot compare {} of type {} to {} of type {}",
e1,
e1.get_type(),
e2,
e2.get_type()
),
})
}
}
(TypedExpression::Uint(e1), TypedExpression::Uint(e2)) => {
if e1.get_type() == e2.get_type() {
Ok(BooleanExpression::UintEq(box e1, box e2).into())
} else {
Err(ErrorInner {
pos: Some(pos),
message: format!(
"Cannot compare {} of type {} to {} of type {}",
e1,
e1.get_type(),
e2,
e2.get_type()
),
})
}
}
(e1, e2) => Err(ErrorInner {
pos: Some(pos),
message: format!(
@ -3136,9 +3178,12 @@ mod tests {
// def bar():
// 2 == foo()
// should fail
let bar_statements: Vec<StatementNode<Bn128Field>> = vec![Statement::Condition(
Expression::FieldConstant(Bn128Field::from(2)).mock(),
Expression::FunctionCall("foo", vec![]).mock(),
let bar_statements: Vec<StatementNode<Bn128Field>> = vec![Statement::Assertion(
Expression::Eq(
box Expression::FieldConstant(Bn128Field::from(2)).mock(),
box Expression::FunctionCall("foo", vec![]).mock(),
)
.mock(),
)
.mock()];
@ -3535,9 +3580,12 @@ mod tests {
// def bar():
// 1 == foo()
// should fail
let bar_statements: Vec<StatementNode<Bn128Field>> = vec![Statement::Condition(
Expression::FieldConstant(Bn128Field::from(1)).mock(),
Expression::FunctionCall("foo", vec![]).mock(),
let bar_statements: Vec<StatementNode<Bn128Field>> = vec![Statement::Assertion(
Expression::Eq(
box Expression::FieldConstant(Bn128Field::from(1)).mock(),
box Expression::FunctionCall("foo", vec![]).mock(),
)
.mock(),
)
.mock()];

View file

@ -248,14 +248,9 @@ pub fn fold_statement<'ast, T: Field>(
.map(|v| zir::ZirStatement::Declaration(v))
.collect()
}
typed_absy::TypedStatement::Condition(left, right) => {
let left = f.fold_expression(left);
let right = f.fold_expression(right);
assert_eq!(left.len(), right.len());
left.into_iter()
.zip(right.into_iter())
.map(|(left, right)| zir::ZirStatement::Condition(left, right))
.collect()
typed_absy::TypedStatement::Assertion(e) => {
let e = f.fold_boolean_expression(e);
vec![zir::ZirStatement::Assertion(e)]
}
typed_absy::TypedStatement::For(..) => unreachable!(),
typed_absy::TypedStatement::MultipleDefinition(variables, elist) => {
@ -555,6 +550,68 @@ pub fn fold_boolean_expression<'ast, T: Field>(
let e2 = f.fold_boolean_expression(e2);
zir::BooleanExpression::BoolEq(box e1, box e2)
}
typed_absy::BooleanExpression::ArrayEq(box e1, box e2) => {
let e1 = f.fold_array_expression(e1);
let e2 = f.fold_array_expression(e2);
assert_eq!(e1.len(), e2.len());
e1.into_iter().zip(e2.into_iter()).fold(
zir::BooleanExpression::Value(true),
|acc, (e1, e2)| {
zir::BooleanExpression::And(
box acc,
box match (e1, e2) {
(
zir::ZirExpression::FieldElement(e1),
zir::ZirExpression::FieldElement(e2),
) => zir::BooleanExpression::FieldEq(box e1, box e2),
(zir::ZirExpression::Boolean(e1), zir::ZirExpression::Boolean(e2)) => {
zir::BooleanExpression::BoolEq(box e1, box e2)
}
(zir::ZirExpression::Uint(e1), zir::ZirExpression::Uint(e2)) => {
zir::BooleanExpression::UintEq(box e1, box e2)
}
_ => unreachable!(),
},
)
},
)
}
typed_absy::BooleanExpression::StructEq(box e1, box e2) => {
let e1 = f.fold_struct_expression(e1);
let e2 = f.fold_struct_expression(e2);
assert_eq!(e1.len(), e2.len());
e1.into_iter().zip(e2.into_iter()).fold(
zir::BooleanExpression::Value(true),
|acc, (e1, e2)| {
zir::BooleanExpression::And(
box acc,
box match (e1, e2) {
(
zir::ZirExpression::FieldElement(e1),
zir::ZirExpression::FieldElement(e2),
) => zir::BooleanExpression::FieldEq(box e1, box e2),
(zir::ZirExpression::Boolean(e1), zir::ZirExpression::Boolean(e2)) => {
zir::BooleanExpression::BoolEq(box e1, box e2)
}
(zir::ZirExpression::Uint(e1), zir::ZirExpression::Uint(e2)) => {
zir::BooleanExpression::UintEq(box e1, box e2)
}
_ => unreachable!(),
},
)
},
)
}
typed_absy::BooleanExpression::UintEq(box e1, box e2) => {
let e1 = f.fold_uint_expression(e1);
let e2 = f.fold_uint_expression(e2);
zir::BooleanExpression::UintEq(box e1, box e2)
}
typed_absy::BooleanExpression::Lt(box e1, box e2) => {
let e1 = f.fold_field_expression(e1);
let e2 = f.fold_field_expression(e2);

View file

@ -55,7 +55,7 @@ impl<'ast, T: Field> TypedProgram<'ast, T> {
let r = VariableAccessRemover::apply(r);
// convert to zir, removing complex types
let zir = Flattener::flatten(r.clone());
let zir = Flattener::flatten(r);
// optimize uint expressions
let zir = UintOptimizer::optimize(zir);

View file

@ -112,13 +112,10 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
TypedStatement::Definition(TypedAssignee::Member(..), _) => {
unreachable!("struct update should have been replaced with full struct redef")
}
// propagate lhs and rhs for conditions
TypedStatement::Condition(e1, e2) => {
// propagate the boolean
TypedStatement::Assertion(e) => {
// could stop execution here if condition is known to fail
Some(TypedStatement::Condition(
self.fold_expression(e1),
self.fold_expression(e2),
))
Some(TypedStatement::Assertion(self.fold_boolean_expression(e)))
}
// only loops with variable bounds are expected here
// we stop propagation here as constants maybe be modified inside the loop body
@ -957,6 +954,11 @@ impl<'ast, T: Field> Folder<'ast, T> for Propagator<'ast, T> {
&mut self,
e: BooleanExpression<'ast, T>,
) -> BooleanExpression<'ast, T> {
// Note: we only propagate when we see constants, as comparing of arbitrary expressions would lead to
// a lot of false negatives due to expressions not being in a canonical form
// For example, `2 * a` is equivalent to `a + a`, but our notion of equality would not detect that here
// These kind of reduction rules are easier to apply later in the process, when we have canonical representations
// of expressions, ie `a + a` would always be written `2 * a`
match e {
BooleanExpression::Identifier(id) => match self
.constants

View file

@ -53,6 +53,24 @@ fn force_no_reduce<'ast, T: Field>(e: UExpression<'ast, T>) -> UExpression<'ast,
}
impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> {
fn fold_boolean_expression(
&mut self,
e: BooleanExpression<'ast, T>,
) -> BooleanExpression<'ast, T> {
match e {
BooleanExpression::UintEq(box left, box right) => {
let left = self.fold_uint_expression(left);
let right = self.fold_uint_expression(right);
let left = force_reduce(left);
let right = force_reduce(right);
BooleanExpression::UintEq(box left, box right)
}
e => fold_boolean_expression(self, e),
}
}
fn fold_uint_expression(&mut self, e: UExpression<'ast, T>) -> UExpression<'ast, T> {
if e.metadata.is_some() {
return e;
@ -287,6 +305,7 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> {
UExpression::right_shift(force_reduce(e), by).with_max(max)
}
IfElse(box condition, box consequence, box alternative) => {
let condition = self.fold_boolean_expression(condition);
let consequence = self.fold_uint_expression(consequence);
let alternative = self.fold_uint_expression(alternative);
@ -397,17 +416,17 @@ impl<'ast, T: Field> Folder<'ast, T> for UintOptimizer<'ast, T> {
)],
},
},
// we need to put back in range to assert
ZirStatement::Condition(lhs, rhs) => {
match (self.fold_expression(lhs), self.fold_expression(rhs)) {
(ZirExpression::Uint(lhs), ZirExpression::Uint(rhs)) => {
vec![ZirStatement::Condition(
force_reduce(lhs).into(),
force_reduce(rhs).into(),
)]
}
(lhs, rhs) => vec![ZirStatement::Condition(lhs, rhs)],
}
ZirStatement::Assertion(BooleanExpression::UintEq(box left, box right)) => {
let left = self.fold_uint_expression(left);
let right = self.fold_uint_expression(right);
// we can only compare two unsigned integers if they are in range
let left = force_reduce(left);
let right = force_reduce(right);
vec![ZirStatement::Assertion(BooleanExpression::UintEq(
box left, box right,
))]
}
s => fold_statement(self, s),
}

View file

@ -84,13 +84,12 @@ impl<'ast> Unroller<'ast> {
match head {
Access::Select(head) => {
statements.insert(TypedStatement::Condition(
statements.insert(TypedStatement::Assertion(
BooleanExpression::Lt(
box head.clone(),
box FieldElementExpression::Number(T::from(size)),
)
.into(),
BooleanExpression::Value(true).into(),
));
ArrayExpressionInner::Value(
@ -1089,13 +1088,12 @@ mod tests {
assert_eq!(
u.fold_statement(s),
vec![
TypedStatement::Condition(
TypedStatement::Assertion(
BooleanExpression::Lt(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(2))
)
.into(),
BooleanExpression::Value(true).into()
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_array(
@ -1227,13 +1225,12 @@ mod tests {
assert_eq!(
u.fold_statement(s),
vec![
TypedStatement::Condition(
TypedStatement::Assertion(
BooleanExpression::Lt(
box FieldElementExpression::Number(Bn128Field::from(1)),
box FieldElementExpression::Number(Bn128Field::from(2))
)
.into(),
BooleanExpression::Value(true).into()
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::with_id_and_type(

View file

@ -39,7 +39,7 @@ impl<'ast, T: Field> VariableAccessRemover<'ast, T> {
_ => unreachable!(),
};
self.statements.push(TypedStatement::Condition(
self.statements.push(TypedStatement::Assertion(
(0..size)
.map(|index| {
BooleanExpression::FieldEq(
@ -53,7 +53,6 @@ impl<'ast, T: Field> VariableAccessRemover<'ast, T> {
})
.unwrap()
.into(),
BooleanExpression::Value(true).into(),
));
(0..size)
@ -170,7 +169,7 @@ mod tests {
assert_eq!(
VariableAccessRemover::new().fold_statement(access),
vec![
TypedStatement::Condition(
TypedStatement::Assertion(
BooleanExpression::Or(
box BooleanExpression::FieldEq(
box FieldElementExpression::Identifier("i".into()),
@ -182,7 +181,6 @@ mod tests {
)
)
.into(),
BooleanExpression::Value(true).into()
),
TypedStatement::Definition(
TypedAssignee::Identifier(Variable::field_element("b")),

View file

@ -165,9 +165,7 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
TypedStatement::Definition(f.fold_assignee(a), f.fold_expression(e))
}
TypedStatement::Declaration(v) => TypedStatement::Declaration(f.fold_variable(v)),
TypedStatement::Condition(left, right) => {
TypedStatement::Condition(f.fold_expression(left), f.fold_expression(right))
}
TypedStatement::Assertion(e) => TypedStatement::Assertion(f.fold_boolean_expression(e)),
TypedStatement::For(v, from, to, statements) => TypedStatement::For(
f.fold_variable(v),
from,
@ -325,6 +323,21 @@ pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>(
let e2 = f.fold_boolean_expression(e2);
BooleanExpression::BoolEq(box e1, box e2)
}
BooleanExpression::ArrayEq(box e1, box e2) => {
let e1 = f.fold_array_expression(e1);
let e2 = f.fold_array_expression(e2);
BooleanExpression::ArrayEq(box e1, box e2)
}
BooleanExpression::StructEq(box e1, box e2) => {
let e1 = f.fold_struct_expression(e1);
let e2 = f.fold_struct_expression(e2);
BooleanExpression::StructEq(box e1, box e2)
}
BooleanExpression::UintEq(box e1, box e2) => {
let e1 = f.fold_uint_expression(e1);
let e2 = f.fold_uint_expression(e2);
BooleanExpression::UintEq(box e1, box e2)
}
BooleanExpression::Lt(box e1, box e2) => {
let e1 = f.fold_field_expression(e1);
let e2 = f.fold_field_expression(e2);

View file

@ -300,7 +300,7 @@ pub enum TypedStatement<'ast, T> {
Return(Vec<TypedExpression<'ast, T>>),
Definition(TypedAssignee<'ast, T>, TypedExpression<'ast, T>),
Declaration(Variable<'ast>),
Condition(TypedExpression<'ast, T>, TypedExpression<'ast, T>),
Assertion(BooleanExpression<'ast, T>),
For(
Variable<'ast>,
FieldElementExpression<'ast, T>,
@ -327,9 +327,7 @@ impl<'ast, T: fmt::Debug> fmt::Debug for TypedStatement<'ast, T> {
TypedStatement::Definition(ref lhs, ref rhs) => {
write!(f, "Definition({:?}, {:?})", lhs, rhs)
}
TypedStatement::Condition(ref lhs, ref rhs) => {
write!(f, "Condition({:?}, {:?})", lhs, rhs)
}
TypedStatement::Assertion(ref e) => write!(f, "Assertion({:?})", e),
TypedStatement::For(ref var, ref start, ref stop, ref list) => {
write!(f, "for {:?} in {:?}..{:?} do\n", var, start, stop)?;
for l in list {
@ -376,7 +374,7 @@ impl<'ast, T: fmt::Display> fmt::Display for TypedStatement<'ast, T> {
}
TypedStatement::Declaration(ref var) => write!(f, "{}", var),
TypedStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs),
TypedStatement::Condition(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
TypedStatement::Assertion(ref e) => write!(f, "assert({})", e),
TypedStatement::For(ref var, ref start, ref stop, ref list) => {
write!(f, "for {} in {}..{} do\n", var, start, stop)?;
for l in list {
@ -639,6 +637,12 @@ pub enum BooleanExpression<'ast, T> {
Box<BooleanExpression<'ast, T>>,
Box<BooleanExpression<'ast, T>>,
),
ArrayEq(Box<ArrayExpression<'ast, T>>, Box<ArrayExpression<'ast, T>>),
StructEq(
Box<StructExpression<'ast, T>>,
Box<StructExpression<'ast, T>>,
),
UintEq(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Ge(
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
@ -906,6 +910,9 @@ impl<'ast, T: fmt::Display> fmt::Display for BooleanExpression<'ast, T> {
BooleanExpression::Le(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
BooleanExpression::FieldEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
BooleanExpression::BoolEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
BooleanExpression::ArrayEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
BooleanExpression::StructEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
BooleanExpression::UintEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
BooleanExpression::Ge(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
BooleanExpression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
BooleanExpression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),
@ -985,6 +992,15 @@ impl<'ast, T: fmt::Debug> fmt::Debug for BooleanExpression<'ast, T> {
BooleanExpression::BoolEq(ref lhs, ref rhs) => {
write!(f, "BoolEq({:?}, {:?})", lhs, rhs)
}
BooleanExpression::ArrayEq(ref lhs, ref rhs) => {
write!(f, "ArrayEq({:?}, {:?})", lhs, rhs)
}
BooleanExpression::StructEq(ref lhs, ref rhs) => {
write!(f, "StructEq({:?}, {:?})", lhs, rhs)
}
BooleanExpression::UintEq(ref lhs, ref rhs) => {
write!(f, "UintEq({:?}, {:?})", lhs, rhs)
}
BooleanExpression::Ge(ref lhs, ref rhs) => write!(f, "Ge({:?}, {:?})", lhs, rhs),
BooleanExpression::Gt(ref lhs, ref rhs) => write!(f, "Gt({:?}, {:?})", lhs, rhs),
BooleanExpression::And(ref lhs, ref rhs) => write!(f, "And({:?}, {:?})", lhs, rhs),

View file

@ -130,9 +130,7 @@ pub fn fold_statement<'ast, T: Field, F: Folder<'ast, T>>(
ZirStatement::Definition(f.fold_assignee(a), f.fold_expression(e))
}
ZirStatement::Declaration(v) => ZirStatement::Declaration(f.fold_variable(v)),
ZirStatement::Condition(left, right) => {
ZirStatement::Condition(f.fold_expression(left), f.fold_expression(right))
}
ZirStatement::Assertion(e) => ZirStatement::Assertion(f.fold_boolean_expression(e)),
ZirStatement::MultipleDefinition(variables, elist) => ZirStatement::MultipleDefinition(
variables.into_iter().map(|v| f.fold_variable(v)).collect(),
f.fold_expression_list(elist),
@ -201,6 +199,11 @@ pub fn fold_boolean_expression<'ast, T: Field, F: Folder<'ast, T>>(
let e2 = f.fold_boolean_expression(e2);
BooleanExpression::BoolEq(box e1, box e2)
}
BooleanExpression::UintEq(box e1, box e2) => {
let e1 = f.fold_uint_expression(e1);
let e2 = f.fold_uint_expression(e2);
BooleanExpression::UintEq(box e1, box e2)
}
BooleanExpression::Lt(box e1, box e2) => {
let e1 = f.fold_field_expression(e1);
let e2 = f.fold_field_expression(e2);

View file

@ -191,7 +191,7 @@ pub enum ZirStatement<'ast, T> {
Return(Vec<ZirExpression<'ast, T>>),
Definition(ZirAssignee<'ast>, ZirExpression<'ast, T>),
Declaration(Variable<'ast>),
Condition(ZirExpression<'ast, T>, ZirExpression<'ast, T>),
Assertion(BooleanExpression<'ast, T>),
MultipleDefinition(Vec<Variable<'ast>>, ZirExpressionList<'ast, T>),
}
@ -212,9 +212,7 @@ impl<'ast, T: fmt::Debug> fmt::Debug for ZirStatement<'ast, T> {
ZirStatement::Definition(ref lhs, ref rhs) => {
write!(f, "Definition({:?}, {:?})", lhs, rhs)
}
ZirStatement::Condition(ref lhs, ref rhs) => {
write!(f, "Condition({:?}, {:?})", lhs, rhs)
}
ZirStatement::Assertion(ref e) => write!(f, "Assertion({:?})", e),
ZirStatement::MultipleDefinition(ref lhs, ref rhs) => {
write!(f, "MultipleDefinition({:?}, {:?})", lhs, rhs)
}
@ -235,9 +233,9 @@ impl<'ast, T: fmt::Display> fmt::Display for ZirStatement<'ast, T> {
}
write!(f, "")
}
ZirStatement::Declaration(ref var) => write!(f, "{}", var),
ZirStatement::Declaration(ref var) => write!(f, "assert({})", var),
ZirStatement::Definition(ref lhs, ref rhs) => write!(f, "{} = {}", lhs, rhs),
ZirStatement::Condition(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
ZirStatement::Assertion(ref e) => write!(f, "{}", e),
ZirStatement::MultipleDefinition(ref ids, ref rhs) => {
for (i, id) in ids.iter().enumerate() {
write!(f, "{}", id)?;
@ -399,6 +397,7 @@ pub enum BooleanExpression<'ast, T> {
Box<BooleanExpression<'ast, T>>,
Box<BooleanExpression<'ast, T>>,
),
UintEq(Box<UExpression<'ast, T>>, Box<UExpression<'ast, T>>),
Ge(
Box<FieldElementExpression<'ast, T>>,
Box<FieldElementExpression<'ast, T>>,
@ -511,6 +510,7 @@ impl<'ast, T: fmt::Display> fmt::Display for BooleanExpression<'ast, T> {
BooleanExpression::Le(ref lhs, ref rhs) => write!(f, "{} <= {}", lhs, rhs),
BooleanExpression::FieldEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
BooleanExpression::BoolEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
BooleanExpression::UintEq(ref lhs, ref rhs) => write!(f, "{} == {}", lhs, rhs),
BooleanExpression::Ge(ref lhs, ref rhs) => write!(f, "{} >= {}", lhs, rhs),
BooleanExpression::Gt(ref lhs, ref rhs) => write!(f, "{} > {}", lhs, rhs),
BooleanExpression::Or(ref lhs, ref rhs) => write!(f, "{} || {}", lhs, rhs),

View file

@ -15,7 +15,7 @@ fn out_of_range() {
let source = r#"
def main(private field a) -> (field):
field x = if a < 5555 then 3333 else 4444 fi
x == 3333
assert(x == 3333)
return 1
"#
.to_string();

View file

@ -1,3 +1,3 @@
def main(field a) -> (field):
a == 1
return 1
def main(field a) -> ():
assert(a == 1)
return

View file

@ -6,9 +6,9 @@ def local(field a) -> (field): // this costs 3 constraints per call
def main(field a) -> ():
// calling a local function many times with the same arg should cost only once
local(a) + local(a) + local(a) + local(a) + local(a) == 5 * (a ** 8)
assert(local(a) + local(a) + local(a) + local(a) + local(a) == 5 * (a ** 8))
// calling an imported function many times with the same arg should cost only once
dep(a) + dep(a) + dep(a) + dep(a) + dep(a) == 5 * (a ** 4)
assert(dep(a) + dep(a) + dep(a) + dep(a) + dep(a) == 5 * (a ** 4))
return

View file

@ -4,15 +4,11 @@
"tests": [
{
"input": {
"values": [
"12"
]
"values": []
},
"output": {
"Ok": {
"values": [
"12"
]
"values": []
}
}
}

View file

@ -1,8 +1,8 @@
def main(field g) -> (field):
9 == 1 + 2 * 2 ** 2 // Checks precedence of arithmetic operators (expecting transitive behaviour)
9 == 2 ** 2 * 2 + 1
7 == 2 ** 2 * 2 - 1
3 == 2 ** 2 / 2 + 1
def main() -> ():
assert(9 == 1 + 2 * 2 ** 2) // Checks precedence of arithmetic operators (expecting transitive behaviour)
assert(9 == 2 ** 2 * 2 + 1)
assert(7 == 2 ** 2 * 2 - 1)
assert(3 == 2 ** 2 / 2 + 1)
field a = if 3 == 2 ** 2 / 2 + 1 && true then 1 else 0 fi // combines arithmetic with boolean operators
field b = if 3 == 3 && 4 < 5 then 1 else 0 fi // checks precedence of boolean operators
@ -11,6 +11,8 @@ def main(field g) -> (field):
field e = if 2 >= 1 && 4 > 5 || 1 == 1 then 1 else 0 fi
field f = if 1 < 2 && false || 4 < 5 && 2 >= 1 then 1 else 0 fi
assert(0x00 ^ 0x00 == 0x00)
//check if all statements have evalutated to true
a * b * c * d * e * f == 1
return g
assert(a * b * c * d * e * f == 1)
return

View file

@ -0,0 +1,4 @@
{
"entry_point": "./tests/tests/uint/eq.zok",
"tests": []
}

View file

@ -0,0 +1,3 @@
def main(private u32 a, u32 b) -> (field):
field result = if a * a == b then 1 else 0 fi
return result

View file

@ -60,47 +60,47 @@ def main(u32 e, u32 f, u32[4] terms) -> ():
// rotate
u32 rotated = right_rotate_4(e)
rotated == 0x81234567
assert(rotated == 0x81234567)
// and
(e & f) == 0x00204460
assert((e & f) == 0x00204460)
// xor
(e ^ f) == 0x1317131f
assert((e ^ f) == 0x1317131f)
// shift
e >> 12 == 0x00012345
e << 12 == 0x45678000
assert(e >> 12 == 0x00012345)
assert(e << 12 == 0x45678000)
// not
!e == 0xedcba987
assert(!e == 0xedcba987)
// add
terms[0] + terms[1] + terms[2] + terms[3] == 0xddddddda
assert(terms[0] + terms[1] + terms[2] + terms[3] == 0xddddddda)
// to_bits
bool[32] bits1 = to_bits(e)
bool[32] expected1 = [false, false, false, true, false, false, true, false, false, false, true, true, false, true, false, false, false, true, false, true, false, true, true, false, false, true, true, true, true, false, false, false]
bits1 == expected1
e == from_bits(expected1)
assert(bits1 == expected1)
assert(e == from_bits(expected1))
bool[32] bits2 = to_bits(f)
bool[32] expected2 = [false, false, false, false, false, false, false, true, false, false, true, false, false, false, true, true, false, true, false, false, false, true, false, true, false, true, true, false, false, true, true, true]
bits2 == expected2
f == from_bits(expected2)
assert(bits2 == expected2)
assert(f == from_bits(expected2))
// S0
u32 e2 = right_rotate_2(e)
u32 e13 = right_rotate_13(e)
u32 e22 = right_rotate_22(e)
u32 S0 = e2 ^ e13 ^ e22
S0 == 0x66146474
assert(S0 == 0x66146474)
// S1
u32 e6 = right_rotate_6(e)
u32 e11 = right_rotate_11(e)
u32 e25 = right_rotate_25(e)
u32 S1 = e6 ^ e11 ^ e25
S1 == 0x3561abda
assert(S1 == 0x3561abda)
return

View file

@ -54,6 +54,7 @@ def right_rotate_22(u32 e) -> (u32):
def right_rotate_25(u32 e) -> (u32):
bool[32] b = to_bits(e)
u32 res = from_bits([...b[7..], ...b[..7]])
return res
def main() -> ():
@ -62,47 +63,47 @@ def main() -> ():
// rotate
u32 rotated = right_rotate_4(e)
rotated == 0x81234567
assert(rotated == 0x81234567)
// and
(e & f) == 0x00204460
assert((e & f) == 0x00204460)
// xor
(e ^ f) == 0x1317131f
assert((e ^ f) == 0x1317131f)
// shift
e >> 12 == 0x00012345
e << 12 == 0x45678000
assert(e >> 12 == 0x00012345)
assert(e << 12 == 0x45678000)
// not
!e == 0xedcba987
assert(!e == 0xedcba987)
// add
0xfefefefe + 0xefefefef + 0xffffffff + 0xeeeeeeee == 0xddddddda
assert(0xfefefefe + 0xefefefef + 0xffffffff + 0xeeeeeeee == 0xddddddda)
// to_bits
bool[32] bits1 = to_bits(e)
bool[32] expected1 = [false, false, false, true, false, false, true, false, false, false, true, true, false, true, false, false, false, true, false, true, false, true, true, false, false, true, true, true, true, false, false, false]
bits1 == expected1
e == from_bits(expected1)
assert(bits1 == expected1)
assert(e == from_bits(expected1))
bool[32] bits2 = to_bits(f)
bool[32] expected2 = [false, false, false, false, false, false, false, true, false, false, true, false, false, false, true, true, false, true, false, false, false, true, false, true, false, true, true, false, false, true, true, true]
bits2 == expected2
f == from_bits(expected2)
assert(bits2 == expected2)
assert(f == from_bits(expected2))
// S0
u32 e2 = right_rotate_2(e)
u32 e13 = right_rotate_13(e)
u32 e22 = right_rotate_22(e)
u32 S0 = e2 ^ e13 ^ e22
S0 == 0x66146474
assert(S0 == 0x66146474)
// S1
u32 e6 = right_rotate_6(e)
u32 e11 = right_rotate_11(e)
u32 e25 = right_rotate_25(e)
u32 S1 = e6 ^ e11 ^ e25
S1 == 0x3561abda
assert(S1 == 0x3561abda)
return

View file

@ -1,7 +1,7 @@
node_modules
/dist
/target
/pkg
/wasm-pack.log
/stdlib
dist
target
pkg
wasm-pack.log
stdlib
stdlib.json

1172
zokrates_js/Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,6 +1,6 @@
[package]
name = "zokrates_js"
version = "1.0.22"
version = "1.0.23"
authors = ["Darko Macesic"]
edition = "2018"

View file

@ -19,19 +19,42 @@ npm install zokrates-js
## Usage
### Importing
Bundlers
```js
import { initialize } from 'zokrates-js';
```
function importResolver(location, path) {
Node
```js
const { initialize } = require('zokrates-js/node');
```
### Example
```js
function importResolver(currentLocation, importLocation) {
// implement your resolving logic here
return {
source: "def main() -> (): return",
location: path
return {
source: "def main() -> (): return",
location: importLocation
};
}
initialize().then((zokratesProvider) => {
// we have to initialize the wasm module before calling api functions
zokratesProvider.compile("def main(private field a) -> (field): return a", "main", importResolver)
// compilation
const artifacts = zokratesProvider.compile("def main(private field a) -> (field): return a * a", "main", importResolver);
// computation
const { witness, output } = zokratesProvider.computeWitness(artifacts, ["2"]);
// run setup
const keypair = zokratesProvider.setup(artifacts.program);
// generate proof
const proof = zokratesProvider.generateProof(artifacts.program, witness, keypair.pk);
// export solidity verifier
const verifier = zokratesProvider.exportSolidityVerifier(keypair.vk, "v1");
});
```
```

View file

@ -5,7 +5,7 @@ const fs = require('fs');
const path = require('path');
/** stdlib constants */
const stdlibRoot = '../zokrates_stdlib/stdlib';
const stdlibRoot = '../zokrates_stdlib/stdlib';
const output = 'stdlib.json';
const options = {
@ -15,7 +15,7 @@ const options = {
/**
* Serializes standard library directory tree to a json file.
*/
gulp.task('stdlib', function (done) {
gulp.task('stdlib', (done) => {
var stdlib = {};
dree.scan(stdlibRoot, options, function (file) {
const content = fs.readFileSync(file.path).toString();

View file

@ -4,6 +4,10 @@ declare module 'zokrates-js' {
export type G2Affine = [G1Affine, G1Affine];
export type ProvingKey = Uint8Array;
export interface CompileConfig {
is_release: boolean
}
export interface VerificationKey {
alpha: G1Affine,
beta: G2Affine,
@ -49,7 +53,7 @@ declare module 'zokrates-js' {
export type ResolveCallback = (location: string, path: string) => ResolverResult;
export interface ZoKratesProvider {
compile(source: string, location: string, callback: ResolveCallback): CompilationArtifacts;
compile(source: string, location: string, callback: ResolveCallback, config?: CompileConfig): CompilationArtifacts;
setup(program: Uint8Array): SetupKeypair;
computeWitness(artifacts: CompilationArtifacts, args: any[]): ComputationResult;
exportSolidityVerifier(verifyingKey: VerificationKey, abi: SolidityAbi): string;

View file

@ -1,61 +1,9 @@
import { appendExtension, getAbsolutePath } from './utils';
import wrapper from './wrapper';
import stdlib from './stdlib.json';
const initialize = async () => {
const EXTENSION_ZOK = '.zok';
const RESERVED_PATHS = [
'ecc/',
'signature/',
'hashes/',
'utils/'
];
// load web assembly module
const zokrates = await import('./pkg/index.js');
const resolveModule = (currentLocation, importLocation, callback) => {
if (isReserved(currentLocation) || isReserved(importLocation)) {
return resolveFromStandardLibrary(currentLocation, importLocation);
}
return callback(currentLocation, importLocation);
}
const isReserved = (path) => RESERVED_PATHS.some(p => path.startsWith(p));
const resolveFromStandardLibrary = (currentLocation, importLocation) => {
let key = appendExtension(getAbsolutePath(currentLocation, importLocation), EXTENSION_ZOK);
let source = stdlib[key];
return source ? { source, location: key } : null;
}
return {
compile: (source, location, callback) => {
let result = zokrates.compile(source, location, (currentLocation, importLocation) =>
resolveModule(currentLocation, importLocation, callback)
);
return {
program: Array.from(result.program),
abi: result.abi
}
},
setup: (program) => {
let result = zokrates.setup(program);
return {
vk: result.vk,
pk: Array.from(result.pk)
};
},
computeWitness: (artifacts, args) => {
return zokrates.compute_witness(artifacts, JSON.stringify(Array.from(args)));
},
exportSolidityVerifier: (verifyingKey, abiVersion) => {
return zokrates.export_solidity_verifier(verifyingKey, abiVersion);
},
generateProof: (program, witness, provingKey) => {
return zokrates.generate_proof(program, witness, provingKey);
}
}
return wrapper({ zokrates, stdlib });
}
export { initialize };

11
zokrates_js/node/index.js Normal file
View file

@ -0,0 +1,11 @@
const wrapper = require('../wrapper.js');
const stdlib = require('../stdlib.json');
const initialize = async () => {
return wrapper({
zokrates: require('./pkg/index.js'),
stdlib
});
}
module.exports = { initialize };

View file

@ -10,21 +10,25 @@
],
"license": "GPLv3",
"files": [
"node",
"pkg",
"index.js",
"index.d.ts",
"utils.js",
"wrapper.js",
"stdlib.json",
"README.md"
],
"types": "index.d.ts",
"scripts": {
"cargo:build": "cargo build --target=wasm32-unknown-unknown",
"wasm-pack:build": "wasm-pack build --out-name index --release --target bundler",
"wasm-pack": "wasm-pack build --out-name index --release",
"setup": "npm install && gulp stdlib",
"prebuild": "npm run setup",
"build": "rimraf pkg && npm run wasm-pack:build",
"pretest": "npm run setup",
"build": "npm run build:bundler && npm run build:node",
"build:bundler": "rimraf pkg && npm run wasm-pack -- --target bundler && npm run clean-pkg",
"build:node": "rimraf node/pkg && npm run wasm-pack -- --target nodejs -d node/pkg && npm run clean-node-pkg",
"clean-pkg": "find pkg/* | grep -P \"^.*\\.(md|d\\.ts)$\" | xargs rm",
"clean-node-pkg": "find node/pkg/* | grep -P \"^.*\\.(md|d\\.ts)$\" | xargs rm",
"pretest": "npm run setup && npm run build:node",
"test": "mocha --require esm --recursive tests"
},
"devDependencies": {

View file

@ -10,8 +10,8 @@ use zokrates_core::compile::{
};
use zokrates_core::imports::Error;
use zokrates_core::ir;
use zokrates_core::proof_system::{ProofSystem, SolidityAbi};
use zokrates_core::proof_system::bellman::groth16::G16;
use zokrates_core::proof_system::{ProofSystem, SolidityAbi};
use zokrates_core::typed_absy::abi::Abi;
use zokrates_core::typed_absy::types::Signature;
use zokrates_field::Bn128Field;
@ -77,7 +77,7 @@ impl<'a> Resolver<Error> for JsResolver<'a> {
)
.map_err(|_| {
Error::new(format!(
"Error thrown in callback: could not resolve {}",
"Error thrown in JS callback: could not resolve {}",
import_location.display()
))
})?;
@ -99,15 +99,26 @@ pub fn compile(
source: JsValue,
location: JsValue,
resolve: &js_sys::Function,
config: JsValue,
) -> Result<JsValue, JsValue> {
let fmt_error = |e: &CompileError| format!("{}:{}", e.file().display(), e.value());
let resolver = JsResolver::new(resolve);
let config: CompileConfig = {
if config.is_object() {
config
.into_serde()
.map_err(|e| JsValue::from_str(&format!("Invalid config format: {}", e)))?
} else {
CompileConfig::default()
}
};
let artifacts: CompilationArtifacts<Bn128Field> = core_compile(
source.as_string().unwrap(),
PathBuf::from(location.as_string().unwrap()),
Some(&resolver),
&CompileConfig::default().with_is_release(true),
&config,
)
.map_err(|ce| {
JsValue::from_str(&format!(

View file

@ -1,30 +0,0 @@
const assert = require('assert');
const utils = require('../utils');
const stdlib = require('../stdlib.json');
describe('stdlib', function() {
it('should resolve module from stdlib (1)', function() {
let basePath = 'hashes/sha256/512bitPacked.zok';
let relativePath = '../../utils/pack/u32/pack128';
let absolutePath = utils.appendExtension(utils.getAbsolutePath(basePath, relativePath), '.zok');
assert.notEqual(stdlib[absolutePath], undefined);
});
it('should resolve module from stdlib (2)', function() {
let basePath = 'hashes/sha256/256bitPadded.zok';
let relativePath = './512bit';
let absolutePath = utils.appendExtension(utils.getAbsolutePath(basePath, relativePath), '.zok');
assert.notEqual(stdlib[absolutePath], undefined);
});
it('should resolve module from stdlib (3)', function() {
let basePath = 'hashes/pedersen/6bit.zok';
let relativePath = 'ecc/babyjubjubParams';
let absolutePath = utils.appendExtension(utils.getAbsolutePath(basePath, relativePath), '.zok');
assert.notEqual(stdlib[absolutePath], undefined);
});
});

123
zokrates_js/tests/tests.js Normal file
View file

@ -0,0 +1,123 @@
const assert = require('assert');
const { initialize } = require('../node/index.js');
describe('tests', function() {
// initialize once before running tests
before(function (done) {
initialize().then(zokrates => {
this.zokrates = zokrates;
done();
});
});
describe("compilation", () => {
it('should compile', function() {
assert.doesNotThrow(() => {
const artifacts = this.zokrates.compile("def main() -> (field): return 42", "main");
assert.ok(artifacts !== undefined);
})
});
it('should throw on invalid code', function() {
assert.throws(() => this.zokrates.compile(":-)", "main"));
});
it('should resolve stdlib module', function() {
assert.doesNotThrow(() => {
const code = 'import "hashes/sha256/512bit" as sha256\ndef main() -> (): return';
this.zokrates.compile(code, "main");
})
});
it('should resolve user module', function() {
assert.doesNotThrow(() => {
const code = 'import "test" as test\ndef main() -> (field): return test()';
this.zokrates.compile(code, "main", (_, path) => {
return {
source: "def main() -> (field): return 1",
location: path
}
});
})
});
it('should throw on invalid module', function() {
assert.throws(() => {
const code = 'import "test" as test\ndef main() -> (field): return test()';
this.zokrates.compile(code, "main", (_loc, _path) => null);
})
});
})
describe("computation", () => {
it('should compute with valid inputs', function() {
assert.doesNotThrow(() => {
const code = 'def main(private field a) -> (field): return a * a';
const artifacts = this.zokrates.compile(code, "main", null);
const result = this.zokrates.computeWitness(artifacts, ["2"])
const output = JSON.parse(result.output);
assert.deepEqual(output, ["4"]);
})
});
it('should throw on invalid input count', function() {
assert.throws(() => {
const code = 'def main(private field a) -> (field): return a * a';
const artifacts = this.zokrates.compile(code, "main", null);
this.zokrates.computeWitness(artifacts, ["1", "2"])
})
});
it('should throw on invalid input type', function() {
assert.throws(() => {
const code = 'def main(private field a) -> (field): return a * a';
const artifacts = this.zokrates.compile(code, "main", null);
this.zokrates.computeWitness(artifacts, [true])
})
});
})
describe("setup", () => {
it('should run setup', function() {
assert.doesNotThrow(() => {
const code = 'def main(private field a) -> (field): return a * a';
const artifacts = this.zokrates.compile(code, "main", null);
this.zokrates.setup(artifacts.program);
})
});
})
describe("export-verifier", () => {
it('should export solidity verifier', function() {
assert.doesNotThrow(() => {
const code = 'def main(private field a) -> (field): return a * a';
const artifacts = this.zokrates.compile(code, "main", null);
const keypair = this.zokrates.setup(artifacts.program);
const verifier = this.zokrates.exportSolidityVerifier(keypair.vk, "v1");
assert.ok(verifier.length > 0)
})
});
})
describe("generate-proof", () => {
it('should generate proof', function() {
assert.doesNotThrow(() => {
const code = 'def main(private field a) -> (field): return a * a';
const artifacts = this.zokrates.compile(code, "main", null);
const computationResult = this.zokrates.computeWitness(artifacts, ["2"])
const keypair = this.zokrates.setup(artifacts.program);
const proof = this.zokrates.generateProof(artifacts.program, computationResult.witness, keypair.pk);
assert.ok(proof !== undefined);
assert.deepEqual(proof.inputs, ["0x0000000000000000000000000000000000000000000000000000000000000004"])
})
});
});
});

View file

@ -1,29 +0,0 @@
const assert = require('assert')
const utils = require('../utils');
describe('absolute path resolving', function() {
it('should resolve valid absolute path (root)', function() {
let basePath = 'hashes/pedersen/6bit';
let relativePath = 'ecc/babyjubjubParams';
let absolutePath = utils.getAbsolutePath(basePath, relativePath);
assert.equal(absolutePath, 'ecc/babyjubjubParams');
});
it('should resolve valid absolute path (../)', function() {
let basePath = 'hashes/sha256/512bitPacked';
let relativePath = '../../utils/pack/u32/pack128';
let absolutePath = utils.getAbsolutePath(basePath, relativePath);
assert.equal(absolutePath, 'utils/pack/u32/pack128');
});
it('should resolve valid absolute path (./)', function() {
let basePath = 'hashes/sha256/256bitPadded';
let relativePath = './512bit';
let absolutePath = utils.getAbsolutePath(basePath, relativePath);
assert.equal(absolutePath, 'hashes/sha256/512bit');
});
});

View file

@ -1,26 +0,0 @@
export function getAbsolutePath(basePath, relativePath) {
if (relativePath[0] !== '.') {
return relativePath;
}
var stack = basePath.split('/');
var chunks = relativePath.split('/');
stack.pop();
for(var i = 0; i < chunks.length; i++) {
if (chunks[i] == '.') {
continue;
} else if (chunks[i] == '..') {
stack.pop();
} else {
stack.push(chunks[i]);
}
}
return stack.join('/');
}
export function appendExtension(path, extension) {
if (path.endsWith(extension)) {
return path;
}
return path.concat(extension);
}

62
zokrates_js/wrapper.js Normal file
View file

@ -0,0 +1,62 @@
const getAbsolutePath = (basePath, relativePath) => {
var stack = basePath.split('/');
var chunks = relativePath.split('/');
stack.pop();
for (var i = 0; i < chunks.length; i++) {
if (chunks[i] == '.') {
continue;
} else if (chunks[i] == '..') {
stack.pop();
} else {
stack.push(chunks[i]);
}
}
return stack.join('/');
}
const getImportPath = (currentLocation, importLocation) => {
let path = getAbsolutePath(currentLocation, importLocation);
const extension = importLocation.slice((path.lastIndexOf(".") - 1 >>> 0) + 2);
return extension ? path : path.concat('.zok');
}
module.exports = (dep) => {
const { zokrates, stdlib } = dep;
const resolveFromStdlib = (currentLocation, importLocation) => {
let key = getImportPath(currentLocation, importLocation);
let source = stdlib[key];
return source ? { source, location: key } : null;
}
return {
compile: (source, location, callback) => {
let importCallback = (currentLocation, importLocation) => {
return resolveFromStdlib(currentLocation, importLocation) || callback(currentLocation, importLocation);
};
const { program, abi } = zokrates.compile(source, location, importCallback);
return {
program: Array.from(program),
abi
}
},
setup: (program) => {
const { vk, pk } = zokrates.setup(program);
return {
vk,
pk: Array.from(pk)
};
},
computeWitness: (artifacts, args) => {
return zokrates.compute_witness(artifacts, JSON.stringify(Array.from(args)));
},
exportSolidityVerifier: (verificationKey, abiVersion) => {
return zokrates.export_solidity_verifier(verificationKey, abiVersion);
},
generateProof: (program, witness, provingKey) => {
return zokrates.generate_proof(program, witness, provingKey);
}
}
};

View file

@ -37,7 +37,7 @@ ace.define("ace/mode/zokrates_highlight_rules",["require","exports","module","ac
var ZoKratesHighlightRules = function () {
var keywords = (
"endfor|as|return|byte|field|bool|if|then|fi|do|else|export|false|def|for|import|from|uint|in|public|private|struct|true"
"assert|endfor|as|return|byte|field|bool|if|then|fi|do|else|export|false|def|for|import|from|uint|in|public|private|struct|true"
);
var keywordMapper = this.createKeywordMapper({

View file

@ -46,7 +46,7 @@ statement = { (return_statement // does not require subsequent newline
iteration_statement = { "for" ~ ty ~ identifier ~ "in" ~ expression ~ ".." ~ expression ~ "do" ~ NEWLINE* ~ statement* ~ "endfor"}
return_statement = { "return" ~ expression_list}
definition_statement = { optionally_typed_assignee_list ~ "=" ~ expression } // declare and assign, so only identifiers are allowed, unlike `assignment_statement`
expression_statement = {expression}
expression_statement = {"assert" ~ "(" ~ expression ~ ")"}
optionally_typed_assignee_list = _{ optionally_typed_assignee ~ ("," ~ optionally_typed_assignee)* }
optionally_typed_assignee = { (ty ~ assignee) | (assignee) } // we don't use { ty? ~ identifier } as with a single token, it gets parsed as `ty` but we want `identifier`
@ -124,6 +124,8 @@ op_unary = { op_not }
WHITESPACE = _{ " " | "\t" | "\\" ~ NEWLINE}
COMMENT = _{ ("/*" ~ (!"*/" ~ ANY)* ~ "*/") | ("//" ~ (!NEWLINE ~ ANY)*) }
keyword = @{"as"|"bool"|"byte"|"def"|"do"|"else"|"endfor"|"export"|"false"|"field"|"for"|"if"|"then"|"fi"|"import"|"from"|
// the ordering of reserved keywords matters: if "as" is before "assert", then "assert" gets parsed as (as)(sert) and incorrectly
// accepted
keyword = @{"assert"|"as"|"bool"|"byte"|"def"|"do"|"else"|"endfor"|"export"|"false"|"field"|"for"|"if"|"then"|"fi"|"import"|"from"|
"in"|"private"|"public"|"return"|"struct"|"true"|"u8"|"u16"|"u32"
}

View file

@ -32,21 +32,22 @@ mod ast {
static ref PREC_CLIMBER: PrecClimber<Rule> = build_precedence_climber();
}
// based on https://docs.python.org/3/reference/expressions.html#operator-precedence
fn build_precedence_climber() -> PrecClimber<Rule> {
PrecClimber::new(vec![
Operator::new(Rule::op_or, Assoc::Left),
Operator::new(Rule::op_and, Assoc::Left),
Operator::new(Rule::op_lt, Assoc::Left)
| Operator::new(Rule::op_lte, Assoc::Left)
| Operator::new(Rule::op_gt, Assoc::Left)
| Operator::new(Rule::op_gte, Assoc::Left)
| Operator::new(Rule::op_not_equal, Assoc::Left)
| Operator::new(Rule::op_equal, Assoc::Left),
Operator::new(Rule::op_bit_or, Assoc::Left),
Operator::new(Rule::op_bit_xor, Assoc::Left),
Operator::new(Rule::op_bit_and, Assoc::Left),
Operator::new(Rule::op_equal, Assoc::Left)
| Operator::new(Rule::op_not_equal, Assoc::Left),
Operator::new(Rule::op_lte, Assoc::Left)
| Operator::new(Rule::op_gte, Assoc::Left)
| Operator::new(Rule::op_lt, Assoc::Left)
| Operator::new(Rule::op_gt, Assoc::Left),
Operator::new(Rule::op_right_shift, Assoc::Left)
| Operator::new(Rule::op_left_shift, Assoc::Left),
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_pow, Assoc::Left),
@ -1174,9 +1175,9 @@ mod tests {
field a = 1
a[32 + x][55] = y
for field i in 0..3 do
a == 1 + 2 + 3+ 4+ 5+ 6+ 6+ 7+ 8 + 4+ 5+ 3+ 4+ 2+ 3
assert(a == 1 + 2 + 3+ 4+ 5+ 6+ 6+ 7+ 8 + 4+ 5+ 3+ 4+ 2+ 3)
endfor
a.member == 1
assert(a.member == 1)
return a
"#;
let res = generate_ast(&source);

View file

@ -4,7 +4,7 @@ from "ecc/babyjubjubParams" import BabyJubJubParams
// Curve parameters are defined with the last argument
// See appendix 3.3.1 of Zcash protocol specification:
// https://github.com/zcash/zips/blob/master/protocol/protocol.pdf
def main(field[2] pt, BabyJubJubParams context) -> (field):
def main(field[2] pt, BabyJubJubParams context) -> (bool):
field a = context.JUBJUBA
field d = context.JUBJUBD
@ -13,6 +13,6 @@ def main(field[2] pt, BabyJubJubParams context) -> (field):
field vv = pt[1] * pt[1]
field uuvv = uu * vv
a * uu + vv == 1 + d * uuvv
assert(a * uu + vv == 1 + d * uuvv)
return 1
return true

View file

@ -6,14 +6,14 @@ from "ecc/babyjubjubParams" import BabyJubJubParams
// Verifies that the point is not one of the low-order points.
// If any of the points is multiplied by the cofactor, the resulting point
// will be infinity.
// Returns 1 if the point is not one of the low-order points, 0 otherwise.
// Returns true if the point is not one of the low-order points, false otherwise.
// Curve parameters are defined with the last argument
// https://github.com/zcash-hackworks/sapling-crypto/blob/master/src/jubjub/edwards.rs#L166
def main(field[2] pt, BabyJubJubParams context) -> (field):
def main(field[2] pt, BabyJubJubParams context) -> (bool):
field cofactor = context.JUBJUBC
cofactor == 8
assert(cofactor == 8)
// Co-factor currently hard-coded to 8 for efficiency reasons
// See discussion here: https://github.com/Zokrates/ZoKrates/pull/301#discussion_r267203391
@ -24,6 +24,4 @@ def main(field[2] pt, BabyJubJubParams context) -> (field):
ptExp = add(ptExp, ptExp, context) // 4*pt
ptExp = add(ptExp, ptExp, context) // 8*pt
field out = if ptExp[0] == 0 && ptExp[1] == 1 then 0 else 1 fi
return out
return !(ptExp[0] == 0 && ptExp[1] == 1)

View file

@ -1,5 +1,5 @@
import "ecc/edwardsAdd" as add
import "ecc/edwardsOnCurve" as assertOnCurve
import "ecc/edwardsOnCurve" as onCurve
from "ecc/babyjubjubParams" import BabyJubJubParams
// Function that implements scalar multiplication for a fixed base point
@ -22,6 +22,6 @@ def main(bool[256] exponent, field[2] pt, BabyJubJubParams context) -> (field[2]
doubledP = add(doubledP, doubledP, context)
endfor
1 == assertOnCurve(accumulatedP, context)
assert(onCurve(accumulatedP, context))
return accumulatedP

View file

@ -34,9 +34,8 @@ def main(private field[2] R, private field S, field[2] A, u32[8] M0, u32[8] M1,
field[2] G = [context.Gu, context.Gv]
// Check if R is on curve and if it is not in a small subgroup. A is public input and can be checked offline
field isOnCurve = onCurve(R, context) // throws if R is not on curve
field isPrimeOrder = orderCheck(R, context)
1 == isPrimeOrder
assert(onCurve(R, context)) // throws if R is not on curve
assert(orderCheck(R, context))
u32[8] Rx = unpack256u(R[0])
u32[8] Ax = unpack256u(A[0])

View file

@ -6,6 +6,6 @@ def main(field i) -> (bool[128]):
bool[254] b = unpack(i)
b[0..126] == [false; 126]
assert(b[0..126] == [false; 126])
return b[126..254]

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": ["1"]
"values": []
}
}
}

View file

@ -5,34 +5,34 @@ from "ecc/babyjubjubParams" import BabyJubJubParams
// Code to create test cases:
// https://github.com/Zokrates/pycrypto
def testDoubleViaAdd() -> (field):
def testDoubleViaAdd() -> (bool):
BabyJubJubParams context = context()
field[2] G = [context.Gu, context.Gv]
field[2] out = add(G, G, context)
out[0] == 17324563846726889236817837922625232543153115346355010501047597319863650987830
out[1] == 20022170825455209233733649024450576091402881793145646502279487074566492066831
assert(out[0] == 17324563846726889236817837922625232543153115346355010501047597319863650987830)
assert(out[1] == 20022170825455209233733649024450576091402881793145646502279487074566492066831)
return 1
return true
def testIdentities() -> (field):
def testIdentities() -> (bool):
BabyJubJubParams context = context()
field[2] G = [context.Gu, context.Gv]
field[2] inf = context.INFINITY
G == add(G, inf, context)
assert(G == add(G, inf, context))
field[2] nG = neg(G)
field[2] nGaddG = add(G, nG, context)
inf == nGaddG
assert(inf == nGaddG)
return 1
return true
def main() -> (field):
def main() -> ():
1 == testDoubleViaAdd()
1 == testIdentities()
assert(testDoubleViaAdd())
assert(testIdentities())
return 1
return

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": ["1"]
"values": []
}
}
}

View file

@ -4,7 +4,7 @@ from "ecc/babyjubjubParams" import BabyJubJubParams
// Code to create test cases:
// https://github.com/Zokrates/pycrypto
def testCompress() -> (field):
def testCompress() -> (bool):
BabyJubJubParams context = context()
field Gu = context.Gu
@ -12,12 +12,12 @@ def testCompress() -> (field):
bool[256] Gcompressed = edwardsCompress([Gu, Gv])
Gcompressed == [true, false, true, false, true, true, true, false, false, false, false, false, false, true, true, true, false, false, true, false, true, false, false, true, false, true, true, true, true, true, true, true, true, false, false, false, true, true, false, true, false, false, true, true, true, true, false, false, false, false, true, true, true, true, false, true, false, true, true, true, true, false, false, false, false, false, false, true, true, false, false, false, true, true, false, true, true, false, true, true, true, true, false, true, true, true, false, true, true, true, true, true, true, true, false, true, false, false, true, false, false, true, false, false, true, true, false, false, false, false, true, true, false, true, false, true, false, true, false, true, true, false, false, false, false, false, true, true, true, true, true, true, true, false, false, true, true, false, true, false, true, false, false, true, true, true, false, true, false, true, false, false, true, true, true, false, true, true, false, true, false, false, false, false, true, true, false, false, true, false, true, true, false, false, false, false, true, true, false, false, false, false, false, true, true, true, false, true, false, false, false, true, false, false, true, true, false, true, false, false, true, false, false, false, true, true, false, true, true, true, false, true, true, false, false, false, true, true, true, true, false, true, true, true, true, true, true, true, true, false, false, true, true, false, false, true, false, false, false, true, false, true, false, true, false, false, true, false, true, true, false, true, false, true, true, true]
assert(Gcompressed == [true, false, true, false, true, true, true, false, false, false, false, false, false, true, true, true, false, false, true, false, true, false, false, true, false, true, true, true, true, true, true, true, true, false, false, false, true, true, false, true, false, false, true, true, true, true, false, false, false, false, true, true, true, true, false, true, false, true, true, true, true, false, false, false, false, false, false, true, true, false, false, false, true, true, false, true, true, false, true, true, true, true, false, true, true, true, false, true, true, true, true, true, true, true, false, true, false, false, true, false, false, true, false, false, true, true, false, false, false, false, true, true, false, true, false, true, false, true, false, true, true, false, false, false, false, false, true, true, true, true, true, true, true, false, false, true, true, false, true, false, true, false, false, true, true, true, false, true, false, true, false, false, true, true, true, false, true, true, false, true, false, false, false, false, true, true, false, false, true, false, true, true, false, false, false, false, true, true, false, false, false, false, false, true, true, true, false, true, false, false, false, true, false, false, true, true, false, true, false, false, true, false, false, false, true, true, false, true, true, true, false, true, true, false, false, false, true, true, true, true, false, true, true, true, true, true, true, true, true, false, false, true, true, false, false, true, false, false, false, true, false, true, false, true, false, false, true, false, true, true, false, true, false, true, true, true])
return 1
return true
def main() -> (field):
def main() -> ():
1 == testCompress()
assert(testCompress())
return 1
return

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": ["1"]
"values": []
}
}
}

View file

@ -4,19 +4,19 @@ import "ecc/edwardsOnCurve" as onCurve
// Code to create test cases:
// https://github.com/Zokrates/pycrypto
def testOnCurveTrue() -> (field):
def testOnCurveTrue() -> (bool):
BabyJubJubParams context = context()
field testU = 17324563846726889236817837922625232543153115346355010501047597319863650987830
field testV = 20022170825455209233733649024450576091402881793145646502279487074566492066831
1 == onCurve([testU, testV], context)
assert(onCurve([testU, testV], context))
return 1
return true
def main() -> (field):
def main() -> ():
1 == testOnCurveTrue()
assert(testOnCurveTrue())
// onCurve throws for false
return 1
return

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": ["1"]
"values": []
}
}
}

View file

@ -4,31 +4,31 @@ from "ecc/babyjubjubParams" import BabyJubJubParams
// Code to create test cases:
// https://github.com/Zokrates/pycrypto
def testOrderCheckTrue() -> (field):
def testOrderCheckTrue() -> (bool):
BabyJubJubParams context = context()
field testU = 17324563846726889236817837922625232543153115346355010501047597319863650987830
field testV = 20022170825455209233733649024450576091402881793145646502279487074566492066831
field out = orderCheck([testU, testV], context)
out == 1
bool out = orderCheck([testU, testV], context)
assert(out)
return 1
return true
def testOrderCheckFalse() -> (field):
def testOrderCheckFalse() -> (bool):
BabyJubJubParams context = context()
field testU = 4342719913949491028786768530115087822524712248835451589697801404893164183326
field testV = 4826523245007015323400664741523384119579596407052839571721035538011798951543
field out = orderCheck([testU, testV], context)
out == 0
bool out = orderCheck([testU, testV], context)
assert(!out)
return 1
return true
def main() -> (field):
def main() -> ():
1 == testOrderCheckFalse()
1 == testOrderCheckTrue()
assert(testOrderCheckFalse())
assert(testOrderCheckTrue())
return 1
return

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": ["1"]
"values": []
}
}
}

View file

@ -4,7 +4,7 @@ import "ecc/edwardsScalarMult" as mul
// Code to create test cases:
// https://github.com/Zokrates/pycrypto
def testCyclic() -> (field):
def testCyclic() -> (bool):
BabyJubJubParams context = context()
field[2] G = [context.Gu, context.Gv]
@ -13,11 +13,11 @@ def testCyclic() -> (field):
field[2] out = mul(exp, G, context)
G == out
assert(G == out)
return 1
return true
def testMul2() -> (field):
def testMul2() -> (bool):
BabyJubJubParams context = context()
field[2] G = [context.Gu, context.Gv]
@ -25,12 +25,12 @@ def testMul2() -> (field):
bool[256] exp = [false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, true, false]
field[2] out = mul(exp, G, context)
out[0] == 17324563846726889236817837922625232543153115346355010501047597319863650987830
out[1] == 20022170825455209233733649024450576091402881793145646502279487074566492066831
assert(out[0] == 17324563846726889236817837922625232543153115346355010501047597319863650987830)
assert(out[1] == 20022170825455209233733649024450576091402881793145646502279487074566492066831)
return 1
return true
def testAssociativity() -> (field):
def testAssociativity() -> (bool):
BabyJubJubParams context = context()
field[2] G = [context.Gu, context.Gv]
@ -55,13 +55,13 @@ def testAssociativity() -> (field):
field[2] Gca = mul(a, Gc, context)
field[2] Gcab = mul(b, Gca, context)
Gabc == Gbca
Gbca == Gcab
Gabc == Gcab
assert(Gabc == Gbca)
assert(Gbca == Gcab)
assert(Gabc == Gcab)
return 1
return true
def testMultiplicative() -> (field):
def testMultiplicative() -> (bool):
BabyJubJubParams context = context()
field[2] G = [context.Gu, context.Gv]
@ -81,16 +81,16 @@ def testMultiplicative() -> (field):
field[2] Gmab = mul(ab, G, context)
Gab == Gba
Gba == Gmab
Gab == Gmab
assert(Gab == Gba)
assert(Gba == Gmab)
assert(Gab == Gmab)
return 1
return true
def main() -> (field):
1 == testMul2()
1 == testCyclic()
1 == testAssociativity()
1 == testMultiplicative()
def main() -> ():
assert(testMul2())
assert(testCyclic())
assert(testAssociativity())
assert(testMultiplicative())
return 1
return

View file

@ -8,7 +8,7 @@
},
"output": {
"Ok": {
"values": ["1"]
"values": []
}
}
}

View file

@ -5,7 +5,7 @@ import "ecc/edwardsScalarMult" as multiply
// Code to create test cases:
// https://github.com/Zokrates/pycrypto
def testOwnershipTrue() -> (field):
def testOwnershipTrue() -> (bool):
BabyJubJubParams context = context()
field[2] G = [context.Gu, context.Gv]
@ -14,22 +14,22 @@ def testOwnershipTrue() -> (field):
bool out = proofOfOwnership(Pk, sk, context)
out == true
return 1
assert(out)
return true
def testtOwnershipFalse() -> (field):
def testtOwnershipFalse() -> (bool):
BabyJubJubParams context = context()
field[2] Pk = [16328093915569409528980874702678312730273137210288183490878184636452430630129, 9377227749598842756429258362864743065769435972445705966557343775367597326529]
field sk = 1997011358982923168928344992199991480689546837621580239342656433234255379025
bool out = proofOfOwnership(Pk, sk, context)
out == false
return 1
assert(!out)
return true
def main() -> (field):
def main() -> ():
1 == testOwnershipTrue()
1 == testtOwnershipFalse()
assert(testOwnershipTrue())
assert(testtOwnershipFalse())
return 1
return

View file

@ -7,9 +7,7 @@
},
"output": {
"Ok": {
"values": [
"1"
]
"values": []
}
}
}

View file

@ -1,9 +1,9 @@
import "hashes/mimc7/mimc7R10"
def main() -> (field):
mimc7R10(0, 0) == 6004544488495356385698286530147974336054653445122716140990101827963729149289
mimc7R10(100, 0) == 2977550761518141183167168643824354554080911485709001361112529600968315693145
mimc7R10(100, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 2977550761518141183167168643824354554080911485709001361112529600968315693145
mimc7R10(21888242871839275222246405745257275088548364400416034343698204186575808495618, 1) == 11476724043755138071320043459606423473319855817296339514744600646762741571430
mimc7R10(21888242871839275222246405745257275088548364400416034343698204186575808495617, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 6004544488495356385698286530147974336054653445122716140990101827963729149289
return 1
def main() -> ():
assert(mimc7R10(0, 0) == 6004544488495356385698286530147974336054653445122716140990101827963729149289)
assert(mimc7R10(100, 0) == 2977550761518141183167168643824354554080911485709001361112529600968315693145)
assert(mimc7R10(100, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 2977550761518141183167168643824354554080911485709001361112529600968315693145)
assert(mimc7R10(21888242871839275222246405745257275088548364400416034343698204186575808495618, 1) == 11476724043755138071320043459606423473319855817296339514744600646762741571430)
assert(mimc7R10(21888242871839275222246405745257275088548364400416034343698204186575808495617, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 6004544488495356385698286530147974336054653445122716140990101827963729149289)
return

View file

@ -7,9 +7,7 @@
},
"output": {
"Ok": {
"values": [
"1"
]
"values": []
}
}
}

View file

@ -1,9 +1,9 @@
import "hashes/mimc7/mimc7R20"
def main() -> (field):
mimc7R20(0, 0) == 19139739902058628561064841933381604453445216873412991992755775746150759284829
mimc7R20(100, 0) == 8623418512398828792274158979964869393034224267928014534933203776818702139758
mimc7R20(100, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 8623418512398828792274158979964869393034224267928014534933203776818702139758
mimc7R20(21888242871839275222246405745257275088548364400416034343698204186575808495618, 1) == 15315177265066649795408805007175121550344555424263995530745989936206840798041
mimc7R20(21888242871839275222246405745257275088548364400416034343698204186575808495617, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 19139739902058628561064841933381604453445216873412991992755775746150759284829
return 1
def main() -> ():
assert(mimc7R20(0, 0) == 19139739902058628561064841933381604453445216873412991992755775746150759284829)
assert(mimc7R20(100, 0) == 8623418512398828792274158979964869393034224267928014534933203776818702139758)
assert(mimc7R20(100, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 8623418512398828792274158979964869393034224267928014534933203776818702139758)
assert(mimc7R20(21888242871839275222246405745257275088548364400416034343698204186575808495618, 1) == 15315177265066649795408805007175121550344555424263995530745989936206840798041)
assert(mimc7R20(21888242871839275222246405745257275088548364400416034343698204186575808495617, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 19139739902058628561064841933381604453445216873412991992755775746150759284829)
return

View file

@ -7,9 +7,7 @@
},
"output": {
"Ok": {
"values": [
"1"
]
"values": []
}
}
}

View file

@ -1,9 +1,9 @@
import "hashes/mimc7/mimc7R50"
def main() -> (field):
mimc7R50(0, 0) == 3049953358280347916081509186284461274525472221619157672645224540758481713173
mimc7R50(100, 0) == 18511388995652647480418174218630545482006454713617579894396683237092568946789
mimc7R50(100, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 18511388995652647480418174218630545482006454713617579894396683237092568946789
mimc7R50(21888242871839275222246405745257275088548364400416034343698204186575808495618, 1) == 9149577627043020462780389988155990926223727917856424056384664564191878439702
mimc7R50(21888242871839275222246405745257275088548364400416034343698204186575808495617, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 3049953358280347916081509186284461274525472221619157672645224540758481713173
return 1
def main() -> ():
assert(mimc7R50(0, 0) == 3049953358280347916081509186284461274525472221619157672645224540758481713173)
assert(mimc7R50(100, 0) == 18511388995652647480418174218630545482006454713617579894396683237092568946789)
assert(mimc7R50(100, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 18511388995652647480418174218630545482006454713617579894396683237092568946789)
assert(mimc7R50(21888242871839275222246405745257275088548364400416034343698204186575808495618, 1) == 9149577627043020462780389988155990926223727917856424056384664564191878439702)
assert(mimc7R50(21888242871839275222246405745257275088548364400416034343698204186575808495617, 21888242871839275222246405745257275088548364400416034343698204186575808495617) == 3049953358280347916081509186284461274525472221619157672645224540758481713173)
return

Some files were not shown because too many files have changed in this diff Show more