lisp.rs 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643
  1. #![allow(non_snake_case)]
  2. use crate::types::LispCircuit;
  3. use bellman::groth16::PreparedVerifyingKey;
  4. use simplelog::*;
  5. use bellman::{groth16};
  6. use bls12_381::Bls12;
  7. use fnv::FnvHashMap;
  8. use itertools::Itertools;
  9. use rand::rngs::OsRng;
  10. use std::time::Instant;
  11. use std::{rc::Rc};
  12. use types::EnforceAllocation;
  13. #[macro_use]
  14. extern crate clap;
  15. #[macro_use]
  16. extern crate lazy_static;
  17. extern crate fnv;
  18. extern crate itertools;
  19. extern crate regex;
  20. #[macro_use]
  21. mod types;
  22. use crate::types::MalErr::{ErrMalVal, ErrString};
  23. use crate::types::MalVal::{Bool, Enforce, Func, Hash, List, MalFunc, Nil, Str, Sym, Vector};
  24. use crate::types::{error, format_error, MalArgs, MalErr, MalRet, MalVal};
  25. mod env;
  26. mod printer;
  27. mod reader;
  28. use crate::env::{env_bind, env_find, env_get, env_new, env_set, env_sets, Env};
  29. #[macro_use]
  30. mod core;
  31. pub const ZK_CIRCUIT_ENV_KEY: &str = "ZKC";
  32. // read
  33. fn read(str: &str) -> MalRet {
  34. reader::read_str(str.to_string())
  35. }
  36. // eval
  37. fn qq_iter(elts: &MalArgs) -> MalVal {
  38. let mut acc = list![];
  39. for elt in elts.iter().rev() {
  40. if let List(v, _) = elt {
  41. if v.len() == 2 {
  42. if let Sym(ref s) = v[0] {
  43. if s == "splice-unquote" {
  44. acc = list![Sym("concat".to_string()), v[1].clone(), acc];
  45. continue;
  46. }
  47. }
  48. }
  49. }
  50. acc = list![Sym("cons".to_string()), quasiquote(&elt), acc];
  51. }
  52. return acc;
  53. }
  54. fn quasiquote(ast: &MalVal) -> MalVal {
  55. match ast {
  56. List(v, _) => {
  57. if v.len() == 2 {
  58. if let Sym(ref s) = v[0] {
  59. if s == "unquote" {
  60. return v[1].clone();
  61. }
  62. }
  63. }
  64. return qq_iter(&v);
  65. }
  66. Vector(v, _) => return list![Sym("vec".to_string()), qq_iter(&v)],
  67. Hash(_, _) | Sym(_) => return list![Sym("quote".to_string()), ast.clone()],
  68. _ => ast.clone(),
  69. }
  70. }
  71. fn is_macro_call(ast: &MalVal, env: &Env) -> Option<(MalVal, MalArgs)> {
  72. match ast {
  73. List(v, _) => match v[0] {
  74. Sym(ref s) => match env_find(env, s) {
  75. Some(e) => match env_get(&e, &v[0]) {
  76. Ok(f @ MalFunc { is_macro: true, .. }) => Some((f, v[1..].to_vec())),
  77. _ => None,
  78. },
  79. _ => None,
  80. },
  81. _ => None,
  82. },
  83. _ => None,
  84. }
  85. }
  86. fn macroexpand(mut ast: MalVal, env: &Env) -> (bool, MalRet) {
  87. let mut was_expanded = false;
  88. while let Some((mf, args)) = is_macro_call(&ast, env) {
  89. //println!("macroexpand 1: {:?}", ast);
  90. ast = match mf.apply(args) {
  91. Err(e) => return (false, Err(e)),
  92. Ok(a) => a,
  93. };
  94. //println!("macroexpand 2: {:?}", ast);
  95. was_expanded = true;
  96. }
  97. (was_expanded, Ok(ast))
  98. }
  99. fn eval_ast(ast: &MalVal, env: &Env) -> MalRet {
  100. match ast {
  101. Sym(_) => Ok(env_get(&env, &ast)?),
  102. List(v, _) => {
  103. let mut lst: MalArgs = vec![];
  104. for a in v.iter() {
  105. lst.push(eval(a.clone(), env.clone())?)
  106. }
  107. Ok(list!(lst))
  108. }
  109. Vector(v, _) => {
  110. let mut lst: MalArgs = vec![];
  111. for a in v.iter() {
  112. lst.push(eval(a.clone(), env.clone())?)
  113. }
  114. Ok(vector!(lst))
  115. }
  116. Hash(hm, _) => {
  117. let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
  118. for (k, v) in hm.iter() {
  119. new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
  120. }
  121. Ok(Hash(Rc::new(new_hm), Rc::new(Nil)))
  122. }
  123. _ => Ok(ast.clone()),
  124. }
  125. }
  126. fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
  127. let ret: MalRet;
  128. 'tco: loop {
  129. ret = match ast.clone() {
  130. List(l, _) => {
  131. if l.len() == 0 {
  132. return Ok(ast);
  133. }
  134. match macroexpand(ast.clone(), &env) {
  135. (true, Ok(new_ast)) => {
  136. ast = new_ast;
  137. continue 'tco;
  138. }
  139. (_, Err(e)) => return Err(e),
  140. _ => (),
  141. }
  142. if l.len() == 0 {
  143. return Ok(ast);
  144. }
  145. let a0 = &l[0];
  146. match a0 {
  147. Sym(ref a0sym) if a0sym == "def!" => {
  148. env_set(&env, l[1].clone(), eval(l[2].clone(), env.clone())?)
  149. }
  150. Sym(ref a0sym) if a0sym == "let*" => {
  151. env = env_new(Some(env.clone()));
  152. let (a1, a2) = (l[1].clone(), l[2].clone());
  153. match a1 {
  154. List(ref binds, _) | Vector(ref binds, _) => {
  155. for (b, e) in binds.iter().tuples() {
  156. match b {
  157. Sym(_) => {
  158. let _ = env_set(
  159. &env,
  160. b.clone(),
  161. eval(e.clone(), env.clone())?,
  162. );
  163. }
  164. _ => {
  165. return error("let* with non-Sym binding");
  166. }
  167. }
  168. }
  169. }
  170. _ => {
  171. return error("let* with non-List bindings");
  172. }
  173. };
  174. ast = a2;
  175. continue 'tco;
  176. }
  177. Sym(ref a0sym) if a0sym == "quote" => Ok(l[1].clone()),
  178. Sym(ref a0sym) if a0sym == "quasiquoteexpand" => Ok(quasiquote(&l[1])),
  179. Sym(ref a0sym) if a0sym == "quasiquote" => {
  180. ast = quasiquote(&l[1]);
  181. continue 'tco;
  182. }
  183. Sym(ref a0sym) if a0sym == "defmacro!" => {
  184. let (a1, a2) = (l[1].clone(), l[2].clone());
  185. let r = eval(a2, env.clone())?;
  186. match r {
  187. MalFunc {
  188. eval,
  189. ast,
  190. env,
  191. params,
  192. ..
  193. } => Ok(env_set(
  194. &env,
  195. a1.clone(),
  196. MalFunc {
  197. eval: eval,
  198. ast: ast.clone(),
  199. env: env.clone(),
  200. params: params.clone(),
  201. is_macro: true,
  202. meta: Rc::new(Nil),
  203. },
  204. )?),
  205. _ => error("set_macro on non-function"),
  206. }
  207. }
  208. Sym(ref a0sym) if a0sym == "macroexpand" => {
  209. match macroexpand(l[1].clone(), &env) {
  210. (_, Ok(new_ast)) => Ok(new_ast),
  211. (_, e) => return e,
  212. }
  213. }
  214. Sym(ref a0sym) if a0sym == "try*" => match eval(l[1].clone(), env.clone()) {
  215. Err(ref e) if l.len() >= 3 => {
  216. let exc = match e {
  217. ErrMalVal(mv) => mv.clone(),
  218. ErrString(s) => Str(s.to_string()),
  219. };
  220. match l[2].clone() {
  221. List(c, _) => {
  222. let catch_env = env_bind(
  223. Some(env.clone()),
  224. list!(vec![c[1].clone()]),
  225. vec![exc],
  226. )?;
  227. eval(c[2].clone(), catch_env)
  228. }
  229. _ => error("invalid catch block"),
  230. }
  231. }
  232. res => res,
  233. },
  234. Sym(ref a0sym) if a0sym == "do" => {
  235. match eval_ast(&list!(l[1..l.len() - 1].to_vec()), &env)? {
  236. List(_, _) => {
  237. ast = l.last().unwrap_or(&Nil).clone();
  238. continue 'tco;
  239. }
  240. _ => error("invalid do form"),
  241. }
  242. }
  243. Sym(ref a0sym) if a0sym == "if" => {
  244. let cond = eval(l[1].clone(), env.clone())?;
  245. match cond {
  246. Bool(false) | Nil if l.len() >= 4 => {
  247. ast = l[3].clone();
  248. continue 'tco;
  249. }
  250. Bool(false) | Nil => Ok(Nil),
  251. _ if l.len() >= 3 => {
  252. ast = l[2].clone();
  253. continue 'tco;
  254. }
  255. _ => Ok(Nil),
  256. }
  257. }
  258. Sym(ref a0sym) if a0sym == "fn*" => {
  259. let (a1, a2) = (l[1].clone(), l[2].clone());
  260. Ok(MalFunc {
  261. eval: eval,
  262. ast: Rc::new(a2),
  263. env: env,
  264. params: Rc::new(a1),
  265. is_macro: false,
  266. meta: Rc::new(Nil),
  267. })
  268. }
  269. Sym(ref a0sym) if a0sym == "eval" => {
  270. ast = eval(l[1].clone(), env.clone())?;
  271. while let Some(ref e) = env.clone().outer {
  272. env = e.clone();
  273. }
  274. continue 'tco;
  275. }
  276. Sym(ref a0sym) if a0sym == "setup" => {
  277. let a1 = l[1].clone();
  278. // todo
  279. ast = eval(a1.clone(), env.clone())?;
  280. let _pvk = setup(a1.clone(), env.clone())?;
  281. continue 'tco;
  282. }
  283. Sym(ref a0sym) if a0sym == "prove" => {
  284. let a1 = l[1].clone();
  285. ast = eval(a1.clone(), env.clone())?;
  286. prove(a1.clone(), env.clone())
  287. }
  288. Sym(ref a0sym) if a0sym == "alloc-const" => {
  289. let a1 = l[1].clone();
  290. let value = eval(l[2].clone(), env.clone())?;
  291. let result = eval(value.clone(), env.clone())?;
  292. let allocs = get_allocations(&env, "AllocationsConst");
  293. let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
  294. for (k, v) in allocs.iter() {
  295. new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
  296. }
  297. new_hm.insert(a1.pr_str(false), result.clone());
  298. env_set(
  299. &env,
  300. Sym("AllocationsConst".to_string()),
  301. Hash(Rc::new(new_hm), Rc::new(Nil)),
  302. )?;
  303. Ok(result.clone())
  304. }
  305. Sym(ref a0sym) if a0sym == "alloc-input" => {
  306. let a1 = l[1].clone();
  307. let value = eval(l[2].clone(), env.clone())?;
  308. let result = eval(value.clone(), env.clone())?;
  309. let allocs = get_allocations(&env, "AllocationsInput");
  310. let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
  311. for (k, v) in allocs.iter() {
  312. new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
  313. }
  314. new_hm.insert(a1.pr_str(false), result.clone());
  315. env_set(
  316. &env,
  317. Sym("AllocationsInput".to_string()),
  318. Hash(Rc::new(new_hm), Rc::new(Nil)),
  319. )?;
  320. Ok(result.clone())
  321. }
  322. Sym(ref a0sym) if a0sym == "alloc" => {
  323. let a1 = l[1].clone();
  324. let value = eval(l[2].clone(), env.clone())?;
  325. let result = eval(value.clone(), env.clone())?;
  326. let allocs = get_allocations(&env, "Allocations");
  327. let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
  328. for (k, v) in allocs.iter() {
  329. new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
  330. }
  331. new_hm.insert(a1.pr_str(false), result.clone());
  332. env_set(
  333. &env,
  334. Sym("Allocations".to_string()),
  335. Hash(Rc::new(new_hm), Rc::new(Nil)),
  336. )?;
  337. Ok(result.clone())
  338. }
  339. //Sym(ref a0sym) if a0sym == "verify" => {
  340. Sym(ref a0sym) if a0sym == "enforce" => {
  341. // here i'm considering that we always have tuple with only two elements
  342. // also it's important to keep in mind for the sake of brevity of this v0
  343. // we will not allow calculation or any lisp evaluations inside the enforce
  344. // it means that every symbol will be on allocations and we will do the
  345. // find/replace on the bellman circuit, it's nasty v0
  346. let mut left_vec = vec![];
  347. let mut right_vec = vec![];
  348. let mut out_vec = vec![];
  349. // todo extract a macro for this
  350. match l[1].clone() {
  351. List(v, _) | Vector(v, _) => {
  352. if let List(_, _) = &v.to_vec()[0] {
  353. for ele in v.to_vec().iter() {
  354. if let List(ele_vec, _) = ele {
  355. left_vec.push((
  356. ele_vec[0].pr_str(false),
  357. ele_vec[1].pr_str(false),
  358. ));
  359. }
  360. }
  361. } else {
  362. left_vec.push((v[0].pr_str(false), v[1].pr_str(false)));
  363. }
  364. }
  365. _ => {}
  366. };
  367. match l[2].clone() {
  368. List(v, _) | Vector(v, _) => {
  369. if let List(_, _) = &v.to_vec()[0] {
  370. for ele in v.to_vec().iter() {
  371. if let List(ele_vec, _) = ele {
  372. right_vec.push((
  373. ele_vec[0].pr_str(false),
  374. ele_vec[1].pr_str(false),
  375. ));
  376. }
  377. }
  378. } else {
  379. right_vec.push((v[0].pr_str(false), v[1].pr_str(false)));
  380. }
  381. }
  382. _ => {}
  383. };
  384. match l[3].clone() {
  385. List(v, _) | Vector(v, _) => {
  386. if let List(_, _) = &v.to_vec()[0] {
  387. for ele in v.to_vec().iter() {
  388. if let List(ele_vec, _) = ele {
  389. out_vec.push((
  390. ele_vec[0].pr_str(false),
  391. ele_vec[1].pr_str(false),
  392. ));
  393. }
  394. }
  395. } else {
  396. out_vec.push((v[0].pr_str(false), v[1].pr_str(false)));
  397. }
  398. }
  399. _ => {}
  400. };
  401. let enforce = EnforceAllocation {
  402. left: left_vec,
  403. right: right_vec,
  404. output: out_vec,
  405. };
  406. let mut new_vec: Vec<EnforceAllocation> = vec![enforce];
  407. for value in get_enforce_allocs(&env).iter() {
  408. new_vec.push(value.clone());
  409. }
  410. env_set(
  411. &env,
  412. Sym("AllocationsEnforce".to_string()),
  413. vector![vec![Enforce(Rc::new(new_vec))]],
  414. );
  415. /*
  416. println!("\n\nallocations {:?}", get_allocations(&env, "Allocations"));
  417. println!(
  418. "\n\nallocations input {:?}",
  419. get_allocations(&env, "AllocationsInput")
  420. );
  421. println!("\n\nallocations enforce {:?}", get_enforce_allocs(&env));
  422. */
  423. Ok(vector![vec![]])
  424. }
  425. _ => match eval_ast(&ast, &env)? {
  426. List(ref el, _) => {
  427. let ref f = el[0].clone();
  428. let args = el[1..].to_vec();
  429. match f {
  430. Func(_, _) => f.apply(args),
  431. MalFunc {
  432. ast: mast,
  433. env: menv,
  434. params,
  435. ..
  436. } => {
  437. let a = &**mast;
  438. let p = &**params;
  439. env = env_bind(Some(menv.clone()), p.clone(), args)?;
  440. ast = a.clone();
  441. continue 'tco;
  442. }
  443. _ => {
  444. Ok(vector![el.to_vec()])
  445. //error("call non-function")
  446. }
  447. }
  448. }
  449. _ => error("expected a list"),
  450. },
  451. }
  452. }
  453. _ => eval_ast(&ast, &env),
  454. };
  455. break;
  456. } // end 'tco loop
  457. ret
  458. }
  459. pub fn get_enforce_allocs(env: &Env) -> Vec<EnforceAllocation> {
  460. // todo need some cleanup
  461. match env_find(env, "AllocationsEnforce") {
  462. Some(e) => match env_get(&e, &Sym("AllocationsEnforce".to_string())) {
  463. Ok(f) => {
  464. if let Vector(val, _) = f {
  465. if let Enforce(ret) = &val[0] {
  466. ret.to_vec()
  467. } else {
  468. vec![]
  469. }
  470. } else {
  471. vec![]
  472. }
  473. }
  474. _ => vec![],
  475. },
  476. _ => vec![],
  477. }
  478. }
  479. pub fn get_allocations(env: &Env, key: &str) -> Rc<FnvHashMap<String, MalVal>> {
  480. let alloc_hm: Rc<FnvHashMap<String, MalVal>> = Rc::new(FnvHashMap::default());
  481. match env_find(env, key) {
  482. Some(e) => match env_get(&e, &Sym(key.to_string())) {
  483. Ok(f) => {
  484. if let Hash(allocs, _) = f {
  485. allocs
  486. } else {
  487. alloc_hm
  488. }
  489. }
  490. _ => alloc_hm,
  491. },
  492. _ => alloc_hm,
  493. }
  494. }
  495. pub fn setup(_ast: MalVal, env: Env) -> Result<PreparedVerifyingKey<Bls12>, MalErr> {
  496. let start = Instant::now();
  497. // Create parameters for our circuit. In a production deployment these would
  498. // be generated securely using a multiparty computation.
  499. let allocs_input = get_allocations(&env, "AllocationsInput");
  500. let allocs = get_allocations(&env, "Allocations");
  501. let allocs_const = get_allocations(&env, "AllocationsConst");
  502. let enforce_allocs = get_enforce_allocs(&env);
  503. let c = LispCircuit {
  504. params: allocs_const.as_ref().clone(),
  505. allocs: allocs.as_ref().clone(),
  506. alloc_inputs: allocs_input.as_ref().clone(),
  507. constraints: enforce_allocs,
  508. env: env.clone(),
  509. };
  510. // TODO move to another fn
  511. let random_parameters =
  512. groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap();
  513. let pvk = groth16::prepare_verifying_key(&random_parameters.vk);
  514. println!("Setup: [{:?}]", start.elapsed());
  515. Ok(pvk)
  516. }
  517. pub fn prove(_ast: MalVal, env: Env) -> MalRet {
  518. // TODO remove it
  519. let _quantity = bls12_381::Scalar::from(3);
  520. let allocs_input = get_allocations(&env, "AllocationsInput");
  521. let allocs = get_allocations(&env, "Allocations");
  522. let enforce_allocs = get_enforce_allocs(&env);
  523. let allocs_const = get_allocations(&env, "AllocationsConst");
  524. let circuit = LispCircuit {
  525. params: allocs_const.as_ref().clone(),
  526. allocs: allocs.as_ref().clone(),
  527. alloc_inputs: allocs_input.as_ref().clone(),
  528. constraints: enforce_allocs,
  529. env: env.clone(),
  530. };
  531. // Create an instance of our circuit (with the preimage as a witness).
  532. // todo check if circuit.clone is valid
  533. let params = {
  534. let c = circuit.clone();
  535. groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
  536. };
  537. let start = Instant::now();
  538. // Create a Groth16 proof with our parameters.
  539. let _proof = groth16::create_random_proof(circuit, &params, &mut OsRng).unwrap();
  540. println!("Prove: [{:?}]", start.elapsed());
  541. Ok(MalVal::Nil)
  542. }
  543. pub fn verify(_ast: &MalVal) -> MalRet {
  544. let _public_input = vec![bls12_381::Scalar::from(27)];
  545. let start = Instant::now();
  546. // Check the proof!
  547. //assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok());
  548. println!("Verify: [{:?}]", start.elapsed());
  549. Ok(MalVal::Nil)
  550. }
  551. // print
  552. fn print(ast: &MalVal) -> String {
  553. ast.pr_str(true)
  554. }
  555. fn rep(str: &str, env: &Env) -> Result<String, MalErr> {
  556. let ast = read(str)?;
  557. let exp = eval(ast, env.clone())?;
  558. Ok(print(&exp))
  559. }
  560. fn main() -> Result<(), ()> {
  561. let matches = clap_app!(zklisp =>
  562. (version: "0.1.0")
  563. (author: "mileschet <miles.chet@gmail.com>")
  564. (about: "A Lisp Interpreter for Zero Knowledge Virtual Machine")
  565. (@subcommand load =>
  566. (about: "Load the file into the interpreter")
  567. (@arg FILE: +required "Lisp Contract filename")
  568. )
  569. )
  570. .get_matches();
  571. CombinedLogger::init(vec![TermLogger::new(
  572. LevelFilter::Debug,
  573. Config::default(),
  574. TerminalMode::Mixed,
  575. )
  576. .unwrap()])
  577. .unwrap();
  578. match matches.subcommand() {
  579. Some(("load", matches)) => {
  580. let file: String = matches.value_of("FILE").unwrap().parse().unwrap();
  581. repl_load(file)?;
  582. }
  583. _ => {
  584. eprintln!("error: Invalid subcommand invoked");
  585. std::process::exit(-1);
  586. }
  587. }
  588. Ok(())
  589. }
  590. fn repl_load(file: String) -> Result<(), ()> {
  591. let repl_env = env_new(None);
  592. for (k, v) in core::ns() {
  593. env_sets(&repl_env, k, v);
  594. }
  595. let _ = rep("(def! not (fn* (a) (if a false true)))", &repl_env);
  596. let _ = rep(
  597. "(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))",
  598. &repl_env,
  599. );
  600. //let _ = rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", &repl_env);
  601. match rep(&format!("(load-file \"{}\")", file), &repl_env) {
  602. Ok(_) => std::process::exit(0),
  603. Err(e) => {
  604. println!("Error: {}", format_error(e));
  605. std::process::exit(1);
  606. }
  607. }
  608. }