From 524cc2e9790935a8649d0b5669a705dd4d160de1 Mon Sep 17 00:00:00 2001 From: Jack Grigg Date: Fri, 23 Oct 2020 22:21:59 +0100 Subject: [PATCH] zcash_client_sqlite: Read rcm correctly from data DB after Canopy ZIP 212 alters the note plaintext to store a seed from which rcm is derived, rather than storing rcm directly. In the mobile SDKs we only need rcm, so for post-ZIP 212 notes, we derive rcm from the seed and store rcm in the data DB. However, when selecting notes to spend, `create_to_address` was using the transaction's target height to determine if Canopy is active, and parsing the rcm value as the seed if so. This effectively applied a seed->rcm derivation to all selected notes' rcms once Canopy activated on the chain. As a result, the note commitments were incorrect, and thus the anchors derived from the witness paths were also incorrect. This caused two kinds of observed failures: - If more than one note was selected, the builder would fail with "anchor mismatch", as the note commitments would be effectively randomised, causing the derived anchors to also randomise. - If a single note was selected, the transaction would be built using the randomised anchor, and then rejected when sent to the network. The fix is to "pretend" in `create_to_address` that all notes are pre-ZIP 212 notes. This works fine because we never need to serialize back to the note plaintext while spending a note. --- zcash_client_sqlite/src/transact.rs | 25 +++++++++++-------------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/zcash_client_sqlite/src/transact.rs b/zcash_client_sqlite/src/transact.rs index 9feab59e8..b16aa8e8c 100644 --- a/zcash_client_sqlite/src/transact.rs +++ b/zcash_client_sqlite/src/transact.rs @@ -7,7 +7,7 @@ use std::convert::TryInto; use std::path::Path; use zcash_client_backend::encoding::encode_extended_full_viewing_key; use zcash_primitives::{ - consensus::{self, NetworkUpgrade, Parameters}, + consensus, keys::OutgoingViewingKey, merkle_tree::{IncrementalWitness, MerklePath}, note_encryption::Memo, @@ -227,19 +227,16 @@ pub fn create_to_address>( let rseed = { let d: Vec<_> = row.get(2)?; - if Network::is_nu_active(NetworkUpgrade::Canopy, height) { - let mut r = [0u8; 32]; - r.copy_from_slice(&d[..]); - Rseed::AfterZip212(r) - } else { - let r = jubjub::Fr::from_repr( - d[..] - .try_into() - .map_err(|_| Error(ErrorKind::InvalidNote))?, - ) - .ok_or(Error(ErrorKind::InvalidNote))?; - Rseed::BeforeZip212(r) - } + // We store rcm directly in the data DB, regardless of whether the note + // used a v1 or v2 note plaintext, so for the purposes of spending let's + // pretend this is a pre-ZIP 212 note. + let r = jubjub::Fr::from_repr( + d[..] + .try_into() + .map_err(|_| Error(ErrorKind::InvalidNote))?, + ) + .ok_or(Error(ErrorKind::InvalidNote))?; + Rseed::BeforeZip212(r) }; let from = extfvk.fvk.vk.to_payment_address(diversifier).unwrap();