From e2743c0b15e923262e5728ae851a25a75d04f15e Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Sat, 28 Mar 2020 04:06:37 -0400 Subject: [PATCH] Add all simple types for Sapling key derivation tree --- zebra-chain/src/keys/sapling.rs | 172 ++++++++++++++++++++++++++++++-- 1 file changed, 166 insertions(+), 6 deletions(-) diff --git a/zebra-chain/src/keys/sapling.rs b/zebra-chain/src/keys/sapling.rs index 3c8d363e..677a8383 100644 --- a/zebra-chain/src/keys/sapling.rs +++ b/zebra-chain/src/keys/sapling.rs @@ -7,17 +7,177 @@ //! //! [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents -use std::{ - fmt, - io::{self}, -}; +use std::fmt; + +use blake2::{Blake2b, Digest}; +use rand_core::{CryptoRng, RngCore}; #[cfg(test)] -use proptest::{array, collection::vec, prelude::*}; +use proptest::prelude::*; #[cfg(test)] use proptest_derive::Arbitrary; -use crate::serialization::{SerializationError, ZcashDeserialize, ZcashSerialize}; +/// Our root secret key of the Sprout key derivation tree. +/// +/// All other Sprout key types derive from the SpendingKey value. +/// +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub struct SpendingKey(pub [u8; 32]); + +impl SpendingKey { + /// Generate a new _SpendingKey_. + pub fn new(csprng: &mut T) -> Self + where + T: RngCore + CryptoRng, + { + let mut bytes = [0u8; 32]; + csprng.fill_bytes(&mut bytes); + + Self::from(bytes) + } +} + +impl From<[u8; 32]> for SpendingKey { + /// Generate a _SpendingKey_ from existing bytes. + fn from(mut bytes: [u8; 32]) -> SpendingKey { + SpendingKey(bytes) + } +} + +/// Derived from a _SpendingKey_. +pub type SpendAuthorizationKey = redjubjub::Scalar; + +impl From for SpendAuthorizationKey { + /// Invokes Blake2b-512 as PRF^expand to derive a + /// SpendAuthorizationKey from a SpendingKey. + /// + /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents + /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs + fn from(spending_key: SpendingKey) -> SpendAuthorizationKey { + let mut block = [0u8; 33]; // Last byte is t=0; + + block[0..32].copy_from_slice(&spending_key.0[..]); + + let mut hasher = Blake2b::new(); + // TODO: check that this counts as personalization. + hasher.input("Zcash_ExpandSeed"); + hasher.input(block); + + Self::from(hasher.result()) + } +} + +/// Derived from a _SpendingKey_. +pub type ProofAuthorizingKey = redjubjub::Scalar; + +impl fmt::Debug for ProofAuthorizingKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("ProofAuthorizingKey") + .field(&hex::encode(&self.0)) + .finish() + } +} + +impl From for ProofAuthorizingKey { + /// For this invocation of Blake2b-512 as PRF^expand, t=1. + /// + /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents + /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs + fn from(spending_key: SpendingKey) -> ProofAuthorizingKey { + let mut block = [0u8; 33]; + block[33] = 1; // Last byte is t=1; + + block[0..32].copy_from_slice(&spending_key.0[..]); + + let mut hasher = Blake2b::new(); + // TODO: check that this counts as personalization. + hasher.input("Zcash_ExpandSeed"); + hasher.input(block); + + Self::from(hasher.result()) + } +} + +/// Derived from a _SpendingKey_. +#[derive(Copy, Clone, Eq, PartialEq)] +pub struct OutgoingViewingKey(pub [u8; 32]); + +impl fmt::Debug for OutgoingViewingKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("OutgoingViewingKey") + .field(&hex::encode(&self.0)) + .finish() + } +} + +impl From for OutgoingViewingKey { + /// For this invocation of Blake2b-512 as PRF^expand, t=1. + /// + /// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents + /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs + fn from(spending_key: SpendingKey) -> OutgoingViewingKey { + let mut block = [0u8; 33]; + block[33] = 2u8; // Last byte is t=2; + + block[0..32].copy_from_slice(&spending_key.0[..]); + + let mut hasher = Blake2b::new(); + // TODO: check that this counts as personalization. + hasher.input("Zcash_ExpandSeed"); + hasher.input(block); + + Self(hasher.result()[0..31]) + } +} + +/// +pub type AuthorizingKey = redjubjub::PublicKeyBytes; + +impl fmt::Debug for AuthorizingKey { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("AuthorizingKey") + .field(&hex::encode(&self.0)) + .finish() + } +} + +/// +pub type NullifierDerivingKey = redjubjub::PublicKeyBytes; + +/// +pub type IncomingViewingKey = redjubjub::Scalar; + +/// +#[derive(Copy, Clone, Display, Eq, PartialEq)] +pub struct Diversifier(pub [u8; 11]); + +impl fmt::Debug for Diversifier { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("Diversifier") + .field(&hex::encode(&self.0)) + .finish() + } +} + +/// Derived from a _IncomingViewingKey_ and a _Diversifier_ +/// +/// Derived by multiplying the diversifier (converted to an affine +/// point on the Jubjub curve) by the incoming view key: +/// pkd = gd * ivk +pub type TransmissionKey = redjubjub::PublicKeyBytes; + +#[cfg(test)] +mod tests { + + use rand_core::OsRng; + + use super::*; + + // #[test] + // TODO: test vectors, not just random data + // fn derive_keys() { + // } +} #[cfg(test)] proptest! {