Parcourir la source

Merge pull request #7 from mileschet/master

Merging lisp v0 to master branch
ada il y a 5 ans
Parent
commit
86f7f08f61
24 fichiers modifiés avec 2669 ajouts et 728 suppressions
  1. 9 0
      Cargo.toml
  2. 12 0
      lisp/README.md
  3. 7 0
      lisp/TODO.md
  4. 9 0
      lisp/bits.lisp
  5. 489 0
      lisp/core.rs
  6. 85 0
      lisp/env.rs
  7. 70 0
      lisp/jubjub.lisp
  8. BIN
      lisp/lisp-cheat-sheet.png
  9. 624 0
      lisp/lisp.rs
  10. 38 0
      lisp/new-cs.lisp
  11. 17 0
      lisp/new.lisp
  12. 63 0
      lisp/printer.rs
  13. 0 0
      lisp/racket/jj.rkt
  14. 0 0
      lisp/racket/zk.rkt
  15. 156 0
      lisp/reader.rs
  16. 2 0
      lisp/run.sh
  17. 360 0
      lisp/types.rs
  18. 2 2
      src/bin/mimc.rs
  19. 3 0
      src/bin/mimc_constants.rs
  20. 3 3
      src/bin/mint.rs
  21. 53 53
      src/bls_extensions.rs
  22. 5 8
      src/old/basic_minimal.rs
  23. 661 661
      src/serial.rs
  24. 1 1
      src/vm.rs

+ 9 - 0
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"

+ 12 - 0
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
+```

+ 7 - 0
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

+ 9 - 0
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)
+      )))))
+                            

+ 489 - 0
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::<Vec<MalVal>>()))
+        }
+        _ => 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::<Vec<MalVal>>();
+            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::<Vec<MalVal>>()))
+        }
+        _ => 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)),
+    ]
+}

+ 85 - 0
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<FnvHashMap<String, MalVal>>,
+    pub outer: Option<Env>,
+}
+
+pub type Env = Rc<EnvStruct>;
+
+// 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>) -> Env {
+    Rc::new(EnvStruct {
+        data: RefCell::new(FnvHashMap::default()),
+        outer: outer,
+    })
+}
+
+// TODO: mbinds and exprs as & types
+pub fn env_bind(outer: Option<Env>, mbinds: MalVal, exprs: Vec<MalVal>) -> Result<Env, MalErr> {
+    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<Env> {
+    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);
+}

+ 70 - 0
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::<Scalar>::zero();
+;; (lc0-args LinearCombination<Scalar>)
+
+;; (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)

BIN
lisp/lisp-cheat-sheet.png


+ 624 - 0
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<String, MalVal> = 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<String, MalVal> = 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<String, MalVal> = 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<EnforceAllocation> = 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<EnforceAllocation> {
+    // 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<FnvHashMap<String, MalVal>> {
+    let alloc_hm: Rc<FnvHashMap<String, MalVal>> = 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<PreparedVerifyingKey<Bls12>, 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::<Bls12, _, _>(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::<Bls12, _, _>(c, &mut OsRng).unwrap()
+    };
+    let start = Instant::now();
+    // Create a Groth16 proof with our parameters.
+    let _proof = groth16::create_random_proof(circuit, &params, &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<String, MalErr> {
+    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 <miles.chet@gmail.com>")
+        (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);
+        }
+    }
+}

+ 38 - 0
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)))

+ 17 - 0
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)

+ 63 - 0
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::<Vec<String>>()
+        .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<MalVal> = hm
+                    .iter()
+                    .flat_map(|(k, v)| vec![Str(k.to_string()), v.clone()])
+                    .collect();
+                pr_seq(&l, print_readably, "{", "}", " ")
+            }
+            Func(f, _) => format!("#<fn {:?}>", 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<MalVal>,
+    print_readably: bool,
+    start: &str,
+    end: &str,
+    join: &str,
+) -> String {
+    let strs: Vec<String> = seq.iter().map(|x| x.pr_str(print_readably)).collect();
+    format!("{}{}{}", start, strs.join(join), end)
+}

+ 0 - 0
lisp/jj.rkt → lisp/racket/jj.rkt


+ 0 - 0
lisp/zk.rkt → lisp/racket/zk.rkt


+ 156 - 0
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<String>,
+    pos: usize,
+}
+
+impl Reader {
+    fn next(&mut self) -> Result<String, MalErr> {
+        self.pos = self.pos + 1;
+        Ok(self
+            .tokens
+            .get(self.pos - 1)
+            .ok_or(ErrString("underflow".to_string()))?
+            .to_string())
+    }
+    fn peek(&self) -> Result<String, MalErr> {
+        Ok(self
+            .tokens
+            .get(self.pos)
+            .ok_or(ErrString("underflow".to_string()))?
+            .to_string())
+    }
+}
+
+fn tokenize(str: &str) -> Vec<String> {
+    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<MalVal> = 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,
+    })
+}

+ 2 - 0
lisp/run.sh

@@ -0,0 +1,2 @@
+#export RUST_BACKTRACE=full
+cargo run --bin lisp load new-cs.lisp

+ 360 - 0
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<Option<Scalar>>,
+    pub allocs: FnvHashMap<String, MalVal>,
+    pub alloc_inputs: FnvHashMap<String, MalVal>,
+    pub constraints: Vec<EnforceAllocation>,
+    pub env: Env,
+}
+
+impl Circuit<bls12_381::Scalar> for LispCircuit {
+    fn synthesize<CS: ConstraintSystem<bls12_381::Scalar>>(
+        self,
+        cs: &mut CS,
+    ) -> Result<(), SynthesisError> {
+        let mut variables: FnvHashMap<String, Variable> = 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::<Scalar>::zero();
+            let mut right = bellman::LinearCombination::<Scalar>::zero();
+            let mut output = bellman::LinearCombination::<Scalar>::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<Vec<MalVal>>, Rc<MalVal>),
+    Vector(Rc<Vec<MalVal>>, Rc<MalVal>),
+    Hash(Rc<FnvHashMap<String, MalVal>>, Rc<MalVal>),
+    Func(fn(MalArgs) -> MalRet, Rc<MalVal>),
+    MalFunc {
+        eval: fn(ast: MalVal, env: Env) -> MalRet,
+        ast: Rc<MalVal>,
+        env: Env,
+        params: Rc<MalVal>,
+        is_macro: bool,
+        meta: Rc<MalVal>,
+    },
+    Atom(Rc<RefCell<MalVal>>),
+    Zk(Rc<LispCircuit>), // TODO remote it
+    Enforce(Rc<Vec<EnforceAllocation>>),
+    ZKScalar(bls12_381::Scalar),
+}
+
+#[derive(Debug)]
+pub enum MalErr {
+    ErrString(String),
+    ErrMalVal(MalVal),
+}
+
+pub type MalArgs = Vec<MalVal>;
+pub type MalRet = Result<MalVal, MalErr>;
+
+// type utility macros
+
+macro_rules! list {
+  ($seq:expr) => {{
+    List(Rc::new($seq),Rc::new(Nil))
+  }};
+  [$($args:expr),*] => {{
+    let v: Vec<MalVal> = 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<MalVal> = 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<String, MalVal>, 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<String, MalVal>, 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<String, MalVal> = FnvHashMap::default();
+    _assoc(hm, kvs)
+}

+ 2 - 2
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;

+ 3 - 0
src/bin/mimc_constants.rs

@@ -324,3 +324,6 @@ pub fn mimc_constants() -> Vec<&'static str> {
         "597cdd384abdad1beccc73fb39f74a18eb44d056951d602c2ef6ef6448fc5626",
     ]
 }
+
+fn main() {
+}

+ 3 - 3
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<T> = std::result::Result<T, failure::Error>;
@@ -13,7 +13,7 @@ type Result<T> = std::result::Result<T, failure::Error>;
 fn unpack<F: PrimeField>(value: F) -> Vec<Scalar> {
     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()),

+ 53 - 53
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<S: io::Write>(&self, mut s: S) -> Result<usize> {
-                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<S: io::Write>(&self, mut s: S) -> Result<usize> {
+let data = self.$to_x();
+assert_eq!(data.len(), $size);
+s.write_slice(&data)?;
+Ok(data.len())
+}
+}
 
-        impl Decodable for $type {
-            fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-                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<D: io::Read>(mut d: D) -> Result<Self> {
+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<u8> = vec![];
-            let result = point.encode(&mut data);
-            assert!(result.is_ok());
+let mut data: Vec<u8> = 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);

+ 5 - 8
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, &params, &mut OsRng).unwrap();
     println!("Prove: [{:?}]", start.elapsed());
 
-    let start = Instant::now();
-
     let public_input = vec![bls12_381::Scalar::from(27)];
 
     let start = Instant::now();

+ 661 - 661
src/serial.rs

@@ -9,185 +9,185 @@ use crate::error::{Error, Result};
 
 /// Encode an object into a vector
 pub fn serialize<T: Encodable + ?Sized>(data: &T) -> Vec<u8> {
-    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<T: Encodable + ?Sized>(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<T: Decodable>(data: &[u8]) -> Result<T> {
-    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<T: Decodable>(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 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 byte slice
-    fn write_slice(&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 boolean
+fn write_bool(&mut self, v: bool) -> 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<u64>;
-    /// Read a 32-bit uint
-    fn read_u32(&mut self) -> Result<u32>;
-    /// Read a 16-bit uint
-    fn read_u16(&mut self) -> Result<u16>;
-    /// Read a 8-bit uint
-    fn read_u8(&mut self) -> Result<u8>;
-
-    /// Read a 64-bit int
-    fn read_i64(&mut self) -> Result<i64>;
-    /// Read a 32-bit int
-    fn read_i32(&mut self) -> Result<i32>;
-    /// Read a 16-bit int
-    fn read_i16(&mut self) -> Result<i16>;
-    /// Read a 8-bit int
-    fn read_i8(&mut self) -> Result<i8>;
-
-    /// Read a boolean
-    fn read_bool(&mut self) -> Result<bool>;
-
-    /// Read a byte slice
-    fn read_slice(&mut self, slice: &mut [u8]) -> Result<()>;
+/// Read a 64-bit uint
+fn read_u64(&mut self) -> Result<u64>;
+/// Read a 32-bit uint
+fn read_u32(&mut self) -> Result<u32>;
+/// Read a 16-bit uint
+fn read_u16(&mut self) -> Result<u16>;
+/// Read a 8-bit uint
+fn read_u8(&mut self) -> Result<u8>;
+
+/// Read a 64-bit int
+fn read_i64(&mut self) -> Result<i64>;
+/// Read a 32-bit int
+fn read_i32(&mut self) -> Result<i32>;
+/// Read a 16-bit int
+fn read_i16(&mut self) -> Result<i16>;
+/// Read a 8-bit int
+fn read_i8(&mut self) -> Result<i8>;
+
+/// Read a boolean
+fn read_bool(&mut self) -> Result<bool>;
+
+/// 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<W: Write> 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);
-
-    #[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)
-    }
+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)
+}
 }
 
 impl<R: Read> 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);
-
-    #[inline]
-    fn read_u8(&mut self) -> Result<u8> {
-        let mut slice = [0u8; 1];
-        self.read_exact(&mut slice)?;
-        Ok(slice[0])
-    }
-    #[inline]
-    fn read_i8(&mut self) -> Result<i8> {
-        let mut slice = [0u8; 1];
-        self.read_exact(&mut slice)?;
-        Ok(slice[0] as i8)
-    }
-    #[inline]
-    fn read_bool(&mut self) -> Result<bool> {
-        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)
-    }
+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<u8> {
+let mut slice = [0u8; 1];
+self.read_exact(&mut slice)?;
+Ok(slice[0])
+}
+#[inline]
+fn read_i8(&mut self) -> Result<i8> {
+let mut slice = [0u8; 1];
+self.read_exact(&mut slice)?;
+Ok(slice[0] as i8)
+}
+#[inline]
+fn read_bool(&mut self) -> Result<bool> {
+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<W: io::Write>(&self, e: W) -> Result<usize>;
+/// 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<W: io::Write>(&self, e: W) -> Result<usize>;
 }
 
 /// 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: io::Read>(d: D) -> Result<Self>;
+/// Decode an object with a well-defined format
+fn decode<D: io::Read>(d: D) -> Result<Self>;
 }
 
 #[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<D: io::Read>(mut d: D) -> Result<Self> {
-                ReadExt::$meth_dec(&mut d).map($ty::from_le)
-            }
-        }
-        impl Encodable for $ty {
-            #[inline]
-            fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize> {
-                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<D: io::Read>(mut d: D) -> Result<Self> {
+ReadExt::$meth_dec(&mut d).map($ty::from_le)
+}
+}
+impl Encodable for $ty {
+#[inline]
+fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize> {
+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<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        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<S: io::Write>(&self, mut s: S) -> Result<usize> {
+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<D: io::Read>(mut d: D) -> Result<Self> {
-        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<D: io::Read>(mut d: D) -> Result<Self> {
+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<S: WriteExt>(&self, mut s: S) -> Result<usize> {
-        s.write_bool(*self)?;
-        Ok(1)
-    }
+#[inline]
+fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize> {
+s.write_bool(*self)?;
+Ok(1)
+}
 }
 
 impl Decodable for bool {
-    #[inline]
-    fn decode<D: io::Read>(mut d: D) -> Result<bool> {
-        ReadExt::read_bool(&mut d)
-    }
+#[inline]
+fn decode<D: io::Read>(mut d: D) -> Result<bool> {
+ReadExt::read_bool(&mut d)
+}
 }
 
 // Strings
 impl Encodable for String {
-    #[inline]
-    fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        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<S: io::Write>(&self, mut s: S) -> Result<usize> {
+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: io::Read>(d: D) -> Result<String> {
-        String::from_utf8(Decodable::decode(d)?)
-            .map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
-    }
+#[inline]
+fn decode<D: io::Read>(d: D) -> Result<String> {
+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<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        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<S: io::Write>(&self, mut s: S) -> Result<usize> {
+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: io::Read>(d: D) -> Result<Cow<'static, str>> {
-        String::from_utf8(Decodable::decode(d)?)
-            .map_err(|_| self::Error::ParseFailed("String was not valid UTF8"))
-            .map(Cow::Owned)
-    }
+#[inline]
+fn decode<D: io::Read>(d: D) -> Result<Cow<'static, str>> {
+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<S: WriteExt>(&self, mut s: S) -> Result<usize> {
-                s.write_slice(&self[..])?;
-                Ok(self.len())
-            }
-        }
-
-        impl Decodable for [u8; $size] {
-            #[inline]
-            fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-                let mut ret = [0; $size];
-                d.read_slice(&mut ret)?;
-                Ok(ret)
-            }
-        }
-    };
+( $size:expr ) => {
+impl Encodable for [u8; $size] {
+#[inline]
+fn encode<S: WriteExt>(&self, mut s: S) -> Result<usize> {
+s.write_slice(&self[..])?;
+Ok(self.len())
+}
+}
+
+impl Decodable for [u8; $size] {
+#[inline]
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+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<S: io::Write>(&self, mut s: S) -> Result<usize> {
-                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<D: io::Read>(mut d: D) -> Result<Self> {
-                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<S: io::Write>(&self, mut s: S) -> Result<usize> {
+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<D: io::Read>(mut d: D) -> Result<Self> {
+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<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        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<S: io::Write>(&self, mut s: S) -> Result<usize> {
+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<D: io::Read>(mut d: D) -> Result<Self> {
-        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<D: io::Read>(mut d: D) -> Result<Self> {
+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<S: io::Write>(&self, mut s: S) -> Result<usize> {
-        let mut len = 0;
-        len += self.ip().encode(&mut s)?;
-        len += self.port().encode(s)?;
-        Ok(len)
-    }
+fn encode<S: io::Write>(&self, mut s: S) -> Result<usize> {
+let mut len = 0;
+len += self.ip().encode(&mut s)?;
+len += self.port().encode(s)?;
+Ok(len)
+}
 }
 
 impl Decodable for SocketAddr {
-    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-        let ip = Decodable::decode(&mut d)?;
-        let port: u16 = Decodable::decode(d)?;
-        Ok(SocketAddr::new(ip, port))
-    }
+fn decode<D: io::Read>(mut d: D) -> Result<Self> {
+let ip = Decodable::decode(&mut d)?;
+let port: u16 = Decodable::decode(d)?;
+Ok(SocketAddr::new(ip, port))
+}
 }
 
 pub fn encode_with_size<S: io::Write>(data: &[u8], mut s: S) -> Result<usize> {
-    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<u8> {
-    #[inline]
-    fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
-        encode_with_size(self, s)
-    }
+#[inline]
+fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
+encode_with_size(self, s)
+}
 }
 
 impl Decodable for Vec<u8> {
-    #[inline]
-    fn decode<D: io::Read>(mut d: D) -> Result<Self> {
-        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<D: io::Read>(mut d: D) -> Result<Self> {
+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<S: io::Write>(&self, s: S) -> Result<usize> {
-        encode_with_size(self, s)
-    }
+#[inline]
+fn encode<S: io::Write>(&self, s: S) -> Result<usize> {
+encode_with_size(self, s)
+}
 }
 
 impl Decodable for Box<[u8]> {
-    #[inline]
-    fn decode<D: io::Read>(d: D) -> Result<Self> {
-        <Vec<u8>>::decode(d).map(From::from)
-    }
+#[inline]
+fn decode<D: io::Read>(d: D) -> Result<Self> {
+<Vec<u8>>::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<S: io::Write>(
-                &self,
-                mut s: S,
-            ) -> Result<usize> {
-                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<D: io::Read>(mut d: D) -> Result<Self> {
-                Ok(($({let $x = Decodable::decode(&mut d)?; $x }),*))
-            }
-        }
-    );
+($($x:ident),*) => (
+impl <$($x: Encodable),*> Encodable for ($($x),*) {
+#[inline]
+#[allow(non_snake_case)]
+fn encode<S: io::Write>(
+&self,
+mut s: S,
+) -> Result<usize> {
+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<D: io::Read>(mut d: D) -> Result<Self> {
+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;
-
-    #[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<VarInt> {
-        let mut input = [0u8; 9];
-        input[0] = n;
-        input[1..x.len() + 1].copy_from_slice(x);
-        deserialize_partial::<VarInt>(&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::<Vec<u8>>(&[0xfd, 0x00, 0x00]).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0x00, 0x00, 0x00]).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0xff, 0x00, 0x00]).unwrap_err()),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(
-                &deserialize::<Vec<u8>>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
-                    .unwrap_err()
-            ),
-            discriminant(&Error::NonMinimalVarInt)
-        );
-        assert_eq!(
-            discriminant(
-                &deserialize::<Vec<u8>>(&[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<u8>>(&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<u8>>(&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<bool>).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<bool>).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<u16> = 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<u32> = 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<i32> = 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<u64> = 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<i64> = 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<Vec<u8>>).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"))
-        );
-    }
+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<VarInt> {
+let mut input = [0u8; 9];
+input[0] = n;
+input[1..x.len() + 1].copy_from_slice(x);
+deserialize_partial::<VarInt>(&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::<Vec<u8>>(&[0xfd, 0x00, 0x00]).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(&deserialize::<Vec<u8>>(&[0xfd, 0xfc, 0x00]).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0x00, 0x00, 0x00]).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(&deserialize::<Vec<u8>>(&[0xfe, 0xff, 0xff, 0x00, 0x00]).unwrap_err()),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(
+&deserialize::<Vec<u8>>(&[0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
+.unwrap_err()
+),
+discriminant(&Error::NonMinimalVarInt)
+);
+assert_eq!(
+discriminant(
+&deserialize::<Vec<u8>>(&[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<u8>>(&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<u8>>(&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<bool>).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<bool>).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<u16> = 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<u32> = 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<i32> = 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<u64> = 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<i64> = 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<Vec<u8>>).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"))
+);
+}
 }

+ 1 - 1
src/vm.rs

@@ -50,7 +50,7 @@ pub enum AllocType {
     Public,
 }
 
-#[derive(Clone)]
+#[derive(Debug, Clone)]
 pub enum ConstraintInstruction {
     Lc0Add(VariableIndex),
     Lc1Add(VariableIndex),