From d5ed68470119a949585cbec8582d467148679df5 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Wed, 27 Nov 2019 15:45:13 +0000 Subject: [PATCH] zcash_client_backend::decrypt_transaction --- zcash_client_backend/src/decrypt.rs | 76 +++++++++++++++++++++++++++++ zcash_client_backend/src/lib.rs | 3 ++ 2 files changed, 79 insertions(+) create mode 100644 zcash_client_backend/src/decrypt.rs diff --git a/zcash_client_backend/src/decrypt.rs b/zcash_client_backend/src/decrypt.rs new file mode 100644 index 000000000..f9830f61b --- /dev/null +++ b/zcash_client_backend/src/decrypt.rs @@ -0,0 +1,76 @@ +use pairing::bls12_381::Bls12; +use zcash_primitives::{ + note_encryption::{try_sapling_note_decryption, try_sapling_output_recovery, Memo}, + primitives::{Note, PaymentAddress}, + transaction::Transaction, + zip32::ExtendedFullViewingKey, + JUBJUB, +}; + +/// A decrypted shielded output. +pub struct DecryptedOutput { + /// The index of the output within [`shielded_outputs`]. + /// + /// [`shielded_outputs`]: zcash_primitives::transaction::TransactionData + pub index: usize, + /// The note within the output. + pub note: Note, + /// The address the note was sent to. + pub to: PaymentAddress, + /// The memo included with the note. + pub memo: Memo, + /// True if this output was recovered using an [`OutgoingViewingKey`], meaning that + /// this is a logical output of the transaction. + /// + /// [`OutgoingViewingKey`]: zcash_primitives::keys::OutgoingViewingKey + pub outgoing: bool, +} + +/// Scans a [`Transaction`] for any information that can be decrypted by the set of +/// [`ExtendedFullViewingKey`]s. +pub fn decrypt_transaction( + tx: &Transaction, + extfvks: &[ExtendedFullViewingKey], +) -> Vec { + let mut decrypted = vec![]; + + // Cache IncomingViewingKey calculation + let vks: Vec<_> = extfvks + .iter() + .map(|extfvk| (extfvk.fvk.vk.ivk(), extfvk.fvk.ovk)) + .collect(); + + for (index, output) in tx.shielded_outputs.iter().enumerate() { + let epk = match output.ephemeral_key.as_prime_order(&JUBJUB) { + Some(p) => p, + None => continue, + }; + + for (ivk, ovk) in &vks { + let ((note, to, memo), outgoing) = + match try_sapling_note_decryption(ivk, &epk, &output.cmu, &output.enc_ciphertext) { + Some(ret) => (ret, false), + None => match try_sapling_output_recovery( + ovk, + &output.cv, + &output.cmu, + &epk, + &output.enc_ciphertext, + &output.out_ciphertext, + ) { + Some(ret) => (ret, true), + None => continue, + }, + }; + decrypted.push(DecryptedOutput { + index, + note, + to, + memo, + outgoing, + }) + } + } + + decrypted +} diff --git a/zcash_client_backend/src/lib.rs b/zcash_client_backend/src/lib.rs index 87a808ced..e3852e6ac 100644 --- a/zcash_client_backend/src/lib.rs +++ b/zcash_client_backend/src/lib.rs @@ -7,8 +7,11 @@ #![deny(intra_doc_link_resolution_failure)] pub mod constants; +mod decrypt; pub mod encoding; pub mod keys; pub mod proto; pub mod wallet; pub mod welding_rig; + +pub use decrypt::{decrypt_transaction, DecryptedOutput};