|
|
@@ -1,26 +1,27 @@
|
|
|
#![allow(non_snake_case)]
|
|
|
|
|
|
-use crate::MalVal::Zk;
|
|
|
+use crate::MalVal::Enforce;
|
|
|
use crate::groth16::VerifyingKey;
|
|
|
use crate::types::LispCircuit;
|
|
|
-use sapvi::{ZKVMCircuit, ZKVirtualMachine};
|
|
|
+use crate::MalVal::Zk;
|
|
|
+use bellman::groth16::PreparedVerifyingKey;
|
|
|
use sapvi::bls_extensions::BlsStringConversion;
|
|
|
+use sapvi::{ZKVMCircuit, ZKVirtualMachine};
|
|
|
|
|
|
use simplelog::*;
|
|
|
|
|
|
-use bellman::{
|
|
|
- gadgets::{
|
|
|
- Assignment,
|
|
|
- },
|
|
|
- groth16, Circuit, ConstraintSystem, SynthesisError,
|
|
|
-};
|
|
|
+use bellman::{gadgets::Assignment, groth16, Circuit, ConstraintSystem, SynthesisError};
|
|
|
use bls12_381::Bls12;
|
|
|
use bls12_381::Scalar;
|
|
|
use ff::{Field, PrimeField};
|
|
|
use rand::rngs::OsRng;
|
|
|
-use std::ops::{AddAssign, MulAssign, SubAssign};
|
|
|
+use types::EnforceAllocation;
|
|
|
+use std::{borrow::BorrowMut, rc::Rc};
|
|
|
use std::time::Instant;
|
|
|
-use std::rc::Rc;
|
|
|
+use std::{
|
|
|
+ cell::RefCell,
|
|
|
+ ops::{AddAssign, MulAssign, SubAssign},
|
|
|
+};
|
|
|
|
|
|
//use std::collections::HashMap;
|
|
|
use fnv::FnvHashMap;
|
|
|
@@ -38,11 +39,8 @@ extern crate regex;
|
|
|
#[macro_use]
|
|
|
mod types;
|
|
|
use crate::types::MalErr::{ErrMalVal, ErrString};
|
|
|
-use crate::types::MalVal::{
|
|
|
- Bool, Func, Hash, List, MalFunc, Nil, Str,
|
|
|
- Sym, Vector,
|
|
|
-};
|
|
|
-use crate::types::{error, format_error, MalArgs, MalErr, MalRet, MalVal};
|
|
|
+use crate::types::MalVal::{Bool, Func, Hash, List, MalFunc, Nil, Str, Sym, Vector};
|
|
|
+use crate::types::{error, format_error, Allocation, MalArgs, MalErr, MalRet, MalVal};
|
|
|
mod env;
|
|
|
mod printer;
|
|
|
mod reader;
|
|
|
@@ -50,7 +48,7 @@ use crate::env::{env_bind, env_find, env_get, env_new, env_set, env_sets, Env};
|
|
|
#[macro_use]
|
|
|
mod core;
|
|
|
|
|
|
-pub const ZK_CIRCUIT_ENV_KEY : &str = "ZKC";
|
|
|
+pub const ZK_CIRCUIT_ENV_KEY: &str = "ZKC";
|
|
|
|
|
|
// read
|
|
|
fn read(str: &str) -> MalRet {
|
|
|
@@ -287,30 +285,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
|
|
|
_ => Ok(Nil),
|
|
|
}
|
|
|
}
|
|
|
- Sym(ref a0sym) if a0sym == "setup" => {
|
|
|
- let a1 = l[1].clone();
|
|
|
- let circuit = setup(&ast)?;
|
|
|
- println!("{:?}", a1);
|
|
|
- env_sets(&env, ZK_CIRCUIT_ENV_KEY, circuit);
|
|
|
- eval(a1.clone(), env.clone())
|
|
|
- }
|
|
|
- Sym(ref a0sym) if a0sym == "prove" => {
|
|
|
- let a1 = l[1].clone();
|
|
|
- println!("{:?}", a1);
|
|
|
- prove(a1.clone(), env.clone())
|
|
|
- }
|
|
|
- //Sym(ref a0sym) if a0sym == "verify" => {
|
|
|
- Sym(ref a0sym) if a0sym == "enforce" => {
|
|
|
- let (a1, a2) = (l[0].clone(), l[1].clone());
|
|
|
- let value = eval_ast(&a2, &env)?;
|
|
|
- match value {
|
|
|
- List(ref el, _) => {
|
|
|
- println!("{:?}", el.to_vec());
|
|
|
- }
|
|
|
- _ => println!("invalid format"),
|
|
|
- }
|
|
|
- Ok(Nil)
|
|
|
- }
|
|
|
+
|
|
|
Sym(ref a0sym) if a0sym == "fn*" => {
|
|
|
let (a1, a2) = (l[1].clone(), l[2].clone());
|
|
|
Ok(MalFunc {
|
|
|
@@ -329,6 +304,103 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
|
|
|
}
|
|
|
continue 'tco;
|
|
|
}
|
|
|
+ Sym(ref a0sym) if a0sym == "setup" => {
|
|
|
+ let a1 = l[1].clone();
|
|
|
+ let pvk = setup(a1.clone(), env.clone())?;
|
|
|
+ ast = eval(a1.clone(), env.clone())?;
|
|
|
+ continue 'tco;
|
|
|
+ }
|
|
|
+ Sym(ref a0sym) if a0sym == "prove" => {
|
|
|
+ let a1 = l[0].clone();
|
|
|
+ println!("prove {:?}", a1);
|
|
|
+ prove(a1.clone(), env.clone())
|
|
|
+ }
|
|
|
+ Sym(ref a0sym) if a0sym == "alloc-input" => {
|
|
|
+ let a1 = l[1].clone();
|
|
|
+ let value = eval(l[2].clone(), env.clone())?;
|
|
|
+ let result = eval(value.clone(), env.clone())?;
|
|
|
+ // let symbol = MalVal::Sym(a1.pr_str(false));
|
|
|
+ // env_set(&env, Sym(a1.pr_str(false)), result.clone());
|
|
|
+ if let Hash(allocs, _) = get_allocations(&env, "AllocationsInput")? {
|
|
|
+ let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
|
|
|
+ for (k, v) in allocs.iter() {
|
|
|
+ new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
|
|
|
+ }
|
|
|
+ new_hm.insert(a1.pr_str(false), result);
|
|
|
+ env_set(
|
|
|
+ &env,
|
|
|
+ Sym("AllocationsInput".to_string()),
|
|
|
+ Hash(Rc::new(new_hm), Rc::new(Nil)),
|
|
|
+ );
|
|
|
+ };
|
|
|
+ Ok(Nil)
|
|
|
+ }
|
|
|
+ Sym(ref a0sym) if a0sym == "alloc" => {
|
|
|
+ let a1 = l[1].clone();
|
|
|
+ let value = eval(l[2].clone(), env.clone())?;
|
|
|
+ let result = eval(value.clone(), env.clone())?;
|
|
|
+ if let Hash(allocs, _) = get_allocations(&env, "Allocations")? {
|
|
|
+ let mut new_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
|
|
|
+ for (k, v) in allocs.iter() {
|
|
|
+ new_hm.insert(k.to_string(), eval(v.clone(), env.clone())?);
|
|
|
+ }
|
|
|
+ new_hm.insert(a1.pr_str(false), result);
|
|
|
+ env_set(
|
|
|
+ &env,
|
|
|
+ Sym("Allocations".to_string()),
|
|
|
+ Hash(Rc::new(new_hm), Rc::new(Nil)),
|
|
|
+ );
|
|
|
+ };
|
|
|
+ Ok(Nil)
|
|
|
+ }
|
|
|
+ //Sym(ref a0sym) if a0sym == "verify" => {
|
|
|
+ Sym(ref a0sym) if a0sym == "enforce" => {
|
|
|
+ // here i'm considering that we always have tuple with only two elements
|
|
|
+ // also it's important to keep in mind for the sake of brevity of this v0
|
|
|
+ // we will not allow calculation or any lisp evaluations inside the enforce
|
|
|
+ // it means that every symbol will be on allocations and we will do the
|
|
|
+ // find/replace on the bellman circuit, it's nasty v0
|
|
|
+ let left = match l[1].clone() {
|
|
|
+ List(v, _) | Vector(v, _) => {
|
|
|
+ (v[0].pr_str(false), v[1].pr_str(false))
|
|
|
+ }
|
|
|
+ _ => {("".to_string(), "".to_string())}
|
|
|
+ };
|
|
|
+ let right = match l[1].clone() {
|
|
|
+ List(v, _) | Vector(v, _) => {
|
|
|
+ (v[0].pr_str(false), v[1].pr_str(false))
|
|
|
+ }
|
|
|
+ _ => {("".to_string(), "".to_string())}
|
|
|
+ };
|
|
|
+ let output = match l[1].clone() {
|
|
|
+ List(v, _) | Vector(v, _) => {
|
|
|
+ (v[0].pr_str(false), v[1].pr_str(false))
|
|
|
+ }
|
|
|
+ _ => {("".to_string(), "".to_string())}
|
|
|
+ };
|
|
|
+ let enforce = EnforceAllocation{left : left, right : right, output : output};
|
|
|
+ let mut new_vec: Vec<EnforceAllocation> = vec![enforce];
|
|
|
+ match get_enforce_allocs(&env)? {
|
|
|
+ Enforce(v) => {
|
|
|
+ println!("---> {:?}", v);
|
|
|
+ for value in v.iter() {
|
|
|
+ new_vec.push(value.to_owned());
|
|
|
+ }
|
|
|
+ },
|
|
|
+ _ => {}
|
|
|
+ };
|
|
|
+ env_set(
|
|
|
+ &env,
|
|
|
+ Sym("AllocationsEnforce".to_string()),
|
|
|
+ vector![vec![Enforce(Rc::new(new_vec))]],
|
|
|
+ );
|
|
|
+
|
|
|
+ // println!("allocations {:?}", get_allocations(&env, "Allocations"));
|
|
|
+ // println!("allocations input {:?}", get_allocations(&env, "AllocationsInput"));
|
|
|
+ println!("allocations enforce {:?}", get_enforce_allocs(&env));
|
|
|
+
|
|
|
+ Ok(vector![vec![]])
|
|
|
+ }
|
|
|
_ => match eval_ast(&ast, &env)? {
|
|
|
List(ref el, _) => {
|
|
|
let ref f = el[0].clone();
|
|
|
@@ -348,7 +420,8 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
|
|
|
continue 'tco;
|
|
|
}
|
|
|
_ => {
|
|
|
- Ok(Nil)
|
|
|
+ Ok(vector![el.to_vec()])
|
|
|
+
|
|
|
//error("call non-function")
|
|
|
}
|
|
|
}
|
|
|
@@ -366,51 +439,79 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
|
|
|
ret
|
|
|
}
|
|
|
|
|
|
-pub fn setup(ast: &MalVal) -> MalRet {
|
|
|
- // TODO get params from ast
|
|
|
+pub fn get_enforce_allocs(env: &Env) -> MalRet {
|
|
|
+ let found = match env_find(env, "AllocationsEnforce") {
|
|
|
+ Some(e) => match env_get(&e, &Sym("AllocationsEnforce".to_string())) {
|
|
|
+ Ok(f) => Ok(f),
|
|
|
+ _ => Ok(vector![vec![]])
|
|
|
+ },
|
|
|
+ _ => Ok(vector![vec![]])
|
|
|
+ };
|
|
|
+ found
|
|
|
+}
|
|
|
+pub fn get_allocations(env: &Env, key: &str) -> MalRet {
|
|
|
+ let mut alloc_hm: FnvHashMap<String, MalVal> = FnvHashMap::default();
|
|
|
+ match env_find(env, key) {
|
|
|
+ Some(e) => match env_get(&e, &Sym(key.to_string())) {
|
|
|
+ Ok(f) => Ok(f),
|
|
|
+ _ => Ok(Hash(Rc::new(alloc_hm), Rc::new(Nil))),
|
|
|
+ },
|
|
|
+ _ => Ok(Hash(Rc::new(alloc_hm), Rc::new(Nil))),
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+pub fn setup(ast: MalVal, mut env: Env) -> Result<PreparedVerifyingKey<Bls12>, MalErr> {
|
|
|
let start = Instant::now();
|
|
|
// Create parameters for our circuit. In a production deployment these would
|
|
|
// be generated securely using a multiparty computation.
|
|
|
- let c = LispCircuit { params: Rc::new(vector!(vec![])) };
|
|
|
- // TODO move to another fn
|
|
|
- let random_parameters = groth16::generate_random_parameters::<Bls12, _, _>(c.clone(), &mut OsRng).unwrap();
|
|
|
+
|
|
|
+ // get all allocs from env
|
|
|
+
|
|
|
+ let mut c = LispCircuit {
|
|
|
+ params: vec![],
|
|
|
+ allocs: vec![],
|
|
|
+ alloc_inputs: vec![],
|
|
|
+ constraints: vec![],
|
|
|
+ env: env.clone(),
|
|
|
+ };
|
|
|
+ // TODO move to another fn
|
|
|
+ let random_parameters =
|
|
|
+ groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap();
|
|
|
let pvk = groth16::prepare_verifying_key(&random_parameters.vk);
|
|
|
println!("Setup: [{:?}]", start.elapsed());
|
|
|
|
|
|
- Ok(MalVal::Zk(Rc::new(c)))
|
|
|
+ Ok(pvk)
|
|
|
}
|
|
|
|
|
|
pub fn prove(mut ast: MalVal, mut env: Env) -> MalRet {
|
|
|
- let c = match env_find(&env, ZK_CIRCUIT_ENV_KEY) {
|
|
|
- Some(e) => match env_get(&e, &Sym(ZK_CIRCUIT_ENV_KEY.to_string()))? {
|
|
|
- Zk(c) => {
|
|
|
- MalVal::Zk(c)
|
|
|
- }
|
|
|
- _ => { MalVal::Nil }
|
|
|
- }
|
|
|
- None => { println!("circuit not found."); MalVal::Nil }
|
|
|
- };
|
|
|
-
|
|
|
- println!("{:?}", c);
|
|
|
-
|
|
|
- // Pick a preimage and compute its hash.
|
|
|
+ // TODO remove it
|
|
|
let quantity = bls12_381::Scalar::from(3);
|
|
|
-
|
|
|
+
|
|
|
// Create an instance of our circuit (with the preimage as a witness).
|
|
|
- let c = LispCircuit {
|
|
|
- params: Rc::new(vector![vec![
|
|
|
- ZKScalar(quantity),
|
|
|
- ZKScalar(quantity * quantity),
|
|
|
- ZKScalar(quantity * quantity * quantity),
|
|
|
- ]]),
|
|
|
+ let params = {
|
|
|
+ let c = LispCircuit {
|
|
|
+ params: vec![],
|
|
|
+ allocs: vec![],
|
|
|
+ alloc_inputs: vec![],
|
|
|
+ constraints: vec![],
|
|
|
+ env: env.clone(),
|
|
|
+ };
|
|
|
+ groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
|
|
|
};
|
|
|
|
|
|
+ let circuit = LispCircuit {
|
|
|
+ params: vec![],
|
|
|
+ allocs: vec![],
|
|
|
+ alloc_inputs: vec![],
|
|
|
+ constraints: vec![],
|
|
|
+ env: env.clone(),
|
|
|
+ };
|
|
|
let start = Instant::now();
|
|
|
// Create a Groth16 proof with our parameters.
|
|
|
- //let proof = groth16::create_random_proof(c, ¶ms, &mut OsRng).unwrap();
|
|
|
+ let proof = groth16::create_random_proof(circuit, ¶ms, &mut OsRng).unwrap();
|
|
|
println!("Prove: [{:?}]", start.elapsed());
|
|
|
Ok(MalVal::Nil)
|
|
|
-}
|
|
|
+}
|
|
|
|
|
|
pub fn verify(ast: &MalVal) -> MalRet {
|
|
|
let public_input = vec![bls12_381::Scalar::from(27)];
|
|
|
@@ -476,7 +577,7 @@ fn repl_load(file: String) -> Result<(), ()> {
|
|
|
"(def! load-file (fn* (f) (eval (read-string (str \"(do \" (slurp f) \"\nnil)\")))))",
|
|
|
&repl_env,
|
|
|
);
|
|
|
- let _ = rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", &repl_env);
|
|
|
+ //let _ = rep("(defmacro! cond (fn* (& xs) (if (> (count xs) 0) (list 'if (first xs) (if (> (count xs) 1) (nth xs 1) (throw \"odd number of forms to cond\")) (cons 'cond (rest (rest xs)))))))", &repl_env);
|
|
|
match rep(&format!("(load-file \"{}\")", file), &repl_env) {
|
|
|
Ok(_) => std::process::exit(0),
|
|
|
Err(e) => {
|