From da3833f906c490631d87273e862db6047a1ea905 Mon Sep 17 00:00:00 2001 From: Kris Nuttycombe Date: Wed, 19 Jan 2022 18:18:22 -0700 Subject: [PATCH] Fix missing use of `dk` in derivation of sapling internal FVK. Also, factor out sapling internal fvk derivation so that it only requires (fvk, dk) since we may not have the full extfvk. --- zcash_primitives/src/zip32.rs | 62 ++++++++++++++++++++++++----------- 1 file changed, 42 insertions(+), 20 deletions(-) diff --git a/zcash_primitives/src/zip32.rs b/zcash_primitives/src/zip32.rs index 9753f31e7..2cdd597d1 100644 --- a/zcash_primitives/src/zip32.rs +++ b/zcash_primitives/src/zip32.rs @@ -235,6 +235,41 @@ pub fn sapling_default_address( sapling_find_address(fvk, dk, DiversifierIndex::new()).unwrap() } +/// Returns the internal full viewing key and diversifier key +/// for the provided external fvk and dk +pub fn sapling_derive_internal_fvk( + fvk: &FullViewingKey, + dk: &DiversifierKey, +) -> (FullViewingKey, DiversifierKey) { + let i = { + let mut h = Blake2bParams::new() + .hash_length(64) + .personal(crate::zip32::ZIP32_SAPLING_INT_PERSONALIZATION) + .to_state(); + h.update(&fvk.to_bytes()); + h.update(&dk.0); + h.finalize() + }; + let i_nsk = jubjub::Fr::from_bytes_wide(prf_expand(i.as_bytes(), &[0x17]).as_array()); + let r = prf_expand(i.as_bytes(), &[0x18]); + let r = r.as_bytes(); + // PROOF_GENERATION_KEY_GENERATOR = \mathcal{H}^Sapling + let nk_internal = PROOF_GENERATION_KEY_GENERATOR * i_nsk + fvk.vk.nk; + let dk_internal = DiversifierKey(r[..32].try_into().unwrap()); + let ovk_internal = OutgoingViewingKey(r[32..].try_into().unwrap()); + + ( + FullViewingKey { + vk: ViewingKey { + ak: fvk.vk.ak, + nk: nk_internal, + }, + ovk: ovk_internal, + }, + dk_internal, + ) +} + /// A Sapling extended spending key #[derive(Clone)] pub struct ExtendedSpendingKey { @@ -415,10 +450,13 @@ impl ExtendedSpendingKey { pub fn derive_internal(&self) -> Self { let i = { let fvk = FullViewingKey::from_expanded_spending_key(&self.expsk); - Blake2bParams::new() + let mut h = Blake2bParams::new() .hash_length(64) .personal(crate::zip32::ZIP32_SAPLING_INT_PERSONALIZATION) - .hash(&fvk.to_bytes()) + .to_state(); + h.update(&fvk.to_bytes()); + h.update(&self.dk.0); + h.finalize() }; let i_nsk = jubjub::Fr::from_bytes_wide(prf_expand(i.as_bytes(), &[0x17]).as_array()); let r = prf_expand(i.as_bytes(), &[0x18]); @@ -546,30 +584,14 @@ impl ExtendedFullViewingKey { } pub fn derive_internal(&self) -> Self { - let i = Blake2bParams::new() - .hash_length(64) - .personal(crate::zip32::ZIP32_SAPLING_INT_PERSONALIZATION) - .hash(&self.fvk.to_bytes()); - let i_nsk = jubjub::Fr::from_bytes_wide(prf_expand(i.as_bytes(), &[0x17]).as_array()); - let r = prf_expand(i.as_bytes(), &[0x18]); - let r = r.as_bytes(); - // PROOF_GENERATION_KEY_GENERATOR = \mathcal{H}^Sapling - let nk_internal = PROOF_GENERATION_KEY_GENERATOR * i_nsk + self.fvk.vk.nk; - let dk_internal = DiversifierKey(r[..32].try_into().unwrap()); - let ovk_internal = OutgoingViewingKey(r[32..].try_into().unwrap()); + let (fvk_internal, dk_internal) = sapling_derive_internal_fvk(&self.fvk, &self.dk); ExtendedFullViewingKey { depth: self.depth, parent_fvk_tag: self.parent_fvk_tag, child_index: self.child_index, chain_code: self.chain_code, - fvk: FullViewingKey { - vk: ViewingKey { - ak: self.fvk.vk.ak, - nk: nk_internal, - }, - ovk: ovk_internal, - }, + fvk: fvk_internal, dk: dk_internal, } }