narodnik 5 лет назад
Родитель
Сommit
5534f31d50
3 измененных файлов с 262 добавлено и 56 удалено
  1. 9 56
      src/bin/spend-classic.rs
  2. 2 0
      src/crypto/mod.rs
  3. 251 0
      src/crypto/spend_proof.rs

+ 9 - 56
src/bin/spend-classic.rs

@@ -7,6 +7,7 @@ use ff::{Field, PrimeField};
 use group::{Curve, GroupEncoding};
 use group::{Curve, GroupEncoding};
 
 
 use sapvi::circuit::spend_contract::SpendContract;
 use sapvi::circuit::spend_contract::SpendContract;
+use sapvi::crypto::{save_params, load_params, setup_spend_prover, create_spend_proof, verify_spend_proof};
 
 
 // This thing is nasty lol
 // This thing is nasty lol
 pub fn merkle_hash(
 pub fn merkle_hash(
@@ -183,62 +184,14 @@ fn main() {
         (bls12_381::Scalar::random(&mut OsRng), true),
         (bls12_381::Scalar::random(&mut OsRng), true),
     ];
     ];
 
 
-    let revealed = SpendRevealedValues::compute(
-        value,
-        &randomness_value,
-        &serial,
-        &randomness_coin,
-        &secret,
-        &merkle_path,
-    );
-
-    let start = Instant::now();
-    let params = {
-        let c = SpendContract {
-            value: None,
-            randomness_value: None,
-            serial: None,
-            randomness_coin: None,
-            secret: None,
-
-            branch_0: None,
-            is_right_0: None,
-            branch_1: None,
-            is_right_1: None,
-            branch_2: None,
-            is_right_2: None,
-            branch_3: None,
-            is_right_3: None,
-        };
-        groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
-    };
-    let pvk = groth16::prepare_verifying_key(&params.vk);
-    println!("Setup: [{:?}]", start.elapsed());
-
-    let c = SpendContract {
-        value: Some(value),
-        randomness_value: Some(randomness_value),
-        serial: Some(serial),
-        randomness_coin: Some(randomness_coin),
-        secret: Some(secret),
-
-        branch_0: Some(merkle_path[0].0),
-        is_right_0: Some(merkle_path[0].1),
-        branch_1: Some(merkle_path[1].0),
-        is_right_1: Some(merkle_path[1].1),
-        branch_2: Some(merkle_path[2].0),
-        is_right_2: Some(merkle_path[2].1),
-        branch_3: Some(merkle_path[3].0),
-        is_right_3: Some(merkle_path[3].1),
-    };
-
-    let start = Instant::now();
-    let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();
-    println!("Prove: [{:?}]", start.elapsed());
+    {
+        let params = setup_spend_prover();
+        save_params("spend.params", &params);
+    }
+    let (params, pvk) = load_params("spend.params").expect("params should load");
 
 
-    let public_input = revealed.make_outputs();
+    let (proof, revealed) = create_spend_proof(&params, value, randomness_value, serial, randomness_coin,
+                                              secret, merkle_path);
 
 
-    let start = Instant::now();
-    assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok());
-    println!("Verify: [{:?}]", start.elapsed());
+    assert!(verify_spend_proof(&pvk, &proof, &revealed));
 }
 }

+ 2 - 0
src/crypto/mod.rs

@@ -1,10 +1,12 @@
 pub mod mint_proof;
 pub mod mint_proof;
+pub mod spend_proof;
 
 
 use bellman::groth16;
 use bellman::groth16;
 use bls12_381::Bls12;
 use bls12_381::Bls12;
 
 
 use crate::error::Result;
 use crate::error::Result;
 pub use mint_proof::{setup_mint_prover, create_mint_proof, verify_mint_proof};
 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 fn save_params(filename: &str, params: &groth16::Parameters<Bls12>) -> Result<()> {
 pub fn save_params(filename: &str, params: &groth16::Parameters<Bls12>) -> Result<()> {
     let buffer = std::fs::File::create(filename)?;
     let buffer = std::fs::File::create(filename)?;

+ 251 - 0
src/crypto/spend_proof.rs

@@ -0,0 +1,251 @@
+use rand::rngs::OsRng;
+use std::time::Instant;
+use bellman::gadgets::multipack;
+use bellman::groth16;
+use bitvec::{order::Lsb0, view::AsBits};
+use blake2s_simd::Params as Blake2sParams;
+use bls12_381::Bls12;
+use ff::{Field, PrimeField};
+use group::{Curve, GroupEncoding};
+
+use crate::error::Result;
+use crate::circuit::spend_contract::SpendContract;
+
+// This thing is nasty lol
+pub fn merkle_hash(
+    depth: usize,
+    lhs: &bls12_381::Scalar,
+    rhs: &bls12_381::Scalar,
+) -> bls12_381::Scalar {
+    let lhs = {
+        let mut tmp = [false; 256];
+        for (a, b) in tmp.iter_mut().zip(lhs.to_repr().as_bits::<Lsb0>()) {
+            *a = *b;
+        }
+        tmp
+    };
+
+    let rhs = {
+        let mut tmp = [false; 256];
+        for (a, b) in tmp.iter_mut().zip(rhs.to_repr().as_bits::<Lsb0>()) {
+            *a = *b;
+        }
+        tmp
+    };
+
+    jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
+        zcash_primitives::pedersen_hash::Personalization::MerkleTree(depth),
+        lhs.iter()
+            .copied()
+            .take(bls12_381::Scalar::NUM_BITS as usize)
+            .chain(
+                rhs.iter()
+                    .copied()
+                    .take(bls12_381::Scalar::NUM_BITS as usize),
+            ),
+    ))
+    .to_affine()
+    .get_u()
+}
+
+pub struct SpendRevealedValues {
+    pub value_commit: jubjub::SubgroupPoint,
+    pub nullifier: [u8; 32],
+    // This should not be here, we just have it for debugging
+    //coin: [u8; 32],
+    pub merkle_root: bls12_381::Scalar,
+}
+
+impl SpendRevealedValues {
+    fn compute(
+        value: u64,
+        randomness_value: &jubjub::Fr,
+        serial: &jubjub::Fr,
+        randomness_coin: &jubjub::Fr,
+        secret: &jubjub::Fr,
+        merkle_path: &[(bls12_381::Scalar, bool)],
+    ) -> Self {
+        let value_commit = (zcash_primitives::constants::VALUE_COMMITMENT_VALUE_GENERATOR
+            * jubjub::Fr::from(value))
+            + (zcash_primitives::constants::VALUE_COMMITMENT_RANDOMNESS_GENERATOR
+                * randomness_value);
+
+        let mut nullifier = [0; 32];
+        nullifier.copy_from_slice(
+            Blake2sParams::new()
+                .hash_length(32)
+                .personal(zcash_primitives::constants::PRF_NF_PERSONALIZATION)
+                .to_state()
+                .update(&secret.to_bytes())
+                .update(&serial.to_bytes())
+                .finalize()
+                .as_bytes(),
+        );
+
+        let public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * secret;
+
+        let mut coin = [0; 32];
+        coin.copy_from_slice(
+            Blake2sParams::new()
+                .hash_length(32)
+                .personal(zcash_primitives::constants::CRH_IVK_PERSONALIZATION)
+                .to_state()
+                .update(&public.to_bytes())
+                .update(&value.to_le_bytes())
+                .update(&serial.to_bytes())
+                .update(&randomness_coin.to_bytes())
+                .finalize()
+                .as_bytes(),
+        );
+
+        let merkle_root =
+            jubjub::ExtendedPoint::from(zcash_primitives::pedersen_hash::pedersen_hash(
+                zcash_primitives::pedersen_hash::Personalization::NoteCommitment,
+                multipack::bytes_to_bits_le(&coin),
+            ));
+        let affine = merkle_root.to_affine();
+        let mut merkle_root = affine.get_u();
+
+        for (i, (right, is_right)) in merkle_path.iter().enumerate() {
+            if *is_right {
+                merkle_root = merkle_hash(i, &right, &merkle_root);
+            } else {
+                merkle_root = merkle_hash(i, &merkle_root, &right);
+            }
+        }
+
+        SpendRevealedValues {
+            value_commit,
+            nullifier,
+            merkle_root,
+        }
+    }
+
+    fn make_outputs(&self) -> [bls12_381::Scalar; 5] {
+        let mut public_input = [bls12_381::Scalar::zero(); 5];
+
+        // CV
+        {
+            let result = jubjub::ExtendedPoint::from(self.value_commit);
+            let affine = result.to_affine();
+            //let (u, v) = (affine.get_u(), affine.get_v());
+            let u = affine.get_u();
+            let v = affine.get_v();
+            public_input[0] = u;
+            public_input[1] = v;
+        }
+
+        // NF
+        {
+            // Pack the hash as inputs for proof verification.
+            let hash = multipack::bytes_to_bits_le(&self.nullifier);
+            let hash = multipack::compute_multipacking(&hash);
+
+            // There are 2 chunks for a blake hash
+            assert_eq!(hash.len(), 2);
+
+            public_input[2] = hash[0];
+            public_input[3] = hash[1];
+        }
+
+        // Not revealed. We leave this code here for debug
+        // Coin
+        /*{
+            // Pack the hash as inputs for proof verification.
+            let hash = multipack::bytes_to_bits_le(&self.coin);
+            let hash = multipack::compute_multipacking(&hash);
+
+            // There are 2 chunks for a blake hash
+            assert_eq!(hash.len(), 2);
+
+            public_input[4] = hash[0];
+            public_input[5] = hash[1];
+        }*/
+
+        public_input[4] = self.merkle_root;
+
+        public_input
+    }
+}
+
+pub fn setup_spend_prover() -> groth16::Parameters<Bls12> {
+    println!("Making random params...");
+    let start = Instant::now();
+    let params = {
+        let c = SpendContract {
+            value: None,
+            randomness_value: None,
+            serial: None,
+            randomness_coin: None,
+            secret: None,
+
+            branch_0: None,
+            is_right_0: None,
+            branch_1: None,
+            is_right_1: None,
+            branch_2: None,
+            is_right_2: None,
+            branch_3: None,
+            is_right_3: None,
+        };
+        groth16::generate_random_parameters::<Bls12, _, _>(c, &mut OsRng).unwrap()
+    };
+    println!("Setup: [{:?}]", start.elapsed());
+    params
+}
+
+pub fn create_spend_proof(
+    params: &groth16::Parameters<Bls12>,
+    value: u64,
+    randomness_value: jubjub::Fr,
+    serial: jubjub::Fr,
+    randomness_coin: jubjub::Fr,
+    secret: jubjub::Fr,
+    merkle_path: [(bls12_381::Scalar, bool); 4]
+    ) -> (groth16::Proof<Bls12>, SpendRevealedValues) {
+    let c = SpendContract {
+        value: Some(value),
+        randomness_value: Some(randomness_value),
+        serial: Some(serial),
+        randomness_coin: Some(randomness_coin),
+        secret: Some(secret),
+
+        branch_0: Some(merkle_path[0].0),
+        is_right_0: Some(merkle_path[0].1),
+        branch_1: Some(merkle_path[1].0),
+        is_right_1: Some(merkle_path[1].1),
+        branch_2: Some(merkle_path[2].0),
+        is_right_2: Some(merkle_path[2].1),
+        branch_3: Some(merkle_path[3].0),
+        is_right_3: Some(merkle_path[3].1),
+    };
+
+    let start = Instant::now();
+    let proof = groth16::create_random_proof(c, params, &mut OsRng).unwrap();
+    println!("Prove: [{:?}]", start.elapsed());
+
+    let revealed = SpendRevealedValues::compute(
+        value,
+        &randomness_value,
+        &serial,
+        &randomness_coin,
+        &secret,
+        &merkle_path,
+    );
+
+    (proof, revealed)
+}
+
+pub fn verify_spend_proof(
+    pvk: &groth16::PreparedVerifyingKey<Bls12>,
+    proof: &groth16::Proof<Bls12>,
+    revealed: &SpendRevealedValues
+    ) -> bool {
+    let public_input = revealed.make_outputs();
+
+    let start = Instant::now();
+    let result = groth16::verify_proof(pvk, proof, &public_input).is_ok();
+    println!("Verify: [{:?}]", start.elapsed());
+    result
+}
+