From ec78bf9ac9505e04ecee60868bab47dc29c0bd0a Mon Sep 17 00:00:00 2001 From: narodnik Date: Sun, 16 May 2021 07:53:21 +0200 Subject: [PATCH] return specific errors for VerifyFailed --- src/bin/tx.rs | 42 +++++++++++++++++++++++++++++++++++++----- src/error.rs | 12 +++++++++++- src/lib.rs | 1 + src/tx.rs | 26 +++++++++++++++----------- 4 files changed, 64 insertions(+), 17 deletions(-) diff --git a/src/bin/tx.rs b/src/bin/tx.rs index fa871f1f9..c81d4a8a4 100644 --- a/src/bin/tx.rs +++ b/src/bin/tx.rs @@ -16,8 +16,33 @@ use sapvi::crypto::{ }; use sapvi::error::{Error, Result}; use sapvi::serial::{Decodable, Encodable, VarInt}; +use sapvi::state::{state_transition, ProgramState, StateUpdates}; use sapvi::tx; +struct MemoryState { + mint_pvk: groth16::PreparedVerifyingKey, + spend_pvk: groth16::PreparedVerifyingKey, + cashier_public: jubjub::SubgroupPoint +} + +impl ProgramState for MemoryState { + fn is_valid_cashier_public_key(&self, public: &jubjub::SubgroupPoint) -> bool { + public == &self.cashier_public + } + + fn mint_pvk(&self) -> &groth16::PreparedVerifyingKey { + &self.mint_pvk + } + fn spend_pvk(&self) -> &groth16::PreparedVerifyingKey { + &self.spend_pvk + } +} + +impl MemoryState { + fn apply(updates: StateUpdates) { + } +} + fn main() { // Auto create trusted ceremony parameters if they don't exist if !Path::new("mint.params").exists() { @@ -38,6 +63,12 @@ fn main() { // This is their public key let cashier_public = zcash_primitives::constants::SPENDING_KEY_GENERATOR * cashier_secret; + let state = MemoryState { + mint_pvk, + spend_pvk, + cashier_public + }; + // Wallet 1 creates a secret key let secret = jubjub::Fr::random(&mut OsRng); // This is their public key @@ -79,12 +110,13 @@ fn main() { } // Now we receive the tx data let note = { + let txx = tx::Transaction::decode(&tx_data[..]).unwrap(); let tx = tx::Transaction::decode(&tx_data[..]).unwrap(); - // Check the public key in the clear inputs - // It should be a valid public key for the cashier - assert_eq!(tx.clear_inputs[0].signature_public, cashier_public); + + let update = state_transition(&state, txx).expect("step 2 state transition failed"); + // Check the tx verifies correctly - assert!(tx.verify(&mint_pvk, &spend_pvk)); + //assert!(tx.verify(&mint_pvk, &spend_pvk)); // Add the new coins to the merkle tree tree.append(Coin::new(tx.outputs[0].revealed.coin)) .expect("append merkle"); @@ -172,6 +204,6 @@ fn main() { // Verify it's valid { let tx = tx::Transaction::decode(&tx_data[..]).unwrap(); - assert!(tx.verify(&mint_pvk, &spend_pvk)); + //assert!(tx.verify(&mint_pvk, &spend_pvk)); } } diff --git a/src/error.rs b/src/error.rs index ef97f9326..b82d4d765 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,9 +1,10 @@ use std::fmt; +use rusqlite; use crate::net::error::NetError; use crate::service::ServicesError; +use crate::state; use crate::vm::ZKVMError; -use rusqlite; pub type Result = std::result::Result; @@ -46,6 +47,7 @@ pub enum Error { NoteDecryptionFailed, ServicesError(ServicesError), ZMQError(zeromq::ZmqError), + VerifyFailed(state::VerifyFailed), } impl std::error::Error for Error {} @@ -92,6 +94,7 @@ impl fmt::Display for Error { Error::NoteDecryptionFailed => f.write_str("Unable to decrypt mint note"), Error::ServicesError(ref err) => write!(f, "Services error: {}", err), Error::ZMQError(ref err) => write!(f, "zmq error: {}", err), + Error::VerifyFailed(ref err) => write!(f, "Verify failed: {}", err), } } } @@ -174,3 +177,10 @@ impl From for Error { Error::Utf8Error } } + +impl From for Error { + fn from(err: state::VerifyFailed) -> Error { + Error::VerifyFailed(err) + } +} + diff --git a/src/lib.rs b/src/lib.rs index 1506ffe47..a90373bcd 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -16,6 +16,7 @@ pub mod net; pub mod rpc; pub mod serial; pub mod service; +pub mod state; pub mod system; pub mod tx; pub mod vm; diff --git a/src/tx.rs b/src/tx.rs index 2f6041cfb..c3ab5e0e8 100644 --- a/src/tx.rs +++ b/src/tx.rs @@ -17,6 +17,7 @@ use crate::crypto::{ use crate::error::{Error, Result}; use crate::impl_vec; use crate::serial::{Decodable, Encodable, VarInt}; +use crate::state; pub struct TransactionBuilder { pub clear_inputs: Vec, @@ -267,43 +268,46 @@ impl Transaction { &self, mint_pvk: &groth16::PreparedVerifyingKey, spend_pvk: &groth16::PreparedVerifyingKey, - ) -> bool { + ) -> std::result::Result<(), state::VerifyFailed> { let mut valcom_total = jubjub::SubgroupPoint::identity(); for input in &self.clear_inputs { valcom_total += Self::compute_value_commit(input.value, &input.valcom_blind); } - for input in &self.inputs { + for (i, input) in self.inputs.iter().enumerate() { if !verify_spend_proof(spend_pvk, &input.spend_proof, &input.revealed) { - return false; + return Err(state::VerifyFailed::SpendProof(i)); } valcom_total += &input.revealed.value_commit; } - for output in &self.outputs { + for (i, output) in self.outputs.iter().enumerate() { if !verify_mint_proof(mint_pvk, &output.mint_proof, &output.revealed) { - println!("mint fail"); - return false; + return Err(state::VerifyFailed::SpendProof(i)); } valcom_total -= &output.revealed.value_commit; } + if valcom_total != jubjub::SubgroupPoint::identity() { + return Err(state::VerifyFailed::MissingFunds); + } + // Verify signatures let mut unsigned_tx_data = vec![]; self.encode_without_signature(&mut unsigned_tx_data) .expect("TODO handle this"); - for input in &self.clear_inputs { + for (i, input) in self.clear_inputs.iter().enumerate() { let public = schnorr::PublicKey(input.signature_public.clone()); if !public.verify(&unsigned_tx_data[..], &input.signature) { - return false; + return Err(state::VerifyFailed::ClearInputSignature(i)); } } - for input in &self.inputs { + for (i, input) in self.inputs.iter().enumerate() { let public = schnorr::PublicKey(input.revealed.signature_public.clone()); if !public.verify(&unsigned_tx_data[..], &input.signature) { - return false; + return Err(state::VerifyFailed::InputSignature(i)); } } - valcom_total == jubjub::SubgroupPoint::identity() + Ok(()) } }