contract/money: Finalize integration test with zk proof verification

This commit is contained in:
parazyd
2022-11-21 17:53:25 +01:00
parent 38b3048da3
commit a1a2da8394
4 changed files with 63 additions and 12 deletions

View File

@@ -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.

View File

@@ -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(),
]
}
}

View File

@@ -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.

View File

@@ -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(())
}