Răsfoiți Sursa

contract/money: Finalize integration test with zk proof verification

parazyd 3 ani în urmă
părinte
comite
a1a2da8394

+ 2 - 1
src/consensus/state.rs

@@ -979,7 +979,8 @@ impl ValidatorState {
 
             // Finally, verify the ZK proofs
             debug!("Verifying transaction ZK proofs");
-            tx.verify_zkps(zkp_table)?;
+            // FIXME XXX:
+            tx.verify_zkps(&[], zkp_table)?;
             debug!("Transaction ZK proofs verified successfully!");
 
             // When the verification stage has passed, just apply all the changes.

+ 4 - 1
src/contract/money/src/client.rs

@@ -333,7 +333,10 @@ impl TransferMintRevealed {
         //       calls in the zkas code.
         vec![
             self.coin.inner(),
-            *valcom_coords.x() * tokcom_coords.y() * valcom_coords.x() * tokcom_coords.y(),
+            *valcom_coords.x(),
+            *valcom_coords.y(),
+            *tokcom_coords.x(),
+            *tokcom_coords.y(),
         ]
     }
 }

+ 15 - 8
src/contract/money/tests/contract_exec.rs

@@ -166,15 +166,18 @@ async fn money_contract_execution() -> Result<()> {
     let sigs = tx.create_sigs(&mut OsRng, &secret_keys)?;
     tx.signatures = vec![sigs];
 
+    // Get our ZK verifying keys in place for the tx verification
+    let vks = verifying_keys.get(&contract_id.inner().to_repr()).unwrap();
+
     // Let's first execute this transaction for the faucet to see if it passes.
     // Then Alice gets the tx and also executes it.
     info!("Executing transaction on the faucet's blockchain db");
-    verify_transaction(&faucet_blockchain, &tx)?;
+    verify_transaction(&faucet_blockchain, vks, &tx)?;
     info!("Adding coin to faucet's Merkle tree");
     faucet_merkle_tree.append(&MerkleNode::from(params.outputs[0].coin));
 
     info!("Executing transaction on Alice's blockchain db");
-    verify_transaction(&alice_blockchain, &tx)?;
+    verify_transaction(&alice_blockchain, vks, &tx)?;
     // TODO: FIXME: Actually have a look at the `merkle_add` calls
     alice_merkle_tree.append(&MerkleNode::from(params.outputs[0].coin));
     let leaf_position = alice_merkle_tree.witness().unwrap();
@@ -227,12 +230,12 @@ async fn money_contract_execution() -> Result<()> {
     tx.signatures = vec![sigs];
 
     info!("Executing transaction on the faucet's blockchain db");
-    verify_transaction(&faucet_blockchain, &tx)?;
+    verify_transaction(&faucet_blockchain, vks, &tx)?;
     info!("Adding coin to faucet's Merkle tree");
     faucet_merkle_tree.append(&MerkleNode::from(params.outputs[0].coin));
 
     info!("Executing transaction on Alice's blockchain db");
-    verify_transaction(&alice_blockchain, &tx)?;
+    verify_transaction(&alice_blockchain, vks, &tx)?;
     // TODO: FIXME: Actually have a look at the `merkle_add` calls
     alice_merkle_tree.append(&MerkleNode::from(params.outputs[0].coin));
     let leaf_position = alice_merkle_tree.witness().unwrap();
@@ -283,18 +286,22 @@ async fn money_contract_execution() -> Result<()> {
     tx.signatures = vec![sigs];
 
     info!("Executing transaction on the faucet's blockchain db");
-    verify_transaction(&faucet_blockchain, &tx)?;
+    verify_transaction(&faucet_blockchain, vks, &tx)?;
     info!("Adding coin to faucet's Merkle tree");
     faucet_merkle_tree.append(&MerkleNode::from(params.outputs[0].coin));
     info!("Executing transaction on Alice's blockchain db");
-    verify_transaction(&alice_blockchain, &tx)?;
+    verify_transaction(&alice_blockchain, vks, &tx)?;
     // TODO: FIXME: Actually have a look at the `merkle_add` calls
     alice_merkle_tree.append(&MerkleNode::from(params.outputs[0].coin));
 
     Ok(())
 }
 
-fn verify_transaction(blockchain: &Blockchain, tx: &Transaction) -> Result<()> {
+fn verify_transaction(
+    blockchain: &Blockchain,
+    verifying_keys: &[(String, VerifyingKey)],
+    tx: &Transaction,
+) -> Result<()> {
     info!("Begin transcation verification");
     // Table of public inputs used for ZK proof verification
     let mut zkp_table = vec![];
@@ -336,7 +343,7 @@ fn verify_transaction(blockchain: &Blockchain, tx: &Transaction) -> Result<()> {
     info!("Signatures verified successfully");
 
     info!("Verifying transaction ZK proofs");
-    tx.verify_zkps(zkp_table)?;
+    tx.verify_zkps(verifying_keys, zkp_table)?;
     info!("Transaction ZK proofs verified successfully");
 
     // After the verification stage has passed, just apply all the changes.

+ 42 - 2
src/tx/mod.rs

@@ -28,7 +28,17 @@ use darkfi_serial::{Encodable, SerialDecodable, SerialEncodable};
 use log::{debug, error};
 use rand::{CryptoRng, RngCore};
 
-use crate::{crypto::Proof, Error, Result};
+use crate::{
+    crypto::{proof::VerifyingKey, Proof},
+    Error, Result, VerifyFailed,
+};
+
+macro_rules! zip {
+    ($x:expr) => ($x);
+    ($x:expr, $($y:expr), +) => (
+        $x.iter().zip(zip!($($y), +))
+    )
+}
 
 /// A Transaction contains an arbitrary number of `ContractCall` objects,
 /// along with corresponding ZK proofs and Schnorr signatures.
@@ -44,7 +54,37 @@ pub struct Transaction {
 
 impl Transaction {
     /// Verify ZK proofs for the entire transaction.
-    pub fn verify_zkps(&self, zkp_table: Vec<Vec<(String, Vec<pallas::Base>)>>) -> Result<()> {
+    pub fn verify_zkps(
+        &self,
+        verifying_keys: &[(String, VerifyingKey)],
+        zkp_table: Vec<Vec<(String, Vec<pallas::Base>)>>,
+    ) -> Result<()> {
+        // TODO: Are we sure we should assert here?
+        assert_eq!(self.calls.len(), self.proofs.len());
+        assert_eq!(self.calls.len(), zkp_table.len());
+
+        for (call, (proofs, pubvals)) in zip!(self.calls, self.proofs, zkp_table) {
+            assert_eq!(proofs.len(), pubvals.len());
+
+            for (i, (proof, (zk_ns, public_vals))) in proofs.iter().zip(pubvals.iter()).enumerate()
+            {
+                if let Some(vk) = verifying_keys.iter().find(|x| &x.0 == zk_ns) {
+                    // We have a verifying key for this
+                    debug!("public inputs: {:#?}", public_vals);
+                    if let Err(e) = proof.verify(&vk.1, public_vals) {
+                        error!("Failed verifying zk proof: {}", e);
+                        return Err(VerifyFailed::ProofVerifyFailed(e.to_string()).into())
+                    }
+                } else {
+                    return Err(VerifyFailed::ProofVerifyFailed(format!(
+                        "Verifying key for {} circuit does not exist",
+                        zk_ns
+                    ))
+                    .into())
+                }
+            }
+        }
+
         Ok(())
     }