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

Intermediary commit. Serialization added, Deserialization still ToDo. Formatted.

This commit is contained in:
Jacob Eberhardt 2017-10-09 13:24:31 +02:00
parent 9528f6576c
commit 5d60e174ee
10 changed files with 2075 additions and 691 deletions

79
Cargo.lock generated
View file

@ -2,12 +2,15 @@
name = "zkc"
version = "0.1.0"
dependencies = [
"bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)",
"clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)",
"gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)",
"glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 0.1.16 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.20 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -26,11 +29,26 @@ dependencies = [
"winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bincode"
version = "0.8.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)",
"serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "bitflags"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "byteorder"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "clap"
version = "2.26.2"
@ -141,6 +159,11 @@ name = "num-traits"
version = "0.1.36"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "quote"
version = "0.3.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "rand"
version = "0.3.15"
@ -167,11 +190,53 @@ name = "rustc-serialize"
version = "0.3.22"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "serde_derive"
version = "1.0.15"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "serde_derive_internals"
version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)",
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "strsim"
version = "0.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.11.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)",
"synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "synom"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "term_size"
version = "0.3.0"
@ -206,6 +271,11 @@ name = "unicode-width"
version = "0.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "vec_map"
version = "0.8.0"
@ -224,7 +294,9 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum ansi_term 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "23ac7c30002a5accbf7e8987d0632fa6de155b7c3d39d0067317a391e00a2ef6"
"checksum atty 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "21e50800ec991574876040fff8ee46b136a53e985286fbe6a3bdfe6421b78860"
"checksum bincode 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e103c8b299b28a9c6990458b7013dc4a8356a9b854c51b9883241f5866fac36e"
"checksum bitflags 0.9.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4efd02e230a02e18f92fc2735f44597385ed02ad8f831e7c1c1156ee5e1ab3a5"
"checksum byteorder 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ff81738b726f5d099632ceaffe7fb65b90212e8dce59d518729e7e8634032d3d"
"checksum clap 2.26.2 (registry+https://github.com/rust-lang/crates.io-index)" = "3451e409013178663435d6f15fdb212f14ee4424a3d74f979d081d0a66b6f1f2"
"checksum gcc 0.3.42 (registry+https://github.com/rust-lang/crates.io-index)" = "291055c78f59ca3d84c99026c9501c469413d386bb46be1e1cf1d285cd1db3b0"
"checksum glob 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "8be18de09a56b60ed0edf84bc9df007e30040691af7acd1c41874faac5895bfb"
@ -238,15 +310,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)" = "287a1c9969a847055e1122ec0ea7a5c5d6f72aad97934e131c83d5c08ab4e45c"
"checksum num-rational 0.1.35 (registry+https://github.com/rust-lang/crates.io-index)" = "54ff603b8334a72fbb27fe66948aac0abaaa40231b3cecd189e76162f6f38aaf"
"checksum num-traits 0.1.36 (registry+https://github.com/rust-lang/crates.io-index)" = "a16a42856a256b39c6d3484f097f6713e14feacd9bfb02290917904fae46c81c"
"checksum quote 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6e920b65c65f10b2ae65c831a81a073a89edd28c7cce89475bff467ab4167a"
"checksum rand 0.3.15 (registry+https://github.com/rust-lang/crates.io-index)" = "022e0636ec2519ddae48154b028864bdce4eaf7d35226ab8e65c611be97b189d"
"checksum redox_syscall 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)" = "8dde11f18c108289bef24469638a04dce49da56084f2d50618b226e47eb04509"
"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
"checksum rustc-serialize 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "237546c689f20bb44980270c73c3b9edd0891c1be49cc1274406134a66d3957b"
"checksum serde 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "6a7046c9d4c6c522d10b2d098f9bebe2bef227e0e74044d8c1bfcf6b476af799"
"checksum serde_derive 1.0.15 (registry+https://github.com/rust-lang/crates.io-index)" = "1afcaae083fd1c46952a315062326bc9957f182358eb7da03b57ef1c688f7aa9"
"checksum serde_derive_internals 0.16.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bd381f6d01a6616cdba8530492d453b7761b456ba974e98768a18cad2cd76f58"
"checksum strsim 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b4d15c810519a91cf877e7e36e63fe068815c678181439f2f29e2562147c3694"
"checksum syn 0.11.11 (registry+https://github.com/rust-lang/crates.io-index)" = "d3b891b9015c88c576343b9b3e41c2c11a51c219ef067b264bd9c8aa9b441dad"
"checksum synom 0.11.3 (registry+https://github.com/rust-lang/crates.io-index)" = "a393066ed9010ebaed60b9eafa373d4b1baac186dd7e008555b0f702b51945b6"
"checksum term_size 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2b6b55df3198cc93372e85dd2ed817f0e38ce8cc0f22eb32391bfad9c4bf209"
"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
"checksum textwrap 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "df8e08afc40ae3459e4838f303e465aa50d823df8d7f83ca88108f6d3afe7edd"
"checksum unicode-width 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "bf3a113775714a22dcb774d8ea3655c53a32debae63a063acc00a91cc586245f"
"checksum unicode-xid 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "8c1f860d7d29cf02cb2f3f359fd35991af3d30bac52c57d265a3c461074cb4dc"
"checksum vec_map 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "887b5b631c2ad01628bbbaa7dd4c869f80d3186688f8d0b6f58774fbe324988c"
"checksum winapi 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "167dc9d6949a9b857f3451275e911c3f44255842c1f7a76f33c55103a909087a"
"checksum winapi-build 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "2d315eee3b34aca4797b2da6b13ed88266e6d612562a0c46390af8299fc699bc"

View file

@ -1,7 +1,7 @@
[package]
name = "zkc"
version = "0.1.0"
authors = ["Dennis Kuhnert <mail@kyroy.com>"]
authors = ["Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>", "Dennis Kuhnert <mail@kyroy.com>"]
repository = "https://github.com/Kyroy/VerifiableStatementCompiler.git"
readme = "README.md"
build = "build.rs"
@ -13,7 +13,12 @@ nolibsnark = []
libc = "0.2.0"
num = "0.1.36"
lazy_static = "0.1.*"
# cli
clap = "2.26.2"
# serialization and deserialization
serde = "1.0"
serde_derive = "1.0"
bincode = "0.8.0"
[dev-dependencies]
glob = "0.2.11"

View file

@ -1,8 +1,8 @@
#[cfg(not(feature="nolibsnark"))]
#[cfg(not(feature = "nolibsnark"))]
extern crate gcc;
fn main() {
#[cfg(not(feature="nolibsnark"))]
#[cfg(not(feature = "nolibsnark"))]
{
println!("cargo:rustc-link-search=/usr/local/lib");
gcc::Config::new()

View file

@ -10,7 +10,7 @@ use std::collections::HashMap;
use std::io::{stdin, BufRead};
use field::Field;
///
#[derive(Serialize, Deserialize)]
pub struct Prog<T: Field> {
/// Functions of the program
pub functions: Vec<Function<T>>,
@ -20,7 +20,7 @@ pub struct Prog<T: Field> {
impl<T: Field> Prog<T> {
// only main flattened function is relevant here, as all other functions are unrolled into it
pub fn get_witness(&self, inputs: Vec<T>) -> HashMap<String, T> {
let main = self.functions.iter().find(|x| x.id=="main").unwrap();
let main = self.functions.iter().find(|x| x.id == "main").unwrap();
assert!(main.arguments.len() == inputs.len());
main.get_witness(inputs)
}
@ -29,16 +29,33 @@ impl<T: Field> Prog<T> {
impl<T: Field> fmt::Display for Prog<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.functions.iter().map(|x| format!("{}", x)).collect::<Vec<_>>().join("\n"))
write!(
f,
"{}",
self.functions
.iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()
.join("\n")
)
}
}
impl<T: Field> fmt::Debug for Prog<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "program(functions: {}\t)", self.functions.iter().map(|x| format!("\t{:?}", x)).collect::<Vec<_>>().join("\n"))
write!(
f,
"program(functions: {}\t)",
self.functions
.iter()
.map(|x| format!("\t{:?}", x))
.collect::<Vec<_>>()
.join("\n")
)
}
}
#[derive(Serialize, Deserialize)]
pub struct Function<T: Field> {
/// Name of the program
pub id: String,
@ -54,8 +71,7 @@ impl<T: Field> Function<T> {
assert!(self.arguments.len() == inputs.len());
let mut witness = HashMap::new();
witness.insert("~one".to_string(), T::one());
for (i, arg) in self.arguments.iter().enumerate()
{
for (i, arg) in self.arguments.iter().enumerate() {
witness.insert(arg.id.to_string(), inputs[i].clone());
}
for statement in &self.statements {
@ -63,14 +79,15 @@ impl<T: Field> Function<T> {
Statement::Return(ref expr) => {
let s = expr.solve(&mut witness);
witness.insert("~out".to_string(), s);
},
Statement::Compiler(ref id, ref expr) |
Statement::Definition(ref id, ref expr) => {
}
Statement::Compiler(ref id, ref expr) | Statement::Definition(ref id, ref expr) => {
let s = expr.solve(&mut witness);
witness.insert(id.to_string(), s);
},
}
Statement::For(..) => unimplemented!(),
Statement::Condition(ref lhs, ref rhs) => assert_eq!(lhs.solve(&mut witness), rhs.solve(&mut witness)),
Statement::Condition(ref lhs, ref rhs) => {
assert_eq!(lhs.solve(&mut witness), rhs.solve(&mut witness))
}
}
}
witness
@ -79,17 +96,41 @@ impl<T: Field> Function<T> {
impl<T: Field> fmt::Display for Function<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "def {}({}):\n{}", self.id, self.arguments.iter().map(|x| format!("{}", x)).collect::<Vec<_>>().join(","), self.statements.iter().map(|x| format!("\t{}", x)).collect::<Vec<_>>().join("\n"))
write!(
f,
"def {}({}):\n{}",
self.id,
self.arguments
.iter()
.map(|x| format!("{}", x))
.collect::<Vec<_>>()
.join(","),
self.statements
.iter()
.map(|x| format!("\t{}", x))
.collect::<Vec<_>>()
.join("\n")
)
}
}
impl<T: Field> fmt::Debug for Function<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "Function(id: {:?}, arguments: {:?}, ...):\n{}", self.id, self.arguments, self.statements.iter().map(|x| format!("\t{:?}", x)).collect::<Vec<_>>().join("\n"))
write!(
f,
"Function(id: {:?}, arguments: {:?}, ...):\n{}",
self.id,
self.arguments,
self.statements
.iter()
.map(|x| format!("\t{:?}", x))
.collect::<Vec<_>>()
.join("\n")
)
}
}
#[derive(Clone)]
#[derive(Clone, Serialize, Deserialize)]
pub enum Statement<T: Field> {
Return(Expression<T>),
Definition(String, Expression<T>),
@ -101,10 +142,11 @@ pub enum Statement<T: Field> {
impl<T: Field> Statement<T> {
pub fn is_flattened(&self) -> bool {
match *self {
Statement::Return(ref x) |
Statement::Definition(_,ref x) => x.is_flattened(),
Statement::Return(ref x) | Statement::Definition(_, ref x) => x.is_flattened(),
Statement::Compiler(..) => true,
Statement::Condition(ref x,ref y) => (x.is_linear() && y.is_flattened()) || (x.is_flattened() && y.is_linear()),
Statement::Condition(ref x, ref y) => {
(x.is_linear() && y.is_flattened()) || (x.is_flattened() && y.is_linear())
}
Statement::For(..) => unimplemented!(), // should not be required, can be implemented later
}
}
@ -123,7 +165,7 @@ impl<T: Field> fmt::Display for Statement<T> {
try!(write!(f, "\t\t{}\n", l));
}
write!(f, "\tendfor")
},
}
Statement::Compiler(ref lhs, ref rhs) => write!(f, "# {} = {}", lhs, rhs),
}
}
@ -133,7 +175,9 @@ impl<T: Field> fmt::Debug for Statement<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match *self {
Statement::Return(ref expr) => write!(f, "Return({:?})", expr),
Statement::Definition(ref lhs, ref rhs) => write!(f, "Definition({:?}, {:?})", lhs, rhs),
Statement::Definition(ref lhs, ref rhs) => {
write!(f, "Definition({:?}, {:?})", lhs, rhs)
}
Statement::Condition(ref lhs, ref rhs) => write!(f, "Condition({:?}, {:?})", lhs, rhs),
Statement::For(ref var, ref start, ref stop, ref list) => {
try!(write!(f, "for {:?} in {:?}..{:?} do\n", var, start, stop));
@ -141,14 +185,16 @@ impl<T: Field> fmt::Debug for Statement<T> {
try!(write!(f, "\t\t{:?}\n", l));
}
write!(f, "\tendfor")
},
}
Statement::Compiler(ref lhs, ref rhs) => write!(f, "Compiler({:?}, {:?})", lhs, rhs),
}
}
}
#[derive(Clone,PartialEq)]
pub struct Parameter { pub id: String }
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub struct Parameter {
pub id: String,
}
impl fmt::Display for Parameter {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
@ -162,7 +208,7 @@ impl fmt::Debug for Parameter {
}
}
#[derive(Clone,PartialEq)]
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub enum Expression<T: Field> {
Number(T),
Identifier(String),
@ -187,19 +233,38 @@ impl<T: Field> Expression<T> {
None => return Expression::Identifier(new_name),
}
}
},
Expression::Add(ref e1, ref e2) => Expression::Add(box e1.apply_substitution(substitution), box e2.apply_substitution(substitution)),
Expression::Sub(ref e1, ref e2) => Expression::Sub(box e1.apply_substitution(substitution), box e2.apply_substitution(substitution)),
Expression::Mult(ref e1, ref e2) => Expression::Mult(box e1.apply_substitution(substitution), box e2.apply_substitution(substitution)),
Expression::Div(ref e1, ref e2) => Expression::Div(box e1.apply_substitution(substitution), box e2.apply_substitution(substitution)),
Expression::Pow(ref e1, ref e2) => Expression::Pow(box e1.apply_substitution(substitution), box e2.apply_substitution(substitution)),
Expression::IfElse(ref c, ref e1, ref e2) => Expression::IfElse(box c.apply_substitution(substitution), box e1.apply_substitution(substitution), box e2.apply_substitution(substitution)),
}
Expression::Add(ref e1, ref e2) => Expression::Add(
box e1.apply_substitution(substitution),
box e2.apply_substitution(substitution),
),
Expression::Sub(ref e1, ref e2) => Expression::Sub(
box e1.apply_substitution(substitution),
box e2.apply_substitution(substitution),
),
Expression::Mult(ref e1, ref e2) => Expression::Mult(
box e1.apply_substitution(substitution),
box e2.apply_substitution(substitution),
),
Expression::Div(ref e1, ref e2) => Expression::Div(
box e1.apply_substitution(substitution),
box e2.apply_substitution(substitution),
),
Expression::Pow(ref e1, ref e2) => Expression::Pow(
box e1.apply_substitution(substitution),
box e2.apply_substitution(substitution),
),
Expression::IfElse(ref c, ref e1, ref e2) => Expression::IfElse(
box c.apply_substitution(substitution),
box e1.apply_substitution(substitution),
box e2.apply_substitution(substitution),
),
Expression::FunctionCall(ref i, ref p) => {
for param in p {
param.apply_substitution(substitution);
}
Expression::FunctionCall(i.clone(), p.clone())
},
}
}
}
@ -222,56 +287,69 @@ impl<T: Field> Expression<T> {
}
assert_eq!(num, T::zero());
} else {
println!("Could not calculate variable {:?}, inputs: {:?}", var, inputs);
println!(
"Could not calculate variable {:?}, inputs: {:?}",
var,
inputs
);
println!("Please enter a value for {:?}:", var);
let mut input = String::new();
let stdin = stdin();
stdin.lock().read_line(&mut input).expect("Did not enter a correct String");
stdin
.lock()
.read_line(&mut input)
.expect("Did not enter a correct String");
inputs.insert(var.to_string(), T::from(input.trim()));
}
}
inputs[var].clone()
},
}
Expression::Add(ref x, ref y) => x.solve(inputs) + y.solve(inputs),
Expression::Sub(ref x, ref y) => x.solve(inputs) - y.solve(inputs),
Expression::Mult(ref x, ref y) => x.solve(inputs) * y.solve(inputs),
Expression::Div(ref x, ref y) => x.solve(inputs) / y.solve(inputs),
Expression::Pow(ref x, ref y) => x.solve(inputs).pow(y.solve(inputs)),
Expression::IfElse(ref condition, ref consequent, ref alternative)
=> if condition.solve(inputs) { consequent.solve(inputs) } else { alternative.solve(inputs) },
Expression::IfElse(ref condition, ref consequent, ref alternative) => {
if condition.solve(inputs) {
consequent.solve(inputs)
} else {
alternative.solve(inputs)
}
}
Expression::FunctionCall(_, _) => unimplemented!(), // should not happen, since never part of flattened functions
}
}
pub fn is_linear(&self) -> bool {
match *self {
Expression::Number(_) |
Expression::Identifier(_) => true,
Expression::Add(ref x, ref y) |
Expression::Sub(ref x, ref y) => x.is_linear() && y.is_linear(),
Expression::Mult(ref x, ref y) |
Expression::Div(ref x, ref y) => match (x.clone(), y.clone()) {
(box Expression::Number(_), box Expression::Number(_)) |
(box Expression::Number(_), box Expression::Identifier(_)) |
(box Expression::Identifier(_), box Expression::Number(_)) => true,
_ => false,
},
Expression::Number(_) | Expression::Identifier(_) => true,
Expression::Add(ref x, ref y) | Expression::Sub(ref x, ref y) => {
x.is_linear() && y.is_linear()
}
Expression::Mult(ref x, ref y) | Expression::Div(ref x, ref y) => {
match (x.clone(), y.clone()) {
(box Expression::Number(_), box Expression::Number(_)) |
(box Expression::Number(_), box Expression::Identifier(_)) |
(box Expression::Identifier(_), box Expression::Number(_)) => true,
_ => false,
}
}
_ => false,
}
}
pub fn is_flattened(&self) -> bool {
match *self {
Expression::Number(_) |
Expression::Identifier(_) => true,
Expression::Add(ref x, ref y) |
Expression::Sub(ref x, ref y) => x.is_linear() && y.is_linear(),
Expression::Mult(ref x, ref y) |
Expression::Div(ref x, ref y) => match (x.clone(), y.clone()) {
(box Expression::Sub(..), _) |
(_, box Expression::Sub(..)) => false,
(box x, box y) => x.is_linear() && y.is_linear()
},
Expression::Number(_) | Expression::Identifier(_) => true,
Expression::Add(ref x, ref y) | Expression::Sub(ref x, ref y) => {
x.is_linear() && y.is_linear()
}
Expression::Mult(ref x, ref y) | Expression::Div(ref x, ref y) => {
match (x.clone(), y.clone()) {
(box Expression::Sub(..), _) | (_, box Expression::Sub(..)) => false,
(box x, box y) => x.is_linear() && y.is_linear(),
}
}
_ => false,
}
}
@ -287,17 +365,23 @@ impl<T: Field> fmt::Display for Expression<T> {
Expression::Mult(ref lhs, ref rhs) => write!(f, "({} * {})", lhs, rhs),
Expression::Div(ref lhs, ref rhs) => write!(f, "({} / {})", lhs, rhs),
Expression::Pow(ref lhs, ref rhs) => write!(f, "{}**{}", lhs, rhs),
Expression::IfElse(ref condition, ref consequent, ref alternative) => write!(f, "if {} then {} else {} fi", condition, consequent, alternative),
Expression::IfElse(ref condition, ref consequent, ref alternative) => write!(
f,
"if {} then {} else {} fi",
condition,
consequent,
alternative
),
Expression::FunctionCall(ref i, ref p) => {
try!(write!(f, "{}(", i,));
for (i, param) in p.iter().enumerate() {
try!(write!(f, "{}",param));
if i<p.len()-1 {
for (i, param) in p.iter().enumerate() {
try!(write!(f, "{}", param));
if i < p.len() - 1 {
try!(write!(f, ","));
}
}
write!(f,")")
},
write!(f, ")")
}
}
}
}
@ -312,17 +396,23 @@ impl<T: Field> fmt::Debug for Expression<T> {
Expression::Mult(ref lhs, ref rhs) => write!(f, "Mult({:?}, {:?})", lhs, rhs),
Expression::Div(ref lhs, ref rhs) => write!(f, "Div({:?}, {:?})", lhs, rhs),
Expression::Pow(ref lhs, ref rhs) => write!(f, "Pow({:?}, {:?})", lhs, rhs),
Expression::IfElse(ref condition, ref consequent, ref alternative) => write!(f, "IfElse({:?}, {:?}, {:?})", condition, consequent, alternative),
Expression::IfElse(ref condition, ref consequent, ref alternative) => write!(
f,
"IfElse({:?}, {:?}, {:?})",
condition,
consequent,
alternative
),
Expression::FunctionCall(ref i, ref p) => {
try!(write!(f, "FunctionCall({:?}, (", i));
try!(f.debug_list().entries(p.iter()).finish());
write!(f,")")
},
write!(f, ")")
}
}
}
}
#[derive(Clone,PartialEq)]
#[derive(Clone, PartialEq, Serialize, Deserialize)]
pub enum Condition<T: Field> {
Lt(Expression<T>, Expression<T>),
Le(Expression<T>, Expression<T>),
@ -334,11 +424,26 @@ pub enum Condition<T: Field> {
impl<T: Field> Condition<T> {
fn apply_substitution(&self, substitution: &HashMap<String, String>) -> Condition<T> {
match *self {
Condition::Lt(ref lhs, ref rhs) => Condition::Lt(lhs.apply_substitution(substitution), rhs.apply_substitution(substitution)),
Condition::Le(ref lhs, ref rhs) => Condition::Le(lhs.apply_substitution(substitution), rhs.apply_substitution(substitution)),
Condition::Eq(ref lhs, ref rhs) => Condition::Eq(lhs.apply_substitution(substitution), rhs.apply_substitution(substitution)),
Condition::Ge(ref lhs, ref rhs) => Condition::Ge(lhs.apply_substitution(substitution), rhs.apply_substitution(substitution)),
Condition::Gt(ref lhs, ref rhs) => Condition::Gt(lhs.apply_substitution(substitution), rhs.apply_substitution(substitution)),
Condition::Lt(ref lhs, ref rhs) => Condition::Lt(
lhs.apply_substitution(substitution),
rhs.apply_substitution(substitution),
),
Condition::Le(ref lhs, ref rhs) => Condition::Le(
lhs.apply_substitution(substitution),
rhs.apply_substitution(substitution),
),
Condition::Eq(ref lhs, ref rhs) => Condition::Eq(
lhs.apply_substitution(substitution),
rhs.apply_substitution(substitution),
),
Condition::Ge(ref lhs, ref rhs) => Condition::Ge(
lhs.apply_substitution(substitution),
rhs.apply_substitution(substitution),
),
Condition::Gt(ref lhs, ref rhs) => Condition::Gt(
lhs.apply_substitution(substitution),
rhs.apply_substitution(substitution),
),
}
}

View file

@ -3,12 +3,13 @@
// @author Dennis Kuhnert <dennis.kuhnert@campus.tu-berlin.de>
// @date 2017
use num::{Integer, Zero, One};
use num::{Integer, One, Zero};
use num::bigint::{BigInt, ToBigInt};
use std::convert::From;
use std::ops::{Add, Sub, Mul, Div};
use std::ops::{Add, Div, Mul, Sub};
use std::fmt;
use std::fmt::{Display, Debug};
use std::fmt::{Debug, Display};
use serde::{Serialize, Deserialize, Serializer};
lazy_static! {
static ref P: BigInt = BigInt::parse_bytes(b"21888242871839275222246405745257275088548364400416034343698204186575808495617", 10).unwrap();
@ -19,14 +20,29 @@ pub trait Pow<RHS> {
fn pow(self, RHS) -> Self::Output;
}
pub trait Field : From<i32> + From<u32> + From<usize> + for<'a> From<&'a str>
+ Zero + One + Clone + PartialEq + PartialOrd + Display + Debug
+ Add<Self, Output=Self> + for<'a> Add<&'a Self, Output=Self>
+ Sub<Self, Output=Self> + for<'a> Sub<&'a Self, Output=Self>
+ Mul<Self, Output=Self> + for<'a> Mul<&'a Self, Output=Self>
+ Div<Self, Output=Self> + for<'a> Div<&'a Self, Output=Self>
+ Pow<usize, Output=Self> + Pow<Self, Output=Self> + for<'a> Pow<&'a Self, Output=Self>
{
pub trait Field
: From<i32>
+ From<u32>
+ From<usize>
+ for<'a> From<&'a str>
+ Zero
+ One
+ Clone
+ PartialEq
+ PartialOrd
+ Display
+ Debug
+ Add<Self, Output = Self>
+ for<'a> Add<&'a Self, Output = Self>
+ Sub<Self, Output = Self>
+ for<'a> Sub<&'a Self, Output = Self>
+ Mul<Self, Output = Self>
+ for<'a> Mul<&'a Self, Output = Self>
+ Div<Self, Output = Self>
+ for<'a> Div<&'a Self, Output = Self>
+ Pow<usize, Output = Self>
+ Pow<Self, Output = Self>
+ for<'a> Pow<&'a Self, Output = Self> {
/// Returns this `Field`'s contents as little-endian byte vector
fn into_byte_vector(&self) -> Vec<u8>;
/// Returns the multiplicative inverse, i.e.: self * self.inverse_mul() = Self::one()
@ -39,8 +55,7 @@ pub trait Field : From<i32> + From<u32> + From<usize> + for<'a> From<&'a str>
fn get_required_bits() -> usize;
}
#[derive(PartialEq,PartialOrd,Clone)]
#[derive(Eq,Ord)] // for tests
#[derive(PartialEq, PartialOrd, Clone, Eq, Ord)]
pub struct FieldPrime {
value: BigInt,
}
@ -61,13 +76,19 @@ impl Field for FieldPrime {
fn inverse_mul(&self) -> FieldPrime {
let (b, s, _) = extended_euclid(&self.value, &*P);
assert_eq!(b, BigInt::one());
FieldPrime{ value: &s - s.div_floor(&*P) * &*P }
FieldPrime {
value: &s - s.div_floor(&*P) * &*P,
}
}
fn min_value() -> FieldPrime {
FieldPrime{ value: ToBigInt::to_bigint(&0).unwrap() }
FieldPrime {
value: ToBigInt::to_bigint(&0).unwrap(),
}
}
fn max_value() -> FieldPrime {
FieldPrime{ value: &*P - ToBigInt::to_bigint(&1).unwrap() }
FieldPrime {
value: &*P - ToBigInt::to_bigint(&1).unwrap(),
}
}
fn get_required_bits() -> usize {
(*P).bits()
@ -89,21 +110,27 @@ impl Debug for FieldPrime {
impl From<i32> for FieldPrime {
fn from(num: i32) -> Self {
let x = ToBigInt::to_bigint(&num).unwrap();
FieldPrime{ value: &x - x.div_floor(&*P) * &*P }
FieldPrime {
value: &x - x.div_floor(&*P) * &*P,
}
}
}
impl From<u32> for FieldPrime {
fn from(num: u32) -> Self {
let x = ToBigInt::to_bigint(&num).unwrap();
FieldPrime{ value: &x - x.div_floor(&*P) * &*P }
FieldPrime {
value: &x - x.div_floor(&*P) * &*P,
}
}
}
impl From<usize> for FieldPrime {
fn from(num: usize) -> Self {
let x = ToBigInt::to_bigint(&num).unwrap();
FieldPrime{ value: &x - x.div_floor(&*P) * &*P }
FieldPrime {
value: &x - x.div_floor(&*P) * &*P,
}
}
}
@ -111,15 +138,19 @@ impl<'a> From<&'a str> for FieldPrime {
fn from(s: &'a str) -> Self {
let x = match BigInt::parse_bytes(s.as_bytes(), 10) {
Some(x) => x,
None => panic!("Could not parse {:?} to BigInt!", &s)
None => panic!("Could not parse {:?} to BigInt!", &s),
};
FieldPrime{ value: &x - x.div_floor(&*P) * &*P }
FieldPrime {
value: &x - x.div_floor(&*P) * &*P,
}
}
}
impl Zero for FieldPrime {
fn zero() -> FieldPrime {
FieldPrime{ value: ToBigInt::to_bigint(&0).unwrap() }
FieldPrime {
value: ToBigInt::to_bigint(&0).unwrap(),
}
}
fn is_zero(&self) -> bool {
self.value == ToBigInt::to_bigint(&0).unwrap()
@ -128,7 +159,9 @@ impl Zero for FieldPrime {
impl One for FieldPrime {
fn one() -> FieldPrime {
FieldPrime{ value: ToBigInt::to_bigint(&1).unwrap() }
FieldPrime {
value: ToBigInt::to_bigint(&1).unwrap(),
}
}
}
@ -136,7 +169,9 @@ impl Add<FieldPrime> for FieldPrime {
type Output = FieldPrime;
fn add(self, other: FieldPrime) -> FieldPrime {
FieldPrime{ value: (self.value + other.value) % &*P }
FieldPrime {
value: (self.value + other.value) % &*P,
}
}
}
@ -144,7 +179,9 @@ impl<'a> Add<&'a FieldPrime> for FieldPrime {
type Output = FieldPrime;
fn add(self, other: &FieldPrime) -> FieldPrime {
FieldPrime{ value: (self.value + other.value.clone()) % &*P }
FieldPrime {
value: (self.value + other.value.clone()) % &*P,
}
}
}
@ -153,7 +190,9 @@ impl Sub<FieldPrime> for FieldPrime {
fn sub(self, other: FieldPrime) -> FieldPrime {
let x = self.value - other.value;
FieldPrime{ value: &x - x.div_floor(&*P) * &*P }
FieldPrime {
value: &x - x.div_floor(&*P) * &*P,
}
}
}
@ -162,7 +201,9 @@ impl<'a> Sub<&'a FieldPrime> for FieldPrime {
fn sub(self, other: &FieldPrime) -> FieldPrime {
let x = self.value - other.value.clone();
FieldPrime{ value: &x - x.div_floor(&*P) * &*P }
FieldPrime {
value: &x - x.div_floor(&*P) * &*P,
}
}
}
@ -170,7 +211,9 @@ impl Mul<FieldPrime> for FieldPrime {
type Output = FieldPrime;
fn mul(self, other: FieldPrime) -> FieldPrime {
FieldPrime{ value: (self.value * other.value) % &*P }
FieldPrime {
value: (self.value * other.value) % &*P,
}
}
}
@ -178,7 +221,9 @@ impl<'a> Mul<&'a FieldPrime> for FieldPrime {
type Output = FieldPrime;
fn mul(self, other: &FieldPrime) -> FieldPrime {
FieldPrime{ value: (self.value * other.value.clone()) % &*P }
FieldPrime {
value: (self.value * other.value.clone()) % &*P,
}
}
}
@ -242,6 +287,15 @@ impl<'a> Pow<&'a FieldPrime> for FieldPrime {
}
}
// custom serde serialization
impl Serialize for FieldPrime {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where S: Serializer
{
serializer.serialize_bytes(&(*self.into_byte_vector().as_slice()))
}
}
/// Calculates the gcd using a iterative implementation of the extended euclidian algorithm.
/// Returning `(d, s, t)` so that `d = s * a + t * b`
///
@ -264,7 +318,7 @@ fn extended_euclid(a: &BigInt, b: &BigInt) -> (BigInt, BigInt, BigInt) {
old_t = t.clone();
t = &tmp_t - &quotient * &t;
}
return (old_r, old_s, old_t)
return (old_r, old_s, old_t);
}
#[cfg(test)]
@ -354,11 +408,15 @@ mod tests {
#[test]
fn subtraction_overflow() {
assert_eq!(
"21888242871839275222246405745257275088548364400416034343698204186575743147394".parse::<BigInt>().unwrap(),
"21888242871839275222246405745257275088548364400416034343698204186575743147394"
.parse::<BigInt>()
.unwrap(),
(FieldPrime::from("68135") - FieldPrime::from("65416358")).value
);
assert_eq!(
"21888242871839275222246405745257275088548364400416034343698204186575743147394".parse::<BigInt>().unwrap(),
"21888242871839275222246405745257275088548364400416034343698204186575743147394"
.parse::<BigInt>()
.unwrap(),
(FieldPrime::from("68135") - &FieldPrime::from("65416358")).value
);
}
@ -378,11 +436,15 @@ mod tests {
#[test]
fn multiplication_negative() {
assert_eq!(
"21888242871839275222246405745257275088548364400416034343698204186575808014369".parse::<BigInt>().unwrap(),
"21888242871839275222246405745257275088548364400416034343698204186575808014369"
.parse::<BigInt>()
.unwrap(),
(FieldPrime::from("54") * FieldPrime::from("-8912")).value
);
assert_eq!(
"21888242871839275222246405745257275088548364400416034343698204186575808014369".parse::<BigInt>().unwrap(),
"21888242871839275222246405745257275088548364400416034343698204186575808014369"
.parse::<BigInt>()
.unwrap(),
(FieldPrime::from("54") * &FieldPrime::from("-8912")).value
);
}
@ -402,12 +464,24 @@ mod tests {
#[test]
fn multiplication_overflow() {
assert_eq!(
"6042471409729479866150380306128222617399890671095126975526159292198160466142".parse::<BigInt>().unwrap(),
(FieldPrime::from("21888242871839225222246405785257275088694311157297823662689037894645225727") * FieldPrime::from("218882428715392752222464057432572755886923")).value
"6042471409729479866150380306128222617399890671095126975526159292198160466142"
.parse::<BigInt>()
.unwrap(),
(FieldPrime::from(
"21888242871839225222246405785257275088694311157297823662689037894645225727"
) *
FieldPrime::from("218882428715392752222464057432572755886923"))
.value
);
assert_eq!(
"6042471409729479866150380306128222617399890671095126975526159292198160466142".parse::<BigInt>().unwrap(),
(FieldPrime::from("21888242871839225222246405785257275088694311157297823662689037894645225727") * &FieldPrime::from("218882428715392752222464057432572755886923")).value
"6042471409729479866150380306128222617399890671095126975526159292198160466142"
.parse::<BigInt>()
.unwrap(),
(FieldPrime::from(
"21888242871839225222246405785257275088694311157297823662689037894645225727"
) *
&FieldPrime::from("218882428715392752222464057432572755886923"))
.value
);
}
@ -470,11 +544,15 @@ mod tests {
#[test]
fn pow_negative() {
assert_eq!(
"21888242871839275222246405745257275088548364400416034343686819230535502784513".parse::<BigInt>().unwrap(),
"21888242871839275222246405745257275088548364400416034343686819230535502784513"
.parse::<BigInt>()
.unwrap(),
(FieldPrime::from("-54").pow(FieldPrime::from("11"))).value
);
assert_eq!(
"21888242871839275222246405745257275088548364400416034343686819230535502784513".parse::<BigInt>().unwrap(),
"21888242871839275222246405745257275088548364400416034343686819230535502784513"
.parse::<BigInt>()
.unwrap(),
(FieldPrime::from("-54").pow(&FieldPrime::from("11"))).value
);
}
@ -484,29 +562,64 @@ mod tests {
fn bigint_assertions() {
let x = BigInt::parse_bytes(b"65", 10).unwrap();
assert_eq!(&x + &x, BigInt::parse_bytes(b"130", 10).unwrap());
assert_eq!("1".parse::<BigInt>().unwrap(), "3".parse::<BigInt>().unwrap().div_floor(&"2".parse::<BigInt>().unwrap()));
assert_eq!("-2".parse::<BigInt>().unwrap(), "-3".parse::<BigInt>().unwrap().div_floor(&"2".parse::<BigInt>().unwrap()));
assert_eq!(
"1".parse::<BigInt>().unwrap(),
"3".parse::<BigInt>()
.unwrap()
.div_floor(&"2".parse::<BigInt>().unwrap())
);
assert_eq!(
"-2".parse::<BigInt>().unwrap(),
"-3".parse::<BigInt>()
.unwrap()
.div_floor(&"2".parse::<BigInt>().unwrap())
);
}
#[test]
fn test_extended_euclid() {
assert_eq!(
(ToBigInt::to_bigint(&1).unwrap(), ToBigInt::to_bigint(&-9).unwrap(), ToBigInt::to_bigint(&47).unwrap()),
extended_euclid(&ToBigInt::to_bigint(&120).unwrap(), &ToBigInt::to_bigint(&23).unwrap())
(
ToBigInt::to_bigint(&1).unwrap(),
ToBigInt::to_bigint(&-9).unwrap(),
ToBigInt::to_bigint(&47).unwrap()
),
extended_euclid(
&ToBigInt::to_bigint(&120).unwrap(),
&ToBigInt::to_bigint(&23).unwrap()
)
);
assert_eq!(
(ToBigInt::to_bigint(&2).unwrap(), ToBigInt::to_bigint(&2).unwrap(), ToBigInt::to_bigint(&-11).unwrap()),
extended_euclid(&ToBigInt::to_bigint(&122).unwrap(), &ToBigInt::to_bigint(&22).unwrap())
(
ToBigInt::to_bigint(&2).unwrap(),
ToBigInt::to_bigint(&2).unwrap(),
ToBigInt::to_bigint(&-11).unwrap()
),
extended_euclid(
&ToBigInt::to_bigint(&122).unwrap(),
&ToBigInt::to_bigint(&22).unwrap()
)
);
assert_eq!(
(ToBigInt::to_bigint(&2).unwrap(), ToBigInt::to_bigint(&-9).unwrap(), ToBigInt::to_bigint(&47).unwrap()),
extended_euclid(&ToBigInt::to_bigint(&240).unwrap(), &ToBigInt::to_bigint(&46).unwrap())
(
ToBigInt::to_bigint(&2).unwrap(),
ToBigInt::to_bigint(&-9).unwrap(),
ToBigInt::to_bigint(&47).unwrap()
),
extended_euclid(
&ToBigInt::to_bigint(&240).unwrap(),
&ToBigInt::to_bigint(&46).unwrap()
)
);
let (b, s, _) = extended_euclid(&ToBigInt::to_bigint(&253).unwrap(), &*P);
assert_eq!(b, BigInt::one());
let s_field = FieldPrime{ value: &s - s.div_floor(&*P) * &*P };
let s_field = FieldPrime {
value: &s - s.div_floor(&*P) * &*P,
};
assert_eq!(
FieldPrime::from("12717674712096337777352654721552646000065650461901806515903699665717959876900"),
FieldPrime::from(
"12717674712096337777352654721552646000065650461901806515903699665717959876900"
),
s_field
);
}

View file

@ -5,7 +5,7 @@
//! @author Jacob Eberhardt <jacob.eberhardt@tu-berlin.de>
//! @date 2017
use std::collections::{HashSet, HashMap};
use std::collections::{HashMap, HashSet};
use absy::*;
use absy::Expression::*;
use field::Field;
@ -32,7 +32,7 @@ impl Flattener {
bits: bits,
variables: HashSet::new(),
substitution: HashMap::new(),
next_var_idx: 0
next_var_idx: 0,
}
}
@ -44,18 +44,36 @@ impl Flattener {
///
/// * `statements_flattened` - Vector where new flattened statements can be added.
/// * `condition` - `Condition` that will be flattened.
fn flatten_condition<T: Field>(&mut self, functions_flattened: &Vec<Function<T>>, arguments_flattened: &Vec<Parameter>, statements_flattened: &mut Vec<Statement<T>>, condition: Condition<T>) -> (Expression<T>, Expression<T>) {
fn flatten_condition<T: Field>(
&mut self,
functions_flattened: &Vec<Function<T>>,
arguments_flattened: &Vec<Parameter>,
statements_flattened: &mut Vec<Statement<T>>,
condition: Condition<T>,
) -> (Expression<T>, Expression<T>) {
match condition {
Condition::Lt(lhs, rhs) => {
let lhs_flattened = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, lhs);
let rhs_flattened = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, rhs);
let lhs_flattened = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
lhs,
);
let rhs_flattened = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
rhs,
);
let lhs_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(lhs_name.to_string(), lhs_flattened));
statements_flattened
.push(Statement::Definition(lhs_name.to_string(), lhs_flattened));
let rhs_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(rhs_name.to_string(), rhs_flattened));
statements_flattened
.push(Statement::Definition(rhs_name.to_string(), rhs_flattened));
let subtraction_result = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
@ -63,39 +81,39 @@ impl Flattener {
subtraction_result.to_string(),
Sub(
box Mult(box Number(T::from(2)), box Identifier(lhs_name.to_string())),
box Mult(box Number(T::from(2)), box Identifier(rhs_name.to_string()))
)
box Mult(box Number(T::from(2)), box Identifier(rhs_name.to_string())),
),
));
for i in 0..self.bits-2 {
for i in 0..self.bits - 2 {
let new_name = format!("{}_b{}", &subtraction_result, i);
statements_flattened.push(Statement::Definition(
new_name.to_string(),
Mult(
box Identifier(new_name.to_string()),
box Identifier(new_name.to_string())
)
box Identifier(new_name.to_string()),
),
));
}
let mut expr = Add(
box Identifier(format!("{}_b0", &subtraction_result)), // * 2^0
box Mult(
box Identifier(format!("{}_b1", &subtraction_result)),
box Number(T::from(2))
)
box Number(T::from(2)),
),
);
for i in 1..self.bits/2 {
for i in 1..self.bits / 2 {
expr = Add(
box expr,
box Add(
box Mult(
box Identifier(format!("{}_b{}", &subtraction_result, 2*i)),
box Number(T::from(2).pow(2*i))
box Identifier(format!("{}_b{}", &subtraction_result, 2 * i)),
box Number(T::from(2).pow(2 * i)),
),
box Mult(
box Identifier(format!("{}_b{}", &subtraction_result, 2*i+1)),
box Number(T::from(2).pow(2*i + 1))
box Identifier(format!("{}_b{}", &subtraction_result, 2 * i + 1)),
box Number(T::from(2).pow(2 * i + 1)),
),
)
),
);
}
if self.bits % 2 == 1 {
@ -103,18 +121,22 @@ impl Flattener {
box expr,
box Mult(
box Identifier(format!("{}_b{}", &subtraction_result, self.bits - 3)),
box Number(T::from(2).pow(self.bits - 1))
)
box Number(T::from(2).pow(self.bits - 1)),
),
)
}
statements_flattened.push(Statement::Definition(subtraction_result.to_string(), expr));
statements_flattened
.push(Statement::Definition(subtraction_result.to_string(), expr));
let cond_true = format!("{}_b0", &subtraction_result);
let cond_false = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(cond_false.to_string(), Sub(box Number(T::one()), box Identifier(cond_true.to_string()))));
statements_flattened.push(Statement::Definition(
cond_false.to_string(),
Sub(box Number(T::one()), box Identifier(cond_true.to_string())),
));
(Identifier(cond_true), Identifier(cond_false))
},
}
Condition::Eq(lhs, rhs) => {
// Wanted: (Y = (X != 0) ? 1 : 0)
// X = a - b
@ -131,30 +153,44 @@ impl Flattener {
let name_1_y = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
let x = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, Sub(box lhs, box rhs));
let x = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
Sub(box lhs, box rhs),
);
statements_flattened.push(Statement::Definition(name_x.to_string(), x));
statements_flattened.push(Statement::Compiler(name_y.to_string(), IfElse(
box Condition::Eq(
Identifier(name_x.to_string()),
Number(T::zero())
statements_flattened.push(Statement::Compiler(
name_y.to_string(),
IfElse(
box Condition::Eq(Identifier(name_x.to_string()), Number(T::zero())),
box Number(T::zero()),
box Number(T::one()),
),
box Number(T::zero()),
box Number(T::one())
)));
statements_flattened.push(Statement::Compiler(name_m.to_string(), IfElse(
box Condition::Eq(
Identifier(name_x.to_string()),
Number(T::zero())
));
statements_flattened.push(Statement::Compiler(
name_m.to_string(),
IfElse(
box Condition::Eq(Identifier(name_x.to_string()), Number(T::zero())),
box Number(T::one()),
box Div(box Number(T::one()), box Identifier(name_x.to_string())),
),
box Number(T::one()),
box Div(box Number(T::one()), box Identifier(name_x.to_string()))
)));
statements_flattened.push(Statement::Condition(Identifier(name_y.to_string()), Mult(box Identifier(name_x.to_string()), box Identifier(name_m))));
statements_flattened.push(Statement::Definition(name_1_y.to_string(), Sub(box Number(T::one()), box Identifier(name_y.to_string()))));
statements_flattened.push(Statement::Condition(Number(T::zero()), Mult(box Identifier(name_1_y.to_string()), box Identifier(name_x))));
));
statements_flattened.push(Statement::Condition(
Identifier(name_y.to_string()),
Mult(box Identifier(name_x.to_string()), box Identifier(name_m)),
));
statements_flattened.push(Statement::Definition(
name_1_y.to_string(),
Sub(box Number(T::one()), box Identifier(name_y.to_string())),
));
statements_flattened.push(Statement::Condition(
Number(T::zero()),
Mult(box Identifier(name_1_y.to_string()), box Identifier(name_x)),
));
(Identifier(name_1_y), Identifier(name_y))
},
}
_ => unimplemented!(),
}
}
@ -166,23 +202,40 @@ impl Flattener {
/// * `functions_flattened` - Vector containing already flattened functions.
/// * `statements_flattened` - Vector where new flattened statements can be added.
/// * `expr` - `Expresstion` that will be flattened.
fn flatten_expression<T: Field>(&mut self, functions_flattened: &Vec<Function<T>>, arguments_flattened: &Vec<Parameter>, statements_flattened: &mut Vec<Statement<T>>, expr: Expression<T>) -> Expression<T> {
fn flatten_expression<T: Field>(
&mut self,
functions_flattened: &Vec<Function<T>>,
arguments_flattened: &Vec<Parameter>,
statements_flattened: &mut Vec<Statement<T>>,
expr: Expression<T>,
) -> Expression<T> {
match expr {
x @ Number(_) |
x @ Identifier(_) => x,
ref x @ Add(..) |
ref x @ Sub(..) |
ref x @ Mult(..) |
ref x @ Div(..) if x.is_flattened() => x.clone(),
x @ Number(_) | x @ Identifier(_) => x,
ref x @ Add(..) | ref x @ Sub(..) | ref x @ Mult(..) | ref x @ Div(..)
if x.is_flattened() =>
{
x.clone()
}
Add(box left, box right) => {
let left_flattened = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, left);
let right_flattened = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, right);
let left_flattened = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
left,
);
let right_flattened = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
right,
);
let new_left = if left_flattened.is_linear() {
left_flattened
} else {
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), left_flattened));
statements_flattened
.push(Statement::Definition(new_name.to_string(), left_flattened));
Identifier(new_name)
};
let new_right = if right_flattened.is_linear() {
@ -190,20 +243,32 @@ impl Flattener {
} else {
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), right_flattened));
statements_flattened
.push(Statement::Definition(new_name.to_string(), right_flattened));
Identifier(new_name)
};
Add(box new_left, box new_right)
},
}
Sub(box left, box right) => {
let left_flattened = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, left);
let right_flattened = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, right);
let left_flattened = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
left,
);
let right_flattened = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
right,
);
let new_left = if left_flattened.is_linear() {
left_flattened
} else {
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), left_flattened));
statements_flattened
.push(Statement::Definition(new_name.to_string(), left_flattened));
Identifier(new_name)
};
let new_right = if right_flattened.is_linear() {
@ -211,19 +276,31 @@ impl Flattener {
} else {
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), right_flattened));
statements_flattened
.push(Statement::Definition(new_name.to_string(), right_flattened));
Identifier(new_name)
};
Sub(box new_left, box new_right)
},
}
Mult(box left, box right) => {
let left_flattened = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, left);
let right_flattened = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, right);
let left_flattened = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
left,
);
let right_flattened = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
right,
);
let new_left = if left_flattened.is_linear() {
if let Sub(..) = left_flattened {
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), left_flattened));
statements_flattened
.push(Statement::Definition(new_name.to_string(), left_flattened));
Identifier(new_name)
} else {
left_flattened
@ -231,14 +308,16 @@ impl Flattener {
} else {
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), left_flattened));
statements_flattened
.push(Statement::Definition(new_name.to_string(), left_flattened));
Identifier(new_name)
};
let new_right = if right_flattened.is_linear() {
if let Sub(..) = right_flattened {
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), right_flattened));
statements_flattened
.push(Statement::Definition(new_name.to_string(), right_flattened));
Identifier(new_name)
} else {
right_flattened
@ -246,20 +325,32 @@ impl Flattener {
} else {
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), right_flattened));
statements_flattened
.push(Statement::Definition(new_name.to_string(), right_flattened));
Identifier(new_name)
};
Mult(box new_left, box new_right)
},
}
Div(box left, box right) => {
let left_flattened = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, left);
let right_flattened = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, right);
let left_flattened = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
left,
);
let right_flattened = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
right,
);
let new_left = if left_flattened.is_linear() {
left_flattened
} else {
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), left_flattened));
statements_flattened
.push(Statement::Definition(new_name.to_string(), left_flattened));
Identifier(new_name)
};
let new_right = if right_flattened.is_linear() {
@ -267,51 +358,54 @@ impl Flattener {
} else {
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), right_flattened));
statements_flattened
.push(Statement::Definition(new_name.to_string(), right_flattened));
Identifier(new_name)
};
Div(box new_left, box new_right)
},
}
Pow(base, exponent) => {
// TODO currently assuming that base is number or variable
match exponent {
box Number(ref x) if x > &T::one() => {
match base {
box Identifier(ref var) => {
let id = if x > &T::from(2) {
let tmp_expression = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
Pow(
box Identifier(var.to_string()),
box Number(x.clone() - T::one())
)
);
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(Statement::Definition(new_name.to_string(), tmp_expression));
new_name
} else {
var.to_string()
};
Mult(
box Identifier(id.to_string()),
box Identifier(var.to_string())
)
},
box Number(var) => Mult(
box Number(var.clone()),
box Number(var)
),
_ => panic!("Only variables and numbers allowed in pow base")
box Number(ref x) if x > &T::one() => match base {
box Identifier(ref var) => {
let id = if x > &T::from(2) {
let tmp_expression = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
Pow(
box Identifier(var.to_string()),
box Number(x.clone() - T::one()),
),
);
let new_name = format!("sym_{}", self.next_var_idx);
self.next_var_idx += 1;
statements_flattened.push(
Statement::Definition(new_name.to_string(), tmp_expression),
);
new_name
} else {
var.to_string()
};
Mult(
box Identifier(id.to_string()),
box Identifier(var.to_string()),
)
}
}
box Number(var) => Mult(box Number(var.clone()), box Number(var)),
_ => panic!("Only variables and numbers allowed in pow base"),
},
_ => panic!("Expected number > 1 as pow exponent"),
}
},
}
IfElse(box condition, consequent, alternative) => {
let (cond_true, cond_false) = self.flatten_condition(functions_flattened, arguments_flattened, statements_flattened, condition);
let (cond_true, cond_false) = self.flatten_condition(
functions_flattened,
arguments_flattened,
statements_flattened,
condition,
);
// (condition_true * consequent) + (condition_false * alternatuve)
self.flatten_expression(
functions_flattened,
@ -319,23 +413,33 @@ impl Flattener {
statements_flattened,
Add(
box Mult(box cond_true, consequent),
box Mult(box cond_false, alternative)
)
box Mult(box cond_false, alternative),
),
)
},
}
FunctionCall(ref id, ref param_expressions) => {
// Replace complex expressions with definitions in parameters
let mut params_flattened: Vec<Parameter> = Vec::new();
for (i,param_expr) in param_expressions.iter().enumerate(){
match param_expr.apply_substitution(&self.substitution){
Expression::Identifier(ref x) =>{params_flattened.push(Parameter{id:x.clone().to_string()})},
for (i, param_expr) in param_expressions.iter().enumerate() {
match param_expr.apply_substitution(&self.substitution) {
Expression::Identifier(ref x) => params_flattened.push(Parameter {
id: x.clone().to_string(),
}),
_ => {
let expr_subbed = param_expr.apply_substitution(&self.substitution);
let rhs = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, expr_subbed);
let intermediate_var = self.use_variable(&format!("{}_param_{}",&id,i));
statements_flattened.push(Statement::Definition(intermediate_var.clone(), rhs));
params_flattened.push(Parameter{id:intermediate_var.clone().to_string()});
let rhs = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
expr_subbed,
);
let intermediate_var =
self.use_variable(&format!("{}_param_{}", &id, i));
statements_flattened
.push(Statement::Definition(intermediate_var.clone(), rhs));
params_flattened.push(Parameter {
id: intermediate_var.clone().to_string(),
});
}
}
}
@ -344,15 +448,16 @@ impl Flattener {
for funct in functions_flattened {
if funct.id == *id && funct.arguments.len() == (*param_expressions).len() {
// add temporary substitution for the parameters
let mut temp_substitution: HashMap<String, String> = HashMap::new(); // substitutions for parameters are only valid during the function call's processing
println!("Called Function's Arguments: {:?}",funct.arguments);
println!("Calling Function's Arguments: {:?}",params_flattened);
for (i,_) in params_flattened.iter().enumerate(){
let identifier_call: String = params_flattened.get(i).unwrap().id.clone();
let identifier_called: String = funct.arguments.get(i).unwrap().id.clone();
println!("Called Function's Arguments: {:?}", funct.arguments);
println!("Calling Function's Arguments: {:?}", params_flattened);
for (i, _) in params_flattened.iter().enumerate() {
let identifier_call: String =
params_flattened.get(i).unwrap().id.clone();
let identifier_called: String =
funct.arguments.get(i).unwrap().id.clone();
temp_substitution.insert(identifier_called, identifier_call);
}
println!("Param substitutions: {:?}", temp_substitution);
@ -364,66 +469,118 @@ impl Flattener {
match stat {
// set return statements right side as expression result
Statement::Return(x) => {
let result = x.apply_substitution(&temp_substitution).apply_substitution(&self.substitution);
let result = x.apply_substitution(&temp_substitution)
.apply_substitution(&self.substitution);
return result;
},
}
Statement::Definition(var, rhs) => {
let new_rhs = rhs.apply_substitution(&temp_substitution).apply_substitution(&self.substitution);
statements_flattened.push(Statement::Definition(self.use_variable(&var), new_rhs));
},
let new_rhs = rhs.apply_substitution(&temp_substitution)
.apply_substitution(&self.substitution);
statements_flattened.push(
Statement::Definition(self.use_variable(&var), new_rhs),
);
}
Statement::Compiler(var, rhs) => {
let new_rhs = rhs.apply_substitution(&temp_substitution).apply_substitution(&self.substitution);
let new_rhs = rhs.apply_substitution(&temp_substitution)
.apply_substitution(&self.substitution);
statements_flattened.push(Statement::Compiler(self.use_variable(&var), new_rhs));
},
}
Statement::Condition(lhs, rhs) => {
let new_lhs = lhs.apply_substitution(&temp_substitution).apply_substitution(&self.substitution);
let new_rhs = rhs.apply_substitution(&temp_substitution).apply_substitution(&self.substitution);
statements_flattened.push(Statement::Condition(new_lhs, new_rhs));
},
let new_lhs = lhs.apply_substitution(&temp_substitution)
.apply_substitution(&self.substitution);
let new_rhs = rhs.apply_substitution(&temp_substitution)
.apply_substitution(&self.substitution);
statements_flattened
.push(Statement::Condition(new_lhs, new_rhs));
}
Statement::For(..) => panic!("Not flattened!"),
}
}
}
}
panic!("Function definition for function {} with {:?} argument(s) not found.",id , param_expressions);
},
panic!(
"Function definition for function {} with {:?} argument(s) not found.",
id,
param_expressions
);
}
}
}
pub fn flatten_statement<T: Field>(&mut self, functions_flattened: &mut Vec<Function<T>>, arguments_flattened: &Vec<Parameter>, statements_flattened: &mut Vec<Statement<T>>, stat: &Statement<T>) {
pub fn flatten_statement<T: Field>(
&mut self,
functions_flattened: &mut Vec<Function<T>>,
arguments_flattened: &Vec<Parameter>,
statements_flattened: &mut Vec<Statement<T>>,
stat: &Statement<T>,
) {
match *stat {
Statement::Return(ref expr) => {
let expr_subbed = expr.apply_substitution(&self.substitution);
let rhs = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, expr_subbed);
let rhs = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
expr_subbed,
);
statements_flattened.push(Statement::Return(rhs));
},
}
Statement::Definition(ref id, ref expr) => {
let expr_subbed = expr.apply_substitution(&self.substitution);
let rhs = self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, expr_subbed);
let rhs = self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
expr_subbed,
);
statements_flattened.push(Statement::Definition(self.use_variable(&id), rhs));
},
}
Statement::Condition(ref expr1, ref expr2) => {
let expr1_subbed = expr1.apply_substitution(&self.substitution);
let expr2_subbed = expr2.apply_substitution(&self.substitution);
let (lhs, rhs) = if expr1_subbed.is_linear() {
(expr1_subbed, self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, expr2_subbed))
(
expr1_subbed,
self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
expr2_subbed,
),
)
} else if expr2_subbed.is_linear() {
(expr2_subbed, self.flatten_expression(functions_flattened, arguments_flattened, statements_flattened, expr1_subbed))
(
expr2_subbed,
self.flatten_expression(
functions_flattened,
arguments_flattened,
statements_flattened,
expr1_subbed,
),
)
} else {
unimplemented!()
};
statements_flattened.push(Statement::Condition(lhs, rhs));
},
}
Statement::For(ref var, ref start, ref end, ref statements) => {
let mut current = start.clone();
while &current < end {
statements_flattened.push(Statement::Definition(self.use_variable(&var), Expression::Number(current.clone())));
statements_flattened.push(Statement::Definition(
self.use_variable(&var),
Expression::Number(current.clone()),
));
for s in statements {
self.flatten_statement(functions_flattened, arguments_flattened, statements_flattened, s);
self.flatten_statement(
functions_flattened,
arguments_flattened,
statements_flattened,
s,
);
}
current = T::one() + &current;
}
},
}
ref s @ Statement::Compiler(..) => statements_flattened.push(s.clone()),
}
}
@ -434,18 +591,33 @@ impl Flattener {
///
/// * `functions_flattened` - Vector where new flattened functions can be added.
/// * `funct` - `Function` that will be flattened.
pub fn flatten_function<T: Field>(&mut self, functions_flattened: &mut Vec<Function<T>>, funct: Function<T>) -> Function<T> {
pub fn flatten_function<T: Field>(
&mut self,
functions_flattened: &mut Vec<Function<T>>,
funct: Function<T>,
) -> Function<T> {
let mut arguments_flattened: Vec<Parameter> = Vec::new();
let mut statements_flattened: Vec<Statement<T>> = Vec::new();
// flatten parameters (substitute name to guarantee global uniqueness)
for arg in funct.arguments {
arguments_flattened.push(Parameter{id:self.use_variable(&arg.id)});
arguments_flattened.push(Parameter {
id: self.use_variable(&arg.id),
});
}
// flatten statements in functions and apply substitution
for stat in funct.statements {
self.flatten_statement(functions_flattened, &arguments_flattened, &mut statements_flattened, &stat);
self.flatten_statement(
functions_flattened,
&arguments_flattened,
&mut statements_flattened,
&stat,
);
}
Function {
id: funct.id,
arguments: arguments_flattened,
statements: statements_flattened,
}
Function { id: funct.id, arguments: arguments_flattened, statements: statements_flattened }
}
/// Returns a flattened `Prog`ram based on the given `prog`.
@ -458,11 +630,13 @@ impl Flattener {
self.variables = HashSet::new();
self.substitution = HashMap::new();
self.next_var_idx = 0;
for func in prog.functions{
for func in prog.functions {
let flattened_func = self.flatten_function(&mut functions_flattened, func);
functions_flattened.push(flattened_func);
}
Prog { functions: functions_flattened}
Prog {
functions: functions_flattened,
}
}
@ -480,13 +654,14 @@ impl Flattener {
} else {
self.variables.insert(new_name.to_string());
if i == 1 {
self.substitution.insert(name.to_string(), new_name.to_string());
self.substitution
.insert(name.to_string(), new_name.to_string());
} else if i > 1 {
self.substitution.insert(format!("{}_{}", name, i - 2), new_name.to_string());
self.substitution
.insert(format!("{}_{}", name, i - 2), new_name.to_string());
}
return new_name;
}
}
}
}

View file

@ -13,20 +13,35 @@ use field::Field;
#[link(name = "supercop")]
#[link(name = "gmp")]
#[link(name = "gmpxx")]
extern {
fn _run_libsnark(A: *const uint8_t, B: *const uint8_t, C: *const uint8_t, witness: *const uint8_t, constraints: c_int, variables: c_int, inputs: c_int) -> bool;
extern "C" {
fn _run_libsnark(
A: *const uint8_t,
B: *const uint8_t,
C: *const uint8_t,
witness: *const uint8_t,
constraints: c_int,
variables: c_int,
inputs: c_int,
) -> bool;
}
// assumes that field elements can be represented with 32 bytes
pub fn run_libsnark<T: Field>(variables: Vec<String>, a: Vec<Vec<(usize, T)>>, b: Vec<Vec<(usize, T)>>, c: Vec<Vec<(usize, T)>>, witness: Vec<T>, num_inputs: usize) -> bool {
pub fn run_libsnark<T: Field>(
variables: Vec<String>,
a: Vec<Vec<(usize, T)>>,
b: Vec<Vec<(usize, T)>>,
c: Vec<Vec<(usize, T)>>,
witness: Vec<T>,
num_inputs: usize,
) -> bool {
let num_constraints = a.len();
let num_variables = variables.len();
//initialize matrix entries with 0s.
let mut a_arr: Vec<[u8;32]> = vec![[0u8;32]; num_constraints * num_variables];
let mut b_arr: Vec<[u8;32]> = vec![[0u8;32]; num_constraints * num_variables];
let mut c_arr: Vec<[u8;32]> = vec![[0u8;32]; num_constraints * num_variables];
let mut w_arr: Vec<[u8;32]> = vec![[0u8;32]; num_variables];
let mut a_arr: Vec<[u8; 32]> = vec![[0u8; 32]; num_constraints * num_variables];
let mut b_arr: Vec<[u8; 32]> = vec![[0u8; 32]; num_constraints * num_variables];
let mut c_arr: Vec<[u8; 32]> = vec![[0u8; 32]; num_constraints * num_variables];
let mut w_arr: Vec<[u8; 32]> = vec![[0u8; 32]; num_variables];
for row in 0..num_constraints {
for &(idx, ref val) in &a[row] {
@ -41,7 +56,7 @@ pub fn run_libsnark<T: Field>(variables: Vec<String>, a: Vec<Vec<(usize, T)>>, b
}
//convert witness
for (index,value) in witness.into_iter().enumerate() {
for (index, value) in witness.into_iter().enumerate() {
w_arr[index] = vec_as_u8_32_array(&value.into_byte_vector());
}
@ -53,16 +68,24 @@ pub fn run_libsnark<T: Field>(variables: Vec<String>, a: Vec<Vec<(usize, T)>>, b
//println!("w_arr {:?}", w_arr);
unsafe {
_run_libsnark(a_arr[0].as_ptr(),b_arr[0].as_ptr(), c_arr[0].as_ptr(), w_arr[0].as_ptr(), num_constraints as i32, num_variables as i32, num_inputs as i32)
_run_libsnark(
a_arr[0].as_ptr(),
b_arr[0].as_ptr(),
c_arr[0].as_ptr(),
w_arr[0].as_ptr(),
num_constraints as i32,
num_variables as i32,
num_inputs as i32,
)
}
}
// utility function. Converts a Fields vector-based byte representation to fixed size array.
fn vec_as_u8_32_array(vec: &Vec<u8>) -> [u8;32]{
assert!(vec.len()<=32);
let mut array = [0u8;32];
for (index,byte) in vec.iter().enumerate() {
array[31-index] = *byte;
fn vec_as_u8_32_array(vec: &Vec<u8>) -> [u8; 32] {
assert!(vec.len() <= 32);
let mut array = [0u8; 32];
for (index, byte) in vec.iter().enumerate() {
array[31 - index] = *byte;
}
array
}
@ -71,7 +94,7 @@ fn vec_as_u8_32_array(vec: &Vec<u8>) -> [u8;32]{
mod tests {
use super::*;
use field::FieldPrime;
use num::bigint::{BigUint};
use num::bigint::BigUint;
#[cfg(test)]
mod libsnark_integration {
@ -80,13 +103,19 @@ mod tests {
#[test]
fn serialization_dec() {
assert_eq!(
BigUint::parse_bytes(b"5472060717959818805561601436314318772174077789324455915672259473661306552146",10).unwrap().to_bytes_le(),
FieldPrime::from("5472060717959818805561601436314318772174077789324455915672259473661306552146").into_byte_vector()
BigUint::parse_bytes(
b"5472060717959818805561601436314318772174077789324455915672259473661306552146",
10
).unwrap()
.to_bytes_le(),
FieldPrime::from(
"5472060717959818805561601436314318772174077789324455915672259473661306552146"
).into_byte_vector()
);
}
#[test]
fn serialization_bin() {
fn serialization_bin() {
assert_eq!(
BigUint::parse_bytes(b"110000011001000100111001110010111000010011000110100000001010011011100001010000010001011011011010000001100000010101100001011101100101111000000101101010100100010110100001110001110010101000110100111100001000001000110000010110110110000111110011111101010010",2).unwrap().to_bytes_le(),
FieldPrime::from("5472060717959818805561601436314318772174077789324455915672259473661306552146").into_byte_vector()
@ -95,10 +124,12 @@ mod tests {
#[test]
fn vec_to_array() {
let byte_vector: Vec<u8> = FieldPrime::from("5472060717959818805561601436314318772174077789324455915672259473661306552146").into_byte_vector();
let array: [u8;32] = vec_as_u8_32_array(&byte_vector);
for (index, value) in byte_vector.iter().enumerate(){
assert_eq!( *value, array[31-index]);
let byte_vector: Vec<u8> = FieldPrime::from(
"5472060717959818805561601436314318772174077789324455915672259473661306552146",
).into_byte_vector();
let array: [u8; 32] = vec_as_u8_32_array(&byte_vector);
for (index, value) in byte_vector.iter().enumerate() {
assert_eq!(*value, array[31 - index]);
}
}

View file

@ -6,32 +6,38 @@
#![feature(box_patterns, box_syntax)]
extern crate clap;
#[macro_use]
extern crate lazy_static;
extern crate num;
extern crate clap; // cli
extern crate num; // cli
extern crate serde; // serialization deserialization
#[macro_use]
extern crate serde_derive;
extern crate bincode;
mod absy;
mod parser;
mod flatten;
mod r1cs;
mod field;
#[cfg(not(feature="nolibsnark"))]
#[cfg(not(feature = "nolibsnark"))]
mod libsnark;
use std::fs::File;
use std::path::Path;
use std::io::{Write, BufWriter};
use std::io::{BufWriter, Write};
use field::{Field, FieldPrime};
use absy::Prog;
use parser::parse_program;
use flatten::Flattener;
use r1cs::r1cs_program;
use clap::{Arg, App, AppSettings, SubCommand};
#[cfg(not(feature="nolibsnark"))]
use clap::{App, AppSettings, Arg, SubCommand};
#[cfg(not(feature = "nolibsnark"))]
use libsnark::run_libsnark;
use bincode::{serialize, deserialize, Infinite};
fn main() {
const FLATTENED_CODE_DEFAULT_PATH: &str = "out";
// cli specification using clap library
let matches = App::new("zkc")
@ -40,18 +46,22 @@ fn main() {
.author("Jacob Eberhardt, Dennis Kuhnert")
.about("Supports generation of zkSNARKs from high level language code including Smart Contracts for proof verification on the Ethereum Blockchain.")
.subcommand(SubCommand::with_name("compile")
.about("Compiles into flattened conditions.")
.about("Compiles into flattened conditions. Produces two files: human-readable '.code' file and binary file")
.arg(Arg::with_name("input")
.short("i")
.long("input")
.help("path of source code file to compile.")
.value_name("FILE")
.takes_value(true)
.required(true)
).arg(Arg::with_name("output")
.short("o")
.long("output")
.help("output file path.")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value("out.code")
.default_value(FLATTENED_CODE_DEFAULT_PATH)
)
)
.subcommand(SubCommand::with_name("setup")
@ -59,7 +69,23 @@ fn main() {
.subcommand(SubCommand::with_name("export-verifier")
.about("Exports a verifier as Solidity smart contract."))
.subcommand(SubCommand::with_name("compute-witness")
.about("Calculates a witness for a given constraint system, i.e., a variable assignment which satisfies all constraints. Interactive if underspecified."))
.about("Calculates a witness for a given constraint system, i.e., a variable assignment which satisfies all constraints. Interactive if arguments underspecified.")
.arg(Arg::with_name("input")
.short("i")
.long("input")
.help("path of comiled code.")
.value_name("FILE")
.takes_value(true)
.required(false)
.default_value(FLATTENED_CODE_DEFAULT_PATH)
).arg(Arg::with_name("arguments")
.short("a")
.long("arguments")
.help("Arguments for the program's main method. Space or comma separated list.")
.takes_value(true)
.multiple(true) // allows multiple values
.required(false)
))
.subcommand(SubCommand::with_name("generate-proof")
.about("Calculates a proof for a given constraint system and witness."))
.subcommand(SubCommand::with_name("deploy-verifier")
@ -69,8 +95,7 @@ fn main() {
//println!("matches: {:?}", matches);
match matches.subcommand() {
("compile", Some(sub_matches)) =>{
("compile", Some(sub_matches)) => {
println!("Compiling {}", sub_matches.value_of("input").unwrap());
let path = Path::new(sub_matches.value_of("input").unwrap());
@ -84,47 +109,102 @@ fn main() {
Err(why) => {
println!("{:?}", why);
std::process::exit(1);
},
}
};
// debugging output
println!("uncompiled program:\n{}", program_ast);
// flatten input program
let program_flattened =
Flattener::new(FieldPrime::get_required_bits()).flatten_program(program_ast);
let program_flattened = Flattener::new(FieldPrime::get_required_bits()).flatten_program(program_ast);
let output_path = Path::new(sub_matches.value_of("output").unwrap());
let mut output_file = match File::create(&output_path) {
// serialize flattened program and write to binary file
let bin_output_path = Path::new(sub_matches.value_of("output").unwrap());
let mut bin_output_file = match File::create(&bin_output_path) {
Ok(file) => file,
Err(why) => panic!("couldn't create {}: {}", output_path.display(), why),
Err(why) => panic!("couldn't create {}: {}", bin_output_path.display(), why),
};
let mut ofb = BufWriter::new(output_file);
write!(&mut ofb, "{}\n", program_flattened).expect("Unable to write data to file.");
ofb.flush();
let encoded: Vec<u8> = serialize(&program_flattened, Infinite).unwrap();
println!("Compiled code written to {}", sub_matches.value_of("output").unwrap());
// write human-readable output file
let hr_output_path = bin_output_path.to_path_buf().with_extension("code");
let mut hr_output_file = match File::create(&hr_output_path) {
Ok(file) => file,
Err(why) => panic!("couldn't create {}: {}", hr_output_path.display(), why),
};
let mut hrofb = BufWriter::new(hr_output_file);
write!(&mut hrofb, "{}\n", program_flattened).expect("Unable to write data to file.");
hrofb.flush();
// debugging output
println!("compiled program:\n{}", program_flattened);
},
println!("Compiled program:\n{}", program_flattened);
println!(
"Compiled code written to {}",
sub_matches.value_of("output").unwrap()
);
}
("compute-witness", Some(sub_matches)) => {
println!("Computing witness...");
},
// read compiled program
let path = Path::new(sub_matches.value_of("input").unwrap());
let file = match File::open(&path) {
Ok(file) => file,
Err(why) => panic!("couldn't open {}: {}", path.display(), why),
};
let program_ast: Prog<FieldPrime> = match parse_program(file) {
Ok(x) => x,
Err(why) => {
println!("{:?}", why);
std::process::exit(1);
}
};
// make sure the input program is actually flattened.
// TODO: is_flattened should be provided as method of Prog in absy.
let program_flattened = program_ast
.functions
.iter()
.find(|x| x.id == "main")
.unwrap();
for stat in program_flattened.statements.clone() {
assert!(
stat.is_flattened(),
format!("Input conditions not flattened: {}", &stat)
);
}
// validate arguments
println!("{:?}", sub_matches.value_of("arguments"));
// calculate witness
// let witness_map = program_flattened.get_witness(args);
// println!("witness_map {:?}", witness_map);
// match witness_map.get("~out") {
// Some(out) => println!("~out: {}", out),
// None => println!("~out not found")
// }
// let witness: Vec<_> = variables.iter().map(|x| witness_map[x].clone()).collect();
// println!("witness {:?}", witness);
}
("setup", Some(sub_matches)) => {
println!("Performing setup...");
},
}
("export-verifier", Some(sub_matches)) => {
println!("Exporting verifier...");
},
}
("generate-proof", Some(sub_matches)) => {
println!("Generating proof...");
},
}
("deploy-verifier", Some(sub_matches)) => {
println!("Deploying verifier...");
// use https://github.com/tomusdrw/rust-web3 for blockchain interaction
// and https://doc.rust-lang.org/std/process/struct.Command.html for solc
}
_ => {unimplemented!()}, // Either no subcommand or one not tested for...
_ => unimplemented!(), // Either no subcommand or one not tested for...
}
@ -196,7 +276,8 @@ mod tests {
Ok(x) => x,
Err(why) => panic!("Error: {:?}", why),
};
let program_flattened = Flattener::new(FieldPrime::get_required_bits()).flatten_program(program_ast);
let program_flattened =
Flattener::new(FieldPrime::get_required_bits()).flatten_program(program_ast);
let (..) = r1cs_program(&program_flattened);
}
}
@ -218,7 +299,8 @@ mod tests {
Ok(x) => x,
Err(why) => panic!("Error: {:?}", why),
};
let program_flattened = Flattener::new(FieldPrime::get_required_bits()).flatten_program(program_ast);
let program_flattened =
Flattener::new(FieldPrime::get_required_bits()).flatten_program(program_ast);
let (..) = r1cs_program(&program_flattened);
let _ = program_flattened.get_witness(vec![FieldPrime::zero()]);
}

File diff suppressed because it is too large Load diff

View file

@ -25,14 +25,15 @@ fn get_summands<T: Field>(expr: &Expression<T>) -> Vec<&Expression<T>> {
loop {
if let Some(e) = trace.pop() {
match *e {
ref e @ Number(_) |
ref e @ Identifier(_) |
ref e @ Mult(..) |
ref e @ Sub(..) if e.is_linear() => add.push(e),
ref e @ Number(_) | ref e @ Identifier(_) | ref e @ Mult(..) | ref e @ Sub(..)
if e.is_linear() =>
{
add.push(e)
}
Add(ref l, ref r) => {
trace.push(l);
trace.push(r);
},
}
ref e => panic!("Not covered: {}", e),
}
} else {
@ -58,20 +59,20 @@ fn count_variables_add<T: Field>(expr: &Expression<T>) -> HashMap<String, T> {
Number(ref x) => {
let num = count.entry("~one".to_string()).or_insert(T::zero());
*num = num.clone() + x;
},
}
Identifier(ref v) => {
let num = count.entry(v.to_string()).or_insert(T::zero());
*num = num.clone() + T::one();
},
}
Mult(box Number(ref x1), box Number(ref x2)) => {
let num = count.entry("~one".to_string()).or_insert(T::zero());
*num = num.clone() + x1 + x2;
},
}
Mult(box Number(ref x), box Identifier(ref v)) |
Mult(box Identifier(ref v), box Number(ref x)) => {
let num = count.entry(v.to_string()).or_insert(T::zero());
*num = num.clone() + x;
},
}
ref e => panic!("Not covered: {}", e),
}
}
@ -92,29 +93,25 @@ fn swap_sub<T: Field>(lhs: &Expression<T>, rhs: &Expression<T>) -> (Expression<T
run = false;
for i in 0..left.len() {
match *left[i] {
ref e @ Number(_) |
ref e @ Identifier(_) |
ref e @ Mult(..) if e.is_linear() => {},
ref e @ Number(_) | ref e @ Identifier(_) | ref e @ Mult(..) if e.is_linear() => {}
Sub(ref l, ref r) => {
run = true;
left.swap_remove(i);
left.extend(get_summands(l));
right.extend(get_summands(r));
},
}
ref e => panic!("Unexpected: {}", e),
}
}
for i in 0..right.len() {
match *right[i] {
ref e @ Number(_) |
ref e @ Identifier(_) |
ref e @ Mult(..) if e.is_linear() => {},
ref e @ Number(_) | ref e @ Identifier(_) | ref e @ Mult(..) if e.is_linear() => {}
Sub(ref l, ref r) => {
run = true;
right.swap_remove(i);
right.extend(get_summands(l));
left.extend(get_summands(r));
},
}
ref e => panic!("Unexpected: {}", e),
}
}
@ -122,8 +119,11 @@ fn swap_sub<T: Field>(lhs: &Expression<T>, rhs: &Expression<T>) -> (Expression<T
if let Some(left_init) = left.pop() {
if let Some(right_init) = right.pop() {
return (
left.iter().fold(left_init.clone(), |acc, &x| Add(box acc, box x.clone())),
right.iter().fold(right_init.clone(), |acc, &x| Add(box acc, box x.clone()))
left.iter()
.fold(left_init.clone(), |acc, &x| Add(box acc, box x.clone())),
right
.iter()
.fold(right_init.clone(), |acc, &x| Add(box acc, box x.clone())),
);
}
}
@ -141,11 +141,17 @@ fn swap_sub<T: Field>(lhs: &Expression<T>, rhs: &Expression<T>) -> (Expression<T
/// * `a_row` - Result row of matrix A
/// * `b_row` - Result row of matrix B
/// * `c_row` - Result row of matrix C
fn r1cs_expression<T: Field>(linear_expr: Expression<T>, expr: Expression<T>, variables: &mut Vec<String>, a_row: &mut Vec<(usize, T)>, b_row: &mut Vec<(usize, T)>, c_row: &mut Vec<(usize, T)>) {
fn r1cs_expression<T: Field>(
linear_expr: Expression<T>,
expr: Expression<T>,
variables: &mut Vec<String>,
a_row: &mut Vec<(usize, T)>,
b_row: &mut Vec<(usize, T)>,
c_row: &mut Vec<(usize, T)>,
) {
assert!(linear_expr.is_linear());
match expr {
e @ Add(..) |
e @ Sub(..) => {
e @ Add(..) | e @ Sub(..) => {
let (lhs, rhs) = swap_sub(&linear_expr, &e);
for (key, value) in count_variables_add(&rhs) {
a_row.push((get_variable_idx(variables, &key), value));
@ -154,7 +160,7 @@ fn r1cs_expression<T: Field>(linear_expr: Expression<T>, expr: Expression<T>, va
for (key, value) in count_variables_add(&lhs) {
c_row.push((get_variable_idx(variables, &key), value));
}
},
}
Mult(lhs, rhs) => {
match lhs {
box Number(x) => a_row.push((0, x)),
@ -175,32 +181,50 @@ fn r1cs_expression<T: Field>(linear_expr: Expression<T>, expr: Expression<T>, va
for (key, value) in count_variables_add(&linear_expr) {
c_row.push((get_variable_idx(variables, &key), value));
}
},
Div(lhs, rhs) => { // a / b = c --> c * b = a
}
Div(lhs, rhs) => {
// a / b = c --> c * b = a
match lhs {
box Number(x) => c_row.push((0, x)),
box Identifier(x) => c_row.push((get_variable_idx(variables, &x), T::one())),
box e @ Add(..) => for (key, value) in count_variables_add(&e) {
c_row.push((get_variable_idx(variables, &key), value));
},
box e @ Sub(..) => return r1cs_expression(Mult(box linear_expr, rhs), e, variables, a_row, b_row, c_row),
box Mult(box Number(ref x1), box Number(ref x2)) => c_row.push((0, x1.clone() * x2)),
box e @ Sub(..) => {
return r1cs_expression(
Mult(box linear_expr, rhs),
e,
variables,
a_row,
b_row,
c_row,
)
}
box Mult(box Number(ref x1), box Number(ref x2)) => {
c_row.push((0, x1.clone() * x2))
}
box Mult(box Number(ref x), box Identifier(ref v)) |
box Mult(box Identifier(ref v), box Number(ref x)) => c_row.push((get_variable_idx(variables, v), x.clone())),
box Mult(box Identifier(ref v), box Number(ref x)) => {
c_row.push((get_variable_idx(variables, v), x.clone()))
}
e @ _ => panic!("(lhs) not supported: {:?}", e),
};
match rhs {
box Number(x) => b_row.push((0, x)),
box Identifier(x) => b_row.push((get_variable_idx(variables, &x), T::one())),
box Mult(box Number(ref x1), box Number(ref x2)) => b_row.push((0, x1.clone() * x2)),
box Mult(box Number(ref x1), box Number(ref x2)) => {
b_row.push((0, x1.clone() * x2))
}
box Mult(box Number(ref x), box Identifier(ref v)) |
box Mult(box Identifier(ref v), box Number(ref x)) => b_row.push((get_variable_idx(variables, v), x.clone())),
box Mult(box Identifier(ref v), box Number(ref x)) => {
b_row.push((get_variable_idx(variables, v), x.clone()))
}
e @ _ => panic!("(rhs) not supported: {:?}", e),
};
for (key, value) in count_variables_add(&linear_expr) {
a_row.push((get_variable_idx(variables, &key), value));
}
},
}
Pow(_, _) => panic!("Pow not flattened"),
IfElse(_, _, _) => panic!("IfElse not flattened"),
FunctionCall(_, _) => panic!("FunctionCall not flattened"),
@ -210,14 +234,14 @@ fn r1cs_expression<T: Field>(linear_expr: Expression<T>, expr: Expression<T>, va
for (key, value) in count_variables_add(&linear_expr) {
c_row.push((get_variable_idx(variables, &key), value));
}
},
}
Number(x) => {
a_row.push((0, x));
b_row.push((0, T::one()));
for (key, value) in count_variables_add(&linear_expr) {
c_row.push((get_variable_idx(variables, &key), value));
}
},
}
}
}
@ -244,7 +268,14 @@ fn get_variable_idx(variables: &mut Vec<String>, var: &String) -> usize {
/// # Arguments
///
/// * `prog` - The program the representation is calculated for.
pub fn r1cs_program<T: Field>(prog: &Prog<T>) -> (Vec<String>, Vec<Vec<(usize, T)>>, Vec<Vec<(usize, T)>>, Vec<Vec<(usize, T)>>){
pub fn r1cs_program<T: Field>(
prog: &Prog<T>,
) -> (
Vec<String>,
Vec<Vec<(usize, T)>>,
Vec<Vec<(usize, T)>>,
Vec<Vec<(usize, T)>>,
) {
let mut variables: Vec<String> = Vec::new();
variables.push("~one".to_string());
let mut a: Vec<Vec<(usize, T)>> = Vec::new();
@ -252,16 +283,40 @@ pub fn r1cs_program<T: Field>(prog: &Prog<T>) -> (Vec<String>, Vec<Vec<(usize, T
let mut c: Vec<Vec<(usize, T)>> = Vec::new();
//Only the main function is relevant in this step, since all calls to other functions were resolved during flattening
let main = prog.functions.iter().find(|x: &&Function<T>| x.id == "main".to_string()).unwrap();
let main = prog.functions
.iter()
.find(|x: &&Function<T>| x.id == "main".to_string())
.unwrap();
variables.extend(main.arguments.iter().map(|x| format!("{}", x)));
for def in &main.statements {
let mut a_row: Vec<(usize, T)> = Vec::new();
let mut b_row: Vec<(usize, T)> = Vec::new();
let mut c_row: Vec<(usize, T)> = Vec::new();
match *def {
Statement::Return(ref expr) => r1cs_expression(Identifier("~out".to_string()), expr.clone(), &mut variables, &mut a_row, &mut b_row, &mut c_row),
Statement::Definition(ref id, ref expr) => r1cs_expression(Identifier(id.to_string()), expr.clone(), &mut variables, &mut a_row, &mut b_row, &mut c_row),
Statement::Condition(ref expr1, ref expr2) => r1cs_expression(expr1.clone(), expr2.clone(), &mut variables, &mut a_row, &mut b_row, &mut c_row),
Statement::Return(ref expr) => r1cs_expression(
Identifier("~out".to_string()),
expr.clone(),
&mut variables,
&mut a_row,
&mut b_row,
&mut c_row,
),
Statement::Definition(ref id, ref expr) => r1cs_expression(
Identifier(id.to_string()),
expr.clone(),
&mut variables,
&mut a_row,
&mut b_row,
&mut c_row,
),
Statement::Condition(ref expr1, ref expr2) => r1cs_expression(
expr1.clone(),
expr2.clone(),
&mut variables,
&mut a_row,
&mut b_row,
&mut c_row,
),
Statement::For(..) => panic!("For-loop not flattened"),
Statement::Compiler(..) => continue,
}
@ -296,8 +351,14 @@ mod tests {
fn add() {
// x = y + 5
let lhs = Identifier(String::from("x"));
let rhs = Add(box Identifier(String::from("y")), box Number(FieldPrime::from(5)));
let mut variables: Vec<String> = vec!["~one", "x", "y"].iter().map(|&x| String::from(x)).collect();
let rhs = Add(
box Identifier(String::from("y")),
box Number(FieldPrime::from(5)),
);
let mut variables: Vec<String> = vec!["~one", "x", "y"]
.iter()
.map(|&x| String::from(x))
.collect();
let mut a_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut b_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut c_row: Vec<(usize, FieldPrime)> = Vec::new();
@ -306,7 +367,10 @@ mod tests {
a_row.sort_by(sort_tup);
b_row.sort_by(sort_tup);
c_row.sort_by(sort_tup);
assert_eq!(vec![(0, FieldPrime::from(5)), (2, FieldPrime::from(1))], a_row);
assert_eq!(
vec![(0, FieldPrime::from(5)), (2, FieldPrime::from(1))],
a_row
);
assert_eq!(vec![(0, FieldPrime::from(1))], b_row);
assert_eq!(vec![(1, FieldPrime::from(1))], c_row);
}
@ -317,29 +381,53 @@ mod tests {
// --> (x + y) + y + 4y + 2z + y == x + 2x + 4y + (z + 3x)
// <=> x + 7*y + 2*z == 6*x + 4y + z
let lhs = Sub(
box Add(box Identifier(String::from("x")), box Identifier(String::from("y"))),
box Add(
box Identifier(String::from("x")),
box Identifier(String::from("y")),
),
box Sub(
box Add(
box Identifier(String::from("z")),
box Mult(box Number(FieldPrime::from(3)), box Identifier(String::from("x")))
box Mult(
box Number(FieldPrime::from(3)),
box Identifier(String::from("x")),
),
),
box Identifier(String::from("y"))
)
box Identifier(String::from("y")),
),
);
let rhs = Add(
box Sub(box Identifier(String::from("x")), box Identifier(String::from("y"))),
box Sub(
box Identifier(String::from("x")),
box Identifier(String::from("y")),
),
box Add(
box Sub(
box Mult(box Number(FieldPrime::from(2)), box Identifier(String::from("x"))),
box Mult(box Number(FieldPrime::from(4)), box Identifier(String::from("y")))
box Mult(
box Number(FieldPrime::from(2)),
box Identifier(String::from("x")),
),
box Mult(
box Number(FieldPrime::from(4)),
box Identifier(String::from("y")),
),
),
box Sub(
box Mult(box Number(FieldPrime::from(4)), box Identifier(String::from("y"))),
box Mult(box Number(FieldPrime::from(2)), box Identifier(String::from("z")))
)
)
box Mult(
box Number(FieldPrime::from(4)),
box Identifier(String::from("y")),
),
box Mult(
box Number(FieldPrime::from(2)),
box Identifier(String::from("z")),
),
),
),
);
let mut variables: Vec<String> = vec!["~one", "x", "y", "z"].iter().map(|&x| String::from(x)).collect();
let mut variables: Vec<String> = vec!["~one", "x", "y", "z"]
.iter()
.map(|&x| String::from(x))
.collect();
let mut a_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut b_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut c_row: Vec<(usize, FieldPrime)> = Vec::new();
@ -348,23 +436,49 @@ mod tests {
a_row.sort_by(sort_tup);
b_row.sort_by(sort_tup);
c_row.sort_by(sort_tup);
assert_eq!(vec![(1, FieldPrime::from(6)), (2, FieldPrime::from(4)), (3, FieldPrime::from(1))], a_row);
assert_eq!(
vec![
(1, FieldPrime::from(6)),
(2, FieldPrime::from(4)),
(3, FieldPrime::from(1)),
],
a_row
);
assert_eq!(vec![(0, FieldPrime::from(1))], b_row);
assert_eq!(vec![(1, FieldPrime::from(1)), (2, FieldPrime::from(7)), (3, FieldPrime::from(2))], c_row);
assert_eq!(
vec![
(1, FieldPrime::from(1)),
(2, FieldPrime::from(7)),
(3, FieldPrime::from(2)),
],
c_row
);
}
#[test]
fn sub() {
// 7 * x + y == 3 * y - z * 6
let lhs = Add(
box Mult(box Number(FieldPrime::from(7)), box Identifier(String::from("x"))),
box Identifier(String::from("y"))
box Mult(
box Number(FieldPrime::from(7)),
box Identifier(String::from("x")),
),
box Identifier(String::from("y")),
);
let rhs = Sub(
box Mult(box Number(FieldPrime::from(3)), box Identifier(String::from("y"))),
box Mult(box Identifier(String::from("z")), box Number(FieldPrime::from(6)))
box Mult(
box Number(FieldPrime::from(3)),
box Identifier(String::from("y")),
),
box Mult(
box Identifier(String::from("z")),
box Number(FieldPrime::from(6)),
),
);
let mut variables: Vec<String> = vec!["~one", "x", "y", "z"].iter().map(|&x| String::from(x)).collect();
let mut variables: Vec<String> = vec!["~one", "x", "y", "z"]
.iter()
.map(|&x| String::from(x))
.collect();
let mut a_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut b_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut c_row: Vec<(usize, FieldPrime)> = Vec::new();
@ -375,7 +489,14 @@ mod tests {
c_row.sort_by(sort_tup);
assert_eq!(vec![(2, FieldPrime::from(3))], a_row); // 3 * y
assert_eq!(vec![(0, FieldPrime::from(1))], b_row); // 1
assert_eq!(vec![(1, FieldPrime::from(7)), (2, FieldPrime::from(1)), (3, FieldPrime::from(6))], c_row); // (7 * x + y) + z * 6
assert_eq!(
vec![
(1, FieldPrime::from(7)),
(2, FieldPrime::from(1)),
(3, FieldPrime::from(6)),
],
c_row
); // (7 * x + y) + z * 6
}
#[test]
@ -384,16 +505,28 @@ mod tests {
// --> 3*y + x == a + 12*x + 2*z
let lhs = Sub(
box Sub(
box Mult(box Number(FieldPrime::from(3)), box Identifier(String::from("y"))),
box Mult(box Identifier(String::from("z")), box Number(FieldPrime::from(2)))
box Mult(
box Number(FieldPrime::from(3)),
box Identifier(String::from("y")),
),
box Mult(
box Identifier(String::from("z")),
box Number(FieldPrime::from(2)),
),
),
box Mult(
box Identifier(String::from("x")),
box Number(FieldPrime::from(12)),
),
box Mult(box Identifier(String::from("x")), box Number(FieldPrime::from(12)))
);
let rhs = Sub(
box Identifier(String::from("a")),
box Identifier(String::from("x"))
box Identifier(String::from("x")),
);
let mut variables: Vec<String> = vec!["~one", "x", "y", "z", "a"].iter().map(|&x| String::from(x)).collect();
let mut variables: Vec<String> = vec!["~one", "x", "y", "z", "a"]
.iter()
.map(|&x| String::from(x))
.collect();
let mut a_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut b_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut c_row: Vec<(usize, FieldPrime)> = Vec::new();
@ -402,9 +535,19 @@ mod tests {
a_row.sort_by(sort_tup);
b_row.sort_by(sort_tup);
c_row.sort_by(sort_tup);
assert_eq!(vec![(1, FieldPrime::from(12)), (3, FieldPrime::from(2)), (4, FieldPrime::from(1))], a_row); // a + 12*x + 2*z
assert_eq!(
vec![
(1, FieldPrime::from(12)),
(3, FieldPrime::from(2)),
(4, FieldPrime::from(1)),
],
a_row
); // a + 12*x + 2*z
assert_eq!(vec![(0, FieldPrime::from(1))], b_row); // 1
assert_eq!(vec![(1, FieldPrime::from(1)), (2, FieldPrime::from(3))], c_row); // 3*y + x
assert_eq!(
vec![(1, FieldPrime::from(1)), (2, FieldPrime::from(3))],
c_row
); // 3*y + x
}
#[test]
@ -412,25 +555,52 @@ mod tests {
// 4 * b + 3 * a + 3 * c == (3 * a + 6 * b + 4 * c) * (31 * a + 4 * c)
let lhs = Add(
box Add(
box Mult(box Number(FieldPrime::from(4)), box Identifier(String::from("b"))),
box Mult(box Number(FieldPrime::from(3)), box Identifier(String::from("a")))
box Mult(
box Number(FieldPrime::from(4)),
box Identifier(String::from("b")),
),
box Mult(
box Number(FieldPrime::from(3)),
box Identifier(String::from("a")),
),
),
box Mult(
box Number(FieldPrime::from(3)),
box Identifier(String::from("c")),
),
box Mult(box Number(FieldPrime::from(3)), box Identifier(String::from("c")))
);
let rhs = Mult(
box Add(
box Add(
box Mult(box Number(FieldPrime::from(3)), box Identifier(String::from("a"))),
box Mult(box Number(FieldPrime::from(6)), box Identifier(String::from("b")))
box Mult(
box Number(FieldPrime::from(3)),
box Identifier(String::from("a")),
),
box Mult(
box Number(FieldPrime::from(6)),
box Identifier(String::from("b")),
),
),
box Mult(
box Number(FieldPrime::from(4)),
box Identifier(String::from("c")),
),
box Mult(box Number(FieldPrime::from(4)), box Identifier(String::from("c")))
),
box Add(
box Mult(box Number(FieldPrime::from(31)), box Identifier(String::from("a"))),
box Mult(box Number(FieldPrime::from(4)), box Identifier(String::from("c")))
)
box Mult(
box Number(FieldPrime::from(31)),
box Identifier(String::from("a")),
),
box Mult(
box Number(FieldPrime::from(4)),
box Identifier(String::from("c")),
),
),
);
let mut variables: Vec<String> = vec!["~one", "a", "b", "c"].iter().map(|&x| String::from(x)).collect();
let mut variables: Vec<String> = vec!["~one", "a", "b", "c"]
.iter()
.map(|&x| String::from(x))
.collect();
let mut a_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut b_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut c_row: Vec<(usize, FieldPrime)> = Vec::new();
@ -439,9 +609,26 @@ mod tests {
a_row.sort_by(sort_tup);
b_row.sort_by(sort_tup);
c_row.sort_by(sort_tup);
assert_eq!(vec![(1, FieldPrime::from(3)), (2, FieldPrime::from(6)), (3, FieldPrime::from(4))], a_row);
assert_eq!(vec![(1, FieldPrime::from(31)), (3, FieldPrime::from(4))], b_row);
assert_eq!(vec![(1, FieldPrime::from(3)), (2, FieldPrime::from(4)), (3, FieldPrime::from(3))], c_row);
assert_eq!(
vec![
(1, FieldPrime::from(3)),
(2, FieldPrime::from(6)),
(3, FieldPrime::from(4)),
],
a_row
);
assert_eq!(
vec![(1, FieldPrime::from(31)), (3, FieldPrime::from(4))],
b_row
);
assert_eq!(
vec![
(1, FieldPrime::from(3)),
(2, FieldPrime::from(4)),
(3, FieldPrime::from(3)),
],
c_row
);
}
#[test]
@ -449,10 +636,19 @@ mod tests {
// x = (3 * x) / (y * 6) --> x * (y * 6) = 3 * x
let lhs = Identifier(String::from("x"));
let rhs = Div(
box Mult(box Number(FieldPrime::from(3)), box Identifier(String::from("x"))),
box Mult(box Identifier(String::from("y")), box Number(FieldPrime::from(6)))
box Mult(
box Number(FieldPrime::from(3)),
box Identifier(String::from("x")),
),
box Mult(
box Identifier(String::from("y")),
box Number(FieldPrime::from(6)),
),
);
let mut variables: Vec<String> = vec!["~one", "x", "y"].iter().map(|&x| String::from(x)).collect();
let mut variables: Vec<String> = vec!["~one", "x", "y"]
.iter()
.map(|&x| String::from(x))
.collect();
let mut a_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut b_row: Vec<(usize, FieldPrime)> = Vec::new();
let mut c_row: Vec<(usize, FieldPrime)> = Vec::new();