diff --git a/Cargo.toml b/Cargo.toml index d6db2f635..0ede3068f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -33,6 +33,11 @@ multimap = "0.8.2" hex = "0.4.2" num_enum = "0.5.0" +lazy_static = "1.4.0" +itertools = "0.8.0" +fnv = "1.0.6" +regex = "1" + simplelog = "0.7.4" clap = "3.0.0-beta.1" failure = "0.1.8" @@ -55,6 +60,10 @@ http-types = "2.9.0" async-h1 = "2.3.0" async-native-tls = "0.3.3" +[[bin]] +name = "lisp" +path = "lisp/lisp.rs" + [[bin]] name = "zkvm" path = "src/bin/zkvm.rs" diff --git a/lisp/README.md b/lisp/README.md new file mode 100644 index 000000000..5f8614950 --- /dev/null +++ b/lisp/README.md @@ -0,0 +1,12 @@ +## zklisp + +This is a DSL for ZKVMCircuit from sapvi language. + +It uses the mal (lisp) version of rust with some modifications to interact with bellman backend and also sapvi vm. + +## run + + +``` +cargo run --bin lisp load new.lisp +``` diff --git a/lisp/TODO.md b/lisp/TODO.md new file mode 100644 index 000000000..3e455c7e5 --- /dev/null +++ b/lisp/TODO.md @@ -0,0 +1,7 @@ +## TODO + +- Document the language +- Integrate with zkvm command line +- Integrate with ZKVMCircuit: allocs and constraints +- Added CryptoOperation such double and square to core.rs +- Adapt ZKContract to use lisp to read contract and execute diff --git a/lisp/bits.lisp b/lisp/bits.lisp new file mode 100644 index 000000000..eb43aed21 --- /dev/null +++ b/lisp/bits.lisp @@ -0,0 +1,9 @@ +(def! bit-dec + (fn* [x] ( + (def! bits (unpack-bits x 256)) + (def! enforce-step-1 (fn* [b] (enforce (add-one-lc0 (sub-lc0 b) (add-lc1 b)))) + (map enforce-step-1 bits) + (map (fn* [b] ((add-lc0 b) double-coeff-lc) bits) + (enforce reset-coeff-lc sub-lc0 add-one-lc1) + ))))) + diff --git a/lisp/core.rs b/lisp/core.rs new file mode 100644 index 000000000..76a4b2d57 --- /dev/null +++ b/lisp/core.rs @@ -0,0 +1,489 @@ +use std::fs::File; +use std::io::Read; +use std::rc::Rc; + +use std::time::{SystemTime, UNIX_EPOCH}; + +use crate::printer::pr_seq; +use crate::reader::read_str; +use crate::types::MalErr::ErrMalVal; +use crate::types::MalVal::{ + Atom, Bool, Func, Hash, Int, List, MalFunc, Nil, Str, Sym, Vector, ZKScalar, +}; +use crate::types::{MalArgs, MalRet, MalVal, _assoc, _dissoc, atom, error, func, hash_map}; + +use bls12_381; +use ff::PrimeField; + +use sapvi::bls_extensions::BlsStringConversion; + +use std::ops::{AddAssign, MulAssign, SubAssign}; + +macro_rules! fn_t_int_int { + ($ret:ident, $fn:expr) => {{ + |a: MalArgs| match (a[0].clone(), a[1].clone()) { + (Int(a0), Int(a1)) => Ok($ret($fn(a0, a1))), + _ => error("expecting (int,int) args"), + } + }}; +} + +macro_rules! fn_is_type { + ($($ps:pat),*) => {{ + |a:MalArgs| { Ok(Bool(match a[0] { $($ps => true,)* _ => false})) } + }}; + ($p:pat if $e:expr) => {{ + |a:MalArgs| { Ok(Bool(match a[0] { $p if $e => true, _ => false})) } + }}; + ($p:pat if $e:expr,$($ps:pat),*) => {{ + |a:MalArgs| { Ok(Bool(match a[0] { $p if $e => true, $($ps => true,)* _ => false})) } + }}; +} + +macro_rules! fn_str { + ($fn:expr) => {{ + |a: MalArgs| match a[0].clone() { + Str(a0) => $fn(a0), + _ => error("expecting (str) arg"), + } + }}; +} + +fn symbol(a: MalArgs) -> MalRet { + match a[0] { + Str(ref s) => Ok(Sym(s.to_string())), + _ => error("illegal symbol call"), + } +} + +fn slurp(f: String) -> MalRet { + let mut s = String::new(); + match File::open(f).and_then(|mut f| f.read_to_string(&mut s)) { + Ok(_) => Ok(Str(s)), + Err(e) => error(&e.to_string()), + } +} + +fn time_ms(_a: MalArgs) -> MalRet { + let ms_e = match SystemTime::now().duration_since(UNIX_EPOCH) { + Ok(d) => d, + Err(e) => return error(&format!("{:?}", e)), + }; + Ok(Int( + ms_e.as_secs() as i64 * 1000 + ms_e.subsec_nanos() as i64 / 1_000_000 + )) +} + +fn get(a: MalArgs) -> MalRet { + match (a[0].clone(), a[1].clone()) { + (Nil, _) => Ok(Nil), + (Hash(ref hm, _), Str(ref s)) => match hm.get(s) { + Some(mv) => Ok(mv.clone()), + None => Ok(Nil), + }, + _ => error("illegal get args"), + } +} + +fn assoc(a: MalArgs) -> MalRet { + match a[0] { + Hash(ref hm, _) => _assoc((**hm).clone(), a[1..].to_vec()), + _ => error("assoc on non-Hash Map"), + } +} + +fn dissoc(a: MalArgs) -> MalRet { + match a[0] { + Hash(ref hm, _) => _dissoc((**hm).clone(), a[1..].to_vec()), + _ => error("dissoc on non-Hash Map"), + } +} + +fn contains_q(a: MalArgs) -> MalRet { + match (a[0].clone(), a[1].clone()) { + (Hash(ref hm, _), Str(ref s)) => Ok(Bool(hm.contains_key(s))), + _ => error("illegal get args"), + } +} + +fn keys(a: MalArgs) -> MalRet { + match a[0] { + Hash(ref hm, _) => Ok(list!(hm.keys().map(|k| { Str(k.to_string()) }).collect())), + _ => error("keys requires Hash Map"), + } +} + +fn vals(a: MalArgs) -> MalRet { + match a[0] { + Hash(ref hm, _) => Ok(list!(hm.values().map(|v| { v.clone() }).collect())), + _ => error("keys requires Hash Map"), + } +} + +fn vec(a: MalArgs) -> MalRet { + match a[0] { + List(ref v, _) | Vector(ref v, _) => Ok(vector!(v.to_vec())), + _ => error("non-seq passed to vec"), + } +} + +fn cons(a: MalArgs) -> MalRet { + match a[1].clone() { + List(v, _) | Vector(v, _) => { + let mut new_v = vec![a[0].clone()]; + new_v.extend_from_slice(&v); + Ok(list!(new_v.to_vec())) + } + _ => error("cons expects seq as second arg"), + } +} + +fn concat(a: MalArgs) -> MalRet { + let mut new_v = vec![]; + for seq in a.iter() { + match seq { + List(v, _) | Vector(v, _) => new_v.extend_from_slice(v), + _ => return error("non-seq passed to concat"), + } + } + Ok(list!(new_v.to_vec())) +} + +fn nth(a: MalArgs) -> MalRet { + match (a[0].clone(), a[1].clone()) { + (List(seq, _), Int(idx)) | (Vector(seq, _), Int(idx)) => { + if seq.len() <= idx as usize { + return error("nth: index out of range"); + } + Ok(seq[idx as usize].clone()) + } + _ => error("invalid args to nth"), + } +} + +fn unpack_bits(a: MalArgs) -> MalRet { + let mut result = vec![]; + match a[0].clone() { + Str(ref s) => { + let value = bls12_381::Scalar::from_string(s); + for (_, bit) in value.to_le_bits().into_iter().cloned().enumerate() { + match bit { + true => result.push(bls12_381::Scalar::one()), + false => result.push(bls12_381::Scalar::zero()), + } + } + Ok(list!(result + .iter() + .map(|a| Str(std::string::ToString::to_string(&a)[2..].to_string())) + .collect::>())) + } + _ => error("invalid args to unpack-bits"), + } +} + +fn last(a: MalArgs) -> MalRet { + match a[0].clone() { + List(ref seq, _) | Vector(ref seq, _) if seq.len() == 0 => Ok(Nil), + List(ref seq, _) | Vector(ref seq, _) => Ok(seq[seq.len() - 1].clone()), + Nil => Ok(Nil), + _ => error("invalid args to first"), + } +} +fn first(a: MalArgs) -> MalRet { + match a[0].clone() { + List(ref seq, _) | Vector(ref seq, _) if seq.len() == 0 => Ok(Nil), + List(ref seq, _) | Vector(ref seq, _) => Ok(seq[0].clone()), + Nil => Ok(Nil), + _ => error("invalid args to first"), + } +} + +fn rest(a: MalArgs) -> MalRet { + match a[0].clone() { + List(ref seq, _) | Vector(ref seq, _) => { + if seq.len() > 1 { + Ok(list!(seq[1..].to_vec())) + } else { + Ok(list![]) + } + } + Nil => Ok(list![]), + _ => error("invalid args to first"), + } +} + +fn apply(a: MalArgs) -> MalRet { + match a[a.len() - 1] { + List(ref v, _) | Vector(ref v, _) => { + let f = &a[0]; + let mut fargs = a[1..a.len() - 1].to_vec(); + fargs.extend_from_slice(&v); + f.apply(fargs) + } + _ => error("apply called with non-seq"), + } +} + +fn map(a: MalArgs) -> MalRet { + match a[1] { + List(ref v, _) | Vector(ref v, _) => { + let mut res = vec![]; + for mv in v.iter() { + res.push(a[0].apply(vec![mv.clone()])?) + } + Ok(list!(res)) + } + _ => error("map called with non-seq"), + } +} + +fn conj(a: MalArgs) -> MalRet { + match a[0] { + List(ref v, _) => { + let sl = a[1..] + .iter() + .rev() + .map(|a| a.clone()) + .collect::>(); + Ok(list!([&sl[..], v].concat())) + } + Vector(ref v, _) => Ok(vector!([v, &a[1..]].concat())), + _ => error("conj: called with non-seq"), + } +} + +fn sub_scalar(a: MalArgs) -> MalRet { + match (a[0].clone(), a[1].clone()) { + (Str(a0), Str(a1)) => { + let (mut s0, s1) = ( + bls12_381::Scalar::from_string(&a0), + bls12_381::Scalar::from_string(&a1), + ); + s0.sub_assign(s1); + Ok(Str(std::string::ToString::to_string(&s0)[2..].to_string())) + } + _ => error("expected (scalar, scalar)"), + } +} + +fn mul_scalar(a: MalArgs) -> MalRet { + match (a[0].clone(), a[1].clone()) { + (ZKScalar(mut a0), ZKScalar(a1)) => { + // let (mut s0, s1) = (Scalar::from_string(&a0), Scalar::from_string(&a1)); + a0.mul_assign(a1); + Ok(ZKScalar(a0)) + } + _ => error("expected (zkscalar, zkscalar)"), + } +} + +fn div_scalar(a: MalArgs) -> MalRet { + match (a[0].clone(), a[1].clone()) { + (Str(a0), Str(a1)) => { + let (s0, s1) = ( + bls12_381::Scalar::from_string(&a0), + bls12_381::Scalar::from_string(&a1), + ); + let ret = s1.invert().map(|other| *&s0 * other); + Ok(Str( + std::string::ToString::to_string(&ret.unwrap())[2..].to_string() + )) + } + _ => error("expected (scalar, scalar)"), + } +} + +fn range(a: MalArgs) -> MalRet { + let mut result = vec![]; + match (a[0].clone(), a[1].clone()) { + (Int(a0), Int(a1)) => { + for n in a0..a1 { + result.push(n); + } + Ok(list!(result.iter().map(|_a| Nil).collect::>())) + } + _ => error("expected int int"), + } +} + +fn scalar_zero(a: MalArgs) -> MalRet { + Ok(vector![vec![ + ZKScalar(bls12_381::Scalar::zero()), + a[0].clone() + ]]) +} + +fn scalar_one(a: MalArgs) -> MalRet { + match a.len() { + 0 => Ok(vector![vec![ZKScalar(bls12_381::Scalar::one())]]), + _ => Ok(vector![vec![ + ZKScalar(bls12_381::Scalar::one()), + a[0].clone() + ]]), + } +} + +fn cs_one(_a: MalArgs) -> MalRet { + Ok(vector![vec![Sym("cs::one".to_string())]]) +} + +fn negate_from(a: MalArgs) -> MalRet { + match a[0].clone() { + ZKScalar(a0) => Ok(ZKScalar(a0.neg())), + _ => match a[0].apply(vec![])? { + List(v, _) | Vector(v, _) => match v[0] { + ZKScalar(val) => Ok(vector![vec![ZKScalar(val.neg())]]), + _ => error("not scalar"), + }, + _ => return error("non zkscalar passed to negate"), + }, + } +} + +fn scalar_from(a: MalArgs) -> MalRet { + match a[0].clone() { + Str(a0) => { + let s0 = bls12_381::Scalar::from_string(&a0.to_string()); + Ok(ZKScalar(s0)) + } + Int(a0) => { + println!("{:?}", a0); + let s0 = bls12_381::Scalar::from(a0 as u64); + Ok(ZKScalar(s0)) + } + _ => error("expected (string or int)"), + } +} + +fn add_scalar(a: MalArgs) -> MalRet { + match (a[0].clone(), a[1].clone()) { + (Str(a0), Str(a1)) => { + let (mut s0, s1) = ( + bls12_381::Scalar::from_string(&a0), + bls12_381::Scalar::from_string(&a1), + ); + s0.add_assign(s1); + Ok(Str(std::string::ToString::to_string(&s0)[2..].to_string())) + } + _ => error("expected (scalar, scalar"), + } +} + +fn seq(a: MalArgs) -> MalRet { + match a[0] { + List(ref v, _) | Vector(ref v, _) if v.len() == 0 => Ok(Nil), + List(ref v, _) | Vector(ref v, _) => Ok(list!(v.to_vec())), + Str(ref s) if s.len() == 0 => Ok(Nil), + Str(ref s) if !a[0].keyword_q() => { + Ok(list!(s.chars().map(|c| { Str(c.to_string()) }).collect())) + } + Nil => Ok(Nil), + _ => error("seq: called with non-seq"), + } +} + +pub fn ns() -> Vec<(&'static str, MalVal)> { + vec![ + ("=", func(|a| Ok(Bool(a[0] == a[1])))), + ("throw", func(|a| Err(ErrMalVal(a[0].clone())))), + ("nil?", func(fn_is_type!(Nil))), + ("true?", func(fn_is_type!(Bool(true)))), + ("false?", func(fn_is_type!(Bool(false)))), + ("symbol", func(symbol)), + ("symbol?", func(fn_is_type!(Sym(_)))), + ( + "string?", + func(fn_is_type!(Str(ref s) if !s.starts_with("\u{29e}"))), + ), + ("keyword", func(|a| a[0].keyword())), + ( + "keyword?", + func(fn_is_type!(Str(ref s) if s.starts_with("\u{29e}"))), + ), + ("number?", func(fn_is_type!(Int(_)))), + ( + "fn?", + func(fn_is_type!(MalFunc{is_macro,..} if !is_macro,Func(_,_))), + ), + ( + "macro?", + func(fn_is_type!(MalFunc{is_macro,..} if is_macro)), + ), + ("pr-str", func(|a| Ok(Str(pr_seq(&a, true, "", "", " "))))), + ("str", func(|a| Ok(Str(pr_seq(&a, false, "", "", ""))))), + ( + "prn", + func(|a| { + println!("{}", pr_seq(&a, true, "", "", " ")); + Ok(Nil) + }), + ), + ( + "println", + func(|a| { + println!("{}", pr_seq(&a, false, "", "", " ")); + Ok(Nil) + }), + ), + ("read-string", func(fn_str!(|s| { read_str(s) }))), + ("slurp", func(fn_str!(|f| { slurp(f) }))), + ("<", func(fn_t_int_int!(Bool, |i, j| { i < j }))), + ("<=", func(fn_t_int_int!(Bool, |i, j| { i <= j }))), + (">", func(fn_t_int_int!(Bool, |i, j| { i > j }))), + (">=", func(fn_t_int_int!(Bool, |i, j| { i >= j }))), + ("+", func(add_scalar)), + ("-", func(sub_scalar)), + ("*", func(mul_scalar)), + ("/", func(div_scalar)), + ("time-ms", func(time_ms)), + ("i+", func(fn_t_int_int!(Int, |i, j| { i + j }))), + ("i-", func(fn_t_int_int!(Int, |i, j| { i - j }))), + ("i*", func(fn_t_int_int!(Int, |i, j| { i * j }))), + ("i/", func(fn_t_int_int!(Int, |i, j| { i / j }))), + ("i<", func(fn_t_int_int!(Bool, |i, j| { i < j }))), + ("i<=", func(fn_t_int_int!(Bool, |i, j| { i <= j }))), + ("i>", func(fn_t_int_int!(Bool, |i, j| { i > j }))), + ("i>=", func(fn_t_int_int!(Bool, |i, j| { i >= j }))), + ("time-ms", func(time_ms)), + ("sequential?", func(fn_is_type!(List(_, _), Vector(_, _)))), + ("list", func(|a| Ok(list!(a)))), + ("list?", func(fn_is_type!(List(_, _)))), + ("vector", func(|a| Ok(vector!(a)))), + ("vector?", func(fn_is_type!(Vector(_, _)))), + ("hash-map", func(|a| hash_map(a))), + ("map?", func(fn_is_type!(Hash(_, _)))), + ("assoc", func(assoc)), + ("dissoc", func(dissoc)), + ("get", func(get)), + ("contains?", func(contains_q)), + ("keys", func(keys)), + ("vals", func(vals)), + ("vec", func(vec)), + ("cons", func(cons)), + ("concat", func(concat)), + ("empty?", func(|a| a[0].empty_q())), + ("nth", func(nth)), + ("first", func(first)), + ("last", func(last)), + ("rest", func(rest)), + ("count", func(|a| a[0].count())), + ("apply", func(apply)), + ("map", func(map)), + ("conj", func(conj)), + ("seq", func(seq)), + ("meta", func(|a| a[0].get_meta())), + ("with-meta", func(|a| a[0].clone().with_meta(&a[1]))), + ("atom", func(|a| Ok(atom(&a[0])))), + ("atom?", func(fn_is_type!(Atom(_)))), + ("deref", func(|a| a[0].deref())), + ("reset!", func(|a| a[0].reset_bang(&a[1]))), + ("swap!", func(|a| a[0].swap_bang(&a[1..].to_vec()))), + ("unpack-bits", func(unpack_bits)), + ("range", func(range)), + ("scalar::one", func(scalar_one)), + ("neg", func(negate_from)), + ("scalar::zero", func(scalar_zero)), + ("scalar", func(scalar_from)), + ("cs::one", func(cs_one)), + ] +} diff --git a/lisp/env.rs b/lisp/env.rs new file mode 100644 index 000000000..27e77b424 --- /dev/null +++ b/lisp/env.rs @@ -0,0 +1,85 @@ +use std::cell::RefCell; +use std::rc::Rc; +//use std::collections::HashMap; +use fnv::FnvHashMap; + +use crate::types::MalErr::ErrString; +use crate::types::MalVal::{List, Nil, Sym, Vector}; +use crate::types::{error, MalErr, MalRet, MalVal}; + +#[derive(Debug)] +pub struct EnvStruct { + data: RefCell>, + pub outer: Option, +} + +pub type Env = Rc; + +// TODO: it would be nice to use impl here but it doesn't work on +// a deftype (i.e. Env) + +pub fn env_new(outer: Option) -> Env { + Rc::new(EnvStruct { + data: RefCell::new(FnvHashMap::default()), + outer: outer, + }) +} + +// TODO: mbinds and exprs as & types +pub fn env_bind(outer: Option, mbinds: MalVal, exprs: Vec) -> Result { + let env = env_new(outer); + match mbinds { + List(binds, _) | Vector(binds, _) => { + for (i, b) in binds.iter().enumerate() { + match b { + Sym(s) if s == "&" => { + env_set(&env, binds[i + 1].clone(), list!(exprs[i..].to_vec()))?; + break; + } + _ => { + env_set(&env, b.clone(), exprs[i].clone())?; + } + } + } + Ok(env) + } + _ => Err(ErrString("env_bind binds not List/Vector".to_string())), + } +} + +pub fn env_find(env: &Env, key: &str) -> Option { + match (env.data.borrow().contains_key(key), env.outer.clone()) { + (true, _) => Some(env.clone()), + (false, Some(o)) => env_find(&o, key), + _ => None, + } +} + +pub fn env_get(env: &Env, key: &MalVal) -> MalRet { + match key { + Sym(ref s) => match env_find(env, s) { + Some(e) => Ok(e + .data + .borrow() + .get(s) + .ok_or(ErrString(format!("'{}' not found", s)))? + .clone()), + _ => error(&format!("'{}' not found", s)), + }, + _ => error("Env.get called with non-Str"), + } +} + +pub fn env_set(env: &Env, key: MalVal, val: MalVal) -> MalRet { + match key { + Sym(ref s) => { + env.data.borrow_mut().insert(s.to_string(), val.clone()); + Ok(val) + } + _ => error("Env.set called with non-Str"), + } +} + +pub fn env_sets(env: &Env, key: &str, val: MalVal) { + env.data.borrow_mut().insert(key.to_string(), val); +} diff --git a/lisp/jubjub.lisp b/lisp/jubjub.lisp new file mode 100644 index 000000000..9fa1703df --- /dev/null +++ b/lisp/jubjub.lisp @@ -0,0 +1,70 @@ +;; public params +(def! a_u "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e") +(def! a_v "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891") +(def! b_u "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e") +(def! b_v "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891") +(def! a "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000") +(def! d "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1") +(def! one "0000000000000000000000000000000000000000000000000000000000000001") +(defzk! circuit ()) +;; U should be evaluated just once +(def! U (fn* [x1 y1 x2 y2] (* (+ x1 y1) (+ x2 y2)))) +(def! A (fn* [x1 y2] (* y2 x1))) +(def! B (fn* [y1 x2] (* x2 y1))) +(def! C (fn* [x1 y1 x2 y2] (* d (A x1 y2) (B y1 x2)))) +(def! P.x (fn* [x1 y1 x2 y2] (/ (+ (A x1 y2) (B y1 x2)) (+ one (C x1 y1 x2 y2))))) +(def! P.y (fn* [x1 y1 x2 y2] (/ (- (U x1 y1 x2 y2) (A x1 y2) (B y1 x2)) (+ one (C x1 y1 x2 y2))))) + + + +;; lc0 = bellman::LinearCombination::::zero(); +;; (lc0-args LinearCombination) + +;; (cs! circuit (lc0-args) (lc1-args) (lc2-args)) + +;; (lc-add-coeff 1 1) + +(def! jubjub-add (fn* [x1 y1 x2 y2] (cs! circuit ( + (add lc0 x1) + (add lc0 y1) + (add lc1 x2) + (add lc1 y2) + (add lc2 (U x1 y1 x2 y2)) + enforce +;; Compute P.x = (A + B) / (1 + C) + (add-one lc0) + (add lc0 (C x1 y1 x2 y2)) + (add lc1 (P.x x1 y1 x2 y2)) + (add lc1 (A x1 y2)) + (add lc1 (B y1 x2)) + enforce +;; Compute P.y = (U - A - B) / (1 - C) + (add-one lc0) + (sub lc0 (C x1 y1 x2 y2)) + (add lc1 (P.y x1 y1 x2 y2)) + (add lc2 (U x1 y1 x2 y2)) + (sub lc2 (A x1 y2)) + (sub lc2 (B y1 x2)) + enforce + )))) +(def! circuit (jubjub-add a_u a_v b_u b_v)) +;;(println circuit) +(def! circuit (cs! circuit ( + (public (P.x a_u a_v b_u b_v)) + (public (P.y a_u a_v b_u b_v)) + (add lc0 (P.x a_u a_v b_u b_v)) + (add-one lc1) + (add lc2 (P.x a_u a_v b_u b_v)) + enforce + (add lc0 (P.y a_u a_v b_u b_v)) + (add-one lc1) + (add lc2 (P.y a_u a_v b_u b_v)) + enforce + ))) +;;(println circuit) +;; contract exection +(def! circuit (cs! circuit ( + (params [a_u a_v b_u b_v]) + ))) + +(println circuit) diff --git a/lisp/lisp-cheat-sheet.png b/lisp/lisp-cheat-sheet.png new file mode 100644 index 000000000..ed929becf Binary files /dev/null and b/lisp/lisp-cheat-sheet.png differ diff --git a/lisp/lisp.rs b/lisp/lisp.rs new file mode 100644 index 000000000..c308b5232 --- /dev/null +++ b/lisp/lisp.rs @@ -0,0 +1,624 @@ +#![allow(non_snake_case)] + +use crate::types::LispCircuit; +use bellman::groth16::PreparedVerifyingKey; + +use simplelog::*; + +use bellman::{groth16}; +use bls12_381::Bls12; +use fnv::FnvHashMap; +use itertools::Itertools; +use rand::rngs::OsRng; +use std::time::Instant; +use std::{rc::Rc}; +use types::EnforceAllocation; + +#[macro_use] +extern crate clap; +#[macro_use] +extern crate lazy_static; +extern crate fnv; +extern crate itertools; +extern crate regex; + +#[macro_use] +mod types; +use crate::types::MalErr::{ErrMalVal, ErrString}; +use crate::types::MalVal::{Bool, Enforce, Func, Hash, List, MalFunc, Nil, Str, Sym, Vector}; +use crate::types::{error, format_error, MalArgs, MalErr, MalRet, MalVal}; +mod env; +mod printer; +mod reader; +use crate::env::{env_bind, env_find, env_get, env_new, env_set, env_sets, Env}; +#[macro_use] +mod core; + +pub const ZK_CIRCUIT_ENV_KEY: &str = "ZKC"; + +// read +fn read(str: &str) -> MalRet { + reader::read_str(str.to_string()) +} + +// eval + +fn qq_iter(elts: &MalArgs) -> MalVal { + let mut acc = list![]; + for elt in elts.iter().rev() { + if let List(v, _) = elt { + if v.len() == 2 { + if let Sym(ref s) = v[0] { + if s == "splice-unquote" { + acc = list![Sym("concat".to_string()), v[1].clone(), acc]; + continue; + } + } + } + } + acc = list![Sym("cons".to_string()), quasiquote(&elt), acc]; + } + return acc; +} + +fn quasiquote(ast: &MalVal) -> MalVal { + match ast { + List(v, _) => { + if v.len() == 2 { + if let Sym(ref s) = v[0] { + if s == "unquote" { + return v[1].clone(); + } + } + } + return qq_iter(&v); + } + Vector(v, _) => return list![Sym("vec".to_string()), qq_iter(&v)], + Hash(_, _) | Sym(_) => return list![Sym("quote".to_string()), ast.clone()], + _ => ast.clone(), + } +} + +fn is_macro_call(ast: &MalVal, env: &Env) -> Option<(MalVal, MalArgs)> { + match ast { + List(v, _) => match v[0] { + Sym(ref s) => match env_find(env, s) { + Some(e) => match env_get(&e, &v[0]) { + Ok(f @ MalFunc { is_macro: true, .. }) => Some((f, v[1..].to_vec())), + _ => None, + }, + _ => None, + }, + _ => None, + }, + _ => None, + } +} + +fn macroexpand(mut ast: MalVal, env: &Env) -> (bool, MalRet) { + let mut was_expanded = false; + while let Some((mf, args)) = is_macro_call(&ast, env) { + //println!("macroexpand 1: {:?}", ast); + ast = match mf.apply(args) { + Err(e) => return (false, Err(e)), + Ok(a) => a, + }; + //println!("macroexpand 2: {:?}", ast); + was_expanded = true; + } + (was_expanded, Ok(ast)) +} + +fn eval_ast(ast: &MalVal, env: &Env) -> MalRet { + match ast { + Sym(_) => Ok(env_get(&env, &ast)?), + List(v, _) => { + let mut lst: MalArgs = vec![]; + for a in v.iter() { + lst.push(eval(a.clone(), env.clone())?) + } + Ok(list!(lst)) + } + Vector(v, _) => { + let mut lst: MalArgs = vec![]; + for a in v.iter() { + lst.push(eval(a.clone(), env.clone())?) + } + Ok(vector!(lst)) + } + Hash(hm, _) => { + let mut new_hm: FnvHashMap = FnvHashMap::default(); + for (k, v) in hm.iter() { + new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?); + } + Ok(Hash(Rc::new(new_hm), Rc::new(Nil))) + } + _ => Ok(ast.clone()), + } +} + +fn eval(mut ast: MalVal, mut env: Env) -> MalRet { + let ret: MalRet; + + 'tco: loop { + ret = match ast.clone() { + List(l, _) => { + if l.len() == 0 { + return Ok(ast); + } + match macroexpand(ast.clone(), &env) { + (true, Ok(new_ast)) => { + ast = new_ast; + continue 'tco; + } + (_, Err(e)) => return Err(e), + _ => (), + } + + if l.len() == 0 { + return Ok(ast); + } + let a0 = &l[0]; + match a0 { + Sym(ref a0sym) if a0sym == "def!" => { + env_set(&env, l[1].clone(), eval(l[2].clone(), env.clone())?) + } + Sym(ref a0sym) if a0sym == "let*" => { + env = env_new(Some(env.clone())); + let (a1, a2) = (l[1].clone(), l[2].clone()); + match a1 { + List(ref binds, _) | Vector(ref binds, _) => { + for (b, e) in binds.iter().tuples() { + match b { + Sym(_) => { + let _ = env_set( + &env, + b.clone(), + eval(e.clone(), env.clone())?, + ); + } + _ => { + return error("let* with non-Sym binding"); + } + } + } + } + _ => { + return error("let* with non-List bindings"); + } + }; + ast = a2; + continue 'tco; + } + Sym(ref a0sym) if a0sym == "quote" => Ok(l[1].clone()), + Sym(ref a0sym) if a0sym == "quasiquoteexpand" => Ok(quasiquote(&l[1])), + Sym(ref a0sym) if a0sym == "quasiquote" => { + ast = quasiquote(&l[1]); + continue 'tco; + } + Sym(ref a0sym) if a0sym == "defmacro!" => { + let (a1, a2) = (l[1].clone(), l[2].clone()); + let r = eval(a2, env.clone())?; + match r { + MalFunc { + eval, + ast, + env, + params, + .. + } => Ok(env_set( + &env, + a1.clone(), + MalFunc { + eval: eval, + ast: ast.clone(), + env: env.clone(), + params: params.clone(), + is_macro: true, + meta: Rc::new(Nil), + }, + )?), + _ => error("set_macro on non-function"), + } + } + Sym(ref a0sym) if a0sym == "macroexpand" => { + match macroexpand(l[1].clone(), &env) { + (_, Ok(new_ast)) => Ok(new_ast), + (_, e) => return e, + } + } + Sym(ref a0sym) if a0sym == "try*" => match eval(l[1].clone(), env.clone()) { + Err(ref e) if l.len() >= 3 => { + let exc = match e { + ErrMalVal(mv) => mv.clone(), + ErrString(s) => Str(s.to_string()), + }; + match l[2].clone() { + List(c, _) => { + let catch_env = env_bind( + Some(env.clone()), + list!(vec![c[1].clone()]), + vec![exc], + )?; + eval(c[2].clone(), catch_env) + } + _ => error("invalid catch block"), + } + } + res => res, + }, + Sym(ref a0sym) if a0sym == "do" => { + match eval_ast(&list!(l[1..l.len() - 1].to_vec()), &env)? { + List(_, _) => { + ast = l.last().unwrap_or(&Nil).clone(); + continue 'tco; + } + _ => error("invalid do form"), + } + } + Sym(ref a0sym) if a0sym == "if" => { + let cond = eval(l[1].clone(), env.clone())?; + match cond { + Bool(false) | Nil if l.len() >= 4 => { + ast = l[3].clone(); + continue 'tco; + } + Bool(false) | Nil => Ok(Nil), + _ if l.len() >= 3 => { + ast = l[2].clone(); + continue 'tco; + } + _ => Ok(Nil), + } + } + + Sym(ref a0sym) if a0sym == "fn*" => { + let (a1, a2) = (l[1].clone(), l[2].clone()); + Ok(MalFunc { + eval: eval, + ast: Rc::new(a2), + env: env, + params: Rc::new(a1), + is_macro: false, + meta: Rc::new(Nil), + }) + } + Sym(ref a0sym) if a0sym == "eval" => { + ast = eval(l[1].clone(), env.clone())?; + while let Some(ref e) = env.clone().outer { + env = e.clone(); + } + continue 'tco; + } + Sym(ref a0sym) if a0sym == "setup" => { + let a1 = l[1].clone(); + // todo + ast = eval(a1.clone(), env.clone())?; + let _pvk = setup(a1.clone(), env.clone())?; + continue 'tco; + } + Sym(ref a0sym) if a0sym == "prove" => { + let a1 = l[1].clone(); + ast = eval(a1.clone(), env.clone())?; + prove(a1.clone(), env.clone()) + } + Sym(ref a0sym) if a0sym == "alloc-input" => { + let a1 = l[1].clone(); + let value = eval(l[2].clone(), env.clone())?; + let result = eval(value.clone(), env.clone())?; + let allocs = get_allocations(&env, "AllocationsInput"); + let mut new_hm: FnvHashMap = FnvHashMap::default(); + for (k, v) in allocs.iter() { + new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?); + } + new_hm.insert(a1.pr_str(false), result); + env_set( + &env, + Sym("AllocationsInput".to_string()), + Hash(Rc::new(new_hm), Rc::new(Nil)), + )?; + Ok(Nil) + } + Sym(ref a0sym) if a0sym == "alloc" => { + let a1 = l[1].clone(); + let value = eval(l[2].clone(), env.clone())?; + let result = eval(value.clone(), env.clone())?; + let allocs = get_allocations(&env, "Allocations"); + let mut new_hm: FnvHashMap = FnvHashMap::default(); + for (k, v) in allocs.iter() { + new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?); + } + new_hm.insert(a1.pr_str(false), result); + env_set( + &env, + Sym("Allocations".to_string()), + Hash(Rc::new(new_hm), Rc::new(Nil)), + )?; + Ok(Nil) + } + //Sym(ref a0sym) if a0sym == "verify" => { + Sym(ref a0sym) if a0sym == "enforce" => { + // here i'm considering that we always have tuple with only two elements + // also it's important to keep in mind for the sake of brevity of this v0 + // we will not allow calculation or any lisp evaluations inside the enforce + // it means that every symbol will be on allocations and we will do the + // find/replace on the bellman circuit, it's nasty v0 + let mut left_vec = vec![]; + let mut right_vec = vec![]; + let mut out_vec = vec![]; + // todo extract a macro for this + match l[1].clone() { + List(v, _) | Vector(v, _) => { + if let List(_, _) = &v.to_vec()[0] { + for ele in v.to_vec().iter() { + if let List(ele_vec, _) = ele { + left_vec.push(( + ele_vec[0].pr_str(false), + ele_vec[1].pr_str(false), + )); + } + } + } else { + left_vec.push((v[0].pr_str(false), v[1].pr_str(false))); + } + } + _ => {} + }; + match l[2].clone() { + List(v, _) | Vector(v, _) => { + if let List(_, _) = &v.to_vec()[0] { + for ele in v.to_vec().iter() { + if let List(ele_vec, _) = ele { + right_vec.push(( + ele_vec[0].pr_str(false), + ele_vec[1].pr_str(false), + )); + } + } + } else { + right_vec.push((v[0].pr_str(false), v[1].pr_str(false))); + } + } + _ => {} + }; + match l[3].clone() { + List(v, _) | Vector(v, _) => { + if let List(_, _) = &v.to_vec()[0] { + for ele in v.to_vec().iter() { + if let List(ele_vec, _) = ele { + out_vec.push(( + ele_vec[0].pr_str(false), + ele_vec[1].pr_str(false), + )); + } + } + } else { + out_vec.push((v[0].pr_str(false), v[1].pr_str(false))); + } + } + _ => {} + }; + let enforce = EnforceAllocation { + left: left_vec, + right: right_vec, + output: out_vec, + }; + let mut new_vec: Vec = vec![enforce]; + for value in get_enforce_allocs(&env).iter() { + new_vec.push(value.clone()); + } + env_set( + &env, + Sym("AllocationsEnforce".to_string()), + vector![vec![Enforce(Rc::new(new_vec))]], + ); + /* + println!("\n\nallocations {:?}", get_allocations(&env, "Allocations")); + println!( + "\n\nallocations input {:?}", + get_allocations(&env, "AllocationsInput") + ); + println!("\n\nallocations enforce {:?}", get_enforce_allocs(&env)); + */ + Ok(vector![vec![]]) + } + _ => match eval_ast(&ast, &env)? { + List(ref el, _) => { + let ref f = el[0].clone(); + let args = el[1..].to_vec(); + match f { + Func(_, _) => f.apply(args), + MalFunc { + ast: mast, + env: menv, + params, + .. + } => { + let a = &**mast; + let p = &**params; + env = env_bind(Some(menv.clone()), p.clone(), args)?; + ast = a.clone(); + continue 'tco; + } + _ => { + Ok(vector![el.to_vec()]) + + //error("call non-function") + } + } + } + _ => error("expected a list"), + }, + } + } + _ => eval_ast(&ast, &env), + }; + + break; + } // end 'tco loop + + ret +} + +pub fn get_enforce_allocs(env: &Env) -> Vec { + // todo need some cleanup + match env_find(env, "AllocationsEnforce") { + Some(e) => match env_get(&e, &Sym("AllocationsEnforce".to_string())) { + Ok(f) => { + if let Vector(val, _) = f { + if let Enforce(ret) = &val[0] { + ret.to_vec() + } else { + vec![] + } + } else { + vec![] + } + } + _ => vec![], + }, + _ => vec![], + } +} +pub fn get_allocations(env: &Env, key: &str) -> Rc> { + let alloc_hm: Rc> = Rc::new(FnvHashMap::default()); + match env_find(env, key) { + Some(e) => match env_get(&e, &Sym(key.to_string())) { + Ok(f) => { + if let Hash(allocs, _) = f { + allocs + } else { + alloc_hm + } + } + _ => alloc_hm, + }, + _ => alloc_hm, + } +} + +pub fn setup(_ast: MalVal, env: Env) -> Result, MalErr> { + let start = Instant::now(); + // Create parameters for our circuit. In a production deployment these would + // be generated securely using a multiparty computation. + let allocs_input = get_allocations(&env, "AllocationsInput"); + let allocs = get_allocations(&env, "Allocations"); + let enforce_allocs = get_enforce_allocs(&env); + + let c = LispCircuit { + params: vec![], + allocs: allocs.as_ref().clone(), + alloc_inputs: allocs_input.as_ref().clone(), + constraints: enforce_allocs, + env: env.clone(), + }; + // TODO move to another fn + let random_parameters = + groth16::generate_random_parameters::(c, &mut OsRng).unwrap(); + let pvk = groth16::prepare_verifying_key(&random_parameters.vk); + println!("Setup: [{:?}]", start.elapsed()); + + Ok(pvk) +} + +pub fn prove(_ast: MalVal, env: Env) -> MalRet { + // TODO remove it + let _quantity = bls12_381::Scalar::from(3); + + let allocs_input = get_allocations(&env, "AllocationsInput"); + let allocs = get_allocations(&env, "Allocations"); + let enforce_allocs = get_enforce_allocs(&env); + + let circuit = LispCircuit { + params: vec![], + allocs: allocs.as_ref().clone(), + alloc_inputs: allocs_input.as_ref().clone(), + constraints: enforce_allocs, + env: env.clone(), + }; + // Create an instance of our circuit (with the preimage as a witness). + // todo check if circuit.clone is valid + let params = { + let c = circuit.clone(); + groth16::generate_random_parameters::(c, &mut OsRng).unwrap() + }; + let start = Instant::now(); + // Create a Groth16 proof with our parameters. + let _proof = groth16::create_random_proof(circuit, ¶ms, &mut OsRng).unwrap(); + println!("Prove: [{:?}]", start.elapsed()); + Ok(MalVal::Nil) +} + +pub fn verify(_ast: &MalVal) -> MalRet { + let _public_input = vec![bls12_381::Scalar::from(27)]; + let start = Instant::now(); + // Check the proof! + //assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok()); + println!("Verify: [{:?}]", start.elapsed()); + Ok(MalVal::Nil) +} + +// print +fn print(ast: &MalVal) -> String { + ast.pr_str(true) +} + +fn rep(str: &str, env: &Env) -> Result { + let ast = read(str)?; + let exp = eval(ast, env.clone())?; + Ok(print(&exp)) +} + +fn main() -> Result<(), ()> { + let matches = clap_app!(zklisp => + (version: "0.1.0") + (author: "mileschet ") + (about: "A Lisp Interpreter for Zero Knowledge Virtual Machine") + (@subcommand load => + (about: "Load the file into the interpreter") + (@arg FILE: +required "Lisp Contract filename") + ) + ) + .get_matches(); + + CombinedLogger::init(vec![TermLogger::new( + LevelFilter::Debug, + Config::default(), + TerminalMode::Mixed, + ) + .unwrap()]) + .unwrap(); + + match matches.subcommand() { + Some(("load", matches)) => { + let file: String = matches.value_of("FILE").unwrap().parse().unwrap(); + repl_load(file)?; + } + _ => { + eprintln!("error: Invalid subcommand invoked"); + std::process::exit(-1); + } + } + + Ok(()) +} + +fn repl_load(file: String) -> Result<(), ()> { + let repl_env = env_new(None); + for (k, v) in core::ns() { + env_sets(&repl_env, k, v); + } + let _ = rep("(def! not (fn* (a) (if a false true)))", &repl_env); + let _ = rep( + "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))", + &repl_env, + ); + //let _ = rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", &repl_env); + match rep(&format!("(load-file \"{}\")", file), &repl_env) { + Ok(_) => std::process::exit(0), + Err(e) => { + println!("Error: {}", format_error(e)); + std::process::exit(1); + } + } +} diff --git a/lisp/new-cs.lisp b/lisp/new-cs.lisp new file mode 100644 index 000000000..bc33782e2 --- /dev/null +++ b/lisp/new-cs.lisp @@ -0,0 +1,38 @@ +(println "new-cs.lisp") + +( (let* [aux (scalar 3) + x (alloc "x" aux) + x2 (alloc "x2" (* aux aux)) + x3 (alloc "x3" (* aux (* aux aux))) + input (alloc-input "input" aux) + ] +(prove + (setup + ( + (enforce + ( + (scalar::one x) + (scalar::one x2) + ) + ;;(scalar::one::neg x) + (scalar::one x) + (scalar::one x2) + ) + + (enforce + (scalar::one x2) + (scalar::one x) + (scalar::one x3) + ) + + (enforce + (scalar::one input) + (scalar::one cs::one) + (scalar::one x3) + ) + ) + ) + ) +) +) +;; (println 'verify (MyCircuit (scalar 27))) diff --git a/lisp/new.lisp b/lisp/new.lisp new file mode 100644 index 000000000..64a10017d --- /dev/null +++ b/lisp/new.lisp @@ -0,0 +1,17 @@ +(def! x "73eda753299d7d483339d80809a1d80553bda402fffe5bfeffffffff00000000") +(def! one "0000000000000000000000000000000000000000000000000000000000000001") +(def! bits (unpack-bits x)) +(defzk! circuit ()) +(def! cvalues (map (fn* [b] (eval + (add lc0 one) + (sub lc0 b) + (add lc1 x) + enforce) + ) bits)) +(def! cs (concat cvalues (list + 'reset-coeff-lc + (sub lc0 x) + (add lc1 one) + 'enforce))) +(println "bit-dec") +(cs! circuit cs) diff --git a/lisp/printer.rs b/lisp/printer.rs new file mode 100644 index 000000000..1a9047c0e --- /dev/null +++ b/lisp/printer.rs @@ -0,0 +1,63 @@ +use crate::types::MalVal; +use crate::types::MalVal::{Atom, Bool, Func, Hash, Int, List, MalFunc, Nil, Str, Sym, Vector}; + +fn escape_str(s: &str) -> String { + s.chars() + .map(|c| match c { + '"' => "\\\"".to_string(), + '\n' => "\\n".to_string(), + '\\' => "\\\\".to_string(), + _ => c.to_string(), + }) + .collect::>() + .join("") +} + +impl MalVal { + pub fn pr_str(&self, print_readably: bool) -> String { + match self { + Nil => String::from("nil"), + Bool(true) => String::from("true"), + Bool(false) => String::from("false"), + Int(i) => format!("{}", i), + //Float(f) => format!("{}", f), + Str(s) => { + if s.starts_with("\u{29e}") { + format!(":{}", &s[2..]) + } else if print_readably { + format!("\"{}\"", escape_str(s)) + } else { + s.clone() + } + } + Sym(s) => s.clone(), + List(l, _) => pr_seq(&**l, print_readably, "(", ")", " "), + Vector(l, _) => pr_seq(&**l, print_readably, "[", "]", " "), + Hash(hm, _) => { + let l: Vec = hm + .iter() + .flat_map(|(k, v)| vec![Str(k.to_string()), v.clone()]) + .collect(); + pr_seq(&l, print_readably, "{", "}", " ") + } + Func(f, _) => format!("#", f), + MalFunc { + ast: a, params: p, .. + } => format!("(fn* {} {})", p.pr_str(true), a.pr_str(true)), + Atom(a) => format!("(atom {})", a.borrow().pr_str(true)), + MalVal::ZKScalar(a) => format!("{:?}", a), + i => format!("{:?}", i.pr_str(true)), + } + } +} + +pub fn pr_seq( + seq: &Vec, + print_readably: bool, + start: &str, + end: &str, + join: &str, +) -> String { + let strs: Vec = seq.iter().map(|x| x.pr_str(print_readably)).collect(); + format!("{}{}{}", start, strs.join(join), end) +} diff --git a/lisp/jj.rkt b/lisp/racket/jj.rkt similarity index 100% rename from lisp/jj.rkt rename to lisp/racket/jj.rkt diff --git a/lisp/zk.rkt b/lisp/racket/zk.rkt similarity index 100% rename from lisp/zk.rkt rename to lisp/racket/zk.rkt diff --git a/lisp/reader.rs b/lisp/reader.rs new file mode 100644 index 000000000..4355ff568 --- /dev/null +++ b/lisp/reader.rs @@ -0,0 +1,156 @@ +use regex::{Captures, Regex}; +use std::rc::Rc; + +use crate::types::MalErr::ErrString; +use crate::types::MalVal::{Bool, Int, List, Nil, Str, Sym, Vector}; +use crate::types::{error, hash_map, MalErr, MalRet, MalVal}; + +#[derive(Debug, Clone)] +struct Reader { + tokens: Vec, + pos: usize, +} + +impl Reader { + fn next(&mut self) -> Result { + self.pos = self.pos + 1; + Ok(self + .tokens + .get(self.pos - 1) + .ok_or(ErrString("underflow".to_string()))? + .to_string()) + } + fn peek(&self) -> Result { + Ok(self + .tokens + .get(self.pos) + .ok_or(ErrString("underflow".to_string()))? + .to_string()) + } +} + +fn tokenize(str: &str) -> Vec { + lazy_static! { + static ref RE: Regex = Regex::new( + r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"?|;.*|[^\s\[\]{}('"`,;)]+)"### + ) + .unwrap(); + } + + let mut res = vec![]; + for cap in RE.captures_iter(str) { + if cap[1].starts_with(";") { + continue; + } + res.push(String::from(&cap[1])); + } + res +} + +fn unescape_str(s: &str) -> String { + lazy_static! { + static ref RE: Regex = Regex::new(r#"\\(.)"#).unwrap(); + } + RE.replace_all(&s, |caps: &Captures| { + format!("{}", if &caps[1] == "n" { "\n" } else { &caps[1] }) + }) + .to_string() +} + +fn read_atom(rdr: &mut Reader) -> MalRet { + lazy_static! { + static ref INT_RE: Regex = Regex::new(r"^-?[0-9]+$").unwrap(); + static ref STR_RE: Regex = Regex::new(r#""(?:\\.|[^\\"])*""#).unwrap(); + } + let token = rdr.next()?; + match &token[..] { + "nil" => Ok(Nil), + "false" => Ok(Bool(false)), + "true" => Ok(Bool(true)), + _ => { + if INT_RE.is_match(&token) { + Ok(Int(token.parse().unwrap())) + } else if STR_RE.is_match(&token) { + Ok(Str(unescape_str(&token[1..token.len() - 1]))) + } else if token.starts_with("\"") { + error("expected '\"', got EOF") + } else if token.starts_with(":") { + Ok(Str(format!("\u{29e}{}", &token[1..]))) + } else { + Ok(Sym(token.to_string())) + } + } + } +} + +fn read_seq(rdr: &mut Reader, end: &str) -> MalRet { + let mut seq: Vec = vec![]; + rdr.next()?; + loop { + let token = match rdr.peek() { + Ok(t) => t, + Err(_) => return error(&format!("expected '{}', got EOF", end)), + }; + if token == end { + break; + } + seq.push(read_form(rdr)?) + } + let _ = rdr.next(); + match end { + ")" => Ok(list!(seq)), + "]" => Ok(vector!(seq)), + "}" => hash_map(seq), + _ => error("read_seq unknown end value"), + } +} + +fn read_form(rdr: &mut Reader) -> MalRet { + let token = rdr.peek()?; + match &token[..] { + "'" => { + let _ = rdr.next(); + Ok(list![Sym("quote".to_string()), read_form(rdr)?]) + } + "`" => { + let _ = rdr.next(); + Ok(list![Sym("quasiquote".to_string()), read_form(rdr)?]) + } + "~" => { + let _ = rdr.next(); + Ok(list![Sym("unquote".to_string()), read_form(rdr)?]) + } + "~@" => { + let _ = rdr.next(); + Ok(list![Sym("splice-unquote".to_string()), read_form(rdr)?]) + } + "^" => { + let _ = rdr.next(); + let meta = read_form(rdr)?; + Ok(list![Sym("with-meta".to_string()), read_form(rdr)?, meta]) + } + "@" => { + let _ = rdr.next(); + Ok(list![Sym("deref".to_string()), read_form(rdr)?]) + } + ")" => error("unexpected ')'"), + "(" => read_seq(rdr, ")"), + "]" => error("unexpected ']'"), + "[" => read_seq(rdr, "]"), + "}" => error("unexpected '}'"), + "{" => read_seq(rdr, "}"), + _ => read_atom(rdr), + } +} + +pub fn read_str(str: String) -> MalRet { + let tokens = tokenize(&str); + //println!("tokens: {:?}", tokens); + if tokens.len() == 0 { + return error("no input"); + } + read_form(&mut Reader { + pos: 0, + tokens: tokens, + }) +} diff --git a/lisp/run.sh b/lisp/run.sh new file mode 100755 index 000000000..b73687adb --- /dev/null +++ b/lisp/run.sh @@ -0,0 +1,2 @@ +#export RUST_BACKTRACE=full +cargo run --bin lisp load new-cs.lisp diff --git a/lisp/types.rs b/lisp/types.rs new file mode 100644 index 000000000..1f0f90d41 --- /dev/null +++ b/lisp/types.rs @@ -0,0 +1,360 @@ +use bellman::{ + gadgets::{ + Assignment, + }, + groth16, Circuit, ConstraintSystem, SynthesisError, +}; +use std::ops::{Add, AddAssign, MulAssign, SubAssign}; +use std::cell::RefCell; +use std::rc::Rc; +//use std::collections::HashMap; +use fnv::FnvHashMap; +use itertools::Itertools; + +use crate::env::{env_bind, Env}; +use crate::types::MalErr::{ErrMalVal, ErrString}; +use crate::types::MalVal::{Atom, Bool, Func, Hash, Int, List, MalFunc, Nil, Str, Sym, Vector}; +use bellman::Variable; +use bls12_381::Scalar; + +#[derive(Debug, Clone)] +pub struct Allocation { + pub symbol: String, + pub value: Scalar, +} + +#[derive(Debug, Clone)] +pub struct EnforceAllocation { + pub left: Vec<(String, String)>, + pub right: Vec<(String, String)>, + pub output: Vec<(String, String)>, +} + +#[derive(Debug, Clone)] +pub struct LispCircuit { + pub params: Vec>, + pub allocs: FnvHashMap, + pub alloc_inputs: FnvHashMap, + pub constraints: Vec, + pub env: Env, +} + +impl Circuit for LispCircuit { + fn synthesize>( + self, + cs: &mut CS, + ) -> Result<(), SynthesisError> { + let mut variables: FnvHashMap = FnvHashMap::default(); + + println!("Allocations\n"); + for (k, v) in &self.allocs { + if let MalVal::ZKScalar(val) = v { + println!("val {:?}", val); + let var = cs.alloc(|| "alloc", || Ok(*val))?; + variables.insert(k.to_string(), var); + } else { + println!("k {:?} v {:?}", k, v); + } + } + + println!("Allocations Input\n"); + for (k, v) in &self.alloc_inputs { + if let MalVal::ZKScalar(val) = v { + println!("val {:?}", val); + let var = cs.alloc_input(|| "alloc", || Ok(*val))?; + variables.insert(k.to_string(), var); + } else { + println!("k {:?} v {:?}", k, v); + } + } + + println!("Enforce Allocations\n"); + for alloc_value in &self.constraints { + println!("{:?}", alloc_value); + let coeff = bls12_381::Scalar::one(); + let mut left = bellman::LinearCombination::::zero(); + let mut right = bellman::LinearCombination::::zero(); + let mut output = bellman::LinearCombination::::zero(); + for values in alloc_value.left.iter() { + let (a, b) = values; + let mut val_b = CS::one(); + if b != "cs::one" { + val_b = *variables.get(b).unwrap(); + } + if a == "scalar::one" { + left = left + (coeff, val_b); + } else if a == "scalar::one::neg" { + left = left + (coeff.neg(), val_b); + } + } + + for values in alloc_value.right.iter() { + let (a, b) = values; + let mut val_b = CS::one(); + if b != "cs::one" { + val_b = *variables.get(b).unwrap(); + } + if a == "scalar::one" { + right = right + (coeff, val_b); + } else if a == "scalar::one::neg" { + right = right + (coeff.neg(), val_b); + } + } + + for values in alloc_value.output.iter() { + let (a, b) = values; + let mut val_b = CS::one(); + if b != "cs::one" { + val_b = *variables.get(b).unwrap(); + } + if a == "scalar::one" { + output = output + (coeff, val_b); + } else if a == "scalar::one::neg" { + output = output + (coeff.neg(), val_b); + } + } + + cs.enforce( + || "constraint", + |_| left.clone(), + |_| right.clone(), + |_| output.clone(), + ); + } + + Ok(()) + } +} + +#[derive(Debug, Clone)] +pub enum MalVal { + Nil, + Bool(bool), + Int(i64), + Str(String), + Sym(String), + List(Rc>, Rc), + Vector(Rc>, Rc), + Hash(Rc>, Rc), + Func(fn(MalArgs) -> MalRet, Rc), + MalFunc { + eval: fn(ast: MalVal, env: Env) -> MalRet, + ast: Rc, + env: Env, + params: Rc, + is_macro: bool, + meta: Rc, + }, + Atom(Rc>), + Zk(Rc), // TODO remote it + Enforce(Rc>), + ZKScalar(bls12_381::Scalar), +} + +#[derive(Debug)] +pub enum MalErr { + ErrString(String), + ErrMalVal(MalVal), +} + +pub type MalArgs = Vec; +pub type MalRet = Result; + +// type utility macros + +macro_rules! list { + ($seq:expr) => {{ + List(Rc::new($seq),Rc::new(Nil)) + }}; + [$($args:expr),*] => {{ + let v: Vec = vec![$($args),*]; + List(Rc::new(v),Rc::new(Nil)) + }} +} + +macro_rules! vector { + ($seq:expr) => {{ + Vector(Rc::new($seq),Rc::new(Nil)) + }}; + [$($args:expr),*] => {{ + let v: Vec = vec![$($args),*]; + Vector(Rc::new(v),Rc::new(Nil)) + }} +} + +// type utility functions + +pub fn error(s: &str) -> MalRet { + Err(ErrString(s.to_string())) +} + +pub fn format_error(e: MalErr) -> String { + match e { + ErrString(s) => s.clone(), + ErrMalVal(mv) => mv.pr_str(true), + } +} + +pub fn atom(mv: &MalVal) -> MalVal { + Atom(Rc::new(RefCell::new(mv.clone()))) +} + +impl MalVal { + pub fn keyword(&self) -> MalRet { + match self { + Str(s) if s.starts_with("\u{29e}") => Ok(Str(s.to_string())), + Str(s) => Ok(Str(format!("\u{29e}{}", s))), + _ => error("invalid type for keyword"), + } + } + + pub fn empty_q(&self) -> MalRet { + match self { + List(l, _) | Vector(l, _) => Ok(Bool(l.len() == 0)), + Nil => Ok(Bool(true)), + _ => error("invalid type for empty?"), + } + } + + pub fn count(&self) -> MalRet { + match self { + List(l, _) | Vector(l, _) => Ok(Int(l.len() as i64)), + Nil => Ok(Int(0)), + _ => error("invalid type for count"), + } + } + + pub fn apply(&self, args: MalArgs) -> MalRet { + match *self { + Func(f, _) => f(args), + MalFunc { + eval, + ref ast, + ref env, + ref params, + .. + } => { + let a = &**ast; + let p = &**params; + let fn_env = env_bind(Some(env.clone()), p.clone(), args)?; + Ok(eval(a.clone(), fn_env)?) + } + _ => error("attempt to call non-function"), + } + } + + pub fn keyword_q(&self) -> bool { + match self { + Str(s) if s.starts_with("\u{29e}") => true, + _ => false, + } + } + + pub fn deref(&self) -> MalRet { + match self { + Atom(a) => Ok(a.borrow().clone()), + _ => error("attempt to deref a non-Atom"), + } + } + + pub fn reset_bang(&self, new: &MalVal) -> MalRet { + match self { + Atom(a) => { + *a.borrow_mut() = new.clone(); + Ok(new.clone()) + } + _ => error("attempt to reset! a non-Atom"), + } + } + + pub fn swap_bang(&self, args: &MalArgs) -> MalRet { + match self { + Atom(a) => { + let f = &args[0]; + let mut fargs = args[1..].to_vec(); + fargs.insert(0, a.borrow().clone()); + *a.borrow_mut() = f.apply(fargs)?; + Ok(a.borrow().clone()) + } + _ => error("attempt to swap! a non-Atom"), + } + } + + pub fn get_meta(&self) -> MalRet { + match self { + List(_, meta) | Vector(_, meta) | Hash(_, meta) => Ok((&**meta).clone()), + Func(_, meta) => Ok((&**meta).clone()), + MalFunc { meta, .. } => Ok((&**meta).clone()), + _ => error("meta not supported by type"), + } + } + + pub fn with_meta(&mut self, new_meta: &MalVal) -> MalRet { + match self { + List(_, ref mut meta) + | Vector(_, ref mut meta) + | Hash(_, ref mut meta) + | Func(_, ref mut meta) + | MalFunc { ref mut meta, .. } => { + *meta = Rc::new((&*new_meta).clone()); + } + _ => return error("with-meta not supported by type"), + }; + Ok(self.clone()) + } +} + +impl PartialEq for MalVal { + fn eq(&self, other: &MalVal) -> bool { + match (self, other) { + (Nil, Nil) => true, + (Bool(ref a), Bool(ref b)) => a == b, + (Int(ref a), Int(ref b)) => a == b, + (Str(ref a), Str(ref b)) => a == b, + (Sym(ref a), Sym(ref b)) => a == b, + (List(ref a, _), List(ref b, _)) + | (Vector(ref a, _), Vector(ref b, _)) + | (List(ref a, _), Vector(ref b, _)) + | (Vector(ref a, _), List(ref b, _)) => a == b, + (Hash(ref a, _), Hash(ref b, _)) => a == b, + (MalFunc { .. }, MalFunc { .. }) => false, + _ => false, + } + } +} + +pub fn func(f: fn(MalArgs) -> MalRet) -> MalVal { + Func(f, Rc::new(Nil)) +} + +pub fn _assoc(mut hm: FnvHashMap, kvs: MalArgs) -> MalRet { + if kvs.len() % 2 != 0 { + return error("odd number of elements"); + } + for (k, v) in kvs.iter().tuples() { + match k { + Str(s) => { + hm.insert(s.to_string(), v.clone()); + } + _ => return error("key is not string"), + } + } + Ok(Hash(Rc::new(hm), Rc::new(Nil))) +} + +pub fn _dissoc(mut hm: FnvHashMap, ks: MalArgs) -> MalRet { + for k in ks.iter() { + match k { + Str(ref s) => { + hm.remove(s); + } + _ => return error("key is not string"), + } + } + Ok(Hash(Rc::new(hm), Rc::new(Nil))) +} + +pub fn hash_map(kvs: MalArgs) -> MalRet { + let hm: FnvHashMap = FnvHashMap::default(); + _assoc(hm, kvs) +} diff --git a/src/bin/mimc.rs b/src/bin/mimc.rs index f79f94368..ecff260b3 100644 --- a/src/bin/mimc.rs +++ b/src/bin/mimc.rs @@ -1,6 +1,6 @@ use bls12_381::Scalar; -use ff::{Field, PrimeField}; -use sapvi::{BlsStringConversion, Decodable, ZKContract}; +use ff::{Field}; +use sapvi::{Decodable, ZKContract}; use std::fs::File; use std::ops::{Add, AddAssign, MulAssign, Neg, SubAssign}; use std::time::Instant; diff --git a/src/bin/mimc_constants.rs b/src/bin/mimc_constants.rs index e80fa3858..3fdf75e99 100644 --- a/src/bin/mimc_constants.rs +++ b/src/bin/mimc_constants.rs @@ -324,3 +324,6 @@ pub fn mimc_constants() -> Vec<&'static str> { "597cdd384abdad1beccc73fb39f74a18eb44d056951d602c2ef6ef6448fc5626", ] } + +fn main() { +} diff --git a/src/bin/mint.rs b/src/bin/mint.rs index 0ddc932c0..f0dae9305 100644 --- a/src/bin/mint.rs +++ b/src/bin/mint.rs @@ -1,10 +1,10 @@ -use sapvi::{BlsStringConversion, Decodable, ZKContract}; +use sapvi::{Decodable, ZKContract}; use std::fs::File; use std::time::Instant; use bls12_381::Scalar; use ff::{Field, PrimeField}; -use group::{Curve, Group, GroupEncoding}; +use group::{Curve, Group}; use rand::rngs::OsRng; type Result = std::result::Result; @@ -13,7 +13,7 @@ type Result = std::result::Result; fn unpack(value: F) -> Vec { let mut bits = Vec::new(); print!("Unpack: "); - for (i, bit) in value.to_le_bits().into_iter().cloned().enumerate() { + for (_i, bit) in value.to_le_bits().into_iter().cloned().enumerate() { match bit { true => bits.push(Scalar::one()), false => bits.push(Scalar::zero()), diff --git a/src/bls_extensions.rs b/src/bls_extensions.rs index ea9fa9eac..b99d4a70d 100644 --- a/src/bls_extensions.rs +++ b/src/bls_extensions.rs @@ -5,77 +5,77 @@ use crate::error::{Error, Result}; use crate::serial::{Decodable, Encodable, ReadExt, WriteExt}; macro_rules! from_slice { - ($data:expr, $len:literal) => {{ - let mut array = [0; $len]; - // panics if not enough data - let bytes = &$data[..array.len()]; - array.copy_from_slice(bytes); - array - }}; +($data:expr, $len:literal) => {{ +let mut array = [0; $len]; +// panics if not enough data +let bytes = &$data[..array.len()]; +array.copy_from_slice(bytes); +array +}}; } pub trait BlsStringConversion { - fn to_string(&self) -> String; - fn from_string(object: &str) -> Self; +fn to_string(&self) -> String; +fn from_string(object: &str) -> Self; } impl BlsStringConversion for bls::Scalar { - fn to_string(&self) -> String { - let mut bytes = self.to_bytes(); - bytes.reverse(); - hex::encode(bytes) - } - fn from_string(object: &str) -> Self { - let mut bytes = from_slice!(&hex::decode(object).unwrap(), 32); - bytes.reverse(); - bls::Scalar::from_bytes(&bytes).unwrap() - } +fn to_string(&self) -> String { +let mut bytes = self.to_bytes(); +bytes.reverse(); +hex::encode(bytes) +} +fn from_string(object: &str) -> Self { +let mut bytes = from_slice!(&hex::decode(object).unwrap(), 32); +bytes.reverse(); +bls::Scalar::from_bytes(&bytes).unwrap() +} } macro_rules! serialization_bls { - ($type:ty, $to_x:ident, $from_x:ident, $size:literal) => { - impl Encodable for $type { - fn encode(&self, mut s: S) -> Result { - let data = self.$to_x(); - assert_eq!(data.len(), $size); - s.write_slice(&data)?; - Ok(data.len()) - } - } +($type:ty, $to_x:ident, $from_x:ident, $size:literal) => { +impl Encodable for $type { +fn encode(&self, mut s: S) -> Result { +let data = self.$to_x(); +assert_eq!(data.len(), $size); +s.write_slice(&data)?; +Ok(data.len()) +} +} - impl Decodable for $type { - fn decode(mut d: D) -> Result { - let mut slice = [0u8; $size]; - d.read_slice(&mut slice)?; - let result = Self::$from_x(&slice); - if bool::from(result.is_none()) { - return Err(Error::ParseFailed("$t conversion from slice failed")); - } - Ok(result.unwrap()) - } - } - }; +impl Decodable for $type { +fn decode(mut d: D) -> Result { +let mut slice = [0u8; $size]; +d.read_slice(&mut slice)?; +let result = Self::$from_x(&slice); +if bool::from(result.is_none()) { +return Err(Error::ParseFailed("$t conversion from slice failed")); +} +Ok(result.unwrap()) +} +} +}; } serialization_bls!(bls::Scalar, to_bytes, from_bytes, 32); macro_rules! make_serialize_deserialize_test { - ($name:ident, $type:ty, $default_func:ident) => { - #[test] - fn $name() { - let point = <$type>::$default_func(); +($name:ident, $type:ty, $default_func:ident) => { +#[test] +fn $name() { +let point = <$type>::$default_func(); - let mut data: Vec = vec![]; - let result = point.encode(&mut data); - assert!(result.is_ok()); +let mut data: Vec = vec![]; +let result = point.encode(&mut data); +assert!(result.is_ok()); - let point2 = <$type>::decode(&data[..]); - assert!(point2.is_ok()); - let point2 = point2.unwrap(); +let point2 = <$type>::decode(&data[..]); +assert!(point2.is_ok()); +let point2 = point2.unwrap(); - assert_eq!(point, point2); - } - }; +assert_eq!(point, point2); +} +}; } make_serialize_deserialize_test!(serial_test_scalar, bls::Scalar, zero); diff --git a/src/old/basic_minimal.rs b/src/old/basic_minimal.rs index 523baef92..610d33a52 100644 --- a/src/old/basic_minimal.rs +++ b/src/old/basic_minimal.rs @@ -1,16 +1,15 @@ use bellman::{ gadgets::{ - boolean::{AllocatedBit, Boolean}, - multipack, num, Assignment, + Assignment, }, groth16, Circuit, ConstraintSystem, SynthesisError, }; use bls12_381::Bls12; -use bls12_381::Scalar; -use ff::{Field, PrimeField}; -use group::Curve; + +use ff::{Field}; + use rand::rngs::OsRng; -use std::ops::{MulAssign, Neg, SubAssign}; + pub const CRH_IVK_PERSONALIZATION: &[u8; 8] = b"Zcashivk"; @@ -105,8 +104,6 @@ fn main() { let proof = groth16::create_random_proof(c, ¶ms, &mut OsRng).unwrap(); println!("Prove: [{:?}]", start.elapsed()); - let start = Instant::now(); - let public_input = vec![bls12_381::Scalar::from(27)]; let start = Instant::now(); diff --git a/src/serial.rs b/src/serial.rs index 814c7caa8..1dc37a68f 100644 --- a/src/serial.rs +++ b/src/serial.rs @@ -9,185 +9,185 @@ use crate::error::{Error, Result}; /// Encode an object into a vector pub fn serialize(data: &T) -> Vec { - let mut encoder = Vec::new(); - let len = data.encode(&mut encoder).unwrap(); - assert_eq!(len, encoder.len()); - encoder +let mut encoder = Vec::new(); +let len = data.encode(&mut encoder).unwrap(); +assert_eq!(len, encoder.len()); +encoder } /// Encode an object into a hex-encoded string pub fn serialize_hex(data: &T) -> String { - hex::encode(serialize(data)) +hex::encode(serialize(data)) } /// Deserialize an object from a vector, will error if said deserialization /// doesn't consume the entire vector. pub fn deserialize(data: &[u8]) -> Result { - let (rv, consumed) = deserialize_partial(data)?; +let (rv, consumed) = deserialize_partial(data)?; - // Fail if data are not consumed entirely. - if consumed == data.len() { - Ok(rv) - } else { - Err(Error::ParseFailed( - "data not consumed entirely when explicitly deserializing", - )) - } +// Fail if data are not consumed entirely. +if consumed == data.len() { +Ok(rv) +} else { +Err(Error::ParseFailed( +"data not consumed entirely when explicitly deserializing", +)) +} } /// Deserialize an object from a vector, but will not report an error if said deserialization /// doesn't consume the entire vector. pub fn deserialize_partial(data: &[u8]) -> Result<(T, usize)> { - let mut decoder = Cursor::new(data); - let rv = Decodable::decode(&mut decoder)?; - let consumed = decoder.position() as usize; +let mut decoder = Cursor::new(data); +let rv = Decodable::decode(&mut decoder)?; +let consumed = decoder.position() as usize; - Ok((rv, consumed)) +Ok((rv, consumed)) } /// Extensions of `Write` to encode data as per Bitcoin consensus pub trait WriteExt { - /// Output a 64-bit uint - fn write_u64(&mut self, v: u64) -> Result<()>; - /// Output a 32-bit uint - fn write_u32(&mut self, v: u32) -> Result<()>; - /// Output a 16-bit uint - fn write_u16(&mut self, v: u16) -> Result<()>; - /// Output a 8-bit uint - fn write_u8(&mut self, v: u8) -> Result<()>; +/// Output a 64-bit uint +fn write_u64(&mut self, v: u64) -> Result<()>; +/// Output a 32-bit uint +fn write_u32(&mut self, v: u32) -> Result<()>; +/// Output a 16-bit uint +fn write_u16(&mut self, v: u16) -> Result<()>; +/// Output a 8-bit uint +fn write_u8(&mut self, v: u8) -> Result<()>; - /// Output a 64-bit int - fn write_i64(&mut self, v: i64) -> Result<()>; - /// Output a 32-bit int - fn write_i32(&mut self, v: i32) -> Result<()>; - /// Output a 16-bit int - fn write_i16(&mut self, v: i16) -> Result<()>; - /// Output a 8-bit int - fn write_i8(&mut self, v: i8) -> Result<()>; +/// Output a 64-bit int +fn write_i64(&mut self, v: i64) -> Result<()>; +/// Output a 32-bit int +fn write_i32(&mut self, v: i32) -> Result<()>; +/// Output a 16-bit int +fn write_i16(&mut self, v: i16) -> Result<()>; +/// Output a 8-bit int +fn write_i8(&mut self, v: i8) -> Result<()>; - /// Output a boolean - fn write_bool(&mut self, v: bool) -> Result<()>; +/// Output a boolean +fn write_bool(&mut self, v: bool) -> Result<()>; - /// Output a byte slice - fn write_slice(&mut self, v: &[u8]) -> Result<()>; +/// Output a byte slice +fn write_slice(&mut self, v: &[u8]) -> Result<()>; } /// Extensions of `Read` to decode data as per Bitcoin consensus pub trait ReadExt { - /// Read a 64-bit uint - fn read_u64(&mut self) -> Result; - /// Read a 32-bit uint - fn read_u32(&mut self) -> Result; - /// Read a 16-bit uint - fn read_u16(&mut self) -> Result; - /// Read a 8-bit uint - fn read_u8(&mut self) -> Result; +/// Read a 64-bit uint +fn read_u64(&mut self) -> Result; +/// Read a 32-bit uint +fn read_u32(&mut self) -> Result; +/// Read a 16-bit uint +fn read_u16(&mut self) -> Result; +/// Read a 8-bit uint +fn read_u8(&mut self) -> Result; - /// Read a 64-bit int - fn read_i64(&mut self) -> Result; - /// Read a 32-bit int - fn read_i32(&mut self) -> Result; - /// Read a 16-bit int - fn read_i16(&mut self) -> Result; - /// Read a 8-bit int - fn read_i8(&mut self) -> Result; +/// Read a 64-bit int +fn read_i64(&mut self) -> Result; +/// Read a 32-bit int +fn read_i32(&mut self) -> Result; +/// Read a 16-bit int +fn read_i16(&mut self) -> Result; +/// Read a 8-bit int +fn read_i8(&mut self) -> Result; - /// Read a boolean - fn read_bool(&mut self) -> Result; +/// Read a boolean +fn read_bool(&mut self) -> Result; - /// Read a byte slice - fn read_slice(&mut self, slice: &mut [u8]) -> Result<()>; +/// Read a byte slice +fn read_slice(&mut self, slice: &mut [u8]) -> Result<()>; } macro_rules! encoder_fn { - ($name:ident, $val_type:ty, $writefn:ident) => { - #[inline] - fn $name(&mut self, v: $val_type) -> Result<()> { - self.write_all(&endian::$writefn(v)).map_err(Error::Io) - } - }; +($name:ident, $val_type:ty, $writefn:ident) => { +#[inline] +fn $name(&mut self, v: $val_type) -> Result<()> { +self.write_all(&endian::$writefn(v)).map_err(Error::Io) +} +}; } macro_rules! decoder_fn { - ($name:ident, $val_type:ty, $readfn:ident, $byte_len: expr) => { - #[inline] - fn $name(&mut self) -> Result<$val_type> { - assert_eq!(::std::mem::size_of::<$val_type>(), $byte_len); // size_of isn't a constfn in 1.22 - let mut val = [0; $byte_len]; - self.read_exact(&mut val[..]).map_err(Error::Io)?; - Ok(endian::$readfn(&val)) - } - }; +($name:ident, $val_type:ty, $readfn:ident, $byte_len: expr) => { +#[inline] +fn $name(&mut self) -> Result<$val_type> { +assert_eq!(::std::mem::size_of::<$val_type>(), $byte_len); // size_of isn't a constfn in 1.22 +let mut val = [0; $byte_len]; +self.read_exact(&mut val[..]).map_err(Error::Io)?; +Ok(endian::$readfn(&val)) +} +}; } impl WriteExt for W { - encoder_fn!(write_u64, u64, u64_to_array_le); - encoder_fn!(write_u32, u32, u32_to_array_le); - encoder_fn!(write_u16, u16, u16_to_array_le); - encoder_fn!(write_i64, i64, i64_to_array_le); - encoder_fn!(write_i32, i32, i32_to_array_le); - encoder_fn!(write_i16, i16, i16_to_array_le); +encoder_fn!(write_u64, u64, u64_to_array_le); +encoder_fn!(write_u32, u32, u32_to_array_le); +encoder_fn!(write_u16, u16, u16_to_array_le); +encoder_fn!(write_i64, i64, i64_to_array_le); +encoder_fn!(write_i32, i32, i32_to_array_le); +encoder_fn!(write_i16, i16, i16_to_array_le); - #[inline] - fn write_i8(&mut self, v: i8) -> Result<()> { - self.write_all(&[v as u8]).map_err(Error::Io) - } - #[inline] - fn write_u8(&mut self, v: u8) -> Result<()> { - self.write_all(&[v]).map_err(Error::Io) - } - #[inline] - fn write_bool(&mut self, v: bool) -> Result<()> { - self.write_all(&[v as u8]).map_err(Error::Io) - } - #[inline] - fn write_slice(&mut self, v: &[u8]) -> Result<()> { - self.write_all(v).map_err(Error::Io) - } +#[inline] +fn write_i8(&mut self, v: i8) -> Result<()> { +self.write_all(&[v as u8]).map_err(Error::Io) +} +#[inline] +fn write_u8(&mut self, v: u8) -> Result<()> { +self.write_all(&[v]).map_err(Error::Io) +} +#[inline] +fn write_bool(&mut self, v: bool) -> Result<()> { +self.write_all(&[v as u8]).map_err(Error::Io) +} +#[inline] +fn write_slice(&mut self, v: &[u8]) -> Result<()> { +self.write_all(v).map_err(Error::Io) +} } impl ReadExt for R { - decoder_fn!(read_u64, u64, slice_to_u64_le, 8); - decoder_fn!(read_u32, u32, slice_to_u32_le, 4); - decoder_fn!(read_u16, u16, slice_to_u16_le, 2); - decoder_fn!(read_i64, i64, slice_to_i64_le, 8); - decoder_fn!(read_i32, i32, slice_to_i32_le, 4); - decoder_fn!(read_i16, i16, slice_to_i16_le, 2); +decoder_fn!(read_u64, u64, slice_to_u64_le, 8); +decoder_fn!(read_u32, u32, slice_to_u32_le, 4); +decoder_fn!(read_u16, u16, slice_to_u16_le, 2); +decoder_fn!(read_i64, i64, slice_to_i64_le, 8); +decoder_fn!(read_i32, i32, slice_to_i32_le, 4); +decoder_fn!(read_i16, i16, slice_to_i16_le, 2); - #[inline] - fn read_u8(&mut self) -> Result { - let mut slice = [0u8; 1]; - self.read_exact(&mut slice)?; - Ok(slice[0]) - } - #[inline] - fn read_i8(&mut self) -> Result { - let mut slice = [0u8; 1]; - self.read_exact(&mut slice)?; - Ok(slice[0] as i8) - } - #[inline] - fn read_bool(&mut self) -> Result { - ReadExt::read_i8(self).map(|bit| bit != 0) - } - #[inline] - fn read_slice(&mut self, slice: &mut [u8]) -> Result<()> { - self.read_exact(slice).map_err(Error::Io) - } +#[inline] +fn read_u8(&mut self) -> Result { +let mut slice = [0u8; 1]; +self.read_exact(&mut slice)?; +Ok(slice[0]) +} +#[inline] +fn read_i8(&mut self) -> Result { +let mut slice = [0u8; 1]; +self.read_exact(&mut slice)?; +Ok(slice[0] as i8) +} +#[inline] +fn read_bool(&mut self) -> Result { +ReadExt::read_i8(self).map(|bit| bit != 0) +} +#[inline] +fn read_slice(&mut self, slice: &mut [u8]) -> Result<()> { +self.read_exact(slice).map_err(Error::Io) +} } /// Data which can be encoded in a consensus-consistent way pub trait Encodable { - /// Encode an object with a well-defined format, should only ever error if - /// the underlying `Write` errors. Returns the number of bytes written on - /// success - fn encode(&self, e: W) -> Result; +/// Encode an object with a well-defined format, should only ever error if +/// the underlying `Write` errors. Returns the number of bytes written on +/// success +fn encode(&self, e: W) -> Result; } /// Data which can be encoded in a consensus-consistent way pub trait Decodable: Sized { - /// Decode an object with a well-defined format - fn decode(d: D) -> Result; +/// Decode an object with a well-defined format +fn decode(d: D) -> Result; } #[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Debug)] @@ -195,21 +195,21 @@ pub struct VarInt(pub u64); // Primitive types macro_rules! impl_int_encodable { - ($ty:ident, $meth_dec:ident, $meth_enc:ident) => { - impl Decodable for $ty { - #[inline] - fn decode(mut d: D) -> Result { - ReadExt::$meth_dec(&mut d).map($ty::from_le) - } - } - impl Encodable for $ty { - #[inline] - fn encode(&self, mut s: S) -> Result { - s.$meth_enc(self.to_le())?; - Ok(mem::size_of::<$ty>()) - } - } - }; +($ty:ident, $meth_dec:ident, $meth_enc:ident) => { +impl Decodable for $ty { +#[inline] +fn decode(mut d: D) -> Result { +ReadExt::$meth_dec(&mut d).map($ty::from_le) +} +} +impl Encodable for $ty { +#[inline] +fn encode(&self, mut s: S) -> Result { +s.$meth_enc(self.to_le())?; +Ok(mem::size_of::<$ty>()) +} +} +}; } impl_int_encodable!(u8, read_u8, write_u8); @@ -222,156 +222,156 @@ impl_int_encodable!(i32, read_i32, write_i32); impl_int_encodable!(i64, read_i64, write_i64); impl VarInt { - /// Gets the length of this VarInt when encoded. - /// Returns 1 for 0...0xFC, 3 for 0xFD...(2^16-1), 5 for 0x10000...(2^32-1), - /// and 9 otherwise. - #[inline] - pub fn len(&self) -> usize { - match self.0 { - 0..=0xFC => 1, - 0xFD..=0xFFFF => 3, - 0x10000..=0xFFFFFFFF => 5, - _ => 9, - } - } +/// Gets the length of this VarInt when encoded. +/// Returns 1 for 0...0xFC, 3 for 0xFD...(2^16-1), 5 for 0x10000...(2^32-1), +/// and 9 otherwise. +#[inline] +pub fn len(&self) -> usize { +match self.0 { +0..=0xFC => 1, +0xFD..=0xFFFF => 3, +0x10000..=0xFFFFFFFF => 5, +_ => 9, +} +} } impl Encodable for VarInt { - #[inline] - fn encode(&self, mut s: S) -> Result { - match self.0 { - 0..=0xFC => { - (self.0 as u8).encode(s)?; - Ok(1) - } - 0xFD..=0xFFFF => { - s.write_u8(0xFD)?; - (self.0 as u16).encode(s)?; - Ok(3) - } - 0x10000..=0xFFFFFFFF => { - s.write_u8(0xFE)?; - (self.0 as u32).encode(s)?; - Ok(5) - } - _ => { - s.write_u8(0xFF)?; - (self.0 as u64).encode(s)?; - Ok(9) - } - } - } +#[inline] +fn encode(&self, mut s: S) -> Result { +match self.0 { +0..=0xFC => { +(self.0 as u8).encode(s)?; +Ok(1) +} +0xFD..=0xFFFF => { +s.write_u8(0xFD)?; +(self.0 as u16).encode(s)?; +Ok(3) +} +0x10000..=0xFFFFFFFF => { +s.write_u8(0xFE)?; +(self.0 as u32).encode(s)?; +Ok(5) +} +_ => { +s.write_u8(0xFF)?; +(self.0 as u64).encode(s)?; +Ok(9) +} +} +} } impl Decodable for VarInt { - #[inline] - fn decode(mut d: D) -> Result { - let n = ReadExt::read_u8(&mut d)?; - match n { - 0xFF => { - let x = ReadExt::read_u64(&mut d)?; - if x < 0x100000000 { - Err(self::Error::NonMinimalVarInt) - } else { - Ok(VarInt(x)) - } - } - 0xFE => { - let x = ReadExt::read_u32(&mut d)?; - if x < 0x10000 { - Err(self::Error::NonMinimalVarInt) - } else { - Ok(VarInt(x as u64)) - } - } - 0xFD => { - let x = ReadExt::read_u16(&mut d)?; - if x < 0xFD { - Err(self::Error::NonMinimalVarInt) - } else { - Ok(VarInt(x as u64)) - } - } - n => Ok(VarInt(n as u64)), - } - } +#[inline] +fn decode(mut d: D) -> Result { +let n = ReadExt::read_u8(&mut d)?; +match n { +0xFF => { +let x = ReadExt::read_u64(&mut d)?; +if x < 0x100000000 { +Err(self::Error::NonMinimalVarInt) +} else { +Ok(VarInt(x)) +} +} +0xFE => { +let x = ReadExt::read_u32(&mut d)?; +if x < 0x10000 { +Err(self::Error::NonMinimalVarInt) +} else { +Ok(VarInt(x as u64)) +} +} +0xFD => { +let x = ReadExt::read_u16(&mut d)?; +if x < 0xFD { +Err(self::Error::NonMinimalVarInt) +} else { +Ok(VarInt(x as u64)) +} +} +n => Ok(VarInt(n as u64)), +} +} } // Booleans impl Encodable for bool { - #[inline] - fn encode(&self, mut s: S) -> Result { - s.write_bool(*self)?; - Ok(1) - } +#[inline] +fn encode(&self, mut s: S) -> Result { +s.write_bool(*self)?; +Ok(1) +} } impl Decodable for bool { - #[inline] - fn decode(mut d: D) -> Result { - ReadExt::read_bool(&mut d) - } +#[inline] +fn decode(mut d: D) -> Result { +ReadExt::read_bool(&mut d) +} } // Strings impl Encodable for String { - #[inline] - fn encode(&self, mut s: S) -> Result { - let b = self.as_bytes(); - let vi_len = VarInt(b.len() as u64).encode(&mut s)?; - s.write_slice(&b)?; - Ok(vi_len + b.len()) - } +#[inline] +fn encode(&self, mut s: S) -> Result { +let b = self.as_bytes(); +let vi_len = VarInt(b.len() as u64).encode(&mut s)?; +s.write_slice(&b)?; +Ok(vi_len + b.len()) +} } impl Decodable for String { - #[inline] - fn decode(d: D) -> Result { - String::from_utf8(Decodable::decode(d)?) - .map_err(|_| self::Error::ParseFailed("String was not valid UTF8")) - } +#[inline] +fn decode(d: D) -> Result { +String::from_utf8(Decodable::decode(d)?) +.map_err(|_| self::Error::ParseFailed("String was not valid UTF8")) +} } // Cow<'static, str> impl Encodable for Cow<'static, str> { - #[inline] - fn encode(&self, mut s: S) -> Result { - let b = self.as_bytes(); - let vi_len = VarInt(b.len() as u64).encode(&mut s)?; - s.write_slice(&b)?; - Ok(vi_len + b.len()) - } +#[inline] +fn encode(&self, mut s: S) -> Result { +let b = self.as_bytes(); +let vi_len = VarInt(b.len() as u64).encode(&mut s)?; +s.write_slice(&b)?; +Ok(vi_len + b.len()) +} } impl Decodable for Cow<'static, str> { - #[inline] - fn decode(d: D) -> Result> { - String::from_utf8(Decodable::decode(d)?) - .map_err(|_| self::Error::ParseFailed("String was not valid UTF8")) - .map(Cow::Owned) - } +#[inline] +fn decode(d: D) -> Result> { +String::from_utf8(Decodable::decode(d)?) +.map_err(|_| self::Error::ParseFailed("String was not valid UTF8")) +.map(Cow::Owned) +} } // Arrays macro_rules! impl_array { - ( $size:expr ) => { - impl Encodable for [u8; $size] { - #[inline] - fn encode(&self, mut s: S) -> Result { - s.write_slice(&self[..])?; - Ok(self.len()) - } - } +( $size:expr ) => { +impl Encodable for [u8; $size] { +#[inline] +fn encode(&self, mut s: S) -> Result { +s.write_slice(&self[..])?; +Ok(self.len()) +} +} - impl Decodable for [u8; $size] { - #[inline] - fn decode(mut d: D) -> Result { - let mut ret = [0; $size]; - d.read_slice(&mut ret)?; - Ok(ret) - } - } - }; +impl Decodable for [u8; $size] { +#[inline] +fn decode(mut d: D) -> Result { +let mut ret = [0; $size]; +d.read_slice(&mut ret)?; +Ok(ret) +} +} +}; } impl_array!(2); @@ -385,150 +385,150 @@ impl_array!(33); // Vectors #[macro_export] macro_rules! impl_vec { - ($type: ty) => { - impl Encodable for Vec<$type> { - #[inline] - fn encode(&self, mut s: S) -> Result { - let mut len = 0; - len += VarInt(self.len() as u64).encode(&mut s)?; - for c in self.iter() { - len += c.encode(&mut s)?; - } - Ok(len) - } - } - impl Decodable for Vec<$type> { - #[inline] - fn decode(mut d: D) -> Result { - let len = VarInt::decode(&mut d)?.0; - let mut ret = Vec::with_capacity(len as usize); - for _ in 0..len { - ret.push(Decodable::decode(&mut d)?); - } - Ok(ret) - } - } - }; +($type: ty) => { +impl Encodable for Vec<$type> { +#[inline] +fn encode(&self, mut s: S) -> Result { +let mut len = 0; +len += VarInt(self.len() as u64).encode(&mut s)?; +for c in self.iter() { +len += c.encode(&mut s)?; +} +Ok(len) +} +} +impl Decodable for Vec<$type> { +#[inline] +fn decode(mut d: D) -> Result { +let len = VarInt::decode(&mut d)?.0; +let mut ret = Vec::with_capacity(len as usize); +for _ in 0..len { +ret.push(Decodable::decode(&mut d)?); +} +Ok(ret) +} +} +}; } impl_vec!(bls::Scalar); impl_vec!(SocketAddr); impl_vec!([u8; 32]); impl Encodable for IpAddr { - fn encode(&self, mut s: S) -> Result { - let mut len = 0; - match self { - IpAddr::V4(ip) => { - let version: u8 = 4; - len += version.encode(&mut s)?; - len += ip.octets().encode(s)?; - } - IpAddr::V6(ip) => { - let version: u8 = 6; - len += version.encode(&mut s)?; - len += ip.octets().encode(s)?; - } - } - Ok(len) - } +fn encode(&self, mut s: S) -> Result { +let mut len = 0; +match self { +IpAddr::V4(ip) => { +let version: u8 = 4; +len += version.encode(&mut s)?; +len += ip.octets().encode(s)?; +} +IpAddr::V6(ip) => { +let version: u8 = 6; +len += version.encode(&mut s)?; +len += ip.octets().encode(s)?; +} +} +Ok(len) +} } impl Decodable for IpAddr { - fn decode(mut d: D) -> Result { - let version: u8 = Decodable::decode(&mut d)?; - match version { - 4 => { - let addr: [u8; 4] = Decodable::decode(&mut d)?; - Ok(IpAddr::from(addr)) - } - 6 => { - let addr: [u8; 16] = Decodable::decode(&mut d)?; - Ok(IpAddr::from(addr)) - } - _ => Err(Error::ParseFailed("couldn't decode IpAddr")), - } - } +fn decode(mut d: D) -> Result { +let version: u8 = Decodable::decode(&mut d)?; +match version { +4 => { +let addr: [u8; 4] = Decodable::decode(&mut d)?; +Ok(IpAddr::from(addr)) +} +6 => { +let addr: [u8; 16] = Decodable::decode(&mut d)?; +Ok(IpAddr::from(addr)) +} +_ => Err(Error::ParseFailed("couldn't decode IpAddr")), +} +} } impl Encodable for SocketAddr { - fn encode(&self, mut s: S) -> Result { - let mut len = 0; - len += self.ip().encode(&mut s)?; - len += self.port().encode(s)?; - Ok(len) - } +fn encode(&self, mut s: S) -> Result { +let mut len = 0; +len += self.ip().encode(&mut s)?; +len += self.port().encode(s)?; +Ok(len) +} } impl Decodable for SocketAddr { - fn decode(mut d: D) -> Result { - let ip = Decodable::decode(&mut d)?; - let port: u16 = Decodable::decode(d)?; - Ok(SocketAddr::new(ip, port)) - } +fn decode(mut d: D) -> Result { +let ip = Decodable::decode(&mut d)?; +let port: u16 = Decodable::decode(d)?; +Ok(SocketAddr::new(ip, port)) +} } pub fn encode_with_size(data: &[u8], mut s: S) -> Result { - let vi_len = VarInt(data.len() as u64).encode(&mut s)?; - s.write_slice(&data)?; - Ok(vi_len + data.len()) +let vi_len = VarInt(data.len() as u64).encode(&mut s)?; +s.write_slice(&data)?; +Ok(vi_len + data.len()) } impl Encodable for Vec { - #[inline] - fn encode(&self, s: S) -> Result { - encode_with_size(self, s) - } +#[inline] +fn encode(&self, s: S) -> Result { +encode_with_size(self, s) +} } impl Decodable for Vec { - #[inline] - fn decode(mut d: D) -> Result { - let len = VarInt::decode(&mut d)?.0 as usize; - let mut ret = vec![0u8; len]; - d.read_slice(&mut ret)?; - Ok(ret) - } +#[inline] +fn decode(mut d: D) -> Result { +let len = VarInt::decode(&mut d)?.0 as usize; +let mut ret = vec![0u8; len]; +d.read_slice(&mut ret)?; +Ok(ret) +} } impl Encodable for Box<[u8]> { - #[inline] - fn encode(&self, s: S) -> Result { - encode_with_size(self, s) - } +#[inline] +fn encode(&self, s: S) -> Result { +encode_with_size(self, s) +} } impl Decodable for Box<[u8]> { - #[inline] - fn decode(d: D) -> Result { - >::decode(d).map(From::from) - } +#[inline] +fn decode(d: D) -> Result { +>::decode(d).map(From::from) +} } // Tuples macro_rules! tuple_encode { - ($($x:ident),*) => ( - impl <$($x: Encodable),*> Encodable for ($($x),*) { - #[inline] - #[allow(non_snake_case)] - fn encode( - &self, - mut s: S, - ) -> Result { - let &($(ref $x),*) = self; - let mut len = 0; - $(len += $x.encode(&mut s)?;)* - Ok(len) - } - } +($($x:ident),*) => ( +impl <$($x: Encodable),*> Encodable for ($($x),*) { +#[inline] +#[allow(non_snake_case)] +fn encode( +&self, +mut s: S, +) -> Result { +let &($(ref $x),*) = self; +let mut len = 0; +$(len += $x.encode(&mut s)?;)* +Ok(len) +} +} - impl<$($x: Decodable),*> Decodable for ($($x),*) { - #[inline] - #[allow(non_snake_case)] - fn decode(mut d: D) -> Result { - Ok(($({let $x = Decodable::decode(&mut d)?; $x }),*)) - } - } - ); +impl<$($x: Decodable),*> Decodable for ($($x),*) { +#[inline] +#[allow(non_snake_case)] +fn decode(mut d: D) -> Result { +Ok(($({let $x = Decodable::decode(&mut d)?; $x }),*)) +} +} +); } tuple_encode!(T0, T1); @@ -538,286 +538,286 @@ tuple_encode!(T0, T1, T2, T3, T4, T5, T6, T7); #[cfg(test)] mod tests { - use super::{deserialize, serialize, Error, Result, VarInt}; - use super::{deserialize_partial, Encodable}; - use crate::endian::{u16_to_array_le, u32_to_array_le, u64_to_array_le}; - use std::io; - use std::mem::discriminant; +use super::{deserialize, serialize, Error, Result, VarInt}; +use super::{deserialize_partial, Encodable}; +use crate::endian::{u16_to_array_le, u32_to_array_le, u64_to_array_le}; +use std::io; +use std::mem::discriminant; - #[test] - fn serialize_int_test() { - // bool - assert_eq!(serialize(&false), vec![0u8]); - assert_eq!(serialize(&true), vec![1u8]); - // u8 - assert_eq!(serialize(&1u8), vec![1u8]); - assert_eq!(serialize(&0u8), vec![0u8]); - assert_eq!(serialize(&255u8), vec![255u8]); - // u16 - assert_eq!(serialize(&1u16), vec![1u8, 0]); - assert_eq!(serialize(&256u16), vec![0u8, 1]); - assert_eq!(serialize(&5000u16), vec![136u8, 19]); - // u32 - assert_eq!(serialize(&1u32), vec![1u8, 0, 0, 0]); - assert_eq!(serialize(&256u32), vec![0u8, 1, 0, 0]); - assert_eq!(serialize(&5000u32), vec![136u8, 19, 0, 0]); - assert_eq!(serialize(&500000u32), vec![32u8, 161, 7, 0]); - assert_eq!(serialize(&168430090u32), vec![10u8, 10, 10, 10]); - // i32 - assert_eq!(serialize(&-1i32), vec![255u8, 255, 255, 255]); - assert_eq!(serialize(&-256i32), vec![0u8, 255, 255, 255]); - assert_eq!(serialize(&-5000i32), vec![120u8, 236, 255, 255]); - assert_eq!(serialize(&-500000i32), vec![224u8, 94, 248, 255]); - assert_eq!(serialize(&-168430090i32), vec![246u8, 245, 245, 245]); - assert_eq!(serialize(&1i32), vec![1u8, 0, 0, 0]); - assert_eq!(serialize(&256i32), vec![0u8, 1, 0, 0]); - assert_eq!(serialize(&5000i32), vec![136u8, 19, 0, 0]); - assert_eq!(serialize(&500000i32), vec![32u8, 161, 7, 0]); - assert_eq!(serialize(&168430090i32), vec![10u8, 10, 10, 10]); - // u64 - assert_eq!(serialize(&1u64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&256u64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&5000u64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&500000u64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]); - assert_eq!( - serialize(&723401728380766730u64), - vec![10u8, 10, 10, 10, 10, 10, 10, 10] - ); - // i64 - assert_eq!( - serialize(&-1i64), - vec![255u8, 255, 255, 255, 255, 255, 255, 255] - ); - assert_eq!( - serialize(&-256i64), - vec![0u8, 255, 255, 255, 255, 255, 255, 255] - ); - assert_eq!( - serialize(&-5000i64), - vec![120u8, 236, 255, 255, 255, 255, 255, 255] - ); - assert_eq!( - serialize(&-500000i64), - vec![224u8, 94, 248, 255, 255, 255, 255, 255] - ); - assert_eq!( - serialize(&-723401728380766730i64), - vec![246u8, 245, 245, 245, 245, 245, 245, 245] - ); - assert_eq!(serialize(&1i64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&256i64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&5000i64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]); - assert_eq!(serialize(&500000i64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]); - assert_eq!( - serialize(&723401728380766730i64), - vec![10u8, 10, 10, 10, 10, 10, 10, 10] - ); - } - - #[test] - fn serialize_varint_test() { - assert_eq!(serialize(&VarInt(10)), vec![10u8]); - assert_eq!(serialize(&VarInt(0xFC)), vec![0xFCu8]); - assert_eq!(serialize(&VarInt(0xFD)), vec![0xFDu8, 0xFD, 0]); - assert_eq!(serialize(&VarInt(0xFFF)), vec![0xFDu8, 0xFF, 0xF]); - assert_eq!( - serialize(&VarInt(0xF0F0F0F)), - vec![0xFEu8, 0xF, 0xF, 0xF, 0xF] - ); - assert_eq!( - serialize(&VarInt(0xF0F0F0F0F0E0)), - vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0] - ); - assert_eq!( - test_varint_encode(0xFF, &u64_to_array_le(0x100000000)).unwrap(), - VarInt(0x100000000) - ); - assert_eq!( - test_varint_encode(0xFE, &u64_to_array_le(0x10000)).unwrap(), - VarInt(0x10000) - ); - assert_eq!( - test_varint_encode(0xFD, &u64_to_array_le(0xFD)).unwrap(), - VarInt(0xFD) - ); - - // Test that length calc is working correctly - test_varint_len(VarInt(0), 1); - test_varint_len(VarInt(0xFC), 1); - test_varint_len(VarInt(0xFD), 3); - test_varint_len(VarInt(0xFFFF), 3); - test_varint_len(VarInt(0x10000), 5); - test_varint_len(VarInt(0xFFFFFFFF), 5); - test_varint_len(VarInt(0xFFFFFFFF + 1), 9); - test_varint_len(VarInt(u64::max_value()), 9); - } - - fn test_varint_len(varint: VarInt, expected: usize) { - let mut encoder = io::Cursor::new(vec![]); - assert_eq!(varint.encode(&mut encoder).unwrap(), expected); - assert_eq!(varint.len(), expected); - } - - fn test_varint_encode(n: u8, x: &[u8]) -> Result { - let mut input = [0u8; 9]; - input[0] = n; - input[1..x.len() + 1].copy_from_slice(x); - deserialize_partial::(&input).map(|t| t.0) - } - - #[test] - fn deserialize_nonminimal_vec() { - // Check the edges for variant int - assert_eq!( - discriminant(&test_varint_encode(0xFF, &u64_to_array_le(0x100000000 - 1)).unwrap_err()), - discriminant(&Error::NonMinimalVarInt) - ); - assert_eq!( - discriminant(&test_varint_encode(0xFE, &u32_to_array_le(0x10000 - 1)).unwrap_err()), - discriminant(&Error::NonMinimalVarInt) - ); - assert_eq!( - discriminant(&test_varint_encode(0xFD, &u16_to_array_le(0xFD - 1)).unwrap_err()), - discriminant(&Error::NonMinimalVarInt) - ); - - assert_eq!( - discriminant(&deserialize::>(&[0xfd, 0x00, 0x00]).unwrap_err()), - discriminant(&Error::NonMinimalVarInt) - ); - assert_eq!( - discriminant(&deserialize::>(&[0xfd, 0xfc, 0x00]).unwrap_err()), - discriminant(&Error::NonMinimalVarInt) - ); - assert_eq!( - discriminant(&deserialize::>(&[0xfd, 0xfc, 0x00]).unwrap_err()), - discriminant(&Error::NonMinimalVarInt) - ); - assert_eq!( - discriminant(&deserialize::>(&[0xfe, 0xff, 0x00, 0x00, 0x00]).unwrap_err()), - discriminant(&Error::NonMinimalVarInt) - ); - assert_eq!( - discriminant(&deserialize::>(&[0xfe, 0xff, 0xff, 0x00, 0x00]).unwrap_err()), - discriminant(&Error::NonMinimalVarInt) - ); - assert_eq!( - discriminant( - &deserialize::>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) - .unwrap_err() - ), - discriminant(&Error::NonMinimalVarInt) - ); - assert_eq!( - discriminant( - &deserialize::>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00]) - .unwrap_err() - ), - discriminant(&Error::NonMinimalVarInt) - ); - - let mut vec_256 = vec![0; 259]; - vec_256[0] = 0xfd; - vec_256[1] = 0x00; - vec_256[2] = 0x01; - assert!(deserialize::>(&vec_256).is_ok()); - - let mut vec_253 = vec![0; 256]; - vec_253[0] = 0xfd; - vec_253[1] = 0xfd; - vec_253[2] = 0x00; - assert!(deserialize::>(&vec_253).is_ok()); - } - - #[test] - fn serialize_vector_test() { - assert_eq!(serialize(&vec![1u8, 2, 3]), vec![3u8, 1, 2, 3]); - // TODO: test vectors of more interesting objects - } - - #[test] - fn serialize_strbuf_test() { - assert_eq!( - serialize(&"Andrew".to_string()), - vec![6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77] - ); - } - - #[test] - fn deserialize_int_test() { - // bool - assert!((deserialize(&[58u8, 0]) as Result).is_err()); - assert_eq!(deserialize(&[58u8]).ok(), Some(true)); - assert_eq!(deserialize(&[1u8]).ok(), Some(true)); - assert_eq!(deserialize(&[0u8]).ok(), Some(false)); - assert!((deserialize(&[0u8, 1]) as Result).is_err()); - - // u8 - assert_eq!(deserialize(&[58u8]).ok(), Some(58u8)); - - // u16 - assert_eq!(deserialize(&[0x01u8, 0x02]).ok(), Some(0x0201u16)); - assert_eq!(deserialize(&[0xABu8, 0xCD]).ok(), Some(0xCDABu16)); - assert_eq!(deserialize(&[0xA0u8, 0x0D]).ok(), Some(0xDA0u16)); - let failure16: Result = deserialize(&[1u8]); - assert!(failure16.is_err()); - - // u32 - assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABu32)); - assert_eq!( - deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD]).ok(), - Some(0xCDAB0DA0u32) - ); - let failure32: Result = deserialize(&[1u8, 2, 3]); - assert!(failure32.is_err()); - // TODO: test negative numbers - assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABi32)); - assert_eq!( - deserialize(&[0xA0u8, 0x0D, 0xAB, 0x2D]).ok(), - Some(0x2DAB0DA0i32) - ); - let failurei32: Result = deserialize(&[1u8, 2, 3]); - assert!(failurei32.is_err()); - - // u64 - assert_eq!( - deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), - Some(0xCDABu64) - ); - assert_eq!( - deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), - Some(0x99000099CDAB0DA0u64) - ); - let failure64: Result = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]); - assert!(failure64.is_err()); - // TODO: test negative numbers - assert_eq!( - deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), - Some(0xCDABi64) - ); - assert_eq!( - deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), - Some(-0x66ffff663254f260i64) - ); - let failurei64: Result = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]); - assert!(failurei64.is_err()); - } - - #[test] - fn deserialize_vec_test() { - assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4])); - assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result>).is_err()); - } - - #[test] - fn deserialize_strbuf_test() { - assert_eq!( - deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), - Some("Andrew".to_string()) - ); - assert_eq!( - deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), - Some(::std::borrow::Cow::Borrowed("Andrew")) - ); - } +#[test] +fn serialize_int_test() { +// bool +assert_eq!(serialize(&false), vec![0u8]); +assert_eq!(serialize(&true), vec![1u8]); +// u8 +assert_eq!(serialize(&1u8), vec![1u8]); +assert_eq!(serialize(&0u8), vec![0u8]); +assert_eq!(serialize(&255u8), vec![255u8]); +// u16 +assert_eq!(serialize(&1u16), vec![1u8, 0]); +assert_eq!(serialize(&256u16), vec![0u8, 1]); +assert_eq!(serialize(&5000u16), vec![136u8, 19]); +// u32 +assert_eq!(serialize(&1u32), vec![1u8, 0, 0, 0]); +assert_eq!(serialize(&256u32), vec![0u8, 1, 0, 0]); +assert_eq!(serialize(&5000u32), vec![136u8, 19, 0, 0]); +assert_eq!(serialize(&500000u32), vec![32u8, 161, 7, 0]); +assert_eq!(serialize(&168430090u32), vec![10u8, 10, 10, 10]); +// i32 +assert_eq!(serialize(&-1i32), vec![255u8, 255, 255, 255]); +assert_eq!(serialize(&-256i32), vec![0u8, 255, 255, 255]); +assert_eq!(serialize(&-5000i32), vec![120u8, 236, 255, 255]); +assert_eq!(serialize(&-500000i32), vec![224u8, 94, 248, 255]); +assert_eq!(serialize(&-168430090i32), vec![246u8, 245, 245, 245]); +assert_eq!(serialize(&1i32), vec![1u8, 0, 0, 0]); +assert_eq!(serialize(&256i32), vec![0u8, 1, 0, 0]); +assert_eq!(serialize(&5000i32), vec![136u8, 19, 0, 0]); +assert_eq!(serialize(&500000i32), vec![32u8, 161, 7, 0]); +assert_eq!(serialize(&168430090i32), vec![10u8, 10, 10, 10]); +// u64 +assert_eq!(serialize(&1u64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]); +assert_eq!(serialize(&256u64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]); +assert_eq!(serialize(&5000u64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]); +assert_eq!(serialize(&500000u64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]); +assert_eq!( +serialize(&723401728380766730u64), +vec![10u8, 10, 10, 10, 10, 10, 10, 10] +); +// i64 +assert_eq!( +serialize(&-1i64), +vec![255u8, 255, 255, 255, 255, 255, 255, 255] +); +assert_eq!( +serialize(&-256i64), +vec![0u8, 255, 255, 255, 255, 255, 255, 255] +); +assert_eq!( +serialize(&-5000i64), +vec![120u8, 236, 255, 255, 255, 255, 255, 255] +); +assert_eq!( +serialize(&-500000i64), +vec![224u8, 94, 248, 255, 255, 255, 255, 255] +); +assert_eq!( +serialize(&-723401728380766730i64), +vec![246u8, 245, 245, 245, 245, 245, 245, 245] +); +assert_eq!(serialize(&1i64), vec![1u8, 0, 0, 0, 0, 0, 0, 0]); +assert_eq!(serialize(&256i64), vec![0u8, 1, 0, 0, 0, 0, 0, 0]); +assert_eq!(serialize(&5000i64), vec![136u8, 19, 0, 0, 0, 0, 0, 0]); +assert_eq!(serialize(&500000i64), vec![32u8, 161, 7, 0, 0, 0, 0, 0]); +assert_eq!( +serialize(&723401728380766730i64), +vec![10u8, 10, 10, 10, 10, 10, 10, 10] +); +} + +#[test] +fn serialize_varint_test() { +assert_eq!(serialize(&VarInt(10)), vec![10u8]); +assert_eq!(serialize(&VarInt(0xFC)), vec![0xFCu8]); +assert_eq!(serialize(&VarInt(0xFD)), vec![0xFDu8, 0xFD, 0]); +assert_eq!(serialize(&VarInt(0xFFF)), vec![0xFDu8, 0xFF, 0xF]); +assert_eq!( +serialize(&VarInt(0xF0F0F0F)), +vec![0xFEu8, 0xF, 0xF, 0xF, 0xF] +); +assert_eq!( +serialize(&VarInt(0xF0F0F0F0F0E0)), +vec![0xFFu8, 0xE0, 0xF0, 0xF0, 0xF0, 0xF0, 0xF0, 0, 0] +); +assert_eq!( +test_varint_encode(0xFF, &u64_to_array_le(0x100000000)).unwrap(), +VarInt(0x100000000) +); +assert_eq!( +test_varint_encode(0xFE, &u64_to_array_le(0x10000)).unwrap(), +VarInt(0x10000) +); +assert_eq!( +test_varint_encode(0xFD, &u64_to_array_le(0xFD)).unwrap(), +VarInt(0xFD) +); + +// Test that length calc is working correctly +test_varint_len(VarInt(0), 1); +test_varint_len(VarInt(0xFC), 1); +test_varint_len(VarInt(0xFD), 3); +test_varint_len(VarInt(0xFFFF), 3); +test_varint_len(VarInt(0x10000), 5); +test_varint_len(VarInt(0xFFFFFFFF), 5); +test_varint_len(VarInt(0xFFFFFFFF + 1), 9); +test_varint_len(VarInt(u64::max_value()), 9); +} + +fn test_varint_len(varint: VarInt, expected: usize) { +let mut encoder = io::Cursor::new(vec![]); +assert_eq!(varint.encode(&mut encoder).unwrap(), expected); +assert_eq!(varint.len(), expected); +} + +fn test_varint_encode(n: u8, x: &[u8]) -> Result { +let mut input = [0u8; 9]; +input[0] = n; +input[1..x.len() + 1].copy_from_slice(x); +deserialize_partial::(&input).map(|t| t.0) +} + +#[test] +fn deserialize_nonminimal_vec() { +// Check the edges for variant int +assert_eq!( +discriminant(&test_varint_encode(0xFF, &u64_to_array_le(0x100000000 - 1)).unwrap_err()), +discriminant(&Error::NonMinimalVarInt) +); +assert_eq!( +discriminant(&test_varint_encode(0xFE, &u32_to_array_le(0x10000 - 1)).unwrap_err()), +discriminant(&Error::NonMinimalVarInt) +); +assert_eq!( +discriminant(&test_varint_encode(0xFD, &u16_to_array_le(0xFD - 1)).unwrap_err()), +discriminant(&Error::NonMinimalVarInt) +); + +assert_eq!( +discriminant(&deserialize::>(&[0xfd, 0x00, 0x00]).unwrap_err()), +discriminant(&Error::NonMinimalVarInt) +); +assert_eq!( +discriminant(&deserialize::>(&[0xfd, 0xfc, 0x00]).unwrap_err()), +discriminant(&Error::NonMinimalVarInt) +); +assert_eq!( +discriminant(&deserialize::>(&[0xfd, 0xfc, 0x00]).unwrap_err()), +discriminant(&Error::NonMinimalVarInt) +); +assert_eq!( +discriminant(&deserialize::>(&[0xfe, 0xff, 0x00, 0x00, 0x00]).unwrap_err()), +discriminant(&Error::NonMinimalVarInt) +); +assert_eq!( +discriminant(&deserialize::>(&[0xfe, 0xff, 0xff, 0x00, 0x00]).unwrap_err()), +discriminant(&Error::NonMinimalVarInt) +); +assert_eq!( +discriminant( +&deserialize::>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00]) +.unwrap_err() +), +discriminant(&Error::NonMinimalVarInt) +); +assert_eq!( +discriminant( +&deserialize::>(&[0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00]) +.unwrap_err() +), +discriminant(&Error::NonMinimalVarInt) +); + +let mut vec_256 = vec![0; 259]; +vec_256[0] = 0xfd; +vec_256[1] = 0x00; +vec_256[2] = 0x01; +assert!(deserialize::>(&vec_256).is_ok()); + +let mut vec_253 = vec![0; 256]; +vec_253[0] = 0xfd; +vec_253[1] = 0xfd; +vec_253[2] = 0x00; +assert!(deserialize::>(&vec_253).is_ok()); +} + +#[test] +fn serialize_vector_test() { +assert_eq!(serialize(&vec![1u8, 2, 3]), vec![3u8, 1, 2, 3]); +// TODO: test vectors of more interesting objects +} + +#[test] +fn serialize_strbuf_test() { +assert_eq!( +serialize(&"Andrew".to_string()), +vec![6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77] +); +} + +#[test] +fn deserialize_int_test() { +// bool +assert!((deserialize(&[58u8, 0]) as Result).is_err()); +assert_eq!(deserialize(&[58u8]).ok(), Some(true)); +assert_eq!(deserialize(&[1u8]).ok(), Some(true)); +assert_eq!(deserialize(&[0u8]).ok(), Some(false)); +assert!((deserialize(&[0u8, 1]) as Result).is_err()); + +// u8 +assert_eq!(deserialize(&[58u8]).ok(), Some(58u8)); + +// u16 +assert_eq!(deserialize(&[0x01u8, 0x02]).ok(), Some(0x0201u16)); +assert_eq!(deserialize(&[0xABu8, 0xCD]).ok(), Some(0xCDABu16)); +assert_eq!(deserialize(&[0xA0u8, 0x0D]).ok(), Some(0xDA0u16)); +let failure16: Result = deserialize(&[1u8]); +assert!(failure16.is_err()); + +// u32 +assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABu32)); +assert_eq!( +deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD]).ok(), +Some(0xCDAB0DA0u32) +); +let failure32: Result = deserialize(&[1u8, 2, 3]); +assert!(failure32.is_err()); +// TODO: test negative numbers +assert_eq!(deserialize(&[0xABu8, 0xCD, 0, 0]).ok(), Some(0xCDABi32)); +assert_eq!( +deserialize(&[0xA0u8, 0x0D, 0xAB, 0x2D]).ok(), +Some(0x2DAB0DA0i32) +); +let failurei32: Result = deserialize(&[1u8, 2, 3]); +assert!(failurei32.is_err()); + +// u64 +assert_eq!( +deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), +Some(0xCDABu64) +); +assert_eq!( +deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), +Some(0x99000099CDAB0DA0u64) +); +let failure64: Result = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]); +assert!(failure64.is_err()); +// TODO: test negative numbers +assert_eq!( +deserialize(&[0xABu8, 0xCD, 0, 0, 0, 0, 0, 0]).ok(), +Some(0xCDABi64) +); +assert_eq!( +deserialize(&[0xA0u8, 0x0D, 0xAB, 0xCD, 0x99, 0, 0, 0x99]).ok(), +Some(-0x66ffff663254f260i64) +); +let failurei64: Result = deserialize(&[1u8, 2, 3, 4, 5, 6, 7]); +assert!(failurei64.is_err()); +} + +#[test] +fn deserialize_vec_test() { +assert_eq!(deserialize(&[3u8, 2, 3, 4]).ok(), Some(vec![2u8, 3, 4])); +assert!((deserialize(&[4u8, 2, 3, 4, 5, 6]) as Result>).is_err()); +} + +#[test] +fn deserialize_strbuf_test() { +assert_eq!( +deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), +Some("Andrew".to_string()) +); +assert_eq!( +deserialize(&[6u8, 0x41, 0x6e, 0x64, 0x72, 0x65, 0x77]).ok(), +Some(::std::borrow::Cow::Borrowed("Andrew")) +); +} } diff --git a/src/vm.rs b/src/vm.rs index 2fb5a58ad..f83224b28 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -50,7 +50,7 @@ pub enum AllocType { Public, } -#[derive(Clone)] +#[derive(Debug, Clone)] pub enum ConstraintInstruction { Lc0Add(VariableIndex), Lc1Add(VariableIndex),