Browse Source

partially working spend contract (just needs merkle inclusion part)

narodnik 5 năm trước cách đây
mục cha
commit
d366922217
8 tập tin đã thay đổi với 263 bổ sung7 xóa
  1. 6 2
      Cargo.toml
  2. 6 0
      proofs/mint.aux
  3. 3 3
      proofs/mint.pism
  4. 93 0
      proofs/spend.pism
  5. 4 0
      run_spend_contract.sh
  6. 2 1
      scripts/pism.py
  7. 1 1
      src/mint.rs
  8. 148 0
      src/spend.rs

+ 6 - 2
Cargo.toml

@@ -14,8 +14,8 @@ 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_proofs = { git = "https://github.com/narodnik/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"
 rand_core = "0.5.1"
@@ -51,3 +51,7 @@ path = "src/simple.rs"
 name = "mint"
 path = "src/mint.rs"
 
+[[bin]]
+name = "spend"
+path = "src/spend.rs"
+

+ 6 - 0
proofs/mint.aux

@@ -3,9 +3,15 @@
         "G_SPEND": {
             "maps_to": "zcash_proofs::constants::SPENDING_KEY_GENERATOR"
         },
+        "G_PROOF": {
+            "maps_to": "zcash_proofs::constants::PROOF_GENERATION_KEY_GENERATOR"
+        },
         "CRH_IVK": {
             "maps_to": "zcash_primitives::constants::CRH_IVK_PERSONALIZATION"
         },
+        "PRF_NF": {
+            "maps_to": "zcash_primitives::constants::PRF_NF_PERSONALIZATION"
+        },
         "G_VCV": {
             "maps_to": "zcash_proofs::constants::VALUE_COMMITMENT_VALUE_GENERATOR"
         },

+ 3 - 3
proofs/mint.pism

@@ -13,7 +13,6 @@ contract mint_contract
 
     param serial Fr
     param randomness_coin Fr
-
     param public Point
 start
     # Witness input values
@@ -34,9 +33,10 @@ start
     # emit cv
     emit_ec cv
 
-    # Build the preimage to hash
-    # coin = Hash(public_key, value, serial, randomness_coin)
+    # Make the coin
+    # C = Hash(public_key, value, serial, randomness_coin)
 
+    # Build the preimage to hash
     alloc_binary preimage
 
     # public_key

+ 93 - 0
proofs/spend.pism

@@ -0,0 +1,93 @@
+constant G_VCV FixedGenerator
+constant G_VCR FixedGenerator
+constant G_SPEND FixedGenerator
+constant CRH_IVK BlakePersonalization
+
+contract spend_contract
+    # Value commitment
+    param value U64
+    param randomness_value Fr
+
+    param serial Fr
+    param randomness_coin Fr
+    param secret Fr
+start
+    # Witness input values
+    u64_as_binary_le value param:value
+    fr_as_binary_le randomness_value param:randomness_value
+
+    # Make value commitment
+    # V = v * G_VCV + r * G_VCR
+
+    ec_mul_const vcv value G_VCV
+    ec_mul_const rcv randomness_value G_VCR
+    ec_add cv vcv rcv
+    # emit cv
+    emit_ec cv
+
+    # Make the nullifier
+    # N = Hash(secret, serial)
+    fr_as_binary_le serial param:serial
+    fr_as_binary_le secret param:secret
+
+    alloc_binary nf_preimage
+
+# Fr values are 252 bits so we need to pad it with extra 0s
+# to match the Rust values which are 256 bits
+{% macro binary_put_fr(binary, var) -%}
+    binary_extend {{ binary }} {{ var }}
+    {% for n in range(4) %}
+        alloc_const_bit zero_bit false
+        binary_push {{ binary }} zero_bit
+    {% endfor %}
+{%- endmacro %}
+
+    # secret
+    binary_clone secret2 secret
+    {{ binary_put_fr("nf_preimage", "secret2") }}
+
+    # serial
+    binary_clone serial2 serial
+    {{ binary_put_fr("nf_preimage", "serial2") }}
+
+    # Secret:           Fr              = 252 + 4 bits padding
+    # Serial:           Fr              = 252 + 4 bits padding
+    # TOTAL: 512 bits for preimage
+    static_assert_binary_size nf_preimage 512
+    blake2s nf nf_preimage CRH_IVK
+    emit_binary nf
+
+    # Derive the public key
+    # P = secret * G
+    ec_mul_const public secret G_SPEND
+
+    # Make the coin (same as mint contract)
+    # C = Hash(public_key, value, serial, randomness_coin)
+    fr_as_binary_le randomness_coin param:randomness_coin
+
+    # Build the preimage to hash
+    alloc_binary preimage
+
+    # public_key
+    ec_repr repr_public public
+    binary_extend preimage repr_public
+
+    # value
+    binary_extend preimage value
+
+    # serial
+    {{ binary_put_fr("preimage", "serial") }}
+
+    # randomness_coin
+    {{ binary_put_fr("preimage", "randomness_coin") }}
+
+    # Public key:       SubgroupPoint   = 256 bits
+    # Value:            u64             = 64 bits
+    # Serial:           Fr              = 252 + 4 bits padding
+    # Randomness coin   Fr              = 252 + 4 bits padding
+    # TOTAL: 832 bits for preimage
+    static_assert_binary_size preimage 832
+    blake2s coin preimage CRH_IVK
+    emit_binary coin
+end
+

+ 4 - 0
run_spend_contract.sh

@@ -0,0 +1,4 @@
+#!/bin/bash -x
+python scripts/preprocess.py proofs/spend.pism > /tmp/spend.pism
+python scripts/pism.py /tmp/spend.pism proofs/mint.aux | rustfmt > src/spend_contract.rs
+cargo run --release --bin spend

+ 2 - 1
scripts/pism.py

@@ -284,7 +284,8 @@ class Contract:
 
     def _includes(self):
         return \
-r"""use bellman::{
+r"""#![allow(unused_imports)]
+use bellman::{
     gadgets::{
         boolean,
         boolean::{AllocatedBit, Boolean},

+ 1 - 1
src/mint.rs

@@ -10,7 +10,7 @@ use mint_contract::MintContract;
 
 struct MintRevealedValues {
     value_commit: jubjub::SubgroupPoint,
-    coin: [u8; 32]
+    coin: [u8; 32],
 }
 
 impl MintRevealedValues {

+ 148 - 0
src/spend.rs

@@ -0,0 +1,148 @@
+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};
+
+mod spend_contract;
+use spend_contract::SpendContract;
+
+struct SpendRevealedValues {
+    value_commit: jubjub::SubgroupPoint,
+    nullifier: [u8; 32],
+    coin: [u8; 32],
+}
+
+impl SpendRevealedValues {
+    fn compute(
+        value: u64,
+        randomness_value: &jubjub::Fr,
+        serial: &jubjub::Fr,
+        randomness_coin: &jubjub::Fr,
+        secret: &jubjub::Fr,
+    ) -> 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::CRH_IVK_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(),
+        );
+
+        SpendRevealedValues { value_commit, nullifier, coin }
+    }
+
+    fn make_outputs(&self) -> [bls12_381::Scalar; 6] {
+        let mut public_input = [bls12_381::Scalar::zero(); 6];
+
+        {
+            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;
+        }
+
+        {
+            // 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];
+        }
+
+        {
+            // 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
+    }
+}
+
+fn main() {
+    use std::time::Instant;
+    use rand::rngs::OsRng;
+
+    let value = 110;
+    let randomness_value: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+
+    let serial: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let randomness_coin: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+    let secret: jubjub::Fr = jubjub::Fr::random(&mut OsRng);
+
+    let revealed =
+        SpendRevealedValues::compute(value, &randomness_value, &serial, &randomness_coin, &secret);
+
+    let start = Instant::now();
+    let params = {
+        let c = SpendContract {
+            value: None,
+            randomness_value: None,
+            serial: None,
+            randomness_coin: None,
+            secret: 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),
+    };
+
+    let start = Instant::now();
+    let proof = groth16::create_random_proof(c, &params, &mut OsRng).unwrap();
+    println!("Prove: [{:?}]", start.elapsed());
+
+    let public_input = revealed.make_outputs();
+
+    let start = Instant::now();
+    assert!(groth16::verify_proof(&pvk, &proof, &public_input).is_ok());
+    println!("Verify: [{:?}]", start.elapsed());
+}
+