Jelajahi Sumber

dao2: added zk verification

x 3 tahun lalu
induk
melakukan
9ad69f373a
2 mengubah file dengan 114 tambahan dan 3 penghapusan
  1. 23 1
      example/dao2/src/main.rs
  2. 91 2
      example/dao2/src/tx.rs

+ 23 - 1
example/dao2/src/main.rs

@@ -253,6 +253,8 @@ async fn main() -> BoxResult<()> {
 
 
     // We can do all exec(), zk proof checks and signature verifies in parallel.
     // We can do all exec(), zk proof checks and signature verifies in parallel.
     let mut updates = vec![];
     let mut updates = vec![];
+    let mut zkpublic_table = vec![];
+    let mut sigpub_table = vec![];
     // Validate all function calls in the tx
     // Validate all function calls in the tx
     for (idx, call) in tx.calls.iter().enumerate() {
     for (idx, call) in tx.calls.iter().enumerate() {
         // So then the verifier will lookup the corresponding state_transition and apply
         // So then the verifier will lookup the corresponding state_transition and apply
@@ -272,6 +274,16 @@ async fn main() -> BoxResult<()> {
                     Runtime::new(&dao_wasm_bytes, blockchain.clone(), dao_contract_id)?;
                     Runtime::new(&dao_wasm_bytes, blockchain.clone(), dao_contract_id)?;
                 let update = runtime.exec(&payload)?;
                 let update = runtime.exec(&payload)?;
                 updates.push(update);
                 updates.push(update);
+
+                let metadata = runtime.metadata(&payload)?;
+                let mut decoder = Cursor::new(&metadata);
+                let zk_public_values: Vec<(String, Vec<pallas::Base>)> =
+                    Decodable::decode(&mut decoder)?;
+                let signature_public_keys: Vec<pallas::Point> =
+                    Decodable::decode(&mut decoder)?;
+
+                zkpublic_table.push(zk_public_values);
+                sigpub_table.push(signature_public_keys);
             }
             }
             money_contract_id => {
             money_contract_id => {
                 debug!(target: "demo", "Money::exec() contract called");
                 debug!(target: "demo", "Money::exec() contract called");
@@ -279,12 +291,22 @@ async fn main() -> BoxResult<()> {
                     Runtime::new(&money_wasm_bytes, blockchain.clone(), money_contract_id)?;
                     Runtime::new(&money_wasm_bytes, blockchain.clone(), money_contract_id)?;
                 let update = runtime.exec(&payload)?;
                 let update = runtime.exec(&payload)?;
                 updates.push(update);
                 updates.push(update);
+
+                let metadata = runtime.metadata(&payload)?;
+                let mut decoder = Cursor::new(&metadata);
+                let zk_public_values: Vec<(String, Vec<pallas::Base>)> =
+                    Decodable::decode(&mut decoder)?;
+                let signature_public_keys: Vec<pallas::Point> =
+                    Decodable::decode(&mut decoder)?;
+
+                zkpublic_table.push(zk_public_values);
+                sigpub_table.push(signature_public_keys);
             }
             }
             _ => {}
             _ => {}
         }
         }
     }
     }
 
 
-    //tx.zk_verify(&zk_bins).unwrap();
+    tx.zk_verify(&zk_bins, &zkpublic_table)?;
     //tx.verify_sigs();
     //tx.verify_sigs();
 
 
     // Now we finished verification stage, just apply all changes
     // Now we finished verification stage, just apply all changes

+ 91 - 2
example/dao2/src/tx.rs

@@ -1,8 +1,97 @@
-use darkfi::crypto::{schnorr::Signature, Proof};
-use darkfi_sdk::tx::ContractCall;
+use log::debug;
+use darkfi::{crypto::{schnorr::Signature, Proof}, Result, VerifyFailed::ProofVerifyFailed};
+use darkfi_sdk::{tx::ContractCall, pasta::pallas};
+
+use crate::{
+    contract::{dao, example, money},
+    note::EncryptedNote2,
+    schema::WalletCache,
+    util::{sign, StateRegistry, ZkContractTable, ZkContractInfo},
+};
+
+macro_rules! zip {
+    ($x: expr) => ($x);
+    ($x: expr, $($y: expr), +) => (
+        $x.iter().zip(
+            zip!($($y), +))
+    )
+}
 
 
 pub struct Transaction {
 pub struct Transaction {
     pub calls: Vec<ContractCall>,
     pub calls: Vec<ContractCall>,
     pub proofs: Vec<Vec<Proof>>,
     pub proofs: Vec<Vec<Proof>>,
     pub signatures: Vec<Vec<Signature>>,
     pub signatures: Vec<Vec<Signature>>,
 }
 }
+
+impl Transaction {
+    /// Verify ZK contracts for the entire tx
+    /// In real code, we could parallelize this for loop
+    /// TODO: fix use of unwrap with Result type stuff
+    pub fn zk_verify(&self, zk_bins: &ZkContractTable, zkpub_table: &Vec<Vec<(String, Vec<pallas::Base>)>>) -> Result<()> {
+        assert_eq!(
+            self.calls.len(),
+            self.proofs.len(),
+            "calls.len()={} and proofs.len()={} do not match",
+            self.calls.len(),
+            self.proofs.len()
+        );
+        assert_eq!(
+            self.calls.len(),
+            zkpub_table.len(),
+            "calls.len()={} and zkpub_table.len()={} do not match",
+            self.calls.len(),
+            zkpub_table.len()
+        );
+        for (call, (proofs, pubvals)) in zip!(self.calls, self.proofs, zkpub_table) {
+            assert_eq!(
+                proofs.len(),
+                pubvals.len(),
+                "proofs.len()={} and pubvals.len()={} do not match",
+                proofs.len(),
+                pubvals.len()
+            );
+
+            for (i, (proof, (key, public_vals))) in
+                proofs.iter().zip(pubvals.iter()).enumerate()
+            {
+                match zk_bins.lookup(key).unwrap() {
+                    ZkContractInfo::Binary(info) => {
+                        let verifying_key = &info.verifying_key;
+                        let verify_result = proof.verify(verifying_key, public_vals);
+                        if verify_result.is_err() {
+                            return Err(ProofVerifyFailed(key.to_string()).into())
+                        }
+                        //assert!(verify_result.is_ok(), "verify proof[{}]='{}' failed", i, key);
+                    }
+                    ZkContractInfo::Native(info) => {
+                        let verifying_key = &info.verifying_key;
+                        let verify_result = proof.verify(verifying_key, public_vals);
+                        if verify_result.is_err() {
+                            return Err(ProofVerifyFailed(key.to_string()).into())
+                        }
+                        //assert!(verify_result.is_ok(), "verify proof[{}]='{}' failed", i, key);
+                    }
+                };
+                debug!(target: "demo", "zk_verify({}) passed [i={}]", key, i);
+            }
+        }
+        Ok(())
+    }
+
+    pub fn verify_sigs(&self) {
+        //let mut unsigned_tx_data = vec![];
+        /*
+        for (i, (func_call, signatures)) in
+            self.func_calls.iter().zip(self.signatures.clone()).enumerate()
+        {
+            func_call.encode(&mut unsigned_tx_data).expect("failed to encode data");
+            let signature_pub_keys = func_call.call_data.signature_public_keys();
+            for (signature_pub_key, signature) in signature_pub_keys.iter().zip(signatures) {
+                let verify_result = signature_pub_key.verify(&unsigned_tx_data[..], &signature);
+                assert!(verify_result, "verify sigs[{}] failed", i);
+            }
+            debug!(target: "demo", "verify_sigs({}) passed", i);
+        }
+        */
+    }
+}