diff --git a/src/consensus/state.rs b/src/consensus/state.rs index f479f4ba2..eac0f0199 100644 --- a/src/consensus/state.rs +++ b/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. diff --git a/src/contract/money/src/client.rs b/src/contract/money/src/client.rs index 7b9dfd70d..e21440111 100644 --- a/src/contract/money/src/client.rs +++ b/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(), ] } } diff --git a/src/contract/money/tests/contract_exec.rs b/src/contract/money/tests/contract_exec.rs index 7693081cc..b381569c6 100644 --- a/src/contract/money/tests/contract_exec.rs +++ b/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. diff --git a/src/tx/mod.rs b/src/tx/mod.rs index 3a1323f76..57c7ad409 100644 --- a/src/tx/mod.rs +++ b/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)>>) -> Result<()> { + pub fn verify_zkps( + &self, + verifying_keys: &[(String, VerifyingKey)], + zkp_table: Vec)>>, + ) -> 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(()) }