Intermediary commit. Serialization added, Deserialization still ToDo. Formatted.
This commit is contained in:
parent
9528f6576c
commit
5d60e174ee
10 changed files with 2075 additions and 691 deletions
79
Cargo.lock
generated
79
Cargo.lock
generated
|
@ -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"
|
||||
|
|
|
@ -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"
|
||||
|
|
4
build.rs
4
build.rs
|
@ -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()
|
||||
|
|
249
src/absy.rs
249
src/absy.rs
|
@ -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),
|
||||
),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
213
src/field.rs
213
src/field.rs
|
@ -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 - "ient * &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
|
||||
);
|
||||
}
|
||||
|
|
487
src/flatten.rs
487
src/flatten.rs
|
@ -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 ¤t < 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() + ¤t;
|
||||
}
|
||||
},
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
146
src/main.rs
146
src/main.rs
|
@ -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()]);
|
||||
}
|
||||
|
|
1142
src/parser.rs
1142
src/parser.rs
File diff suppressed because it is too large
Load diff
364
src/r1cs.rs
364
src/r1cs.rs
|
@ -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();
|
||||
|
|
Loading…
Reference in a new issue