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.
This commit is contained in:
Deirdre Connolly 2020-03-27 05:30:16 -04:00 committed by Deirdre Connolly
parent 5f7f851481
commit 2e063998fb
2 changed files with 31 additions and 8 deletions

View File

@ -1,6 +1,6 @@
//! Sprout Shielded Payment Address types. //! Sprout Shielded Payment Address types.
use std::{fmt, io, str::FromStr}; use std::{fmt, io};
use bs58; use bs58;
@ -154,6 +154,8 @@ impl Arbitrary for SproutShieldedAddress {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use std::str::FromStr;
use super::*; use super::*;
#[test] #[test]

View File

@ -9,6 +9,7 @@
use std::fmt; use std::fmt;
use byteorder::{ByteOrder, LittleEndian}; use byteorder::{ByteOrder, LittleEndian};
use rand_core::{CryptoRng, RngCore};
#[cfg(test)] #[cfg(test)]
use proptest::prelude::*; use proptest::prelude::*;
@ -24,11 +25,34 @@ use sha2;
#[derive(Copy, Clone, Debug, Eq, PartialEq)] #[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub struct SpendingKey(pub [u8; 32]); 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<T>(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_. /// Derived from a _SpendingKey_.
pub type ReceivingKey = x25519_dalek::StaticSecret; pub type ReceivingKey = x25519_dalek::StaticSecret;
impl From<SpendingKey> for ReceivingKey { impl From<SpendingKey> 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 /// is populated by default in an empty block of all zeros to
/// start. /// start.
/// ///
@ -63,7 +87,7 @@ impl fmt::Debug for PayingKey {
} }
impl From<SpendingKey> for PayingKey { impl From<SpendingKey> 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#sproutkeycomponents
/// https://zips.z.cash/protocol/protocol.pdf#concreteprfs /// https://zips.z.cash/protocol/protocol.pdf#concreteprfs
@ -98,17 +122,14 @@ pub struct IncomingViewingKey {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use rand_core::{OsRng, RngCore}; use rand_core::OsRng;
use super::*; use super::*;
#[test] #[test]
// TODO: test vectors, not just random data // TODO: test vectors, not just random data
fn derive_keys() { fn derive_keys() {
let mut bytes = [0u8; 32]; let spending_key = SpendingKey::new(&mut OsRng);
OsRng.fill_bytes(&mut bytes);
let spending_key = SpendingKey(bytes);
println!("{:?}", spending_key); println!("{:?}", spending_key);