From 2e063998fbd33d0a148b10b9065adb3a0b706398 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Fri, 27 Mar 2020 05:30:16 -0400 Subject: [PATCH] Add a new() and impl From<[u8; 32]> for SpendingKey Currently fills/receives 32 random bytes and forces the top 4 bits to zero, ala clamping. If there is a nicer way to csprng'ly fill 252 bits without clamping, that would be nicer, less bias. --- zebra-chain/src/addresses/sprout.rs | 4 +++- zebra-chain/src/keys/sprout.rs | 35 +++++++++++++++++++++++------ 2 files changed, 31 insertions(+), 8 deletions(-) diff --git a/zebra-chain/src/addresses/sprout.rs b/zebra-chain/src/addresses/sprout.rs index c0943a61..6fd39a27 100644 --- a/zebra-chain/src/addresses/sprout.rs +++ b/zebra-chain/src/addresses/sprout.rs @@ -1,6 +1,6 @@ //! Sprout Shielded Payment Address types. -use std::{fmt, io, str::FromStr}; +use std::{fmt, io}; use bs58; @@ -154,6 +154,8 @@ impl Arbitrary for SproutShieldedAddress { #[cfg(test)] mod tests { + use std::str::FromStr; + use super::*; #[test] diff --git a/zebra-chain/src/keys/sprout.rs b/zebra-chain/src/keys/sprout.rs index 53c1311d..48f1af48 100644 --- a/zebra-chain/src/keys/sprout.rs +++ b/zebra-chain/src/keys/sprout.rs @@ -9,6 +9,7 @@ use std::fmt; use byteorder::{ByteOrder, LittleEndian}; +use rand_core::{CryptoRng, RngCore}; #[cfg(test)] use proptest::prelude::*; @@ -24,11 +25,34 @@ use sha2; #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub struct SpendingKey(pub [u8; 32]); +impl SpendingKey { + /// Generate a new _SpendingKey_ with the highest 4 bits set to + /// zero (ie, 256 random bits, clamped to 252). + 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, with the highest + /// 4 bits set to zero (ie, 256 bits clamped to 252). + fn from(mut bytes: [u8; 32]) -> SpendingKey { + bytes[0] &= 0b0000_1111; // Force the 4 high-order bits to zero. + SpendingKey(bytes) + } +} + /// Derived from a _SpendingKey_. pub type ReceivingKey = x25519_dalek::StaticSecret; impl From for ReceivingKey { - /// For this invocation of SHA256Compress as the PRF, t=0, which + /// For this invocation of SHA256Compress as PRF^addr, t=0, which /// is populated by default in an empty block of all zeros to /// start. /// @@ -63,7 +87,7 @@ impl fmt::Debug for PayingKey { } impl From for PayingKey { - /// For this invocation of SHA256Compress as the PRF, t=1. + /// For this invocation of SHA256Compress as PRF^addr, t=1. /// /// https://zips.z.cash/protocol/protocol.pdf#sproutkeycomponents /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs @@ -98,17 +122,14 @@ pub struct IncomingViewingKey { #[cfg(test)] mod tests { - use rand_core::{OsRng, RngCore}; + use rand_core::OsRng; use super::*; #[test] // TODO: test vectors, not just random data fn derive_keys() { - let mut bytes = [0u8; 32]; - OsRng.fill_bytes(&mut bytes); - - let spending_key = SpendingKey(bytes); + let spending_key = SpendingKey::new(&mut OsRng); println!("{:?}", spending_key);