Просмотр исходного кода

Merge branch 'master' of github.com:narodnik/sapvi

rachel-rose 5 лет назад
Родитель
Сommit
07a94587d8

+ 9 - 2
Cargo.toml

@@ -16,8 +16,10 @@ bellman = { version = "0.8", default-features = false, features = ["groth16"] }
 bls12_381 = "0.3.1"
 jubjub = "0.5.1"
 
-zcash_primitives = { git = "https://github.com/zcash/librustzcash" }
-zcash_proofs = { git = "https://github.com/zcash/librustzcash" }
+zcash_primitives = "0.5.0"
+zcash_proofs = "0.5.0" 
+# zcash_primitives = { git = "https://github.com/zcash/librustzcash" }
+#zcash_proofs = { git = "https://github.com/zcash/librustzcash" }
 #zcash_proofs = { git = "https://github.com/narodnik/librustzcash" }
 #bench-utils = { git = "https://github.com/scipr-lab/zexe", features = ["print-trace"]}
 rand = "0.7.3"
@@ -25,6 +27,7 @@ rand_core = "0.5.1"
 sha2 = "0.9.1"
 rand_xorshift = "0.2"
 blake2s_simd = "0.5"
+blake2b_simd = "0.5.11"
 bitvec = "0.18"
 bimap = "0.5.2"
 async-trait = "0.1.42"
@@ -100,6 +103,10 @@ path = "src/bin/mint-classic.rs"
 name = "spend-classic"
 path = "src/bin/spend-classic.rs"
 
+[[bin]]
+name = "tx"
+path = "src/bin/tx.rs"
+
 [[bin]]
 name = "dfg"
 path = "src/bin/dfg.rs"

+ 2 - 2
lisp/core.rs

@@ -628,8 +628,8 @@ fn scalar_is_zero(a: MalArgs) -> MalRet {
     }
 }
 
-fn add_scalar(a: MalArgs) -> MalRet {  
-    println!("add_scalar {:?}", a);  
+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() {

+ 8 - 10
lisp/lisp.rs

@@ -11,11 +11,9 @@ use bls12_381::Bls12;
 // use fnv::FnvHashMap;
 use itertools::Itertools;
 use rand::rngs::OsRng;
+use std::borrow::{Borrow, BorrowMut};
 use std::rc::Rc;
 use std::time::Instant;
-use std::{
-    borrow::{Borrow, BorrowMut},    
-};
 use std::{cell::RefCell, collections::HashMap};
 use types::EnforceAllocation;
 
@@ -353,7 +351,7 @@ fn eval(mut ast: MalVal, mut env: Env) -> MalRet {
                     }
                     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();
@@ -652,7 +650,7 @@ pub fn setup(_ast: MalVal, env: Env) -> Result<VerifyKeyParams, MalErr> {
     })
 }
 
-pub fn prove(_ast: MalVal, env: Env) -> MalRet {    
+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");
@@ -691,12 +689,12 @@ pub fn prove(_ast: MalVal, env: Env) -> MalRet {
         };
     }
     println!("groth16::create_random_proof: {:?}", start.elapsed());
-    // verification process 
+    // 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);    
+    println!("result {:?}", result);
     Ok(MalVal::Nil)
 }
 
@@ -766,13 +764,13 @@ fn repl_load(file: String) -> Result<(), ()> {
     match rep(&format!("(load-file \"{}\")", file), &repl_env) {
         Ok(_) => {
             println!("lisp end \t {:?}", start.elapsed());
-            std::process::exit(0) 
-        },
+            std::process::exit(0)
+        }
         Err(e) => {
             println!("Error: {}", format_error(e));
             std::process::exit(1);
         }
-    }    
+    }
 }
 
 #[cfg(test)]

+ 10 - 7
lisp/types.rs

@@ -1,8 +1,11 @@
 use bellman::{gadgets::Assignment, groth16, Circuit, ConstraintSystem, SynthesisError};
 use sapvi::bls_extensions::BlsStringConversion;
-use std::{ops::{Add, AddAssign, MulAssign, SubAssign}, time::Instant};
 use std::rc::Rc;
 use std::{cell::RefCell, collections::HashMap};
+use std::{
+    ops::{Add, AddAssign, MulAssign, SubAssign},
+    time::Instant,
+};
 // use fnv::FnvHashMap;
 use itertools::Itertools;
 
@@ -77,7 +80,7 @@ impl Circuit<bls12_381::Scalar> for LispCircuit {
         let circuitTime = Instant::now();
         let start = Instant::now();
         // println!("Allocations\n");
-        // TODO is the private and params 
+        // TODO is the private and params
         for (k, v) in &self.allocs {
             match v {
                 MalVal::ZKScalar(val) => {
@@ -101,7 +104,7 @@ impl Circuit<bls12_381::Scalar> for LispCircuit {
             }
         }
         println!("circuit alloc \t {:?}", start.elapsed());
-        let start = Instant::now();        
+        let start = Instant::now();
         // println!("Allocations Input\n");
         // TODO alloc-input is the public value
         for (k, v) in &self.alloc_inputs {
@@ -122,7 +125,7 @@ impl Circuit<bls12_381::Scalar> for LispCircuit {
                 }
             }
         }
-        println!("circuit alloc input \t {:?}", start.elapsed());        
+        println!("circuit alloc input \t {:?}", start.elapsed());
         let start = Instant::now();
         let mut enforce_sorted = self.constraints.clone();
         // enforce_sorted.sort_by(|a, b| a.idx.cmp(&b.idx));
@@ -249,9 +252,9 @@ impl Circuit<bls12_381::Scalar> for LispCircuit {
                 |_| right.clone(),
                 |_| output.clone(),
             );
-        }     
-        println!("circuit enforce \t {:?}", start.elapsed());        
-        println!("end circuit \t {:?}", circuitTime.elapsed());        
+        }
+        println!("circuit enforce \t {:?}", start.elapsed());
+        println!("end circuit \t {:?}", circuitTime.elapsed());
         Ok(())
     }
 }

+ 11 - 3
src/bin/mint-classic.rs

@@ -5,7 +5,9 @@ use bls12_381::Bls12;
 use ff::Field;
 use group::{Curve, Group, GroupEncoding};
 
-use sapvi::crypto::{save_params, load_params, setup_mint_prover, create_mint_proof, verify_mint_proof};
+use sapvi::crypto::{
+    create_mint_proof, load_params, save_params, setup_mint_prover, verify_mint_proof,
+};
 
 fn main() {
     use rand::rngs::OsRng;
@@ -25,8 +27,14 @@ fn main() {
     }
     let (params, pvk) = load_params("mint.params").expect("params should load");
 
-    let (proof, revealed) = create_mint_proof(&params, value, randomness_value, serial, randomness_coin,
-                                              public);
+    let (proof, revealed) = create_mint_proof(
+        &params,
+        value,
+        randomness_value,
+        serial,
+        randomness_coin,
+        public,
+    );
 
     assert!(verify_mint_proof(&pvk, &proof, &revealed));
 }

+ 12 - 3
src/bin/spend-classic.rs

@@ -7,7 +7,9 @@ use ff::{Field, PrimeField};
 use group::{Curve, GroupEncoding};
 
 use sapvi::circuit::spend_contract::SpendContract;
-use sapvi::crypto::{save_params, load_params, setup_spend_prover, create_spend_proof, verify_spend_proof};
+use sapvi::crypto::{
+    create_spend_proof, load_params, save_params, setup_spend_prover, verify_spend_proof,
+};
 
 // This thing is nasty lol
 pub fn merkle_hash(
@@ -190,8 +192,15 @@ fn main() {
     }
     let (params, pvk) = load_params("spend.params").expect("params should load");
 
-    let (proof, revealed) = create_spend_proof(&params, value, randomness_value, serial, randomness_coin,
-                                              secret, merkle_path);
+    let (proof, revealed) = create_spend_proof(
+        &params,
+        value,
+        randomness_value,
+        serial,
+        randomness_coin,
+        secret,
+        merkle_path,
+    );
 
     assert!(verify_spend_proof(&pvk, &proof, &revealed));
 }

+ 145 - 0
src/bin/tx.rs

@@ -0,0 +1,145 @@
+use bellman::groth16;
+use bls12_381::Bls12;
+use ff::Field;
+use group::Group;
+use rand::rngs::OsRng;
+
+use sapvi::crypto::{
+    create_mint_proof, load_params, save_params, setup_mint_prover, verify_mint_proof,
+    MintRevealedValues,
+};
+
+struct TransactionBuilder {
+    clear_inputs: Vec<TransactionBuilderClearInputInfo>,
+    outputs: Vec<TransactionBuilderOutputInfo>,
+}
+
+impl TransactionBuilder {
+    fn compute_remainder_blind(
+        clear_inputs: &Vec<TransactionClearInput>,
+        output_blinds: &Vec<jubjub::Fr>,
+    ) -> jubjub::Fr {
+        let mut lhs_total = jubjub::Fr::zero();
+        for input in clear_inputs {
+            lhs_total += input.valcom_blind;
+        }
+
+        let mut rhs_total = jubjub::Fr::zero();
+        for output_blind in output_blinds {
+            rhs_total += output_blind;
+        }
+
+        lhs_total - rhs_total
+    }
+
+    fn build(self, mint_params: &groth16::Parameters<Bls12>) -> Transaction {
+        let mut clear_inputs = vec![];
+        for input in &self.clear_inputs {
+            let valcom_blind: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+            let clear_input = TransactionClearInput {
+                value: input.value,
+                valcom_blind,
+            };
+            clear_inputs.push(clear_input);
+        }
+
+        let mut outputs = vec![];
+        let mut output_blinds = vec![];
+        for (i, output) in self.outputs.iter().enumerate() {
+            let valcom_blind = if i == self.outputs.len() - 1 {
+                Self::compute_remainder_blind(&clear_inputs, &output_blinds)
+            } else {
+                jubjub::Fr::random(&mut OsRng)
+            };
+            output_blinds.push(valcom_blind);
+
+            let serial: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+            let coin_blind: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+
+            let (mint_proof, revealed) = create_mint_proof(
+                mint_params,
+                output.value,
+                valcom_blind,
+                serial,
+                coin_blind,
+                output.public,
+            );
+            let output = TransactionOutput {
+                mint_proof,
+                revealed,
+            };
+            outputs.push(output);
+        }
+
+        Transaction {
+            clear_inputs,
+            outputs,
+        }
+    }
+}
+
+struct TransactionBuilderClearInputInfo {
+    value: u64,
+}
+
+struct TransactionBuilderOutputInfo {
+    value: u64,
+    public: jubjub::SubgroupPoint,
+}
+
+struct Transaction {
+    clear_inputs: Vec<TransactionClearInput>,
+    outputs: Vec<TransactionOutput>,
+}
+
+impl Transaction {
+    fn compute_value_commit(value: u64, blind: &jubjub::Fr) -> jubjub::SubgroupPoint {
+        let value_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
+            * jubjub::Fr::from(value))
+            + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR * blind);
+        value_commit
+    }
+
+    fn verify(&self, pvk: &groth16::PreparedVerifyingKey<Bls12>) -> bool {
+        let mut valcom_total = jubjub::SubgroupPoint::identity();
+        for input in &self.clear_inputs {
+            valcom_total += Self::compute_value_commit(input.value, &input.valcom_blind);
+        }
+        for output in &self.outputs {
+            if !verify_mint_proof(pvk, &output.mint_proof, &output.revealed) {
+                return false;
+            }
+            valcom_total -= &output.revealed.value_commit;
+        }
+
+        valcom_total == jubjub::SubgroupPoint::identity()
+    }
+}
+
+struct TransactionClearInput {
+    value: u64,
+    valcom_blind: jubjub::Fr,
+}
+
+struct TransactionOutput {
+    mint_proof: groth16::Proof<Bls12>,
+    revealed: MintRevealedValues,
+}
+
+fn main() {
+    {
+        let params = setup_mint_prover();
+        save_params("mint.params", &params);
+    }
+    let (mint_params, mint_pvk) = load_params("mint.params").expect("params should load");
+
+    let public = jubjub::SubgroupPoint::random(&mut OsRng);
+
+    let builder = TransactionBuilder {
+        clear_inputs: vec![TransactionBuilderClearInputInfo { value: 110 }],
+        outputs: vec![TransactionBuilderOutputInfo { value: 110, public }],
+    };
+
+    let tx = builder.build(&mint_params);
+    assert!(tx.verify(&mint_pvk));
+}

+ 0 - 1
src/circuit/mod.rs

@@ -1,3 +1,2 @@
 pub mod mint_contract;
 pub mod spend_contract;
-

+ 31 - 0
src/crypto/diffie_hellman.rs

@@ -0,0 +1,31 @@
+use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
+use group::{cofactor::CofactorGroup, GroupEncoding};
+
+pub const KDF_SAPLING_PERSONALIZATION: &[u8; 16] = b"DarkFiSaplingKDF";
+
+/// Functions used for encrypting the note in transaction outputs.
+
+/// Sapling key agreement for note encryption.
+///
+/// Implements section 5.4.4.3 of the Zcash Protocol Specification.
+pub fn sapling_ka_agree(esk: &jubjub::Fr, pk_d: &jubjub::ExtendedPoint) -> jubjub::SubgroupPoint {
+    // [8 esk] pk_d
+    // <ExtendedPoint as CofactorGroup>::clear_cofactor is implemented using
+    // ExtendedPoint::mul_by_cofactor in the jubjub crate.
+
+    let mut wnaf = group::Wnaf::new();
+    wnaf.scalar(esk).base(*pk_d).clear_cofactor()
+}
+
+/// Sapling KDF for note encryption.
+///
+/// Implements section 5.4.4.4 of the Zcash Protocol Specification.
+fn kdf_sapling(dhsecret: jubjub::SubgroupPoint, epk: &jubjub::ExtendedPoint) -> Blake2bHash {
+    Blake2bParams::new()
+        .hash_length(32)
+        .personal(KDF_SAPLING_PERSONALIZATION)
+        .to_state()
+        .update(&dhsecret.to_bytes())
+        .update(&epk.to_bytes())
+        .finalize()
+}

+ 7 - 8
src/crypto/mint_proof.rs

@@ -1,14 +1,14 @@
-use rand::rngs::OsRng;
-use std::time::Instant;
 use bellman::gadgets::multipack;
 use bellman::groth16;
 use blake2s_simd::Params as Blake2sParams;
 use bls12_381::Bls12;
 use ff::Field;
 use group::{Curve, Group, GroupEncoding};
+use rand::rngs::OsRng;
+use std::time::Instant;
 
-use crate::error::Result;
 use crate::circuit::mint_contract::MintContract;
+use crate::error::Result;
 
 pub struct MintRevealedValues {
     pub value_commit: jubjub::SubgroupPoint,
@@ -97,8 +97,8 @@ pub fn create_mint_proof(
     randomness_value: jubjub::Fr,
     serial: jubjub::Fr,
     randomness_coin: jubjub::Fr,
-    public: jubjub::SubgroupPoint
-    ) -> (groth16::Proof<Bls12>, MintRevealedValues) {
+    public: jubjub::SubgroupPoint,
+) -> (groth16::Proof<Bls12>, MintRevealedValues) {
     let revealed =
         MintRevealedValues::compute(value, &randomness_value, &serial, &randomness_coin, &public);
 
@@ -120,8 +120,8 @@ pub fn create_mint_proof(
 pub fn verify_mint_proof(
     pvk: &groth16::PreparedVerifyingKey<Bls12>,
     proof: &groth16::Proof<Bls12>,
-    revealed: &MintRevealedValues
-    ) -> bool {
+    revealed: &MintRevealedValues,
+) -> bool {
     let public_input = revealed.make_outputs();
 
     let start = Instant::now();
@@ -129,4 +129,3 @@ pub fn verify_mint_proof(
     println!("Verify: [{:?}]", start.elapsed());
     result
 }
-

+ 13 - 4
src/crypto/mod.rs

@@ -1,12 +1,17 @@
+pub mod diffie_hellman;
 pub mod mint_proof;
+pub mod schnorr;
 pub mod spend_proof;
+pub mod util;
 
 use bellman::groth16;
 use bls12_381::Bls12;
 
 use crate::error::Result;
-pub use mint_proof::{setup_mint_prover, create_mint_proof, verify_mint_proof};
-pub use spend_proof::{setup_spend_prover, create_spend_proof, verify_spend_proof};
+pub use mint_proof::{create_mint_proof, setup_mint_prover, verify_mint_proof, MintRevealedValues};
+pub use spend_proof::{
+    create_spend_proof, setup_spend_prover, verify_spend_proof, SpendRevealedValues,
+};
 
 pub fn save_params(filename: &str, params: &groth16::Parameters<Bls12>) -> Result<()> {
     let buffer = std::fs::File::create(filename)?;
@@ -14,10 +19,14 @@ pub fn save_params(filename: &str, params: &groth16::Parameters<Bls12>) -> Resul
     Ok(())
 }
 
-pub fn load_params(filename: &str) -> Result<(groth16::Parameters<Bls12>, groth16::PreparedVerifyingKey<Bls12>)> {
+pub fn load_params(
+    filename: &str,
+) -> Result<(
+    groth16::Parameters<Bls12>,
+    groth16::PreparedVerifyingKey<Bls12>,
+)> {
     let buffer = std::fs::File::open(filename)?;
     let params = groth16::Parameters::<Bls12>::read(buffer, false)?;
     let pvk = groth16::prepare_verifying_key(&params.vk);
     Ok((params, pvk))
 }
-

+ 55 - 0
src/crypto/schnorr.rs

@@ -0,0 +1,55 @@
+use ff::Field;
+use group::{Group, GroupEncoding};
+use rand::rngs::OsRng;
+
+use super::util::hash_to_scalar;
+
+pub struct SecretKey(pub jubjub::Fr);
+
+impl SecretKey {
+    pub fn random() -> Self {
+        Self(jubjub::Fr::random(&mut OsRng))
+    }
+
+    pub fn sign(&self, message: &[u8]) -> Signature {
+        let mask = jubjub::Fr::random(&mut OsRng);
+        let commit = zcash_primitives::constants::SPENDING_KEY_GENERATOR * mask;
+
+        let challenge = hash_to_scalar(b"DarkFi_Schnorr", &commit.to_bytes(), message);
+
+        let response = mask + challenge * self.0;
+
+        Signature { commit, response }
+    }
+
+    pub fn public_key(&self) -> PublicKey {
+        let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * self.0;
+        PublicKey(public)
+    }
+}
+
+pub struct PublicKey(pub jubjub::SubgroupPoint);
+
+pub struct Signature {
+    commit: jubjub::SubgroupPoint,
+    response: jubjub::Fr,
+}
+
+impl PublicKey {
+    pub fn verify(&self, message: &[u8], signature: &Signature) -> bool {
+        let challenge = hash_to_scalar(b"DarkFi_Schnorr", &signature.commit.to_bytes(), message);
+        zcash_primitives::constants::SPENDING_KEY_GENERATOR * signature.response
+            - self.0 * challenge
+            == signature.commit
+    }
+}
+
+#[test]
+fn test_schnorr() {
+    let secret = SecretKey::random();
+    let message = b"Foo bar";
+    let signature = secret.sign(&message[..]);
+    let public = secret.public_key();
+    assert!(public.verify(&message[..], &signature));
+}
+

+ 7 - 8
src/crypto/spend_proof.rs

@@ -1,5 +1,3 @@
-use rand::rngs::OsRng;
-use std::time::Instant;
 use bellman::gadgets::multipack;
 use bellman::groth16;
 use bitvec::{order::Lsb0, view::AsBits};
@@ -7,9 +5,11 @@ use blake2s_simd::Params as Blake2sParams;
 use bls12_381::Bls12;
 use ff::{Field, PrimeField};
 use group::{Curve, GroupEncoding};
+use rand::rngs::OsRng;
+use std::time::Instant;
 
-use crate::error::Result;
 use crate::circuit::spend_contract::SpendContract;
+use crate::error::Result;
 
 // This thing is nasty lol
 pub fn merkle_hash(
@@ -201,8 +201,8 @@ pub fn create_spend_proof(
     serial: jubjub::Fr,
     randomness_coin: jubjub::Fr,
     secret: jubjub::Fr,
-    merkle_path: [(bls12_381::Scalar, bool); 4]
-    ) -> (groth16::Proof<Bls12>, SpendRevealedValues) {
+    merkle_path: [(bls12_381::Scalar, bool); 4],
+) -> (groth16::Proof<Bls12>, SpendRevealedValues) {
     let c = SpendContract {
         value: Some(value),
         randomness_value: Some(randomness_value),
@@ -239,8 +239,8 @@ pub fn create_spend_proof(
 pub fn verify_spend_proof(
     pvk: &groth16::PreparedVerifyingKey<Bls12>,
     proof: &groth16::Proof<Bls12>,
-    revealed: &SpendRevealedValues
-    ) -> bool {
+    revealed: &SpendRevealedValues,
+) -> bool {
     let public_input = revealed.make_outputs();
 
     let start = Instant::now();
@@ -248,4 +248,3 @@ pub fn verify_spend_proof(
     println!("Verify: [{:?}]", start.elapsed());
     result
 }
-

+ 9 - 0
src/crypto/util.rs

@@ -0,0 +1,9 @@
+use blake2b_simd::Params;
+
+pub fn hash_to_scalar(persona: &[u8], a: &[u8], b: &[u8]) -> jubjub::Fr {
+    let mut hasher = Params::new().hash_length(64).personal(persona).to_state();
+    hasher.update(a);
+    hasher.update(b);
+    let ret = hasher.finalize();
+    jubjub::Fr::from_bytes_wide(ret.as_array())
+}