diff --git a/zebra-chain/src/keys/sapling.rs b/zebra-chain/src/keys/sapling.rs index 7dcf81ed..135d71d3 100644 --- a/zebra-chain/src/keys/sapling.rs +++ b/zebra-chain/src/keys/sapling.rs @@ -56,13 +56,13 @@ pub const RANDOMNESS_BEACON_URS: &[u8; 64] = /// PRF^expand(sk, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || t) /// /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs -fn prf_expand(sk: [u8; 32], t: u8) -> [u8; 64] { +fn prf_expand(sk: [u8; 32], t: &[u8]) -> [u8; 64] { let hash = blake2b_simd::Params::new() .hash_length(64) .personal(b"Zcash_ExpandSeed") .to_state() .update(&sk[..]) - .update(&[t]) + .update(t) .finalize(); *hash.as_array() @@ -278,7 +278,7 @@ impl From for SpendAuthorizingKey { /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs fn from(spending_key: SpendingKey) -> SpendAuthorizingKey { - let hash_bytes = prf_expand(spending_key.bytes, 0); + let hash_bytes = prf_expand(spending_key.bytes, &[0]); Self(Scalar::from_bytes_wide(&hash_bytes)) } @@ -314,7 +314,7 @@ impl From for ProofAuthorizingKey { /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs fn from(spending_key: SpendingKey) -> ProofAuthorizingKey { - let hash_bytes = prf_expand(spending_key.bytes, 1); + let hash_bytes = prf_expand(spending_key.bytes, &[1]); Self(Scalar::from_bytes_wide(&hash_bytes)) } @@ -356,7 +356,7 @@ impl From for OutgoingViewingKey { /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs fn from(spending_key: SpendingKey) -> OutgoingViewingKey { - let hash_bytes = prf_expand(spending_key.bytes, 2); + let hash_bytes = prf_expand(spending_key.bytes, &[2]); let mut bytes = [0u8; 32]; bytes[..].copy_from_slice(&hash_bytes[0..32]); @@ -592,8 +592,6 @@ impl std::str::FromStr for IncomingViewingKey { #[cfg_attr(test, derive(Arbitrary))] pub struct Diversifier(pub [u8; 11]); -// TODO: _DefaultDiversifier_ - impl fmt::Debug for Diversifier { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("Diversifier") @@ -602,6 +600,35 @@ impl fmt::Debug for Diversifier { } } +impl From for Diversifier { + /// Derives a [_default diversifier_][4.2.2] from a SpendingKey. + /// + /// 'For each spending key, there is also a default diversified + /// payment address with a “random-looking” diversifier. This + /// allows an implementation that does not expose diversified + /// addresses as a user-visible feature, to use a default address + /// that cannot be distinguished (without knowledge of the + /// spending key) from one with a random diversifier...' + /// + /// [4.2.2]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents + fn from(sk: SpendingKey) -> Diversifier { + let mut i = 0u8; + + loop { + let mut d_bytes = [0u8; 11]; + d_bytes[..].copy_from_slice(&prf_expand(sk.bytes, &[3, i])[..11]); + + if diversify_hash(d_bytes).is_some() { + break Self(d_bytes); + } + + assert!(i < 255); + + i += 1; + } + } +} + impl Diversifier { /// Generate a new _Diversifier_ that has already been confirmed /// as a preimage to a valid diversified base point when used to @@ -613,7 +640,6 @@ impl Diversifier { where T: RngCore + CryptoRng, { - // Is this loop overkill? loop { let mut bytes = [0u8; 11]; csprng.fill_bytes(&mut bytes); diff --git a/zebra-chain/src/keys/sapling/tests.rs b/zebra-chain/src/keys/sapling/tests.rs index 640d7ed0..a69333f9 100644 --- a/zebra-chain/src/keys/sapling/tests.rs +++ b/zebra-chain/src/keys/sapling/tests.rs @@ -82,9 +82,7 @@ mod tests { IncomingViewingKey::from((authorizing_key, nullifier_deriving_key)); assert_eq!(incoming_viewing_key.scalar.to_bytes(), test_vector.ivk); - // TODO: replace with _DefaultDiversifier_ with spending - // key bytes as input. - let diversifier = Diversifier(test_vector.default_d); + let diversifier = Diversifier::from(spending_key); assert_eq!(diversifier.0, test_vector.default_d); let transmission_key = TransmissionKey::from(incoming_viewing_key, diversifier);