diff --git a/lisp/lisp-cheat-sheet.png b/lisp/lisp-cheat-sheet.png deleted file mode 100644 index ed929becf..000000000 Binary files a/lisp/lisp-cheat-sheet.png and /dev/null differ diff --git a/lisp/lisp.rs b/lisp/lisp.rs index be133575e..e59902f1b 100644 --- a/lisp/lisp.rs +++ b/lisp/lisp.rs @@ -29,6 +29,7 @@ extern crate regex; mod types; use crate::types::MalErr::{ErrMalVal, ErrString}; use crate::types::MalVal::{Bool, Enforce, Func, Hash, List, MalFunc, Nil, Str, Sym, Vector}; +use crate::types::VerifyKeyParams; use crate::types::{error, format_error, MalArgs, MalErr, MalRet, MalVal}; mod env; mod printer; @@ -297,7 +298,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet { let a1 = l[1].clone(); // todo ast = eval(a1.clone(), env.clone())?; - let _pvk = setup(a1.clone(), env.clone())?; +// let _pvk = setup(a1.clone(), env.clone())?; continue 'tco; } Sym(ref a0sym) if a0sym == "prove" => { @@ -517,69 +518,73 @@ pub fn get_allocations(env: &Env, key: &str) -> Rc> { } } -pub fn setup(_ast: MalVal, env: Env) -> Result, MalErr> { +pub fn setup(_ast: MalVal, env: Env) -> Result { 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: None, - allocs: None, - alloc_inputs: None, - constraints: None, - }; - // TODO move to another fn + let c = LispCircuit { + params: FnvHashMap::default(), + allocs: FnvHashMap::default(), + alloc_inputs: FnvHashMap::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(pvk) + 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"); - let start = Instant::now(); + let params = Some({ + let c = LispCircuit { + params: FnvHashMap::default(), + allocs: FnvHashMap::default(), + alloc_inputs: FnvHashMap::default(), + constraints: Vec::new() + }; + groth16::generate_random_parameters::(c, &mut OsRng)? + }); + let verifying_key = Some(groth16::prepare_verifying_key(¶ms.as_ref().unwrap().vk)); + let circuit = LispCircuit { - params: Some(allocs_const.as_ref().clone()), - allocs: Some(allocs.as_ref().clone()), - alloc_inputs: Some(allocs_input.as_ref().clone()), - constraints: Some(enforce_allocs), - }; - let params = { - let c = circuit.clone(); - groth16::generate_random_parameters::(c, &mut OsRng).unwrap() + params: allocs_const.as_ref().clone(), + allocs: allocs.as_ref().clone(), + alloc_inputs: allocs_input.as_ref().clone(), + constraints: enforce_allocs.clone(), }; - let proof = groth16::create_random_proof(circuit, ¶ms, &mut OsRng).unwrap(); - let mut buf = File::create("proof.output").unwrap(); - proof.write(buf); - println!("Prove: [{:?}]", start.elapsed()); - let proof_file = File::open("proof.output").unwrap(); - let reader = std::io::BufReader::new(proof_file); - let proof_read: groth16::Proof = groth16::Proof::read(reader).unwrap(); + let proof = + groth16::create_random_proof(circuit, params.as_ref().unwrap(), &mut OsRng)?; + let mut vec_input = vec![]; for (k, val) in allocs_input.iter() { if let MalVal::ZKScalar(v) = val { vec_input.push(*v); } } - let pvk = setup(_ast.clone(), env.clone()).unwrap(); - println!("{:?}", vec_input); - let verify_result = groth16::verify_proof(&pvk, &proof, &vec_input.as_slice()); - println!("{:?}", verify_result); + println!("vec input {:?}", vec_input); + let result = groth16::verify_proof( + verifying_key.as_ref().unwrap(), + &proof, + vec_input.as_slice(), + ); + println!("{:?}", result); + Ok(MalVal::Nil) } pub fn verify(_ast: &MalVal) -> MalRet { let _public_input = vec![bls12_381::Scalar::from(27)]; let start = Instant::now(); - // Check the proof! - //assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok()); println!("Verify: [{:?}]", start.elapsed()); Ok(MalVal::Nil) } diff --git a/lisp/new-cs.lisp b/lisp/new-cs.lisp index f28a446cf..5a7dc6c88 100644 --- a/lisp/new-cs.lisp +++ b/lisp/new-cs.lisp @@ -4,7 +4,7 @@ x (alloc "x" aux) x2 (alloc "x2" (* aux aux)) x3 (alloc "x3" (* aux (* aux aux))) - input (alloc-input "input" (scalar 27)) + input (alloc-input "input" (scalar 3)) ] (prove (setup diff --git a/lisp/types.rs b/lisp/types.rs index 129fad361..e6fcf1bc1 100644 --- a/lisp/types.rs +++ b/lisp/types.rs @@ -11,6 +11,7 @@ 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)] @@ -26,124 +27,17 @@ pub struct EnforceAllocation { pub output: Vec<(String, String)>, } -#[derive(Debug, Clone)] -pub struct LispCircuit { - pub params: Option>, - pub allocs: Option>, - pub alloc_inputs: Option>, - pub constraints: Option>, +pub struct VerifyKeyParams { + pub random_params: groth16::Parameters, + pub verifying_key: groth16::PreparedVerifyingKey, } -impl Circuit for LispCircuit { - fn synthesize>( - self, - cs: &mut CS, - ) -> Result<(), SynthesisError> { - let mut variables: FnvHashMap = FnvHashMap::default(); - let mut params_const = self.params.unwrap_or(FnvHashMap::default()); - - println!("Allocations\n"); - for (k, v) in &self.allocs.unwrap_or(FnvHashMap::default()) { - println!("k {:?} v {:?}", k, v); - match v { - MalVal::ZKScalar(val) => { - let var = cs.alloc(|| "alloc", || Ok(*val))?; - variables.insert(k.to_string(), var); - } - MalVal::Str(val) => { - let val_scalar = bls12_381::Scalar::from_string(&*val); - let var = cs.alloc(|| "alloc", || Ok(val_scalar))?; - variables.insert(k.to_string(), var); - } - _ => { - println!("not allocated k {:?} v {:?}", k, v); - } - } - } - - println!("Allocations Input\n"); - for (k, v) in &self.alloc_inputs.unwrap_or(FnvHashMap::default()) { - println!("k {:?} v {:?}", k, v); - match v { - MalVal::ZKScalar(val) => { - let var = cs.alloc_input(|| "alloc", || Ok(*val))?; - variables.insert(k.to_string(), var); - } - MalVal::Str(val) => { - let val_scalar = bls12_381::Scalar::from_string(&*val); - let var = cs.alloc_input(|| "alloc", || Ok(val_scalar))?; - variables.insert(k.to_string(), var); - } - _ => { - println!("not allocated k {:?} v {:?}", k, v); - } - } - } - - println!("Enforce Allocations\n"); - // we need to keep order - for alloc_value in self.constraints.unwrap_or(Vec::::new()).iter() { - 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; - println!("a {:?} b {:?}", a, b); - let mut val_b = CS::one(); - if b != "cs::one" { - val_b = *variables.get(b).unwrap(); - } - if a == "scalar::one" { - left = left + (coeff, val_b); - } else if a == "scalar::one::neg" { - left = left + (coeff.neg(), val_b); - } else { - if let Some(value) = params_const.get(a) { - if let MalVal::ZKScalar(val) = value { - left = left + (*val, val_b); - } - } - } - } - - for values in alloc_value.right.iter() { - let (a, b) = values; - let mut val_b = CS::one(); - if b != "cs::one" { - val_b = *variables.get(b).unwrap(); - } - if a == "scalar::one" { - right = right + (coeff, val_b); - } else if a == "scalar::one::neg" { - right = right + (coeff.neg(), val_b); - } - } - - for values in alloc_value.output.iter() { - let (a, b) = values; - let mut val_b = CS::one(); - if b != "cs::one" { - val_b = *variables.get(b).unwrap(); - } - if a == "scalar::one" { - output = output + (coeff, val_b); - } else if a == "scalar::one::neg" { - output = output + (coeff.neg(), val_b); - } - } - - cs.enforce( - || "constraint", - |_| left.clone(), - |_| right.clone(), - |_| output.clone(), - ); - - } - - Ok(()) - } +#[derive(Debug, Clone)] +pub struct LispCircuit { + pub params: FnvHashMap, + pub allocs: FnvHashMap, + pub alloc_inputs: FnvHashMap, + pub constraints: Vec, } #[derive(Debug, Clone)] @@ -171,12 +65,136 @@ pub enum MalVal { ZKScalar(bls12_381::Scalar), } +impl Circuit for LispCircuit { + fn synthesize>( + self, + cs: &mut CS, + ) -> Result<(), SynthesisError> { + let mut variables: FnvHashMap = FnvHashMap::default(); + let mut params_const = self.params; + + println!("Allocations\n"); + for (k, v) in &self.allocs { + println!("k {:?} v {:?}", k, v); + match v { + MalVal::ZKScalar(val) => { + let var = cs.alloc(|| "alloc", || Ok(*val))?; + variables.insert(k.to_string(), var); + } + MalVal::Str(val) => { + let val_scalar = bls12_381::Scalar::from_string(&*val); + let var = cs.alloc(|| "alloc", || Ok(val_scalar))?; + variables.insert(k.to_string(), var); + } + _ => { + println!("not allocated k {:?} v {:?}", k, v); + } + } + } + + println!("Allocations Input\n"); + for (k, v) in &self.alloc_inputs { + println!("k {:?} v {:?}", k, v); + match v { + MalVal::ZKScalar(val) => { + let var = cs.alloc_input(|| "alloc", || Ok(*val))?; + variables.insert(k.to_string(), var); + } + MalVal::Str(val) => { + let val_scalar = bls12_381::Scalar::from_string(&*val); + let var = cs.alloc_input(|| "alloc", || Ok(val_scalar))?; + variables.insert(k.to_string(), var); + } + _ => { + println!("not allocated k {:?} v {:?}", k, v); + } + } + } + + println!("Enforce Allocations\n"); + // we need to keep order + for alloc_value in self.constraints.iter() { + 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; + println!("left: a {:?} b {:?}", a, b); + let mut val_b = CS::one(); + if b != "cs::one" { + val_b = *variables.get(b).unwrap(); + } + if a == "scalar::one" { + left = left + (coeff, val_b); + } else if a == "scalar::one::neg" { + left = left + (coeff.neg(), val_b); + } else { + if let Some(value) = params_const.get(a) { + if let MalVal::ZKScalar(val) = value { + left = left + (*val, val_b); + } + } + println!("here i am"); + } + } + + for values in alloc_value.right.iter() { + let (a, b) = values; + println!("right: a {:?} b {:?}", a, b); + 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 { + println!("here i am"); + } + } + + for values in alloc_value.output.iter() { + let (a, b) = values; + println!("output: a {:?} b {:?}", a, b); + let mut val_b = CS::one(); + if b != "cs::one" { + val_b = *variables.get(b).unwrap(); + } + if a == "scalar::one" { + output = output + (Scalar::one(), val_b); + } else if a == "scalar::one::neg" { + output = output + (Scalar::one().neg(), val_b); + } else { + println!("here i am"); + } + } + + cs.enforce( + || "constraint", + |_| left.clone(), + |_| right.clone(), + |_| output.clone(), + ); + } + + Ok(()) + } +} + #[derive(Debug)] pub enum MalErr { ErrString(String), ErrMalVal(MalVal), } +impl From for MalErr { + fn from(err: SynthesisError) -> MalErr { + ErrString("SynthesisError".to_string()) + } +} + pub type MalArgs = Vec; pub type MalRet = Result;