From 7de40e7f013faaee4e0d9d2b264fec74b8657593 Mon Sep 17 00:00:00 2001 From: lunar-mining Date: Mon, 13 Sep 2021 09:13:39 +0200 Subject: [PATCH] removed /lisp and added king.png --- king.png | Bin 0 -> 118096 bytes lisp/README.md | 12 - lisp/TODO.md | 7 - lisp/core.rs | 831 ---------------------------- lisp/env.rs | 85 --- lisp/examples/jubjub-add-macro.lisp | 52 -- lisp/examples/jubjub.lisp | 79 --- lisp/examples/macro-test.lisp | 321 ----------- lisp/examples/mimc-constants.lisp | 323 ----------- lisp/examples/mint2.lisp | 341 ------------ lisp/examples/util.lisp | 26 - lisp/lisp.rs | 781 -------------------------- lisp/printer.rs | 63 --- lisp/racket/jj.rkt | 113 ---- lisp/racket/zk.rkt | 141 ----- lisp/reader.rs | 156 ------ lisp/run.sh | 4 - lisp/types.rs | 471 ---------------- 18 files changed, 3806 deletions(-) create mode 100644 king.png delete mode 100644 lisp/README.md delete mode 100644 lisp/TODO.md delete mode 100644 lisp/core.rs delete mode 100644 lisp/env.rs delete mode 100644 lisp/examples/jubjub-add-macro.lisp delete mode 100644 lisp/examples/jubjub.lisp delete mode 100644 lisp/examples/macro-test.lisp delete mode 100644 lisp/examples/mimc-constants.lisp delete mode 100644 lisp/examples/mint2.lisp delete mode 100644 lisp/examples/util.lisp delete mode 100644 lisp/lisp.rs delete mode 100644 lisp/printer.rs delete mode 100644 lisp/racket/jj.rkt delete mode 100644 lisp/racket/zk.rkt delete mode 100644 lisp/reader.rs delete mode 100755 lisp/run.sh delete mode 100644 lisp/types.rs diff --git a/king.png b/king.png new file mode 100644 index 0000000000000000000000000000000000000000..acdeb07775a7add8857aca4778d871d5264b83d5 GIT binary patch literal 118096 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%0Akr?K;x)zVz{EqlN`mVaeB&gv2qTH#W{Vt|OKl_X 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 literal 0 HcmV?d00001 diff --git a/lisp/README.md b/lisp/README.md deleted file mode 100644 index 3b3a22266..000000000 --- a/lisp/README.md +++ /dev/null @@ -1,12 +0,0 @@ -## zklisp - -This is a DSL for ZkVmCircuit from drk language. - -It uses the mal (lisp) version of rust with some modifications to interact with bellman backend and also drk vm. - -## run - - -``` -cargo run --bin lisp load new.lisp -``` diff --git a/lisp/TODO.md b/lisp/TODO.md deleted file mode 100644 index 3658b672e..000000000 --- a/lisp/TODO.md +++ /dev/null @@ -1,7 +0,0 @@ -## TODO - -- Document the language -- Integrate with zkvm command line -- Integrate with ZkVmCircuit: allocs and constraints -- Added CryptoOperation such double and square to core.rs -- Adapt ZkContract to use lisp to read contract and execute diff --git a/lisp/core.rs b/lisp/core.rs deleted file mode 100644 index b4aa930bd..000000000 --- a/lisp/core.rs +++ /dev/null @@ -1,831 +0,0 @@ -use rand::Rng; -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::{Field, PrimeField}; -use rand::rngs::OsRng; - -use drk::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().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::>())) - } - ZKScalar(ref s) => { - for (_, bit) in s.to_le_bits().into_iter().enumerate() { - match bit { - true => result.push(bls12_381::Scalar::one()), - false => result.push(bls12_381::Scalar::zero()), - } - } - Ok(list!(result - .iter() - .map(|a| Str(std::string::ToString::to_string(&a)[2..].to_string())) - .collect::>())) - } - _ => error(&format!("invalid args to unpack-bits found \n {:?}", a).to_string()), - } -} - -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 second(a: MalArgs) -> MalRet { - match a[0].clone() { - List(ref seq, _) | Vector(ref seq, _) if seq.len() < 2 => Ok(Nil), - List(ref seq, _) | Vector(ref seq, _) => Ok(seq[1].clone()), - Nil => Ok(Nil), - _ => error("invalid args to first"), - } -} - -fn rest(a: MalArgs) -> MalRet { - match a[0].clone() { - List(ref seq, _) | Vector(ref seq, _) => { - if seq.len() > 1 { - Ok(list!(seq[1..].to_vec())) - } else { - Ok(list![]) - } - } - Nil => Ok(list![]), - _ => error("invalid args to first"), - } -} - -fn apply(a: MalArgs) -> MalRet { - match a[a.len() - 1] { - List(ref v, _) | Vector(ref v, _) => { - let f = &a[0]; - let mut fargs = a[1..a.len() - 1].to_vec(); - fargs.extend_from_slice(&v); - f.apply(fargs) - } - _ => error("apply called with non-seq"), - } -} - -fn map(a: MalArgs) -> MalRet { - match a[1] { - List(ref v, _) | Vector(ref v, _) => { - let mut res = vec![]; - for mv in v.iter() { - res.push(a[0].apply(vec![mv.clone()])?) - } - Ok(list!(res)) - } - _ => error("map called with non-seq"), - } -} - -fn conj(a: MalArgs) -> MalRet { - match a[0] { - List(ref v, _) => { - let sl = a[1..] - .iter() - .rev() - .map(|a| a.clone()) - .collect::>(); - Ok(list!([&sl[..], v].concat())) - } - Vector(ref v, _) => Ok(vector!([v, &a[1..]].concat())), - _ => error("conj: called with non-seq"), - } -} - -fn sub_scalar(a: MalArgs) -> MalRet { - match (a[0].clone(), a[1].clone()) { - (Func(_, _), ZKScalar(a1)) => { - if let Vector(ref values, _) = a[0].apply(vec![]).unwrap() { - if let ZKScalar(mut a0) = values[0] { - a0.sub_assign(a1); - Ok(ZKScalar(a0)) - } else { - error("scalar sub expect (zkscalar, zkscalar) found (func, zkscalar)") - } - } else { - error("scalar sub expect (zkscalar, zkscalar)") - } - } - (Func(_, _), Str(a1)) => { - if let Vector(ref values, _) = a[0].apply(vec![]).unwrap() { - let s1 = bls12_381::Scalar::from_string(&a1); - if let ZKScalar(mut a0) = values[0] { - a0.sub_assign(s1); - Ok(ZKScalar(a0)) - } else { - error("scalar sub expect (zkscalar, zkscalar) found (func, zkscalar)") - } - } else { - error("scalar sub expect (zkscalar, zkscalar)") - } - } - (ZKScalar(mut a0), ZKScalar(a1)) => { - a0.sub_assign(a1); - Ok(ZKScalar(a0)) - } - (Str(a0), ZKScalar(a1)) => { - let (mut s0, s1) = (bls12_381::Scalar::from_string(&a0), a1); - s0.sub_assign(s1); - Ok(Str(std::string::ToString::to_string(&s0)[2..].to_string())) - } - (ZKScalar(a0), Str(a1)) => { - let (mut s0, s1) = (a0, bls12_381::Scalar::from_string(&a1)); - s0.sub_assign(s1); - Ok(Str(std::string::ToString::to_string(&s0)[2..].to_string())) - } - (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(&format!("scalar sub expect (zkscalar, zkscalar) found \n {:?}", a).to_string()), - } -} - -fn mul_scalar(a: MalArgs) -> MalRet { - println!("mul {:?}", a[0]); - match (a[0].clone(), a[1].clone()) { - (Func(_, _), ZKScalar(a1)) => { - if let Vector(ref values, _) = a[0].apply(vec![]).unwrap() { - if let ZKScalar(mut a0) = values[0] { - a0.mul_assign(a1); - Ok(ZKScalar(a0)) - } else { - error("scalar mul expect (zkscalar, zkscalar) found (func, zkscalar)") - } - } else { - error("scalar mul expect (zkscalar, zkscalar)") - } - } - (ZKScalar(a1), Func(_, _)) => { - if let Vector(ref values, _) = a[1].apply(vec![]).unwrap() { - if let ZKScalar(mut a0) = values[0] { - a0.mul_assign(a1); - Ok(ZKScalar(a0)) - } else { - error("scalar mul expect (zkscalar, zkscalar) found (func, zkscalar)") - } - } else { - error("scalar mul expect (zkscalar, zkscalar)") - } - } - (ZKScalar(mut a0), ZKScalar(a1)) => { - a0.mul_assign(a1); - Ok(ZKScalar(a0)) - } - (Str(a0), Str(a1)) => { - let (mut s0, s1) = ( - bls12_381::Scalar::from_string(&a0), - bls12_381::Scalar::from_string(&a1), - ); - s0.mul_assign(s1); - Ok(Str(std::string::ToString::to_string(&s0)[2..].to_string())) - } - (ZKScalar(a0), Str(a1)) => { - let (mut s0, s1) = (a0, bls12_381::Scalar::from_string(&a1)); - s0.mul_assign(s1); - Ok(Str(std::string::ToString::to_string(&s0)[2..].to_string())) - } - (Str(a0), ZKScalar(a1)) => { - let (mut s0, s1) = (bls12_381::Scalar::from_string(&a0), a1); - s0.mul_assign(s1); - Ok(Str(std::string::ToString::to_string(&s0)[2..].to_string())) - } - _ => error(&format!("scalar mul expect (zkscalar, zkscalar) \n {:?}", a).to_string()), - } -} - -fn div_scalar(a: MalArgs) -> MalRet { - match (a[0].clone(), a[1].clone()) { - (ZKScalar(s0), ZKScalar(s1)) => { - let ret = s1.invert().map(|other| *&s0 * other); - if bool::from(ret.is_some()) { - Ok(Str( - std::string::ToString::to_string(&ret.unwrap())[2..].to_string() - )) - } else { - error("DivisionByZero") - } - } - (Str(a0), ZKScalar(a1)) => { - let (s0, s1) = (bls12_381::Scalar::from_string(&a0), a1); - let ret = s1.invert().map(|other| *&s0 * other); - if bool::from(ret.is_some()) { - Ok(Str( - std::string::ToString::to_string(&ret.unwrap())[2..].to_string() - )) - } else { - error("DivisionByZero") - } - } - (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); - if bool::from(ret.is_some()) { - Ok(Str( - std::string::ToString::to_string(&ret.unwrap())[2..].to_string() - )) - } else { - error("DivisionByZero") - } - } - _ => error(&format!("scalar div expect (zkscalar, zkscalar) \n {:?}", a).to_string()), - } -} - -fn range(a: MalArgs) -> MalRet { - let mut result = vec![]; - match (a[0].clone(), a[1].clone()) { - (Int(a0), Int(a1)) => { - for n in a0..a1 { - result.push(n); - } - Ok(list!(result.iter().map(|_a| Nil).collect::>())) - } - _ => error("expected int int"), - } -} - -fn scalar_zero(a: MalArgs) -> MalRet { - match a.len() { - 0 => Ok(vector![vec![ZKScalar(bls12_381::Scalar::zero())]]), - _ => 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 scalar_one_neg(a: MalArgs) -> MalRet { - match a.len() { - 0 => Ok(vector![vec![ZKScalar(bls12_381::Scalar::one().neg())]]), - _ => Ok(vector![vec![ - ZKScalar(bls12_381::Scalar::one().neg()), - 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() { - ZKScalar(s0) => Ok(ZKScalar(s0)), - Str(a0) => { - let s0 = bls12_381::Scalar::from_string(&a0.to_string()); - Ok(ZKScalar(s0)) - } - Int(a0) => { - let s0 = bls12_381::Scalar::from(a0 as u64); - Ok(ZKScalar(s0)) - } - _ => error("scalar from expected (string or int)"), - } -} - -fn scalar_square(a: MalArgs) -> MalRet { - match a[0].clone() { - ZKScalar(a0) => { - let z0 = a0.clone(); - Ok(ZKScalar(z0.square())) - } - Str(a0) => { - let s0 = bls12_381::Scalar::from_string(&a0); - Ok(ZKScalar(s0.square())) - } - _ => error( - &format!("scalar square expect (zkscalar or string) found \n {:?}", a).to_string(), - ), - } -} - -fn scalar_double(a: MalArgs) -> MalRet { - match a[0].clone() { - Func(_, _) => { - if let Vector(ref values, _) = a[0].apply(vec![]).unwrap() { - if let ZKScalar(a0) = values[0] { - a0.double(); - Ok(ZKScalar(a0)) - } else { - error( - &format!("scalar double expect (zkscalar or string) found \n {:?}", a) - .to_string(), - ) - } - } else { - error( - &format!("scalar double expect (zkscalar or string) found \n {:?}", a) - .to_string(), - ) - } - } - ZKScalar(a0) => { - let z0 = a0.clone(); - Ok(ZKScalar(z0.double())) - } - Str(a0) => { - let s0 = bls12_381::Scalar::from_string(&a0); - Ok(ZKScalar(s0.double())) - } - _ => error( - &format!("scalar double expect (zkscalar or string) found \n {:?}", a).to_string(), - ), - } -} - -fn scalar_invert(a: MalArgs) -> MalRet { - match a[0].clone() { - Func(_, _) => { - if let Vector(ref values, _) = a[0].apply(vec![]).unwrap() { - if let ZKScalar(a0) = values[0] { - if a0.is_zero() { - error(&format!("scalar invert divizion by zero \n {:?}", a0).to_string()) - } else { - Ok(ZKScalar(a0.invert().unwrap())) - } - } else { - error( - &format!("scalar invert expect (zkscalar or string) found \n {:?}", a) - .to_string(), - ) - } - } else { - error( - &format!("scalar invert expect (zkscalar or string) found \n {:?}", a) - .to_string(), - ) - } - } - ZKScalar(a0) => { - let z0 = a0.clone(); - Ok(ZKScalar(z0.invert().unwrap())) - } - Str(a0) => { - let s0 = bls12_381::Scalar::from_string(&a0); - Ok(ZKScalar(s0.invert().unwrap())) - } - _ => error( - &format!("scalar invert expect (zkscalar or string) found \n {:?}", a).to_string(), - ), - } -} - -fn scalar_is_zero(a: MalArgs) -> MalRet { - match a[0].clone() { - Func(_, _) => { - if let Vector(ref values, _) = a[0].apply(vec![]).unwrap() { - if let ZKScalar(a0) = values[0] { - Ok(Bool(a0.is_zero())) - } else { - error( - &format!( - "scalar is zero expect (zkscalar or string) found \n {:?}", - a - ) - .to_string(), - ) - } - } else { - error( - &format!( - "scalar is zero expect (zkscalar or string) found \n {:?}", - a - ) - .to_string(), - ) - } - } - ZKScalar(a0) => { - let z0 = a0.clone(); - Ok(Bool(z0.is_zero())) - } - Str(a0) => { - let s0 = bls12_381::Scalar::from_string(&a0); - Ok(Bool(s0.is_zero())) - } - _ => error( - &format!( - "scalar is zero expect (zkscalar or string) found \n {:?}", - a - ) - .to_string(), - ), - } -} - -fn add_scalar(a: MalArgs) -> MalRet { - println!("add_scalar {:?}", a); - match (a[0].clone(), a[1].clone()) { - (Func(_, _), ZKScalar(a1)) => { - if let Vector(ref values, _) = a[0].apply(vec![]).unwrap() { - if let ZKScalar(mut a0) = values[0] { - a0.add_assign(a1); - Ok(ZKScalar(a0)) - } else { - error("scalar add expect (zkscalar, zkscalar) found (func, zkscalar)") - } - } else { - error("scalar add expect (zkscalar, zkscalar)") - } - } - (Func(_, _), Str(a1)) => { - if let Vector(ref values, _) = a[0].apply(vec![]).unwrap() { - if let ZKScalar(mut a0) = values[0] { - let s1 = bls12_381::Scalar::from_string(&a1); - a0.add_assign(s1); - Ok(ZKScalar(a0)) - } else { - error("scalar add expect (zkscalar, zkscalar) found (func, zkscalar)") - } - } else { - error("scalar add expect (zkscalar, zkscalar)") - } - } - (ZKScalar(a0), ZKScalar(a1)) => { - let (mut z0, z1) = (a0.clone(), a1.clone()); - z0.add_assign(z1); - Ok(ZKScalar(z0)) - } - (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(ZKScalar(s0)) - } - (Str(a0), ZKScalar(a1)) => { - let (mut s0, s1) = (bls12_381::Scalar::from_string(&a0), a1); - s0.add_assign(s1); - Ok(ZKScalar(s0)) - } - (ZKScalar(a1), Str(a0)) => { - let (mut s0, s1) = (bls12_381::Scalar::from_string(&a0), a1); - s0.add_assign(s1); - Ok(ZKScalar(s0)) - } - // (List(a0, _), ZKScalar(mut a1)) => { - // let first_slice = a0.to_vec(); - // let result = first_slice[0].apply(first_slice[1..].to_vec()); - // println!("result {:?}", result); - // if let ZKScalar(value) = result.unwrap() { - // a1.add_assign(value); - // } - // Ok(ZKScalar(a1)) - // } - _ => error(&format!("scalar add expect (zkscalar, zkscalar) found \n {:?}", a).to_string()), - } -} - -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"), - } -} - -fn gen_rand(_a: MalArgs) -> MalRet { - let mut rng = rand::thread_rng(); - Ok(MalVal::Int(rng.gen::())) -} - -fn scalar_rnd(_a: MalArgs) -> MalRet { - let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng); - let value = bls12_381::Scalar::from_bytes(&randomness_value.to_bytes()); - Ok(MalVal::ZKScalar(value.unwrap())) -} - -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)), - ("scalar::one::neg", func(scalar_one_neg)), - ("neg", func(negate_from)), - ("scalar::zero", func(scalar_zero)), - ("scalar", func(scalar_from)), - ("square", func(scalar_square)), - ("cs::one", func(cs_one)), - ("second", func(second)), - ("genrand", func(gen_rand)), - ("double", func(scalar_double)), - ("invert", func(scalar_invert)), - ("zero?", func(scalar_is_zero)), - ("rnd-scalar", func(scalar_rnd)), - ] -} diff --git a/lisp/env.rs b/lisp/env.rs deleted file mode 100644 index f265f3f01..000000000 --- a/lisp/env.rs +++ /dev/null @@ -1,85 +0,0 @@ -use std::cell::RefCell; -use std::collections::HashMap; -use std::rc::Rc; -// use fnv::FnvHashMap; - -use crate::types::MalErr::ErrString; -use crate::types::MalVal::{List, Nil, Sym, Vector}; -use crate::types::{error, MalErr, MalRet, MalVal}; - -#[derive(Debug)] -pub struct EnvStruct { - data: RefCell>, - pub outer: Option, -} - -pub type Env = Rc; - -// TODO: it would be nice to use impl here but it doesn't work on -// a deftype (i.e. Env) - -pub fn env_new(outer: Option) -> Env { - Rc::new(EnvStruct { - data: RefCell::new(HashMap::default()), - outer: outer, - }) -} - -// TODO: mbinds and exprs as & types -pub fn env_bind(outer: Option, mbinds: MalVal, exprs: Vec) -> Result { - let env = env_new(outer); - match mbinds { - List(binds, _) | Vector(binds, _) => { - for (i, b) in binds.iter().enumerate() { - match b { - Sym(s) if s == "&" => { - env_set(&env, binds[i + 1].clone(), list!(exprs[i..].to_vec()))?; - break; - } - _ => { - env_set(&env, b.clone(), exprs[i].clone())?; - } - } - } - Ok(env) - } - _ => Err(ErrString("env_bind binds not List/Vector".to_string())), - } -} - -pub fn env_find(env: &Env, key: &str) -> Option { - match (env.data.borrow().contains_key(key), env.outer.clone()) { - (true, _) => Some(env.clone()), - (false, Some(o)) => env_find(&o, key), - _ => None, - } -} - -pub fn env_get(env: &Env, key: &MalVal) -> MalRet { - match key { - Sym(ref s) => match env_find(env, s) { - Some(e) => Ok(e - .data - .borrow() - .get(s) - .ok_or(ErrString(format!("'{}' not found", s)))? - .clone()), - _ => error(&format!("'{}' not found", s)), - }, - _ => error("Env.get called with non-Str"), - } -} - -pub fn env_set(env: &Env, key: MalVal, val: MalVal) -> MalRet { - match key { - Sym(ref s) => { - env.data.borrow_mut().insert(s.to_string(), val.clone()); - Ok(val) - } - _ => error("Env.set called with non-Str"), - } -} - -pub fn env_sets(env: &Env, key: &str, val: MalVal) { - env.data.borrow_mut().insert(key.to_string(), val); -} diff --git a/lisp/examples/jubjub-add-macro.lisp b/lisp/examples/jubjub-add-macro.lisp deleted file mode 100644 index 4704b8e41..000000000 --- a/lisp/examples/jubjub-add-macro.lisp +++ /dev/null @@ -1,52 +0,0 @@ -(println "jubjub-add-macro.lisp") -(load-file "util.lisp") - -(defmacro! jubjub-add (fn* [param1 param2 param3 param4] - (let* [u1 (gensym) v1 (gensym) u2 (gensym) v2 (gensym) - EDWARDS_D (gensym) U (gensym) A (gensym) B (gensym) - C (gensym) u3 (gensym) v3 (gensym)] ( - `(def! ~u1 (alloc ~u1 param1)) - `(def! ~v1 (alloc ~v1 param2)) - `(def! ~u2 (alloc ~u2 param3)) - `(def! ~v2 (alloc ~v2 param4)) - `(def! ~EDWARDS_D (alloc-const ~EDWARDS_D (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))) - `(def! ~U (alloc ~U (* (+ ~u1 ~v1) (+ ~u2 ~v2)))) - `(def! ~A (alloc ~A (* ~v2 ~u1))) - `(def! ~B (alloc ~B (* ~u2 ~v1))) - `(def! ~C (alloc ~C (* ~EDWARDS_D (* ~A ~B)))) - `(def! ~u3 (alloc-input ~u3 (/ (+ ~A ~B) (+ scalar::one ~C)))) - `(def! ~v3 (alloc-input ~v3 (/ (- (- ~U ~A) ~B) (- scalar::one ~C)))) - `(enforce - ((scalar::one ~u1) (scalar::one ~v1)) - ((scalar::one ~u2) (scalar::one ~v2)) - (scalar::one ~U) - ) - `(enforce - (~EDWARDS_D ~A) - (scalar::one ~B) - (scalar::one ~C) - ) - `(enforce - ((scalar::one cs::one)(scalar::one ~C)) - (scalar::one ~u3) - ((scalar::one ~A) (scalar::one ~B)) - ) - `(enforce - ((scalar::one cs::one) (scalar::one::neg ~C)) - (scalar::one ~v3) - ((scalar::one ~U) (scalar::one::neg ~A) (scalar::one::neg ~B)) - ) - ) - ;; improve return values -) -)) - -(def! param4 (scalar "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891")) -(def! param3 (scalar "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e")) -(def! param2 (scalar "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891")) -(def! param1 (scalar "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e")) - -(prove ( - (def! result1 (jubjub-add param1 param2 param3 param4)) - (println 'jubjub-result result1) -)) \ No newline at end of file diff --git a/lisp/examples/jubjub.lisp b/lisp/examples/jubjub.lisp deleted file mode 100644 index d75911af8..000000000 --- a/lisp/examples/jubjub.lisp +++ /dev/null @@ -1,79 +0,0 @@ -(println "jubjub-add.lisp") -(load-file "util.lisp") - -(defmacro! zk-square (fn* [var] ( - (let* [v1 (gensym) - v2 (gensym)] ( - `(alloc ~v1 ~var) - `(alloc ~v2 (square ~var)) - `(enforce - (scalar::one ~v1) - (scalar::one ~v1) - (scalar::one ~v2) - ) - ) - )) -)) - -;; -u^2 + v^2 = 1 + du^2v^2 -(defmacro! zk-witness (fn* [val1 val2] ( - (let* [v (gensym) - u (gensym) - u2v2 (gensym)] ( - `(alloc ~v1 ~var) - `(alloc ~v2 (square ~var)) - `(enforce - (scalar::one ~v1) - (scalar::one ~v1) - (scalar::one ~v2) - ) - ) - )) -)) - -(defmacro! jubjub-add (fn* [param1 param2 param3 param4] - (let* [u1 (gensym) v1 (gensym) u2 (gensym) v2 (gensym) - EDWARDS_D (gensym) U (gensym) A (gensym) B (gensym) - C (gensym) u3 (gensym) v3 (gensym)] ( - `(def! ~u1 (alloc ~u1 param1)) - `(def! ~v1 (alloc ~v1 param2)) - `(def! ~u2 (alloc ~u2 param3)) - `(def! ~v2 (alloc ~v2 param4)) - `(def! ~EDWARDS_D (alloc-const ~EDWARDS_D (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))) - `(def! ~U (alloc ~U (* (+ ~u1 ~v1) (+ ~u2 ~v2)))) - `(def! ~A (alloc ~A (* ~v2 ~u1))) - `(def! ~B (alloc ~B (* ~u2 ~v1))) - `(def! ~C (alloc ~C (* ~EDWARDS_D (* ~A ~B)))) - `(def! ~u3 (alloc-input ~u3 (/ (+ ~A ~B) (+ scalar::one ~C)))) - `(def! ~v3 (alloc-input ~v3 (/ (- (- ~U ~A) ~B) (- scalar::one ~C)))) - `(enforce - ((scalar::one ~u1) (scalar::one ~v1)) - ((scalar::one ~u2) (scalar::one ~v2)) - (scalar::one ~U) - ) - `(enforce - (~EDWARDS_D ~A) - (scalar::one ~B) - (scalar::one ~C) - ) - `(enforce - ((scalar::one cs::one)(scalar::one ~C)) - (scalar::one ~u3) - ((scalar::one ~A) (scalar::one ~B)) - ) - `(enforce - ((scalar::one cs::one) (scalar::one::neg ~C)) - (scalar::one ~v3) - ((scalar::one ~U) (scalar::one::neg ~A) (scalar::one::neg ~B)) - ) - ) - ;; improve return values -) -)) - -(prove - ( - (def! result-witness (zk-witness param1 param2)) - (println 'result-witness (nth (nth result-witness 0) 1)) - ) -) \ No newline at end of file diff --git a/lisp/examples/macro-test.lisp b/lisp/examples/macro-test.lisp deleted file mode 100644 index a3909c136..000000000 --- a/lisp/examples/macro-test.lisp +++ /dev/null @@ -1,321 +0,0 @@ -(load-file "util.lisp") - -(def! zk-not-small-order? (fn* [u v] ( - (def! first-doubling (last (last (zk-double u v)))) - (def! second-doubling (last (last - (zk-double (get first-doubling "u3") (get first-doubling "v3"))))) - (def! third-doubling (last (last - (zk-double (get second-doubling "u3") (get second-doubling "v3"))))) - (zk-nonzero? (get third-doubling "u3")) - ) - ) -) - -(defmacro! zk-nonzero? (fn* [var] ( - (let* [inv (gensym) - v1 (gensym)] ( - `(alloc ~inv (invert ~var)) - `(alloc ~v1 ~var) - `(enforce - (scalar::one ~v1) - (scalar::one ~inv) - (scalar::one cs::one) - ) - ) - )) -)) - -(defmacro! zk-square (fn* [var] ( - (let* [v1 (gensym) - v2 (gensym)] ( - `(alloc ~v1 ~var) - `(def! output (alloc-input ~v2 (square ~var))) - `(enforce - (scalar::one ~v1) - (scalar::one ~v1) - (scalar::one ~v2) - ) - `{ "v2" output } - ) - )) -)) - -(defmacro! zk-mul (fn* [val1 val2] ( - (let* [v1 (gensym) - v2 (gensym) - var (gensym)] ( - `(alloc ~v1 ~val1) - `(alloc ~v2 ~val2) - `(def! result (alloc-input ~var (* ~val1 ~val2))) - `(enforce - (scalar::one ~v1) - (scalar::one ~v2) - (scalar::one ~var) - ) - `{ "result" result } - ) - )) -)) - -(defmacro! zk-witness (fn* [val1 val2] ( - (let* [u2 (gensym) - v2 (gensym) - u2v2 (gensym) - EDWARDS_D (gensym)] ( - `(def! ~EDWARDS_D (alloc-const ~EDWARDS_D (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))) - `(def! ~u2 (alloc ~u2 (get (nth (nth (zk-square ~val1) 0) 3) "v2"))) - `(def! ~v2 (alloc ~v2 (get (nth (nth (zk-square ~val2) 0) 3) "v2"))) - `(def! result (alloc-input ~u2v2 (get (last (last (zk-mul ~u2 ~v2))) "result"))) - `(enforce - ((scalar::one::neg ~u2) (scalar::one ~v2)) - (scalar::one cs::one) - ((scalar::one cs::one) (~EDWARDS_D ~u2v2)) - ) - `{ "result" result } - ) - )) -)) - -(defmacro! zk-double (fn* [val1 val2] ( - (let* [u (gensym) - v (gensym) - u3 (gensym) - v3 (gensym) - T (gensym) - A (gensym) - C (gensym) - EDWARDS_D (gensym)] ( - `(def! ~EDWARDS_D (alloc-const ~EDWARDS_D (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))) - `(def! ~u (alloc ~u ~val1)) - `(def! ~v (alloc ~v ~val2)) - `(def! ~T (alloc ~T (* (+ ~val1 ~val2) (+ ~val1 ~val2)))) - `(def! ~A (alloc ~A (* ~u ~v))) - `(def! ~C (alloc ~C (* (square ~A) ~EDWARDS_D))) - `(def! ~u3 (alloc-input ~u3 (/ (double ~A) (+ scalar::one ~C)))) - `(def! ~v3 (alloc-input ~v3 (/ (- ~T (double ~A)) (- scalar::one ~C)))) - `(enforce - ((scalar::one ~u) (scalar::one ~v)) - ((scalar::one ~u) (scalar::one ~v)) - (scalar::one ~T) - ) - `(enforce - (~EDWARDS_D ~A) - (scalar::one ~A) - (scalar::one ~C) - ) - `(enforce - ((scalar::one cs::one) (scalar::one ~C)) - (scalar::one ~u3) - ((scalar::one ~A) (scalar::one ~A)) - ) - `(enforce - ((scalar::one cs::one) (scalar::one::neg ~C)) - (scalar::one ~v3) - ((scalar::one ~T) (scalar::one::neg ~A) (scalar::one::neg ~A)) - ) - { "u3" u3, "v3" v3 } - ) - )) -)) - -(defmacro! conditionally-select (fn* [val1 val2 val3] ( - (let* [u-prime (gensym) - v-prime (gensym) - u (gensym) - v (gensym) - condition (gensym) - ] ( - `(def! ~u (alloc ~u ~val1)) - `(def! ~v (alloc ~v ~val2)) - `(def! ~condition (alloc ~condition ~val3)) - `(def! ~u-prime (alloc-input ~u-prime (* ~u ~condition))) - `(def! ~v-prime (alloc-input ~v-prime (* ~v ~condition))) - `(enforce - (scalar::one ~u) - (scalar::one ~condition) - (scalar::one ~u-prime) - ) - `(enforce - (scalar::one ~v) - (scalar::one ~condition) - (scalar::one ~v-prime) - ) - { "u-prime" u-prime, "v-prime" v-prime } - ) -)))) - -(defmacro! jj-add (fn* [param1 param2 param3 param4] - (let* [u1 (gensym) v1 (gensym) u2 (gensym) v2 (gensym) - EDWARDS_D (gensym) U (gensym) A (gensym) B (gensym) - C (gensym) u3 (gensym) v3 (gensym)] ( - ;; debug - ;; `(println 'jj-add ~param1 ~param2 ~param3 ~param4) - `(def! ~u1 (alloc ~u1 ~param1)) - `(def! ~v1 (alloc ~v1 ~param2)) - `(def! ~u2 (alloc ~u2 ~param3)) - `(def! ~v2 (alloc ~v2 ~param4)) - `(def! ~EDWARDS_D (alloc-const ~EDWARDS_D (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))) - `(def! ~U (alloc ~U (* (+ ~u1 ~v1) (+ ~u2 ~v2)))) - `(def! ~A (alloc ~A (* ~v2 ~u1))) - `(def! ~B (alloc ~B (* ~u2 ~v1))) - `(def! ~C (alloc ~C (* ~EDWARDS_D (* ~A ~B)))) - `(def! ~u3 (alloc-input ~u3 (/ (+ ~A ~B) (+ scalar::one ~C)))) - `(def! ~v3 (alloc-input ~v3 (/ (- (- ~U ~A) ~B) (- scalar::one ~C)))) - `(enforce - ((scalar::one ~u1) (scalar::one ~v1)) - ((scalar::one ~u2) (scalar::one ~v2)) - (scalar::one ~U) - ) - `(enforce - (~EDWARDS_D ~A) - (scalar::one ~B) - (scalar::one ~C) - ) - `(enforce - ((scalar::one cs::one)(scalar::one ~C)) - (scalar::one ~u3) - ((scalar::one ~A) (scalar::one ~B)) - ) - `(enforce - ((scalar::one cs::one) (scalar::one::neg ~C)) - (scalar::one ~v3) - ((scalar::one ~U) (scalar::one::neg ~A) (scalar::one::neg ~B)) - ) - `{ "u3" u3, "v3" v3 } - ) -) -)) - -(defmacro! zk-boolean (fn* [val] ( - (let* [var (gensym)] ( - `(alloc ~var ~val) - `(enforce - (scalar::one cs::one) (scalar::one ~var) - (scalar::one ~var) - () - ) - ) -)))) - -(def! jj-mul (fn* [u v b] ( - (def! result (unpack-bits b)) - (eval (map zk-boolean result)) - (def! val (last (last (zk-double u v)))) - (def! acc 0) - (dotimes (count result) ( - (def! u3 (get val "u3")) - (def! v3 (get val "v3")) - (def! r (nth result acc)) - (def! cond-result (last (last (conditionally-select u3 v3 r)))) - (def! u-prime (get cond-result "u-prime")) - (def! v-prime (get cond-result "v-prime")) - (def! add-result (last (jj-add u3 v3 u-prime v-prime))) - (def! u-add (get add-result "u3")) - (def! v-add (get add-result "v3")) - (def! val (last (last (zk-double u-add v-add)))) - (def! acc (i+ acc 1)) - )) - (val) - ;; { "u3" (get val "u3"), "v3" (get val "v3") } -))) - -(load-file "mimc-constants.lisp") -(defmacro! mimc-macro (fn* [left-value right-value acc] ( - (let* [tmp-xl (gensym2 'tmp_xl) - xl-new-value (gensym2 'xl_new_value) - cur-mimc-const (gensym2 'cur_mimc_const) - xl (gensym2 'xl) - xr (gensym2 'xr)] ( - `(def! ~xl (alloc ~xl ~left-value)) - `(def! ~xr (alloc ~xr ~right-value)) - `(def! ~cur-mimc-const (alloc-const ~cur-mimc-const (nth mimc-constants ~acc))) - `(def! ~tmp-xl (alloc ~tmp-xl (square (+ ~cur-mimc-const ~xl)))) - `(enforce - ((scalar::one ~xl) (~cur-mimc-const cs::one)) - ((scalar::one ~xl) (~cur-mimc-const cs::one)) - (scalar::one ~tmp-xl) - ) - `(def! new-value (+ (* ~tmp-xl (+ ~cur-mimc-const ~xl)) ~xr)) - `(if (= ~acc 321) - (def! ~xl-new-value (alloc-input ~xl-new-value new-value)) - (def! ~xl-new-value (alloc ~xl-new-value new-value)) - ) - `(enforce - (scalar::one ~tmp-xl) - ((scalar::one ~xl) (~cur-mimc-const cs::one)) - ((scalar::one ~xl-new-value) (scalar::one::neg ~xr)) - ) - `{ "left" new-value } - ) -)))) - -(def! mimc (fn* [left right] ( - (def! acc 0) - (def! xl left) - (def! xr right) - (dotimes 322 ( - (def! result (mimc-macro xl xr acc)) - (def! result-value (get (last (last result)) "left")) - (println acc) - (println xl xr) - (println result-value) - (def! xr xl) - (def! xl result-value) - (def! acc (i+ acc 1)) - )) -))) - -(def! mint-contract (fn* [public-u public-v] ( - (def! randomness (rnd-scalar)) - (def! witness-result (zk-witness public-u public-v)) - (def! not-small-order (zk-not-small-order? public-u public-v)) - (def! g-vcr-u (alloc-input "g-vcr-u" public-u)) - (def! g-vcr-v (alloc-input "g-vcr-v" public-v)) - (def! mul-result (last (last (jj-mul g-vcr-u g-vcr-v randomness)))) - (def! rcvu (alloc "rcvu" (get mul-result "u3"))) - (def! rcvr (alloc "rcvr" (get mul-result "v3"))) - (enforce - (scalar::one rcvu) - (scalar::one cs::one) - (scalar::one rcvu) - ) - (enforce - (scalar::one rcvr) - (scalar::one cs::one) - (scalar::one rcvr) - ) -))) - -(prove - ( - (def! param-u (scalar "6800f4fa0f001cfc7ff6826ad58004b4d1d8da41af03744e3bce3b7793664337")) - (def! param-v (scalar "6d81d3a9cb45dedbe6fb2a6e1e22ab50ad46f1b0473b803b3caefab9380b6a8b")) - (mint-contract param-u param-v) - ) -) - -;; following some examples -;; (def! left (scalar "15a36d1f0f390d8852a35a8c1908dd87a361ee3fd48fdf77b9819dc82d90607e")) -;; (def! right (scalar "015d8c7f5b43fe33f7891142c001d9251f3abeeb98fad3e87b0dc53c4ebf1891")) -;; (mimc left right) -;; (def! param3 (rnd-scalar)) -;; (jj-mul param-u param-v param3) -;; (def! param3 (rnd-scalar)) -;; (def! param-u (scalar "6800f4fa0f001cfc7ff6826ad58004b4d1d8da41af03744e3bce3b7793664337")) -;; (def! param-v (scalar "6d81d3a9cb45dedbe6fb2a6e1e22ab50ad46f1b0473b803b3caefab9380b6a8b")) -;; (jj-mul param-u param-v param3) -;; (def! param3 (rnd-scalar)) -;; (println 'rnd-scalar param3) -;; (def! param-u (scalar "6800f4fa0f001cfc7ff6826ad58004b4d1d8da41af03744e3bce3b7793664337")) -;; (def! param-v (scalar "6d81d3a9cb45dedbe6fb2a6e1e22ab50ad46f1b0473b803b3caefab9380b6a8b")) -;; (println (zk-mul param1 param2)) -;; (jj-mul param-u param-v param3) -;; (println (zk-mul param1 param2)) -;; (def! param1 (scalar 3)) -;; (def! param2 (scalar 9)) -;; (println (zk-square param1)) -;; (println (zk-mul param1 param2)) -;; (println 'witness (zk-witness param-u param-v)) -;; (println 'double (last (last (zk-double param-u param-v)))) -;; (println 'nonzero (zk-nonzero? param3)) -;; (println 'not-small-order? (zk-not-small-order? param-u param-v)) diff --git a/lisp/examples/mimc-constants.lisp b/lisp/examples/mimc-constants.lisp deleted file mode 100644 index 06b9a5507..000000000 --- a/lisp/examples/mimc-constants.lisp +++ /dev/null @@ -1,323 +0,0 @@ -(def! mimc-constants ("4699afdd3f9ce9916eaffcfbef597c5009ae9d3209c3b15feb6928a4a8d4b59e" -"41e2431761fee4a40b468524d91b3d64590b3c242de10d18f55f0c5e3883ef02" -"5a04a1ea758bf1cc1140fcec1ce2c9d68da53d6cf7ee8dfeedfb2ee45db08c27" -"2e4b930078e93e73581d7b71120a8e8b9627955a0aabf139bbfa5feceaab2e3b" -"6a9db69e4fd0a3f94402cf22076bd18300c344c69bf665542129ad887f0030ab" -"4458f2de4e16ce2ead3fe9dd164cca36d2b70a25e71f55cf0c51ca553a4f83ad" -"04f539ab6ea2d344049219c720a16c4e6033f8360b124519fdbb6d441428143b" -"6b9c7b12a4b3cf92e2f2b386426058709573f9abdf1bcc5411dacd7ea0eaf8f3" -"4375e3120921697155b3ea15c32b9412adce3a8ff8e28e1b8c95935cc71ad853" -"041854bb643e9e5e5d8aa6e828dc4c732c8fa24192a160f40da85737372c5d0c" -"65d9cc7ab2a2060d198d66310a902bddeeb7f5150173190036d2fae68de1c2b9" -"1e7d2b472c6a40254a228b0543aff318084e7f6152617a6cf7fc405d917bfc37" -"35293381012ebaf649d8c6db4e4d5e594bd114c99c234ddff7b9b5f6f8a9ec36" -"3a50794418ac54a1467578ed61e34d8be5d52c5f188f42955fe8d5e257ad3e89" -"446d905f60110dbd51129896a63a0e34bb0502101ad6311998ad2dfd74818277" -"3eee70356bab144c54b5fc1095f9bce59c727a57a5582dcbbd5c3afc3c61ceca" -"40b08ae056833e12c82f7e15e2dc72febc15d3275b51ec70afaffa6ce8bbb3d0" -"205923e6eb137869a552b4857bb64f946c912f3335a94291ebb8b29ecd3e6034" -"2a6aebced756f7e33c466bca2169ba24c471a088c8363fe0a966a223fd3b59ea" -"566efaf4e022036a8e073fd9812376888ac9f37c794daebe3fa77b1a87bf109e" -"1ee814f2660e7272712d588477e458c06f8f06950402e97c542d3682ad5f9aed" -"257fe0ace4965622be247dba9185f108707f4ab16c910c03c565afab43b0fb4f" -"43e156f0cad02ff6b763645c97663ab72229bb0a34f975681359797ccd58093c" -"317f43b78cc26f0332a3ec3ec187332d4de0f2baf04f62fe76bee9b11256130b" -"076ca6cd23830e3b3ece767b774e1b2243408098a7c5b816e7c616cb88f6b916" -"14e30a644f034c72cf40b1bc790200c2e8ab3e750e38f3fb0160188e817e4560" -"02eb02bfbac795a497a0882d66b718bb23de64f9fe7644179ddd3241cc407942" -"644f175cf6f2268d451e5188e467c508bc91d870646de9297911be2aedf26daf" -"14aef8f4f5499a0387e521a1c6064094590f149c52fb99e37b583434ca6bd46c" -"2ddc7c6bba8895913f3deee128bc63b5e34797274de80da775c4a0c810ac60e6" -"46adc33428a63a20459699183272b14797a5a7d1d66079701d214bced9a4be71" -"552847d9a2a5b03f726b277ba01ad61c0e28114667e7a9e11229b83224f74349" -"624921e44f5811f76c06ab74a11ad56e5241e4c597e9d172ee3c862bf6d4b1fd" -"506af906fab5f9407ee71824d72dfcd99115c5a2eb53b55a1d5877910a645282" -"514ddde7e75b27ae6f31efb7375bc209dcdd0ab4c277ee0f8b362cb5211def31" -"2e3be2e2a10f8e24b411902d9578d44e2a4a5042036ecc397e1cc5ab88e76329" -"61755a2f6a9729a3bd8d21aea98f4cf885aa1751a714e251a517395711674bf5" -"68f8f91713d81c2a6d601411447e944c27f7a1862855b940ef3521cbf4074e96" -"32e6b3dfaa0162846620ace97838a93f48999b5bbc078964687c795a9e5b71a0" -"3c783bf0caa35bd381603b9e3aa5dbcc4ed4fc93b03d69a49fa15286a6374f8d" -"4a3f322f033de27244d79dd5c6c2f34d84c24c917ce95cfb6458d72124280e70" -"3ee0abb7af79168e05566994017fade2d69bdb55c4253f996362b73d49f3f70e" -"15498a06e80c6060320e9a01292ee1a805c2aafd7b92f76b5f5e8be515e0a3b3" -"02424410de65455350831f5b1c3554626f6bbf373ed0f627b42f0d3ec2fdd487" -"5886da407f6014665272b45d213cb388987503398d407732f278c9a35267622d" -"15f6180f287d2ef5d9d057dc18eb7df732d97632bfb31e93ac065dcf0c67fd40" -"65f5dc85c9660f184a09ee768ae9af0f62911af31920d3b5c49ac0360d261441" -"65751a6bbccb0ea7fd79fe7231d03d2f14ec6a24c5d9c4a77d1a86acf3d027a9" -"4c21c6990442cb96b2ca684c9d427dc41090447248378f50b4de15b616f1f133" -"34cde97ef5c2459e29dbad8324fbefa5097f744f737cc59ad2681e49dfa43f99" -"5df3e3787510f9e2b32beb2fdf76fc6d646b3fb94d4ede65309762fc515ffb55" -"30394778b396dd8191e78cb7627636eb82b15b0de788c1e2db2788b05caedd8b" -"695a64cc6953c658f40c1c2666715790410e302d3d902fcb809924896c2d1f4e" -"6a4fe5863990f4b4d588841b0e52c4dc7a8c4644edfec7c721ab66b162ec5de9" -"62e4428cb1856ae809589806e5e7869ab0fb818d6c0a696d94ee616fe549400e" -"0b1e8a6d6581c13b6888d0bd9816bda3695f917d03510d9b42452f3501e3d55a" -"5e5a2b767f853d0f0bf0e3cae872fb942065db112cb48a12dbce3ce4da28aa87" -"2c1c59e21a9741edbaf1e5a275c573bbeb395c6a79abdd0e532e000298dc8c00" -"25d648572388935cac47095b4f38b3ebe6519766a0d03bf7de9b4368b7bc1b58" -"475a00fdc58c8a7092cae8942af520dd5e0f476dc469f0c3e908da68be55e6ff" -"3fe62baf8e0a5286b0055e16e712ad06d233fa71fb374557d4c3d585e33dd37b" -"54d74923f593c55659f92b34bf5c05a400187e143850173786c8a1dd2f3a1283" -"6aa3afe84262b6c5bc8994a2c0e66a64a534904efcf47ead067fa09cd2d58a6a" -"2069d079cd963cec28ccac413172576ace57da0b4ab502c11289fff6ff2de6eb" -"364b3a05a8b1271aa61d5894b51a445c5896e86a535869b70e56e1e0f7f49f42" -"1c904753197233afda76661025e67f6a8e7a5c209292e151a7f34119397c281f" -"45f6d1ed8bc4395ccc6cfc90a1cf5f636248e966d82d040d795014f5d184b3ac" -"1bdbb396d84fe4c8b5b230e1c925e9f0f5f88faea9b713b319c7c11c307cbdbe" -"347c35497a65e93d8f4ec06c1546991841fd680868e145849195e38ef783d1a4" -"1d9c23cb0d4a20c384d629c6e706ebaf12fe0fc4eb0860c8175e687742e941cc" -"59378cc30bc5948d66a6f1671e84e2e9ef342e0e3dd682015d93f96a68159f3a" -"59992c34faff2238e03be3d6e87086a427e6eef2c5647a690363a9ddc0c82d67" -"60b13d9cae9b2504ca982c50b14ee5a628d40832bab95108e6640b9a8ef8a853" -"4cea35b5ebf7d7956c0c592d4238051c37bdb8bcb4c08fa29239ffaff00793bf" -"25344d0db88e9df26d216c287ddc36a958ba1e4d4c05a9cd59715de870d47e36" -"19a1c0a1f3aa80db57b014a2dad65eecf645fcd442a09b97e78d044a50ba58c3" -"32a6b9ba275d0204fd0e3de5fed3eac823aa8ce0ef5eca627fe92030e4506fe3" -"4e4f1056e9e3b8861117ba8bba1a1c37e784ef9e1358473aa55156e3b1523dff" -"710f51f9f3866ab261df0fad6ad3986f75d9990bf7776f4e4775f9c8f95045c2" -"48623d21c816d6a47a6339d9bda7ff31f2b32b8491c72967b93f2734ec37f64d" -"69aae3a126e0625c52d05e8c98ea912f56a582419cef7f13f31be66ec14bd43c" -"2f7264fc97a0ff9188c506d5df4bf3d4f28cb1d12fa2767e18d023f8a7e907b0" -"54bf8632b89211a06bbf9c0ee5ba2328b1f2cbc1892b76282599c0fb432d761d" -"0deb44dd3e20b34cfb473944f4f8f07b4d337da0fc18021777c983bf3e4e7f44" -"37a108a7b9e612231e21f0b4c7186163e3cc59325cbb17a39e1e25b4c4345dba" -"317515ddac6dcb33a4ac68d4c02c6d93d147b61cd892474292258ebceaf5ce83" -"38e225b4f524fa89f414976687473eb4c5f3edfe983dbdd07d3e8486f3b93c0a" -"636b27e505a14fb8362beb2e436582db991e3089e6edaeb9aaba3d67f58c8c60" -"28fd1afb8cf1e9c7594b5b8d6b50ff1f81aa19f211c5c271f2181836158bb625" -"1a8cf4f8569d80ca7d878d7a76d959956ac5e7edb37fbcfd2f5d130e3841dbc0" -"2cfbffcc25a0a01ab7cd1e700030d0e363ac170dd000397fa83d107a6d12bd54" -"325355d6824f71f550b102c6fa6c8c129de58d325174c5981c562e606a58c55f" -"1716f66b4ad2388a23ce111dd5ff7c04d4478dd81930050fdf0c4a90fcd6d381" -"02992cefec8ee9bef9602858d51c87a2c4180d9fe0c02e6c6003531010793572" -"2132b3fd309dd69a9f3c39b450534d857721dd5a2bcb23b479a29b08e8f8551e" -"369986658b8e7e4f990fd6fc09b99a056d81ee47c7a9e46b4109d8af0956678c" -"25e00309f0c3097a6500df9ed5587ec128b20a97379814b4a0522f7e775a4548" -"529a8ecdddfb500c68b664f7303dad768da802c29a933801b2199cf74a3470f5" -"3cf98a6dc8290785ede38da9455dbd28a64a1bda35a48d6c6b1b35ba6df3268b" -"127401f379aa992d492782910baee0fb331b3e9c1a66492c9b002a37999f356a" -"449dabe3e12e7b495e0421de157acbd4b3852cb824bba7171c8e3da565e3f95e" -"410d1d4fb041736101f5468ebdfd9380f2066593534339bc419f35d530c92cd7" -"09747f87db187d67e7881e1b64345754ec9bc9ec353e9b055bc377f1618ef17e" -"5fec471449175525c56b18200dd8ab96b2f9ee383849545628f0ceff76f631d8" -"0c7e402c723170d5dc5f15e229f4bacc5eb50b34dbfb6129215ee662288e159c" -"158896654586f5c3a34808ef7ab93def61fc9257d5b7631ed6869259a45d1d01" -"57ab3eab90ec38cfb23625e7110948e4b56e38a1ccc2cfffc344876d28aceddd" -"08d08f8650f5ca7bf03aad9a80ae09c697327a131827a9c2aec67d1d9f58064e" -"273607089f1e9c2b99812e032dfb62c359438c76556a15692a3de02b8c13df4d" -"55bf5cd5a1a89d7e3d1d274cc5b1b765e42a9eab5cfd32148c1633550ecfffce" -"5c4f6e0acb889fbb573583767535e95bc537641769c35063c0bd3a65812ade57" -"581faa1d0a57ef947001fd8e57eee26e645d15eebedb7ebb1d85581968544ca6" -"48b77ab45f5fb6d615bd759a6661097bb8a3b5c27ba35f1b127d2ee12f043bc4" -"590618389009da43c679b6254ae4cc86dbfa397981f4dff30e064e07bfdc9eab" -"3ef9bd95ccaa3c577ab98d3fad87fe69953bbbba6c8bbca0301a6c88e9bed8e6" -"2bc1dd87795feb2a5e8d98759371592ba7147ee4c2a3473d18c496ebe3721216" -"620ba5be31e353f1f3c72a4380f32c016f0746f5446f9e1743fb01fe6994051e" -"151d0bcf972db311553ef8da672b1c861d118e9b78da632d24c49d4a0fa177b7" -"01f1bda7ed65ad241d6fa13d8c5cb40cc335a0b2a31b433f2c65cb01e8dad5bc" -"4aec58578fdfd5e59d18063bdcc69086dae303518f5155facdc2824878862c53" -"1ca2d39cd13b6c690faf2be3da4d4517e28244fbf9ca0f8f4d80565205fb86f2" -"72432f39b454d6457ffae81f2e843df03c1526920384c50136beca0627f9054a" -"1910c2e6bb35a12e22ec46cd0db6185f352bf3581cf46d2f9c494daf8d94b993" -"4e47d6f9080e682d34ae07d5886c29869d16324c468782bea9c62334b583251f" -"3240024a0dd08da0c135caf8114ea8d333ab181e94a3a01edabb760a64adcee4" -"1669aabbd01c4541575f150981af0cf9a196e0b98908af53ea14b81734ecce5a" -"316aa08fd611919a73b60dc2b3175b3843f17035d71b9edf2f72c32850629574" -"4919d1e48c28eb1d36a689d8a5826c4ae4cd4e84a8347a9c9238b825a0b53a8e" -"4572211d4d1c8257d142ff2335eea65ccbf3177a982fed00931410f3bdf08c19" -"5d2d04f110bb9a50adf25427b232870f2be2307685f19df47f9b2f1bae984a04" -"472609c977c6854de75985c9154f70a7fda1843a38f10dd4985ab8dc353ad5a7" -"5c2ba4f8bec80b52e65afbe7b2ff41ad73542275e40acba8730403e9e33c7697" -"267614d22d526f429346fb2e9dcc4930880971780e85ef44a199feabe2b48227" -"1110d3da8ece3e4eda99c2d63f6724779af505b9527f0b191b34b5bfabbf5584" -"68fc77023c046909572d302630c6508922cbc03e6c6d9a05108bc8db71e045ff" -"1b6630a5ab959106f3951689fcbc6a757c97511d08a3d4652b8ee7eab820d575" -"2e34a9c19201971c6cffc366e7955b33d0b7dc59fbaf87cadeb8d0c099cfb541" -"060bd11957a053af7aec4b2c2caf7e227512d9e856552e5cf6f4ed4b04753bec" -"0d8a6987303d76b12f97eaeacfd783401ffef6ac2e994182eaa93843300385ae" -"0e9b15bfa73141c59edc9d11ec4ee316525ba53c4b91e4f1a8adb8d372e91dff" -"55215d958a6afccf90247026efb61dd9bae318cd31ad27746b227de8873add8c" -"4ccb674b94da03efd3404a424a422d42fd4f3a8b9f73de3aa7377e728400e797" -"256f31bdb0e0cad47ec44da9bdd1fc146d0284f1d71c596e12b0c690e202d1c4" -"60797d9977e8cf8484240c0ac4d3703818c096db8d61ca640bab83ea4e675919" -"57fd867a56f6fba130d5cd80d1aa2562ca3bdb6956892c0f66e8d9bbe1fe49e7" -"09115f248d518063beb8d89c11115a6b53ac2927b2eeb0c50b50b3e82c314e5e" -"6a10f8ecb4e14465b19148ae366be2452b809596eec80f4913a2240e5e89c98d" -"0399008978536884058e8b36c86b622d5da6cde04ceabb591fe8057153f6c7b2" -"2c7ba50ad84ce603d8206950a09277dbf59da814c5b5119763a208953d946812" -"02a697c90f23766d5fde4b61101665b865375243f1bde57522bcb4bcda33804d" -"3bba46c732127685e3a7c6963ec063f961bfa23dce70af06fbbdba02d295aa8a" -"206c47de6dfd8600586a42f98aea1284742671c605e7a274a306e188015e031d" -"608a94a91f8e4e1b0adf94c1af4992b0176fc84d8d79b881ec02d2613f4d9083" -"28f906b6e3e6d01ac90251789b81001bb5d96ec2f55be04354b37bd7211c8731" -"25c66f7f7c9db885d9f7d7b64bd555f7e2e939878a6f1f1056c0c5af008949a7" -"4992f08ef5816859cd16e02a367e55fb073cc08ba19fce061e83288caba6e308" -"432fd05cdbd6ce762396cc6b88f6db33f0e6daa1e4faf602a599575fe797979d" -"4961bcdf4ad6da150ed71fe78f84c9faaa28e63e378af83aedd33870e337c362" -"4d1025421a43054ecb8eab1d4ed666a8cfc7b3e1d3f5243bd945032b7ae19a1b" -"0eb68c99851461def5baf569dff154f8ac4591e8ad194f641dc5fcfbc157c07d" -"256cd6ef41e108838bc52d51af281be02ad6c5d2a3e6f49f2cb864bcf2397447" -"0df82b76b04d8813711f92ed2bc6dda5f32e4778b5f1b328bd3b2a3b82928645" -"73397a58cf55ae9d2b14647125725f053dc0a9d5d5599f67955b8b8ceb8c43d8" -"352a6762b6764cd234a5e7e24e1beaed50618b691be9e40d4b15813d6023439a" -"4ebe36c93f3561edd31170f6775e38889598f0b40a3a2967882b60c6bcf8d6f6" -"4af798462ebca10935795dcb09770d98e2a93bc25a99af876c1f080fdf04047e" -"6f9acbad33e5d972376f1f67457fb5565582c0cc233006fe51942c48479a3c9f" -"395558ce9453ad4999a1d87585bc88b08731882ae0ffbbec886db1cc3fc7ee62" -"17b48a7db220b2b4e4a3e9139168f050056e71049e4080ded3949222d3915dd2" -"13266faaffcb6e011f73a4065bb1f7bdc373571d1b9c0210674f4f9d18cdbf3f" -"0edbbed85597c4beb59685811f7f3c0ce807083c032e6c71e5869004bb37c93d" -"64a7409e0e833df31fb574e1c12f764ecf0e3d335cc53afcdc22ac13d7a81da8" -"730fbba0d85d06eabf3f517d4826457bacb2fa8c2f24168c1b026ada9eca5bf5" -"1ffdde6d216f269f8d25efca3b28590416ea7340d92df2c02d111e30302ba020" -"6551f0ba88e2b256f61e052c2ed98e5253fb7791614da7f7f10f9db1dbace96f" -"5a40abaaa2542543cd1710bab187798b01f6c7d93395e3a1cdaed5b8866018e9" -"7021fa2631484663ef5e14124c49b3078b460d77c9972b9f3aa8fe7bed79bed6" -"28e1b47a74ed1328c9cf0188bcce0e6bc8e32d808ad91d62d747382141e7c439" -"267bb1817a59e83c9cb67f740cb31fccde2ae0f6dc49745f826267f78136bc5a" -"6f2a6bdaf2152c1368e51b4d1ae3ce48bb8a62e00d92f2f9f21393c691243aee" -"00cd4b3d36b639b44a828c3dfe8e8da68a7cccaf7063fa92877683c0e5080869" -"3e8e056dee60929e925fdcd2395a9959202ef71b82a638fd1e3decba9051d016" -"651baeb3fea106c59cefec6a9c8973347a481a75b04f547d8d2f63a1ced57161" -"1e6ea48da02249378957d446d9603e4a1e0efd343426933d0cf5a1400148f654" -"5eb2faa76b282614614ae97db1e0bb722146ac8230739cf9abb35058ae7f6363" -"6400a9ba34a8ce081b7755a5241338c78c10c07ff6cc97ac94f29b23775922f3" -"5c475b1284568d5c55fae4840fd5bf9b9f8041fb4c75f3fd902681d97d4b09d2" -"037e3fa79fcab75541fe4ceed6404d2a89228694646835e0422fb558477fb128" -"39186a11b8693a21684796f4dd227523ac2782d6d23330d8287d77e19f106923" -"44b4264d680b2bfa7081436798dce5bc3b20bedf250dfb2103abdde5b3f24eb2" -"01fd3211afd7ab17103dd5a181b91982d83e69f9df9568ed132db65c23bfba2d" -"66bd19f66bf63ef557cd87c638d6a97f2853a284307ff04392e61b7a68e56b12" -"09e3ea8c3c87110454cb0045179ac850f74285652c6854351682cd1706b54f88" -"22b7ffce8814457850e403085d0f725dc72396144565f4542d5bf826f4627106" -"255b1285cd235b83bbdc8032f637a74bc8b33a798e2751969ebe67c593b578bb" -"5b568413938daa1acec17d776af723451fc067e63ed8a24d58cefc27ef7feca9" -"4fc38e950b447f3040484e58a7d106386da69400c9292640014886e33eb7596f" -"044e95a76627fade400c813061a56bd38ae137734ac1b7b11fce4a12eed6bb68" -"129d3939b05352392ee46921665e027d3cb9c9857f0b2f161bb1f0fdd58a74bf" -"327b98a9fc847d6b6d54a175aaed3678172d615d37cf1c4448c9d4588a2eb7c7" -"63675e996ad78bc6725b923b4cbeacf40f7d4b85bf38fd8b5ed0f63424779ab5" -"7374af204d7432c7954dbbd12ed973b79fd0a6d7109061ffd10ecb2f6942d5fd" -"0fdf70b408b29ce4bb3ef9a02c333ba7789fffbf2b17dc2ef4dce8714ada06a8" -"4373b306976a59fbd07f82bb44c4ee4e4a11806801960c5c18f32f7679321d3c" -"1b218fbc57953d8d44ab45c19993b223939a121a1e6bf87b4ca549e06699880a" -"09b95f647fc4e11ed6a4757be6287d3f4d6bbdc6da8173da072d7a5d046862b1" -"1def7155ba82eebd07611e2dd694a49dac9085004c1b4e9de2b4f0bf40c063fd" -"38921799f2fae22e5dc387e3b63a8d4d2210ad60690f61cce190bad2a304c035" -"2cfc11979ac028eea6636015cd2241a9ca2b9256bcdbae2f89df853751f63589" -"21e602b39eade2ce622e3da4c76124a5f9b2580296037a33f88044895aa8562c" -"25c9a818e3691a8d36cc881eed8513110fbcd2c855270ae265cc4a53283e2f4e" -"6d17e4bdef0620c74ce13ee9b219e49bf2c8ac57cb1882bca03c64ec7c7c69fc" -"2285fe01b02e1cb4331c2e86272f10d7e7daeac3d368b914e9115d832aab4e12" -"3fb801cc1a5264babd7f35a65091d15eb9b47a6f06ab9422defafaee4cd35a84" -"5b2ae60ec46971d3b3535743c3ab4d99f07ee2f551bfb2212ecfc7120169c8eb" -"5322e28426199923aab00dcb5aa2c0c92690628e69ddbeaa8a9e0b92e4d84aa4" -"1db225ddf28a651a6f809533078dfc8a006d4b76b59afde3d3356c7f26bf1ac2" -"600fcc0f370b76ed88186364efc8d0435ba4efe84abd6b2573e87e213cb405dc" -"007c21ae6a4471fb33141d353cb73f3769ee63d78cbc5d7e6a8c1bdb7cf3eb4f" -"17520db9848586770ced86adfca305209a0884592720f70eb91f9e3a22c23a94" -"3db8aeed94f87b37fc9cfee7a7c027605bec03af4965b840a8942b89fef39ecf" -"10b3102359b66388bf079dd2f30d8131ec4da41bf159fae392838a9708e1cfc9" -"0c9f537a5a0efc930019893a3fbd46c5e2a85b78b22b4bb60c0c1ec2da334a07" -"165f9cb0313efaf5a0636141f39c3ff22089c0f9c494ebc40e9e8060b84f149f" -"001879a49e2e539bf9e9c713416f517ee14f6e510a9cafb9a321fef9ca23ed49" -"32e53a1e65305675144ebd5bb49bdcf81879daab30fff361eba5cfef952184a3" -"51b4edb20a2bbb2daf144d4ab3b72a5a4cc956d9bd9e2ba5017c2163928118c3" -"140c9db4c384a0e3757a41ae5005b2557148cb3c190ab7101059053039d655ed" -"1737e47c806e74be09d8f7daf7c9d12ede33929f5152eda6c8c008064cfc1be3" -"23f3501123499df44f5cd31b08fa1338be61194a023c9101a41ce7518acddcdd" -"68dcbacbeb6727e3b47ef3a6291421496a78d81a645f2451c2cd89818715329b" -"2f1dd4d3ce3e7b49d67a4bca9ba8b5b64ee37a20496ddbc302aa8c1bed9b2fbf" -"2b5427a54294793e926c0ed030eff8b5020801ae8a46b1d7cecc49d01d2cd4a1" -"1bcdebbdce2545485d5db25d9776f7bdc31dc799c61cb726e20e0071e939e4c4" -"6021616995863e2b6fb9015892f2f361b60656bf1998239aa471d4c698564e9f" -"4816704f77b55fba8188d9424143ffd7b015587467072992b2482e9bacd4f072" -"60aad5cbecde71eae3fb3e8355137d5890f2947227093bacd23291a731720e79" -"5bff651adb907adde66b4a4810173bb8cc0cc618e6698e236979750865b68466" -"4dc639d5986ad912fc2632704ad03b039c6982fccad820b16ce2e519de54dcb0" -"1780c0f66f7afefb6b32a019956b2a209224b9eeba8a643a222f7355214be300" -"6d23740f70b21671e66d9bb35d7387b017dd56c78b65973db44e5479567c27a0" -"1784ada0fe2211721dff5b63c46ddbd0cc2a7161e42f24b26b10cf0a807398c9" -"3721b5cbdc714dc02db737a41bac0ad9dfd640229e4ef73c780f2abc7907a101" -"6777e0e8612172897bde7e5e4d7edafdfac32f855d07b645ef0a2c2b6815d7bd" -"5430480105f06250a915e429d5436268eeff94a54606848883d84eece231db3a" -"5b06f0578c8e419abaf9365b1e0e4605a270d831b886b1310c2b30830f70aa05" -"064faf1daa9415f3bf666dccf10e96a660e3c3e08945cecfad74bcf656a09b63" -"5a7cf453cdc309e004ac0d4b161686c9497ddd5333302ce1ac689d3cd3f15fe8" -"3d1cdaba6330736b0b9c17a27d3f31b58ea7b0aa1a46faa5cbc191faef9e41ef" -"59c894b434302a88c78f3438263ff4a3f82f27af2f086958497b75ba9ede3267" -"4f96eab2814accfe7cc529624df63fd4d9d3932ecace112a52d488ebd64f86a9" -"5c3395a99f651f587c1e9f88fb32ffde50f312874219daec0f67f604ba56f55a" -"10bc86369a85dae2cbcb60d1a110675555b1f29f01af909d0b0a452fd6f8aa0a" -"025c11c9d5846be858ed85b2706718d0859b14b5e6afafc50e5b7cab9390e88d" -"6a0df7099df32bbf845516682d8b2c40d5b238bab4493508146ec7da5280b31d" -"15dee1455b9289a97a4fb4561cd05cc4eaac7f45e2098e6db369c4e38780a898" -"6b00cd849365b050f85b3bcb73dc91ae063ed60360b053ccecd4ea226f5d3480" -"36ba01e51f6cce897b12718e2947d0ded1b43f1ad65045d9e80792cc0d2afbcf" -"705ec3f8f1bdd15381e69d0241b37349e11963b509f73dde27e4d00f7173e9d2" -"00259c2c2a277983602c80547343f0037a7a3c7edfdf98a1ffd16bea20204aa2" -"07ba65993dc66a3359f96e202f8408f9367d24e37a83164c622f682ef4d113d0" -"56324ef5c5a36793bc76d0c2a38e6ae35916ab04bc072325036d9e832981518d" -"3cdc6e8fc9101d4e6be6b5fb368a3911ac13c4090ea7da9f345cd5f7ae7b1e6c" -"3fe62a321b08da7f8f6cd2080867b98b6c9f54bf910bac77db5a71da68b18270" -"53915ca5503403181327eea9143a99782e31f1636a324a946882376fb9d07681" -"45ec1e9c297bdd973aec556197b1168f8a55b0d7bb0519b5db479f95d11cd045" -"7310ab366f789b5264f16fd563b6dd31462f3e352a92fbb5e2357a9fbb9a1f16" -"739ebe2484fabba7b18d7f3a213bb9d3bb2d78a8c05f41515aa20533b933cc2e" -"048f8d7f23612a95c09d90137f7a4d87e340a1e83ec3c94284d6784ea8006423" -"49a59faf4bbf57ee29b5e186bb0008a4ec74c8fdb7ea8fe7e1aa46bc40873b50" -"5cf260d13f5da4870855a40e71d4effda202f310a955db2d140e9317e4238998" -"38c2eba027b51ab146dc61e33b7403789b63641a5cba018829e3dfc9336cbcb8" -"1f90a83ada4e0d548c8beea8f902f4bdd8466948161fe2760a0127f44a0edea8" -"6b65cc39e2d766f83e8f6f59fd5e40290bf8b887c99da8c166417d5a9cae1444" -"1da9f1f317f97e9c6132dc6808def44d32daa0c2dbcffe580d8f35b85400ccc3" -"3df94f558d1e935080d48183a3e742f6be2992f5aea51387f01c90219e980fa2" -"59974c89246e978cbee6e84478252843235f550eb7ba45324d4a7ea572ca7e2b" -"094be891b94edbc55530775ac31dd8f5ac0d1e2462579c158ce2f28843a2e9b2" -"02c997879aff55f85e9e19e36a32758b868a0504ff0cb4a704fabdb897f308bd" -"090a6946efff80828d498845e43aebaf02f19cc8a5459db7b12952e4924e1fd1" -"3cf7d767a121eb81462c2731ee18da4f5579e007ed7e198ed9c74d0e4122d247" -"4dafcb7ed415b248c5f169092d29b0f5d213e599e2bf15ade507d9ae2c9d764d" -"5204fb985e7a86bb77fd705bf71787c4a09b97e7729318e6828a422f70aabcea" -"0e1b38375d5ded933a6c9d7512ade1e96679651be670f381f875dd62c7279827" -"6b612638db66a469241a60b7222956ca0364f2d77ea8849aeb99fad2a0b5637f" -"3626c1544bd18d8a9bde32d6210aa6179839b1ebefb87fdb914d3735db50f92e" -"222fd118f0cc69ef015f43fdd95a4db3fc08eec734f4cd3fce78e73348373e03" -"369885b7348e2be8c21dce937e248cc6c390c703a09dddbb88b39bbfb3fa2943" -"0794753806f2502ff43f7b8c4990e446c37677a49f78e0a8e38622a23c34eb60" -"4b9b69b8b54c2ba38a23c409263b2ea543ba2082b6fded12c3c9b9dc754c4202" -"06fae323404cc19a099fb298803a76737720c25913e21f38a75f1c8e63a96b9c" -"50461e3977f12ec2de486071fc3924cd1aef82a6bc9fbde215eaddee6780de1d" -"5ff12618767830d17a759dadc62c40221cc848ef84da8cd91b76e5ca59ccaa37" -"6b7bdeac8d4dc989219510a928aa2e2a8995f4aba16e9f59d85e88ae3f6f5f5f" -"5fbc48469f2e94eaee4ce3cc7af5c45f27a6532f0b7d8aaad76e61091a319ecd" -"024ec0f964b1ce01b08352c231662c238c623cd66a2da4ef330debc7323dba8e" -"0dfd978f5c1e804bd89e9d579edb44c49335296cd5948420d7650775cf88fc0c" -"57ecafcf80a257780a9bbac3793c3e772fde0c88d6ce8e39399c7eb0a7e76d6a" -"705b423e84afdccba45b0286397d1a29896cc1dc3fb41721e9e14942a2c13db6" -"61efd69d156931b397d7aebd87d6c7599f6a5e2925cb7d8891fd751b7757c486" -"5b0a8e0bc9d55850e65cb119b6b43abd5eda13de38ffd6e45130a6b2c7184251" -"2ee9eb134a2f83e93bb4b09c71da3e7810d9a2bd01acaacf70fc7b43ccc2fec6" -"136a3734420b9a29249f23e3292d871653540c3a86fdfbdbb655596aac99d0ce" -"11ea5a840d53c0f0eaa111e6f43d953cdadcddedd8b7658d82266fd0897cd71a" -"51a4d6a93c09813a72f272b043ef5cf88fe27eeadb2065cb75c95620874ea281" -"00b698d1b30b8486b7fb7cafdae54bb93ac182be3623f1feffa7edc12486d4e8" -"22386f894f2a9326c7ab4cfbceae435cb69f3e359ee49946dc566f242f4238de" -"636d98aea6cb6afe50fd1e96bb8bfdf18a9d54a87e66fd79e3dff80abda98c18" -"067a4de70930459165ff7d84a0dc375adb145ac07e67eb0e1fadebd4e2610eeb" -"64721850463f2d1dfe148e429e472914d67d9867409de6c39150225106d4d425" -"6c87827aa64247be6bb132c49e271a6e23c54c8334f2c3eca5551b4ae5260f05" -"65cbbc751ea4f5e7956628b8645708187b37f2d65c6c297a5854355256de476e" -"6bf24b343856b4066e2835b1fe3e5d16496a36f41386c2afd44d001ba886fdc7" -"41d82825d409ab7c996773b516f6720e34cbfdebdc9c069fa579dcea11ef44f6" -"45f741f2e9481a85b86467ab30d363fd0328e33d53fce6b39286c2494ee7bd28" -"6c06f72d4e071f9c1ddca4f9ea231853f6d8c5e9b7418e9c564c995912d19c18" -"154f9ecfb65370a8b59a12cd736348aead2e59a7e3701d20a669bec15363fe62" -"0c4d910fbd3b57be6d6680e8d2db47c1454712b240b78468cb764702be5c1aec" -"0e1ac575e1125f5ee86da3342018bc4f3c1e2310148043d5074eb4ee22fc55b6" -"273531c7d0d03d8f97b722ef1f0c324dac39f804e0222202f7502946647ef332" -"101464d19cf380958e5aef1084736db89f4cb131033ae670f6de0a5cf9d92b73" -"597cdd384abdad1beccc73fb39f74a18eb44d056951d602c2ef6ef6448fc5626" -)) diff --git a/lisp/examples/mint2.lisp b/lisp/examples/mint2.lisp deleted file mode 100644 index 9f9e709a2..000000000 --- a/lisp/examples/mint2.lisp +++ /dev/null @@ -1,341 +0,0 @@ -(load-file "util.lisp") - -(def! zk-not-small-order? (fn* [u v] ( - (def! first-doubling (last (last (zk-double u v)))) - (def! second-doubling (last (last - (zk-double (get first-doubling "u3") (get first-doubling "v3"))))) - (def! third-doubling (last (last - (zk-double (get second-doubling "u3") (get second-doubling "v3"))))) - (zk-nonzero? (get third-doubling "u3")) - ) - ) -) - -(defmacro! zk-nonzero? (fn* [var] ( - (let* [inv (gensym) - v1 (gensym)] ( - `(alloc ~inv (invert ~var)) - `(alloc ~v1 ~var) - `(enforce - (scalar::one ~v1) - (scalar::one ~inv) - (scalar::one cs::one) - ) - ) - )) -)) - -(defmacro! zk-square (fn* [var] ( - (let* [v1 (gensym) - v2 (gensym)] ( - `(alloc ~v1 ~var) - `(def! output (alloc-input ~v2 (square ~var))) - `(enforce - (scalar::one ~v1) - (scalar::one ~v1) - (scalar::one ~v2) - ) - `{ "v2" output } - ) - )) -)) - -(defmacro! zk-mul (fn* [val1 val2] ( - (let* [v1 (gensym) - v2 (gensym) - var (gensym)] ( - `(alloc ~v1 ~val1) - `(alloc ~v2 ~val2) - `(def! result (alloc-input ~var (* ~val1 ~val2))) - `(enforce - (scalar::one ~v1) - (scalar::one ~v2) - (scalar::one ~var) - ) - `{ "result" result } - ) - )) -)) - -(defmacro! zk-witness (fn* [val1 val2] ( - (let* [u2 (gensym) - v2 (gensym) - u2v2 (gensym) - EDWARDS_D (gensym)] ( - `(def! ~EDWARDS_D (alloc-const ~EDWARDS_D (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))) - `(def! ~u2 (alloc ~u2 (get (nth (nth (zk-square ~val1) 0) 3) "v2"))) - `(def! ~v2 (alloc ~v2 (get (nth (nth (zk-square ~val2) 0) 3) "v2"))) - `(def! result (alloc-input ~u2v2 (get (last (last (zk-mul ~u2 ~v2))) "result"))) - `(enforce - ((scalar::one::neg ~u2) (scalar::one ~v2)) - (scalar::one cs::one) - ((scalar::one cs::one) (~EDWARDS_D ~u2v2)) - ) - `{ "result" result } - ) - )) -)) - -(defmacro! zk-double (fn* [val1 val2] ( - (let* [u (gensym) - v (gensym) - u3 (gensym) - v3 (gensym) - T (gensym) - A (gensym) - C (gensym) - EDWARDS_D (gensym)] ( - `(def! ~EDWARDS_D (alloc-const ~EDWARDS_D (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))) - `(def! ~u (alloc ~u ~val1)) - `(def! ~v (alloc ~v ~val2)) - `(def! ~T (alloc ~T (* (+ ~val1 ~val2) (+ ~val1 ~val2)))) - `(def! ~A (alloc ~A (* ~u ~v))) - `(def! ~C (alloc ~C (* (square ~A) ~EDWARDS_D))) - `(def! ~u3 (alloc ~u3 (/ (double ~A) (+ scalar::one ~C)))) - `(def! ~v3 (alloc ~v3 (/ (- ~T (double ~A)) (- scalar::one ~C)))) - `(enforce - ((scalar::one ~u) (scalar::one ~v)) - ((scalar::one ~u) (scalar::one ~v)) - (scalar::one ~T) - ) - `(enforce - (~EDWARDS_D ~A) - (scalar::one ~A) - (scalar::one ~C) - ) - `(enforce - ((scalar::one cs::one) (scalar::one ~C)) - (scalar::one ~u3) - ((scalar::one ~A) (scalar::one ~A)) - ) - `(enforce - ((scalar::one cs::one) (scalar::one::neg ~C)) - (scalar::one ~v3) - ((scalar::one ~T) (scalar::one::neg ~A) (scalar::one::neg ~A)) - ) - { "u3" u3, "v3" v3 } - ) - )) -)) - -(defmacro! conditionally-select (fn* [val1 val2 val3] ( - (let* [u-prime (gensym) - v-prime (gensym) - u (gensym) - v (gensym) - condition (gensym) - ] ( - `(def! ~u (alloc ~u ~val1)) - `(def! ~v (alloc ~v ~val2)) - `(def! ~condition (alloc ~condition ~val3)) - `(def! ~u-prime (alloc ~u-prime (* ~u ~condition))) - `(def! ~v-prime (alloc ~v-prime (* ~v ~condition))) - `(enforce - (scalar::one ~u) - (scalar::one ~condition) - (scalar::one ~u-prime) - ) - `(enforce - (scalar::one ~v) - (scalar::one ~condition) - (scalar::one ~v-prime) - ) - { "u-prime" u-prime, "v-prime" v-prime } - ) -)))) - -(defmacro! jj-add (fn* [param1 param2 param3 param4] - (let* [u1 (gensym) v1 (gensym) u2 (gensym) v2 (gensym) - EDWARDS_D (gensym) U (gensym) A (gensym) B (gensym) - C (gensym) u3 (gensym) v3 (gensym)] ( - ;; debug - ;; `(println 'jj-add ~param1 ~param2 ~param3 ~param4) - `(def! ~u1 (alloc ~u1 ~param1)) - `(def! ~v1 (alloc ~v1 ~param2)) - `(def! ~u2 (alloc ~u2 ~param3)) - `(def! ~v2 (alloc ~v2 ~param4)) - `(def! ~EDWARDS_D (alloc-const ~EDWARDS_D (scalar "2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1"))) - `(def! ~U (alloc ~U (* (+ ~u1 ~v1) (+ ~u2 ~v2)))) - `(def! ~A (alloc ~A (* ~v2 ~u1))) - `(def! ~B (alloc ~B (* ~u2 ~v1))) - `(def! ~C (alloc ~C (* ~EDWARDS_D (* ~A ~B)))) - `(def! ~u3 (alloc ~u3 (/ (+ ~A ~B) (+ scalar::one ~C)))) - `(def! ~v3 (alloc ~v3 (/ (- (- ~U ~A) ~B) (- scalar::one ~C)))) - `(enforce - ((scalar::one ~u1) (scalar::one ~v1)) - ((scalar::one ~u2) (scalar::one ~v2)) - (scalar::one ~U) - ) - `(enforce - (~EDWARDS_D ~A) - (scalar::one ~B) - (scalar::one ~C) - ) - `(enforce - ((scalar::one cs::one)(scalar::one ~C)) - (scalar::one ~u3) - ((scalar::one ~A) (scalar::one ~B)) - ) - `(enforce - ((scalar::one cs::one) (scalar::one::neg ~C)) - (scalar::one ~v3) - ((scalar::one ~U) (scalar::one::neg ~A) (scalar::one::neg ~B)) - ) - { "u3" u3, "v3" v3 } - ) -) -)) - -(defmacro! zk-boolean (fn* [val] ( - (let* [var (gensym)] ( - `(alloc ~var ~val) - `(enforce - ((scalar::one cs::one) (scalar::one::neg ~var)) - (scalar::one ~var) - () - ) - ) -)))) - -(def! jj-mul (fn* [u v b] ( - (def! result (unpack-bits b)) - (eval (map zk-boolean result)) - (def! val (last (last (zk-double u v)))) - (def! acc 0) - (dotimes (count result) ( - (def! u3 (get val "u3")) - (def! v3 (get val "v3")) - (def! r (nth result acc)) - (def! cond-result (last (last (conditionally-select u3 v3 r)))) - (def! u-prime (get cond-result "u-prime")) - (def! v-prime (get cond-result "v-prime")) - (def! add-result (last (jj-add u3 v3 u-prime v-prime))) - (def! u-add (get add-result "u3")) - (def! v-add (get add-result "v3")) - (def! val (last (last (zk-double u-add v-add)))) - (println acc val) - (def! acc (i+ acc 1)) - )) - (val) - ;; { "u3" (get val "u3"), "v3" (get val "v3") } -))) - -(load-file "mimc-constants.lisp") -(defmacro! mimc-macro (fn* [left-value right-value acc] ( - (let* [tmp-xl (gensym2 'tmp_xl) - xl-new-value (gensym2 'xl_new_value) - cur-mimc-const (gensym2 'cur_mimc_const) - xl (gensym2 'xl) - xr (gensym2 'xr)] ( - `(def! ~xl (alloc ~xl ~left-value)) - `(def! ~xr (alloc ~xr ~right-value)) - `(def! ~cur-mimc-const (alloc-const ~cur-mimc-const (nth mimc-constants ~acc))) - `(def! ~tmp-xl (alloc ~tmp-xl (square (+ ~cur-mimc-const ~xl)))) - `(enforce - ((scalar::one ~xl) (~cur-mimc-const cs::one)) - ((scalar::one ~xl) (~cur-mimc-const cs::one)) - (scalar::one ~tmp-xl) - ) - `(def! new-value (+ (* ~tmp-xl (+ ~cur-mimc-const ~xl)) ~xr)) - `(if (= ~acc 321) - (def! ~xl-new-value (alloc-input ~xl-new-value new-value)) - (def! ~xl-new-value (alloc ~xl-new-value new-value)) - ) - `(enforce - (scalar::one ~tmp-xl) - ((scalar::one ~xl) (~cur-mimc-const cs::one)) - ((scalar::one ~xl-new-value) (scalar::one::neg ~xr)) - ) - `{ "left" new-value } - ) -)))) - -(def! mimc (fn* [left right] ( - (def! acc 0) - (def! xl left) - (def! xr right) - (dotimes 322 ( - (def! result (mimc-macro xl xr acc)) - (def! result-value (get (last (last result)) "left")) - (def! xr xl) - (def! xl result-value) - (def! acc (i+ acc 1)) - )) - { "result" result-value } -))) - -(defmacro! rangeproof-alloc (fn* [value value-digit] ( - (let* [bit (gensym2 'bit) - digit (gensym2 'digit)] ( - `(def! ~bit (alloc ~bit ~value)) - `(def! ~digit (alloc-const ~digit ~value-digit)) - `(enforce - (scalar::one ~bit) - ((scalar::one cs::one) (scalar::one::neg ~bit)) - () - ) - { "lc" ((str digit) (str bit)) } -))))) - -(def! rangeproof (fn* [value] ( - (def! values-bit (unpack-bits value)) - (def! idx 0) - (def! digit (scalar 1)) - (def! value-result ()) - (dotimes 64 ( - (def! bit (nth values-bit idx)) - (def! value-result - (conj value-result - (get (last (last - (rangeproof-alloc bit digit))) "lc"))) - (def! digit (double digit)) - (def! idx (i+ idx 1)) - )) - (def! value-alloc (alloc-input "value-alloc" value)) - (enforce - (value-result) - (scalar::one cs::one) - (scalar::one value-alloc) - ) -))) - -;; mint contract -(def! generator-coin-u (scalar "0d7b70a0c82cbabf8f59ee61a63b8e0adcff42e9f2da7bda84f9308b3531dd18")) -(def! generator-coin-v (scalar "0d89cafb242b9e892153ac70335956e6f5c042997da77cf5e164233a9bbfb7b4")) -(def! generator-value-commit-u (scalar "01ae4ea270f5c6a1c0cd1dd4e067a82110fa27409dfc0aa4edd18883897a4c6b")) -(def! generator-value-commit-v (scalar "09d2a25018194750e9adacf78531ee3bfddbadd767671d517aa788c352641ff1")) -(def! generator-value-random-u (scalar "002924d15ccf8014ce724a41753d17dce3a9f7382a3db18fba3c8e286bb77382")) -(def! generator-value-random-v (scalar "0cb825b790b0601c4999e52d9added7d10d013b33fd95ca7d2ddd51691a09075")) -(def! mint-contract (fn* [public-u public-v value serial rnd-coin rnd-value] ( - (def! mimc-round-1 (get (last (mimc public-u public-v)) "result")) - (def! mimc-round-2 (get (last (mimc mimc-round-1 value)) "result")) - (def! mimc-round-3 (get (last (mimc mimc-round-2 serial)) "result")) - (def! coin (get (last (mimc mimc-round-3 rnd-coin)) "result")) - (rangeproof value) - (def! result-mul-value - (last (last (jj-mul generator-value-commit-u generator-value-commit-v value)))) - (def! result-mul-rnd-value - (last (last (jj-mul generator-value-random-u generator-value-random-v rnd-value)))) - (def! add-result (jj-add (get result-mul-value "u3") (get result-mul-value "v3") - (get result-mul-rnd-value "u3") (get result-mul-rnd-value "v3"))) - (println 'add-result add-result) - ;;(alloc-input "value-commit" add-result) -))) - -;; (def! spend-contract (fn* -;; [secret-u secret-v serial coin-merkle-branch coin-merkle-is-right] ( -;; (def! nullifier (mimc secret serial)) - -;; ))) - -(prove - ( - (def! public-u (scalar "0d7b70a0c82cbabf8f59ee61a63b8e0adcff42e9f2da7bda84f9308b3531dd18")) - (def! public-v (scalar "0cb825b790b0601c4999e52d9added7d10d013b33fd95ca7d2ddd51691a09075")) - (def! value (scalar 3)) - (def! serial (scalar 4)) - (def! rnd-coin (rnd-scalar)) - (def! rnd-value (rnd-scalar)) - (mint-contract public-u public-v value serial rnd-coin rnd-value) - ) -) diff --git a/lisp/examples/util.lisp b/lisp/examples/util.lisp deleted file mode 100644 index a4edd1c96..000000000 --- a/lisp/examples/util.lisp +++ /dev/null @@ -1,26 +0,0 @@ -(def! inc (fn* [a] (i+ a 1))) -(def! gensym - (let* [counter (atom 0)] - (fn* [] - (symbol (str "G__" (swap! counter inc)))))) - -(def! gensym2 - (let* [counter (atom 0)] - (fn* [name] - (symbol (str name "__" (swap! counter inc)))))) -;; Like load-file, but will never load the same path twice. - -;; This file is normally loaded with `load-file`, so it needs a -;; different mechanism to neutralize multiple inclusions of -;; itself. Moreover, the file list should never be reset. - -(def! load-file-once - (try* - load-file-once - (catch* _ - (let* [seen (atom {"../lib/util.mal" nil})] - (fn* [filename] - (if (not (contains? @seen filename)) - (do - (swap! seen assoc filename nil) - (load-file filename)))))))) diff --git a/lisp/lisp.rs b/lisp/lisp.rs deleted file mode 100644 index 34b26276d..000000000 --- a/lisp/lisp.rs +++ /dev/null @@ -1,781 +0,0 @@ -#![allow(non_snake_case)] - -use crate::types::LispCircuit; - -use drk::BlsStringConversion; - -use bellman::groth16; -use bls12_381::Bls12; -// use fnv::FnvHashMap; -use itertools::Itertools; -use rand::rngs::OsRng; -use std::rc::Rc; -use std::time::Instant; -use std::{cell::RefCell, collections::HashMap}; -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::{ - Alloc, Bool, Enforce, Func, Hash, List, MalFunc, Nil, Str, Sym, Vector, -}; -use crate::types::VerifyKeyParams; -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; - -// 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: HashMap = HashMap::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; - - let start = Instant::now(); - - 'tco: loop { - // TODO check DEBUG symbol on env - println!("debug eval \t {:?} \t {:?}", _ast, start.elapsed()); - 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 == "zk*" => { - // println!("zk* {:?}", l[1]); - 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 == "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, - 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 == "dotimes" => { - match eval(l[1].clone(), env.clone())? { - MalVal::Int(v) => { - for _i in 0..v { - _ast = eval_ast(&l[2], &env)?; - } - Ok(Nil) - } - _ => error("invalid args for dotimes"), - } - } - 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, - ast: Rc::new(a2), - 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(); - eval(a1.clone(), env.clone())?; - // TODO add debug param - prove(a1.clone(), env.clone()) - } - Sym(ref a0sym) if a0sym == "kill" => { - error(&format!("KILL at: {:?}", _ast).to_string()) - } - Sym(ref a0sym) if a0sym == "alloc-const" => { - let start = Instant::now(); - let a1 = l[1].clone(); - let mut value = eval(l[2].clone(), env.clone())?; - if let Func(_, _) = value { - value = value.apply(vec![]).unwrap(); - } - let result = eval(value.clone(), env.clone())?; - let allocs = get_allocations(&env, "AllocationsConst"); - allocs.borrow_mut().insert(a1.pr_str(false), result.clone()); - if let Some(e) = &env.outer { - env_set(&e, Sym("AllocationsConst".to_string()), Alloc(allocs))?; - } else { - env_set(&env, Sym("AllocationsConst".to_string()), Alloc(allocs))?; - } - println!("Alloc Const: {:?}", start.elapsed()); - Ok(result.clone()) - } - Sym(ref a0sym) if a0sym == "alloc-input" => { - let start = Instant::now(); - let a1 = l[1].clone(); - let mut value = eval(l[2].clone(), env.clone())?; - if let Func(_, _) = value { - value = value.apply(vec![]).unwrap(); - } - let result = eval(value.clone(), env.clone())?; - let allocs = get_allocations(&env, "AllocationsInput"); - allocs.borrow_mut().insert(a1.pr_str(false), result.clone()); - if let Some(e) = &env.outer { - env_set(&e, Sym("AllocationsInput".to_string()), Alloc(allocs))?; - } else { - env_set(&env, Sym("AllocationsInput".to_string()), Alloc(allocs))?; - } - println!("Alloc Input: {:?}", start.elapsed()); - Ok(result.clone()) - } - Sym(ref a0sym) if a0sym == "alloc" => { - let start = Instant::now(); - let a1 = l[1].clone(); - let mut value = eval(l[2].clone(), env.clone())?; - if let Func(_, _) = value { - value = value.apply(vec![]).unwrap(); - } - let result = eval(value.clone(), env.clone())?; - let allocs = get_allocations(&env, "Allocations"); - allocs.borrow_mut().insert(a1.pr_str(false), result.clone()); - if let Some(e) = &env.outer { - env_set(&e, Sym("Allocations".to_string()), Alloc(allocs))?; - } else { - env_set(&env, Sym("Allocations".to_string()), Alloc(allocs))?; - } - println!("Alloc:\t{:?}\t{:?}\t{:?}", value, result, start.elapsed()); - Ok(result.clone()) - } - //Sym(ref a0sym) if a0sym == "verify" => { - Sym(ref a0sym) if a0sym == "enforce" => { - let mut left_vec = vec![]; - let mut right_vec = vec![]; - let mut out_vec = vec![]; - match l[1].clone() { - List(v, _) | Vector(v, _) => { - if v.to_vec().len() > 0 { - // println!("{:?} {:?}", v, v.to_vec().len()); - 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 { - if v.to_vec().len() == 1 { - let result = eval(v.to_vec()[0].clone(), env.clone())?; - if let List(val, _) = result { - for ele in val.iter() { - // println!("{:?}", ele); - if let Vector(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 v.to_vec().len() > 0 { - 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 { - if v.to_vec().len() == 1 { - let result = eval(v.to_vec()[0].clone(), env.clone())?; - if let List(val, _) = result { - for ele in val.iter() { - // println!("{:?}", ele); - if let Vector(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 v.to_vec().len() > 0 { - 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 { - if v.to_vec().len() == 1 { - let result = eval(v.to_vec()[0].clone(), env.clone())?; - if let List(val, _) = result { - for ele in val.iter() { - // println!("{:?}", ele); - if let Vector(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 mut enforce_vec = get_enforce_allocs(&env).clone(); - let enforce = EnforceAllocation { - idx: enforce_vec.len() + 1, - left: left_vec, - right: right_vec, - output: out_vec, - }; - enforce_vec.push(enforce); - if let Some(e) = &env.outer { - env_set( - &e, - Sym("AllocationsEnforce".to_string()), - vector![vec![Enforce(Rc::new(enforce_vec))]], - )?; - } else { - env_set( - &env, - Sym("AllocationsEnforce".to_string()), - vector![vec![Enforce(Rc::new(enforce_vec))]], - )?; - } - - Ok(MalVal::Str("enforce-eof".to_string())) - } - _ => 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; - } - _ => { - // println!("{:?}", args); - Ok(vector![el.to_vec()]) - //error("call non-function") - } - } - } - _ => error("expected a list"), - }, - } - } - _ => eval_ast(&_ast, &env), - }; - - break; - } // end 'tco loop - - // println!("debug eval \t {:?} \t {:?}", ast, start.elapsed()); - ret -} - -pub fn get_enforce_allocs(env: &Env) -> Vec { - if let Some(e) = &env.outer { - get_enforce_allocs_nested(&e) - } else { - get_enforce_allocs_nested(&env) - } -} - -pub fn get_enforce_allocs_nested(env: &Env) -> Vec { - 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) -> RefCell> { - if let Some(e) = &env.outer { - get_allocations_nested(&e, key) - } else { - get_allocations_nested(&env, key) - } -} - -pub fn get_allocations_nested(env: &Env, key: &str) -> RefCell> { - let alloc_hm: RefCell> = RefCell::new(HashMap::default()); - match env_find(env, key) { - Some(e) => match env_get(&e, &Sym(key.to_string())) { - Ok(f) => { - if let MalVal::Alloc(allocs) = f { - allocs - } else { - alloc_hm - } - } - _ => alloc_hm, - }, - _ => alloc_hm, - } -} - -pub fn setup(_ast: MalVal, _env: Env) -> Result { - let start = Instant::now(); - let c = LispCircuit { - params: HashMap::default(), - allocs: HashMap::default(), - alloc_inputs: HashMap::default(), - constraints: Vec::new(), - }; - let random_parameters = - groth16::generate_random_parameters::(c, &mut OsRng).unwrap(); - let pvk = groth16::prepare_verifying_key(&random_parameters.vk); - println!("Setup: [{:?}]", start.elapsed()); - - Ok(VerifyKeyParams { - verifying_key: pvk, - random_params: random_parameters, - }) -} - -pub fn prove(_ast: MalVal, env: Env) -> MalRet { - let start = Instant::now(); - let allocs_input = get_allocations(&env, "AllocationsInput"); - let allocs = get_allocations(&env, "Allocations"); - let enforce_allocs = get_enforce_allocs(&env); - let allocs_const = get_allocations(&env, "AllocationsConst"); - //setup - let params = Some({ - let circuit = LispCircuit { - params: allocs_const.borrow().clone(), - allocs: allocs.borrow().clone(), - alloc_inputs: allocs_input.borrow().clone(), - constraints: enforce_allocs.clone(), - }; - groth16::generate_random_parameters::(circuit, &mut OsRng)? - }); - - let verifying_key = Some(groth16::prepare_verifying_key(¶ms.as_ref().unwrap().vk)); - // prove - let circuit = LispCircuit { - params: allocs_const.borrow().clone(), - allocs: allocs.borrow().clone(), - alloc_inputs: allocs_input.borrow().clone(), - constraints: enforce_allocs.clone(), - }; - let proof = groth16::create_random_proof(circuit, params.as_ref().unwrap(), &mut OsRng)?; - let mut vec_input = vec![]; - for (_k, val) in allocs_input.borrow_mut().iter() { - match val { - MalVal::Str(v) => { - vec_input.push(bls12_381::Scalar::from_string(&v.to_string())); - } - MalVal::ZKScalar(v) => { - vec_input.push(bls12_381::Scalar::from(*v)); - } - _ => {} - }; - } - println!("groth16::create_random_proof: {:?}", start.elapsed()); - // verification process - let start = Instant::now(); - let result = groth16::verify_proof(verifying_key.as_ref().unwrap(), &proof, &vec_input); - println!("groth16::verify_proof: {:?}", start.elapsed()); - println!("vec public {:?}", vec_input); - println!("result {:?}", result); - Ok(MalVal::Nil) -} - -pub fn verify(_ast: &MalVal) -> MalRet { - let _public_input = vec![bls12_381::Scalar::from(27)]; - let start = Instant::now(); - println!("Verify: [{:?}]", start.elapsed()); - Ok(MalVal::Nil) -} - -// print -fn print(ast: &MalVal) -> String { - ast.pr_str(true) -} - -fn rep(str: &str, env: &Env) -> Result { - let ast = read(str)?; - let exp = eval(ast, env.clone())?; - Ok(print(&exp)) -} - -fn main() -> Result<(), ()> { - let matches = clap_app!(zklisp => - (version: "0.1.0") - (author: "Dark Renaissance") - (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() { - ("load", matches) => { - if let Some(matches) = 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 start = Instant::now(); - 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, - ); - match rep(&format!("(load-file \"{}\")", file), &repl_env) { - Ok(_) => { - println!("lisp end \t {:?}", start.elapsed()); - std::process::exit(0) - } - Err(e) => { - println!("Error: {}", format_error(e)); - std::process::exit(1); - } - } -} - -#[cfg(test)] -mod tests { - #[test] - fn it_works() { - assert_eq!(2 + 2, 4); - } -} diff --git a/lisp/printer.rs b/lisp/printer.rs deleted file mode 100644 index 1a9047c0e..000000000 --- a/lisp/printer.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::types::MalVal; -use crate::types::MalVal::{Atom, Bool, Func, Hash, Int, List, MalFunc, Nil, Str, Sym, Vector}; - -fn escape_str(s: &str) -> String { - s.chars() - .map(|c| match c { - '"' => "\\\"".to_string(), - '\n' => "\\n".to_string(), - '\\' => "\\\\".to_string(), - _ => c.to_string(), - }) - .collect::>() - .join("") -} - -impl MalVal { - pub fn pr_str(&self, print_readably: bool) -> String { - match self { - Nil => String::from("nil"), - Bool(true) => String::from("true"), - Bool(false) => String::from("false"), - Int(i) => format!("{}", i), - //Float(f) => format!("{}", f), - Str(s) => { - if s.starts_with("\u{29e}") { - format!(":{}", &s[2..]) - } else if print_readably { - format!("\"{}\"", escape_str(s)) - } else { - s.clone() - } - } - Sym(s) => s.clone(), - List(l, _) => pr_seq(&**l, print_readably, "(", ")", " "), - Vector(l, _) => pr_seq(&**l, print_readably, "[", "]", " "), - Hash(hm, _) => { - let l: Vec = hm - .iter() - .flat_map(|(k, v)| vec![Str(k.to_string()), v.clone()]) - .collect(); - pr_seq(&l, print_readably, "{", "}", " ") - } - Func(f, _) => format!("#", f), - MalFunc { - ast: a, params: p, .. - } => format!("(fn* {} {})", p.pr_str(true), a.pr_str(true)), - Atom(a) => format!("(atom {})", a.borrow().pr_str(true)), - MalVal::ZKScalar(a) => format!("{:?}", a), - i => format!("{:?}", i.pr_str(true)), - } - } -} - -pub fn pr_seq( - seq: &Vec, - print_readably: bool, - start: &str, - end: &str, - join: &str, -) -> String { - let strs: Vec = seq.iter().map(|x| x.pr_str(print_readably)).collect(); - format!("{}{}{}", start, strs.join(join), end) -} diff --git a/lisp/racket/jj.rkt b/lisp/racket/jj.rkt deleted file mode 100644 index 5e79f16a0..000000000 --- a/lisp/racket/jj.rkt +++ /dev/null @@ -1,113 +0,0 @@ -#lang racket - -(require "zk.rkt") - -(struct jj_point - (u v) -) - -(define (create_jj_param_point name) - (jj_point - (zk_param (string-append name "_u")) - (zk_param (string-append name "_v")) - ) -) -(define (create_jj_public_point name) - (jj_point - (zk_public (string-append name "_u")) - (zk_public (string-append name "_v")) - ) -) - -(define (zk_jj_add namespace result a b) - (zk_comment "call jj_add()") - (let* ([namespace (append namespace (list "_jj_add"))] - [U (zk_private namespace 'U)] - [A (zk_private namespace 'A)] - [B (zk_private namespace 'B)] - [C (zk_private namespace 'C)] - [tmp (zk_local namespace 'tmp)]) - (zk_comment "Compute U = (x1 + y1) * (y2 - EDWARDS_A*x2)") - (zk_comment " = (x1 + y1) * (x2 + y2)") - (zk_set U (jj_point-u a)) - (zk_add U (jj_point-v a)) - - (zk_set tmp (jj_point-u b)) - (zk_add tmp (jj_point-v b)) - - (zk_mul U tmp) - - (zk_comment "assert (x1 + y1) * (x2 + y2) == U") - (zk_lc0_add (jj_point-u a)) - (zk_lc0_add (jj_point-v a)) - (zk_lc1_add (jj_point-u b)) - (zk_lc1_add (jj_point-v b)) - (zk_lc2_add U) - (zk_enforce) - - (zk_comment "Compute A = y2 * x1") - (zk_set A (jj_point-v b)) - (zk_mul A (jj_point-u a)) - (zk_comment "Compute B = x2 * y1") - (zk_set B (jj_point-u b)) - (zk_mul B (jj_point-v a)) - (zk_comment "Compute C = d*A*B") - (zk_load C const_d) - (zk_mul C A) - (zk_mul C B) - - (zk_comment "assert (d * A) * (B) == C") - (zk_lc0_add_coeff const_d A) - (zk_lc1_add B) - (zk_lc2_add C) - (zk_enforce) - - (zk_comment "Compute P.x = (A + B) / (1 + C)") - (zk_set (jj_point-u result) A) - (zk_add (jj_point-u result) B) - ; Re-use the tmp variable from earlier here - (zk_load tmp const_one) - (zk_add tmp C) - (zk_divide (jj_point-u result) tmp) - - (zk_lc0_add_one) - (zk_lc0_add C) - (zk_lc1_add (jj_point-u result)) - (zk_lc2_add A) - (zk_lc2_add B) - (zk_enforce) - - (zk_comment "Compute P.y = (U - A - B) / (1 - C)") - (zk_set (jj_point-v result) U) - (zk_sub (jj_point-v result) A) - (zk_sub (jj_point-v result) B) - ; Re-use the tmp variable from earlier here - (zk_load tmp const_one) - (zk_sub tmp C) - (zk_divide (jj_point-v result) tmp) - - (zk_lc0_add_one) - (zk_lc0_sub C) - (zk_lc1_add (jj_point-v result)) - (zk_lc2_add U) - (zk_lc2_sub A) - (zk_lc2_sub B) - (zk_enforce) - ) -) - -(create_zk_output "jj.psm") - -(define const_d (zk_constant - "d" "0x2a9318e74bfa2b48f5fd9207e6bd7fd4292d7f6d37579d2601065fd6d6343eb1")) -(define const_one (zk_constant - "one" "0x0000000000000000000000000000000000000000000000000000000000000001")) - -(zk_contract_begin "foo") -(define namespace (list "_")) -(define a (create_jj_param_point "a")) -(define b (create_jj_param_point "b")) -(define result (create_jj_public_point "result")) -(zk_jj_add namespace result a b) -(zk_contract_end) - diff --git a/lisp/racket/zk.rkt b/lisp/racket/zk.rkt deleted file mode 100644 index 1c89ba1c4..000000000 --- a/lisp/racket/zk.rkt +++ /dev/null @@ -1,141 +0,0 @@ -#lang racket - -(provide zk_variable) -(provide zk_constant) -(provide zk_param) -(provide zk_public) -(provide zk_local) -(provide zk_private) -(provide zk_comment) -(provide zk_set) -(provide zk_add) -(provide zk_sub) -(provide zk_mul) -(provide zk_divide) -(provide zk_load) -(provide zk_lc0_add) -(provide zk_lc1_add) -(provide zk_lc2_add) -(provide zk_lc0_sub) -(provide zk_lc1_sub) -(provide zk_lc2_sub) -(provide zk_lc0_add_coeff) -(provide zk_lc1_add_coeff) -(provide zk_lc2_add_coeff) -(provide zk_lc0_add_one) -(provide zk_lc1_add_one) -(provide zk_lc2_add_one) -(provide zk_enforce) - -(provide create_zk_output) -(provide zk_contract_begin) -(provide zk_contract_end) - -(define out '0) -(define (create_zk_output filename) - (set! out (open-output-file "jj.psm" #:exists 'truncate)) -) - -(struct zk_variable - (name type) -) - -(define (zk_constant name hex_value) - (fprintf out "constant ~a ~a\n" name hex_value) - name -) - -(define (zk_contract_begin contract_name) - (fprintf out "contract ~a\n" contract_name) -) -(define (zk_contract_end) - (fprintf out "end\n") -) - -(define (zk_param name) - (fprintf out "param ~a\n" name) - (zk_variable name 'param) -) - -(define (zk_public name) - (fprintf out "public ~a\n" name) - (zk_variable name 'public) -) - -(define (strings->string sts) - (apply string-append sts)) - -(define (apply_ns namespace name) - (strings->string - (append namespace - (list "__" (symbol->string name)) - ))) - -(define (zk_local namespace name) - (let ([name (apply_ns namespace name)]) - (fprintf out "local ~a\n" name) - (zk_variable name 'local) - ) -) - -(define (zk_private namespace name) - (let ([name (apply_ns namespace name)]) - (fprintf out "private ~a\n" name) - (zk_variable name 'private) - ) -) - -(define (zk_comment str) - (fprintf out "# ~a\n" str) -) - -(define (zk_set self other) - (fprintf out "set ~a ~a\n" (zk_variable-name self) (zk_variable-name other)) -) -(define (zk_add self other) - (fprintf out "add ~a ~a\n" (zk_variable-name self) (zk_variable-name other)) -) -(define (zk_sub self other) - (fprintf out "sub ~a ~a\n" (zk_variable-name self) (zk_variable-name other)) -) -(define (zk_mul self other) - (fprintf out "mul ~a ~a\n" (zk_variable-name self) (zk_variable-name other)) -) -(define (zk_divide self other) - (fprintf out "divide ~a ~a\n" - (zk_variable-name self) (zk_variable-name other)) -) - -(define (zk_load self constant) - (fprintf out "load ~a ~a\n" (zk_variable-name self) constant) -) - -(define (zk_lc0_add self) - (fprintf out "lc0_add ~a\n" (zk_variable-name self))) -(define (zk_lc1_add self) - (fprintf out "lc1_add ~a\n" (zk_variable-name self))) -(define (zk_lc2_add self) - (fprintf out "lc2_add ~a\n" (zk_variable-name self))) -(define (zk_lc0_sub self) - (fprintf out "lc0_sub ~a\n" (zk_variable-name self))) -(define (zk_lc1_sub self) - (fprintf out "lc1_sub ~a\n" (zk_variable-name self))) -(define (zk_lc2_sub self) - (fprintf out "lc2_sub ~a\n" (zk_variable-name self))) -(define (zk_lc0_add_coeff constant self) - (fprintf out "lc0_add_coeff ~a ~a\n" constant (zk_variable-name self))) -(define (zk_lc1_add_coeff constant self) - (fprintf out "lc1_add_coeff ~a ~a\n" constant (zk_variable-name self))) -(define (zk_lc2_add_coeff constant self) - (fprintf out "lc2_add_coeff ~a ~a\n" constant (zk_variable-name self))) -(define (zk_lc0_add_one) - (fprintf out "lc0_add_one\n")) -(define (zk_lc1_add_one) - (fprintf out "lc1_add_one\n")) -(define (zk_lc2_add_one) - (fprintf out "lc2_add_one\n")) -(define (zk_enforce) - (fprintf out "enforce\n") -) - - diff --git a/lisp/reader.rs b/lisp/reader.rs deleted file mode 100644 index 4355ff568..000000000 --- a/lisp/reader.rs +++ /dev/null @@ -1,156 +0,0 @@ -use regex::{Captures, Regex}; -use std::rc::Rc; - -use crate::types::MalErr::ErrString; -use crate::types::MalVal::{Bool, Int, List, Nil, Str, Sym, Vector}; -use crate::types::{error, hash_map, MalErr, MalRet, MalVal}; - -#[derive(Debug, Clone)] -struct Reader { - tokens: Vec, - pos: usize, -} - -impl Reader { - fn next(&mut self) -> Result { - self.pos = self.pos + 1; - Ok(self - .tokens - .get(self.pos - 1) - .ok_or(ErrString("underflow".to_string()))? - .to_string()) - } - fn peek(&self) -> Result { - Ok(self - .tokens - .get(self.pos) - .ok_or(ErrString("underflow".to_string()))? - .to_string()) - } -} - -fn tokenize(str: &str) -> Vec { - lazy_static! { - static ref RE: Regex = Regex::new( - r###"[\s,]*(~@|[\[\]{}()'`~^@]|"(?:\\.|[^\\"])*"?|;.*|[^\s\[\]{}('"`,;)]+)"### - ) - .unwrap(); - } - - let mut res = vec![]; - for cap in RE.captures_iter(str) { - if cap[1].starts_with(";") { - continue; - } - res.push(String::from(&cap[1])); - } - res -} - -fn unescape_str(s: &str) -> String { - lazy_static! { - static ref RE: Regex = Regex::new(r#"\\(.)"#).unwrap(); - } - RE.replace_all(&s, |caps: &Captures| { - format!("{}", if &caps[1] == "n" { "\n" } else { &caps[1] }) - }) - .to_string() -} - -fn read_atom(rdr: &mut Reader) -> MalRet { - lazy_static! { - static ref INT_RE: Regex = Regex::new(r"^-?[0-9]+$").unwrap(); - static ref STR_RE: Regex = Regex::new(r#""(?:\\.|[^\\"])*""#).unwrap(); - } - let token = rdr.next()?; - match &token[..] { - "nil" => Ok(Nil), - "false" => Ok(Bool(false)), - "true" => Ok(Bool(true)), - _ => { - if INT_RE.is_match(&token) { - Ok(Int(token.parse().unwrap())) - } else if STR_RE.is_match(&token) { - Ok(Str(unescape_str(&token[1..token.len() - 1]))) - } else if token.starts_with("\"") { - error("expected '\"', got EOF") - } else if token.starts_with(":") { - Ok(Str(format!("\u{29e}{}", &token[1..]))) - } else { - Ok(Sym(token.to_string())) - } - } - } -} - -fn read_seq(rdr: &mut Reader, end: &str) -> MalRet { - let mut seq: Vec = vec![]; - rdr.next()?; - loop { - let token = match rdr.peek() { - Ok(t) => t, - Err(_) => return error(&format!("expected '{}', got EOF", end)), - }; - if token == end { - break; - } - seq.push(read_form(rdr)?) - } - let _ = rdr.next(); - match end { - ")" => Ok(list!(seq)), - "]" => Ok(vector!(seq)), - "}" => hash_map(seq), - _ => error("read_seq unknown end value"), - } -} - -fn read_form(rdr: &mut Reader) -> MalRet { - let token = rdr.peek()?; - match &token[..] { - "'" => { - let _ = rdr.next(); - Ok(list![Sym("quote".to_string()), read_form(rdr)?]) - } - "`" => { - let _ = rdr.next(); - Ok(list![Sym("quasiquote".to_string()), read_form(rdr)?]) - } - "~" => { - let _ = rdr.next(); - Ok(list![Sym("unquote".to_string()), read_form(rdr)?]) - } - "~@" => { - let _ = rdr.next(); - Ok(list![Sym("splice-unquote".to_string()), read_form(rdr)?]) - } - "^" => { - let _ = rdr.next(); - let meta = read_form(rdr)?; - Ok(list![Sym("with-meta".to_string()), read_form(rdr)?, meta]) - } - "@" => { - let _ = rdr.next(); - Ok(list![Sym("deref".to_string()), read_form(rdr)?]) - } - ")" => error("unexpected ')'"), - "(" => read_seq(rdr, ")"), - "]" => error("unexpected ']'"), - "[" => read_seq(rdr, "]"), - "}" => error("unexpected '}'"), - "{" => read_seq(rdr, "}"), - _ => read_atom(rdr), - } -} - -pub fn read_str(str: String) -> MalRet { - let tokens = tokenize(&str); - //println!("tokens: {:?}", tokens); - if tokens.len() == 0 { - return error("no input"); - } - read_form(&mut Reader { - pos: 0, - tokens: tokens, - }) -} diff --git a/lisp/run.sh b/lisp/run.sh deleted file mode 100755 index 94c219b74..000000000 --- a/lisp/run.sh +++ /dev/null @@ -1,4 +0,0 @@ -export RUST_BACKTRACE=full -cargo run --bin lisp load mint2.lisp -#cargo run --bin lisp load jubjub-mul.lisp -#cargo run --bin lisp load new-cs.lisp diff --git a/lisp/types.rs b/lisp/types.rs deleted file mode 100644 index 9dab0f1e8..000000000 --- a/lisp/types.rs +++ /dev/null @@ -1,471 +0,0 @@ -use bellman::{groth16, Circuit, ConstraintSystem, SynthesisError}; -use drk::bls_extensions::BlsStringConversion; -use std::rc::Rc; -use std::time::Instant; -use std::{cell::RefCell, 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::Bls12; -use bls12_381::Scalar; - -#[derive(Debug, Clone)] -pub struct Allocation { - pub symbol: String, - pub value: Scalar, -} - -#[derive(Debug, Clone)] -pub struct EnforceAllocation { - pub idx: usize, - pub left: Vec<(String, String)>, - pub right: Vec<(String, String)>, - pub output: Vec<(String, String)>, -} - -pub struct VerifyKeyParams { - pub random_params: groth16::Parameters, - pub verifying_key: groth16::PreparedVerifyingKey, -} - -#[derive(Debug, Clone)] -pub struct LispCircuit { - pub params: HashMap, - pub allocs: HashMap, - pub alloc_inputs: HashMap, - pub constraints: Vec, -} - -#[derive(Debug, Clone)] -pub enum MalVal { - Nil, - Bool(bool), - Int(i64), - Str(String), - Sym(String), - List(Rc>, Rc), - Vector(Rc>, Rc), - Hash(Rc>, Rc), - Func(fn(MalArgs) -> MalRet, Rc), - MalFunc { - eval: fn(ast: MalVal, env: Env) -> MalRet, - ast: Rc, - env: Env, - params: Rc, - is_macro: bool, - meta: Rc, - }, - Atom(Rc>), - Alloc(RefCell>), - Enforce(Rc>), - ZKScalar(bls12_381::Scalar), -} - -impl Circuit for LispCircuit { - fn synthesize>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { - let mut variables: HashMap = HashMap::default(); - // TODO change the name from alloc-const to constant - let params_const = self.params; - - let circuitTime = Instant::now(); - let start = Instant::now(); - // println!("Allocations\n"); - // TODO is the private and params - for (k, v) in &self.allocs { - match v { - MalVal::ZKScalar(val) => { - let var = cs.alloc(|| k, || Ok(*val))?; - variables.insert(k.to_string(), var); - } - MalVal::Str(val) => { - let val_scalar = bls12_381::Scalar::from_string(&*val); - let var = cs.alloc(|| k, || Ok(val_scalar))?; - variables.insert(k.to_string(), var); - } - MalVal::Vector(val, _) => { - if let MalVal::ZKScalar(v) = &val.to_vec()[0] { - let var = cs.alloc(|| k, || Ok(*v))?; - variables.insert(k.to_string(), var); - } - } - _ => { - println!("not allocated k {:?} v {:?}", k, v); - } - } - } - println!("circuit alloc \t {:?}", start.elapsed()); - let start = Instant::now(); - // println!("Allocations Input\n"); - // TODO alloc-input is the public value - for (k, v) in &self.alloc_inputs { - match v { - MalVal::ZKScalar(val) => { - let var = cs.alloc_input(|| k, || Ok(*val))?; - variables.insert(k.to_string(), var); - // println!("k {:?} v {:?} var {:?}", k, v, var); - } - MalVal::Str(val) => { - let val_scalar = bls12_381::Scalar::from_string(&*val); - let var = cs.alloc_input(|| k, || Ok(val_scalar))?; - variables.insert(k.to_string(), var); - // println!("k {:?} v {:?} var {:?}", k, v, var); - } - _ => { - println!("not allocated k {:?} v {:?}", k, v); - } - } - } - println!("circuit alloc input \t {:?}", start.elapsed()); - let start = Instant::now(); - let enforce_sorted = self.constraints.clone(); - // enforce_sorted.sort_by(|a, b| a.idx.cmp(&b.idx)); - for alloc_value in enforce_sorted.iter() { - // println!("Enforce -> {:?}", alloc_value); - let coeff = bls12_381::Scalar::one(); - let mut left = bellman::LinearCombination::::zero(); - let mut right = bellman::LinearCombination::::zero(); - let mut output = bellman::LinearCombination::::zero(); - for values in alloc_value.left.iter() { - let (a, b) = values; - let mut val_b = CS::one(); - if b != "cs::one" { - // println!("{:?}", b); - 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); - } else { - if let Some(value) = params_const.get(a) { - match value { - MalVal::ZKScalar(val) => { - left = left + (*val, val_b); - } - MalVal::Str(s) => { - let val = bls12_381::Scalar::from_string(&s.to_string()); - left = left + (val, val_b); - } - MalVal::Func(_, _) => { - if let MalVal::Vector(val, _) = value.apply(vec![]).unwrap() { - if let MalVal::ZKScalar(res) = val.to_vec()[0] { - left = left + (res, val_b); - } - } - } - _ => { - println!("not a valid param {:?}", value) - } - } - } - } - // println!("left: a {:?} b {:?} val_b: {:?}", a, b, 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); - } else { - if let Some(value) = params_const.get(a) { - match value { - MalVal::ZKScalar(val) => { - right = right + (*val, val_b); - } - MalVal::Str(s) => { - let val = bls12_381::Scalar::from_string(&s.to_string()); - right = right + (val, val_b); - } - MalVal::Func(_, _) => { - if let MalVal::Vector(val, _) = value.apply(vec![]).unwrap() { - if let MalVal::ZKScalar(res) = val.to_vec()[0] { - right = right + (res, val_b); - } - } - } - _ => { - println!("not a valid param {:?}", value) - } - } - } - } - // println!("right: a {:?} b {:?} val_b: {:?}", a, b, val_b); - } - - for values in alloc_value.output.iter() { - let (a, b) = values; - let mut val_b = CS::one(); - if b != "cs::one" { - // println!("{:?}", b); - 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); - } else { - if let Some(value) = params_const.get(a) { - match value { - MalVal::ZKScalar(val) => { - output = output + (*val, val_b); - } - MalVal::Str(s) => { - let val = bls12_381::Scalar::from_string(&s.to_string()); - output = output + (val, val_b); - } - MalVal::Func(_, _) => { - if let MalVal::Vector(val, _) = value.apply(vec![]).unwrap() { - if let MalVal::ZKScalar(res) = val.to_vec()[0] { - output = output + (res, val_b); - } - } - } - _ => { - println!("not a valid param {:?}", value) - } - } - } - } - // println!("output: a {:?} b {:?} val_b: {:?}", a, b, val_b); - } - - // println!("Enforcing ..."); - cs.enforce( - || "constraint", - |_| left.clone(), - |_| right.clone(), - |_| output.clone(), - ); - } - println!("circuit enforce \t {:?}", start.elapsed()); - println!("end circuit \t {:?}", circuitTime.elapsed()); - Ok(()) - } -} - -#[derive(Debug)] -pub enum MalErr { - ErrString(String), - ErrMalVal(MalVal), -} - -impl From for MalErr { - fn from(err: SynthesisError) -> MalErr { - ErrString(err.to_string()) - } -} - -pub type MalArgs = Vec; -pub type MalRet = Result; - -// type utility macros - -macro_rules! list { - ($seq:expr) => {{ - List(Rc::new($seq),Rc::new(Nil)) - }}; - [$($args:expr),*] => {{ - let v: Vec = vec![$($args),*]; - List(Rc::new(v),Rc::new(Nil)) - }} -} - -macro_rules! vector { - ($seq:expr) => {{ - Vector(Rc::new($seq),Rc::new(Nil)) - }}; - [$($args:expr),*] => {{ - let v: Vec = vec![$($args),*]; - Vector(Rc::new(v),Rc::new(Nil)) - }} -} - -// type utility functions - -pub fn error(s: &str) -> MalRet { - Err(ErrString(s.to_string())) -} - -pub fn format_error(e: MalErr) -> String { - match e { - ErrString(s) => s.clone(), - ErrMalVal(mv) => mv.pr_str(true), - } -} - -pub fn atom(mv: &MalVal) -> MalVal { - Atom(Rc::new(RefCell::new(mv.clone()))) -} - -impl MalVal { - pub fn keyword(&self) -> MalRet { - match self { - Str(s) if s.starts_with("\u{29e}") => Ok(Str(s.to_string())), - Str(s) => Ok(Str(format!("\u{29e}{}", s))), - _ => error("invalid type for keyword"), - } - } - - pub fn empty_q(&self) -> MalRet { - match self { - List(l, _) | Vector(l, _) => Ok(Bool(l.len() == 0)), - Nil => Ok(Bool(true)), - _ => error("invalid type for empty?"), - } - } - - pub fn count(&self) -> MalRet { - match self { - List(l, _) | Vector(l, _) => Ok(Int(l.len() as i64)), - Nil => Ok(Int(0)), - _ => error("invalid type for count"), - } - } - - pub fn apply(&self, args: MalArgs) -> MalRet { - match *self { - Func(f, _) => f(args), - MalFunc { - eval, - ref ast, - ref env, - ref params, - .. - } => { - let a = &**ast; - let p = &**params; - let fn_env = env_bind(Some(env.clone()), p.clone(), args)?; - Ok(eval(a.clone(), fn_env)?) - } - _ => error("attempt to call non-function"), - } - } - - pub fn keyword_q(&self) -> bool { - match self { - Str(s) if s.starts_with("\u{29e}") => true, - _ => false, - } - } - - pub fn deref(&self) -> MalRet { - match self { - Atom(a) => Ok(a.borrow().clone()), - _ => error("attempt to deref a non-Atom"), - } - } - - pub fn reset_bang(&self, new: &MalVal) -> MalRet { - match self { - Atom(a) => { - *a.borrow_mut() = new.clone(); - Ok(new.clone()) - } - _ => error("attempt to reset! a non-Atom"), - } - } - - pub fn swap_bang(&self, args: &MalArgs) -> MalRet { - match self { - Atom(a) => { - let f = &args[0]; - let mut fargs = args[1..].to_vec(); - fargs.insert(0, a.borrow().clone()); - *a.borrow_mut() = f.apply(fargs)?; - Ok(a.borrow().clone()) - } - _ => error("attempt to swap! a non-Atom"), - } - } - - pub fn get_meta(&self) -> MalRet { - match self { - List(_, meta) | Vector(_, meta) | Hash(_, meta) => Ok((&**meta).clone()), - Func(_, meta) => Ok((&**meta).clone()), - MalFunc { meta, .. } => Ok((&**meta).clone()), - _ => error("meta not supported by type"), - } - } - - pub fn with_meta(&mut self, new_meta: &MalVal) -> MalRet { - match self { - List(_, ref mut meta) - | Vector(_, ref mut meta) - | Hash(_, ref mut meta) - | Func(_, ref mut meta) - | MalFunc { ref mut meta, .. } => { - *meta = Rc::new((&*new_meta).clone()); - } - _ => return error("with-meta not supported by type"), - }; - Ok(self.clone()) - } -} - -impl PartialEq for MalVal { - fn eq(&self, other: &MalVal) -> bool { - match (self, other) { - (Nil, Nil) => true, - (Bool(ref a), Bool(ref b)) => a == b, - (Int(ref a), Int(ref b)) => a == b, - (Str(ref a), Str(ref b)) => a == b, - (Sym(ref a), Sym(ref b)) => a == b, - (List(ref a, _), List(ref b, _)) - | (Vector(ref a, _), Vector(ref b, _)) - | (List(ref a, _), Vector(ref b, _)) - | (Vector(ref a, _), List(ref b, _)) => a == b, - (Hash(ref a, _), Hash(ref b, _)) => a == b, - (MalFunc { .. }, MalFunc { .. }) => false, - _ => false, - } - } -} - -pub fn func(f: fn(MalArgs) -> MalRet) -> MalVal { - Func(f, Rc::new(Nil)) -} - -pub fn _assoc(mut hm: HashMap, 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: HashMap, 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: HashMap = HashMap::default(); - _assoc(hm, kvs) -}