Pass height to methods which encrypt or decrypt Sapling outputs

This commit is contained in:
therealyingtong 2020-07-30 13:13:59 +08:00
parent 71d31abad6
commit b537f0f712
No known key found for this signature in database
GPG Key ID: 179F32A1503D607E
6 changed files with 106 additions and 41 deletions

View File

@ -1,5 +1,6 @@
use pairing::bls12_381::Bls12;
use zcash_primitives::{
consensus,
note_encryption::{try_sapling_note_decryption, try_sapling_output_recovery, Memo},
primitives::{Note, PaymentAddress},
transaction::Transaction,
@ -30,7 +31,8 @@ pub struct DecryptedOutput {
/// Scans a [`Transaction`] for any information that can be decrypted by the set of
/// [`ExtendedFullViewingKey`]s.
pub fn decrypt_transaction(
pub fn decrypt_transaction<P: consensus::Parameters>(
parameters: &P,
tx: &Transaction,
extfvks: &[ExtendedFullViewingKey],
) -> Vec<DecryptedOutput> {
@ -49,21 +51,29 @@ pub fn decrypt_transaction(
};
for (account, (ivk, ovk)) in vks.iter().enumerate() {
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,
},
};
let ((note, to, memo), outgoing) = match try_sapling_note_decryption(
parameters,
tx.expiry_height,
ivk,
&epk,
&output.cmu,
&output.enc_ciphertext,
) {
Some(ret) => (ret, false),
None => match try_sapling_output_recovery(
parameters,
tx.expiry_height,
ovk,
&output.cv,
&output.cmu,
&epk,
&output.enc_ciphertext,
&output.out_ciphertext,
) {
Some(ret) => (ret, true),
None => continue,
},
};
decrypted.push(DecryptedOutput {
index,
note,

View File

@ -4,6 +4,7 @@ use ff::PrimeField;
use std::collections::HashSet;
use subtle::{ConditionallySelectable, ConstantTimeEq, CtOption};
use zcash_primitives::{
consensus,
jubjub::fs::Fs,
merkle_tree::{CommitmentTree, IncrementalWitness},
note_encryption::try_sapling_compact_note_decryption,
@ -22,7 +23,9 @@ use crate::wallet::{WalletShieldedOutput, WalletShieldedSpend, WalletTx};
///
/// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are incremented
/// with this output's commitment.
fn scan_output(
fn scan_output<P: consensus::Parameters>(
parameters: &P,
height: u32,
(index, output): (usize, CompactOutput),
ivks: &[Fs],
spent_from_accounts: &HashSet<usize>,
@ -49,10 +52,11 @@ fn scan_output(
tree.append(node).unwrap();
for (account, ivk) in ivks.iter().enumerate() {
let (note, to) = match try_sapling_compact_note_decryption(ivk, &epk, &cmu, &ct) {
Some(ret) => ret,
None => continue,
};
let (note, to) =
match try_sapling_compact_note_decryption(parameters, height, ivk, &epk, &cmu, &ct) {
Some(ret) => ret,
None => continue,
};
// A note is marked as "change" if the account that received it
// also spent notes in the same transaction. This will catch,
@ -83,7 +87,8 @@ fn scan_output(
///
/// The given [`CommitmentTree`] and existing [`IncrementalWitness`]es are
/// incremented appropriately.
pub fn scan_block(
pub fn scan_block<P: consensus::Parameters>(
parameters: &P,
block: CompactBlock,
extfvks: &[ExtendedFullViewingKey],
nullifiers: &[(&[u8], usize)],
@ -151,6 +156,8 @@ pub fn scan_block(
.collect();
if let Some(output) = scan_output(
parameters,
block.height as u32,
to_scan,
&ivks,
&spent_from_accounts,
@ -187,6 +194,7 @@ mod tests {
use pairing::bls12_381::{Bls12, Fr};
use rand_core::{OsRng, RngCore};
use zcash_primitives::{
consensus,
jubjub::{fs::Fs, FixedGenerators, JubjubParams, ToUniform},
merkle_tree::CommitmentTree,
note_encryption::{Memo, SaplingNoteEncryption},
@ -318,7 +326,14 @@ mod tests {
assert_eq!(cb.vtx.len(), 2);
let mut tree = CommitmentTree::new();
let txs = scan_block(cb, &[extfvk], &[], &mut tree, &mut []);
let txs = scan_block(
&consensus::MainNetwork,
cb,
&[extfvk],
&[],
&mut tree,
&mut [],
);
assert_eq!(txs.len(), 1);
let tx = &txs[0];
@ -350,7 +365,14 @@ mod tests {
assert_eq!(cb.vtx.len(), 3);
let mut tree = CommitmentTree::new();
let txs = scan_block(cb, &[extfvk], &[], &mut tree, &mut []);
let txs = scan_block(
&consensus::MainNetwork,
cb,
&[extfvk],
&[],
&mut tree,
&mut [],
);
assert_eq!(txs.len(), 1);
let tx = &txs[0];
@ -378,7 +400,14 @@ mod tests {
assert_eq!(cb.vtx.len(), 2);
let mut tree = CommitmentTree::new();
let txs = scan_block(cb, &[], &[(&nf, account)], &mut tree, &mut []);
let txs = scan_block(
&consensus::MainNetwork,
cb,
&[],
&[(&nf, account)],
&mut tree,
&mut [],
);
assert_eq!(txs.len(), 1);
let tx = &txs[0];

View File

@ -9,6 +9,7 @@ use zcash_client_backend::{
proto::compact_formats::CompactBlock, welding_rig::scan_block,
};
use zcash_primitives::{
consensus,
merkle_tree::{CommitmentTree, IncrementalWitness},
sapling::Node,
transaction::Transaction,
@ -188,6 +189,7 @@ pub fn scan_cached_blocks<P: AsRef<Path>, Q: AsRef<Path>>(
let nf_refs: Vec<_> = nullifiers.iter().map(|(nf, acc)| (&nf[..], *acc)).collect();
let mut witness_refs: Vec<_> = witnesses.iter_mut().map(|w| &mut w.witness).collect();
scan_block(
&consensus::MainNetwork,
block,
&extfvks[..],
&nf_refs,
@ -372,7 +374,7 @@ pub fn decrypt_and_store_transaction<P: AsRef<Path>>(
.collect::<Result<Result<Option<_>, _>, _>>()??
.ok_or(Error(ErrorKind::IncorrectHRPExtFVK))?;
let outputs = decrypt_transaction(tx, &extfvks);
let outputs = decrypt_transaction(&consensus::MainNetwork, tx, &extfvks);
if outputs.is_empty() {
// Nothing to see here

View File

@ -5,10 +5,10 @@ use std::fmt;
/// Zcash consensus parameters.
pub trait Parameters {
fn activation_height(nu: NetworkUpgrade) -> Option<u32>;
fn activation_height(&self, nu: NetworkUpgrade) -> Option<u32>;
fn is_nu_active(nu: NetworkUpgrade, height: u32) -> bool {
match Self::activation_height(nu) {
fn is_nu_active(&self, nu: NetworkUpgrade, height: u32) -> bool {
match self.activation_height(nu) {
Some(h) if h <= height => true,
_ => false,
}
@ -20,7 +20,7 @@ pub trait Parameters {
pub struct MainNetwork;
impl Parameters for MainNetwork {
fn activation_height(nu: NetworkUpgrade) -> Option<u32> {
fn activation_height(&self, nu: NetworkUpgrade) -> Option<u32> {
match nu {
NetworkUpgrade::Overwinter => Some(347_500),
NetworkUpgrade::Sapling => Some(419_200),
@ -36,7 +36,7 @@ impl Parameters for MainNetwork {
pub struct TestNetwork;
impl Parameters for TestNetwork {
fn activation_height(nu: NetworkUpgrade) -> Option<u32> {
fn activation_height(&self, nu: NetworkUpgrade) -> Option<u32> {
match nu {
NetworkUpgrade::Overwinter => Some(207_500),
NetworkUpgrade::Sapling => Some(280_000),
@ -174,9 +174,9 @@ impl BranchId {
/// the given height.
///
/// This is the branch ID that should be used when creating transactions.
pub fn for_height<C: Parameters>(height: u32) -> Self {
pub fn for_height<C: Parameters>(parameters: C, height: u32) -> Self {
for nu in UPGRADES_IN_ORDER.iter().rev() {
if C::is_nu_active(*nu, height) {
if parameters.is_nu_active(*nu, height) {
return nu.branch_id();
}
}

View File

@ -1,6 +1,8 @@
//! Implementation of in-band secret distribution for Zcash transactions.
use crate::{
consensus,
consensus::NetworkUpgrade,
jubjub::{
edwards,
fs::{Fs, FsRepr},
@ -335,7 +337,9 @@ impl SaplingNoteEncryption {
}
}
fn parse_note_plaintext_without_memo(
fn parse_note_plaintext_without_memo<P: consensus::Parameters>(
parameters: &P,
height: u32,
ivk: &Fs,
cmu: &Fr,
plaintext: &[u8],
@ -380,7 +384,9 @@ fn parse_note_plaintext_without_memo(
/// `PaymentAddress` to which the note was sent.
///
/// Implements section 4.17.2 of the Zcash Protocol Specification.
pub fn try_sapling_note_decryption(
pub fn try_sapling_note_decryption<P: consensus::Parameters>(
parameters: &P,
height: u32,
ivk: &Fs,
epk: &edwards::Point<Bls12, PrimeOrder>,
cmu: &Fr,
@ -405,7 +411,7 @@ pub fn try_sapling_note_decryption(
NOTE_PLAINTEXT_SIZE
);
let (note, to) = parse_note_plaintext_without_memo(ivk, cmu, &plaintext)?;
let (note, to) = parse_note_plaintext_without_memo(parameters, height, ivk, cmu, &plaintext)?;
let mut memo = [0u8; 512];
memo.copy_from_slice(&plaintext[COMPACT_NOTE_SIZE..NOTE_PLAINTEXT_SIZE]);
@ -422,7 +428,9 @@ pub fn try_sapling_note_decryption(
/// Implements the procedure specified in [`ZIP 307`].
///
/// [`ZIP 307`]: https://github.com/zcash/zips/pull/226
pub fn try_sapling_compact_note_decryption(
pub fn try_sapling_compact_note_decryption<P: consensus::Parameters>(
parameters: &P,
height: u32,
ivk: &Fs,
epk: &edwards::Point<Bls12, PrimeOrder>,
cmu: &Fr,
@ -438,7 +446,7 @@ pub fn try_sapling_compact_note_decryption(
plaintext.copy_from_slice(&enc_ciphertext);
ChaCha20Ietf::xor(key.as_bytes(), &[0u8; 12], 1, &mut plaintext);
parse_note_plaintext_without_memo(ivk, cmu, &plaintext)
parse_note_plaintext_without_memo(parameters, height, ivk, cmu, &plaintext)
}
/// Recovery of the full note plaintext by the sender.
@ -448,7 +456,9 @@ pub fn try_sapling_compact_note_decryption(
/// `PaymentAddress` to which the note was sent.
///
/// Implements section 4.17.3 of the Zcash Protocol Specification.
pub fn try_sapling_output_recovery(
pub fn try_sapling_output_recovery<P: consensus::Parameters>(
parameters: &P,
height: u32,
ovk: &OutgoingViewingKey,
cv: &edwards::Point<Bls12, Unknown>,
cmu: &Fr,
@ -717,6 +727,7 @@ mod tests {
}
fn random_enc_ciphertext_with<R: RngCore + CryptoRng>(
height: u32,
ivk: Fs,
mut rng: &mut R,
) -> (

View File

@ -13,6 +13,7 @@ use std::fmt;
use crate::{
consensus,
consensus::NetworkUpgrade,
keys::OutgoingViewingKey,
legacy::TransparentAddress,
merkle_tree::MerklePath,
@ -86,7 +87,9 @@ pub struct SaplingOutput {
}
impl SaplingOutput {
pub fn new<R: RngCore + CryptoRng>(
pub fn new<R: RngCore + CryptoRng, P: consensus::Parameters>(
parameters: P,
height: u32,
rng: &mut R,
ovk: OutgoingViewingKey,
to: PaymentAddress<Bls12>,
@ -304,6 +307,7 @@ impl TransactionMetadata {
/// Generates a [`Transaction`] from its inputs and outputs.
pub struct Builder<R: RngCore + CryptoRng> {
rng: R,
height: u32,
mtx: TransactionData,
fee: Amount,
anchor: Option<Fr>,
@ -344,6 +348,7 @@ impl<R: RngCore + CryptoRng> Builder<R> {
Builder {
rng,
height,
mtx,
fee: DEFAULT_FEE,
anchor: None,
@ -399,7 +404,15 @@ impl<R: RngCore + CryptoRng> Builder<R> {
value: Amount,
memo: Option<Memo>,
) -> Result<(), Error> {
let output = SaplingOutput::new(&mut self.rng, ovk, to, value, memo)?;
let output = SaplingOutput::new(
consensus::MainNetwork,
self.height,
&mut self.rng,
ovk,
to,
value,
memo,
)?;
self.mtx.value_balance -= value;