diff --git a/sapling-crypto/src/primitives/mod.rs b/sapling-crypto/src/primitives/mod.rs index 402bf4b0d..fea332c9c 100644 --- a/sapling-crypto/src/primitives/mod.rs +++ b/sapling-crypto/src/primitives/mod.rs @@ -62,6 +62,7 @@ impl ProofGenerationKey { } } +#[derive(Debug)] pub struct ViewingKey { pub ak: edwards::Point, pub nk: edwards::Point diff --git a/zcash_primitives/src/keys.rs b/zcash_primitives/src/keys.rs index 4268c32ea..e6066e3ee 100644 --- a/zcash_primitives/src/keys.rs +++ b/zcash_primitives/src/keys.rs @@ -27,7 +27,7 @@ pub fn prf_expand_vec(sk: &[u8], ts: &[&[u8]]) -> Blake2bResult { } /// An outgoing viewing key -#[derive(Clone, Copy, PartialEq)] +#[derive(Clone, Copy, Debug, PartialEq)] pub struct OutgoingViewingKey(pub [u8; 32]); /// A Sapling expanded spending key @@ -39,6 +39,7 @@ pub struct ExpandedSpendingKey { } /// A Sapling full viewing key +#[derive(Debug)] pub struct FullViewingKey { pub vk: ViewingKey, pub ovk: OutgoingViewingKey, @@ -134,10 +135,16 @@ impl FullViewingKey { None => { return Err(io::Error::new( io::ErrorKind::InvalidData, - "ak not of prime order", + "ak not in prime-order subgroup", )); } }; + if ak == edwards::Point::zero() { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "ak not of prime order", + )); + } let nk = edwards::Point::::read(&mut reader, params)?; let nk = match nk.as_prime_order(params) { @@ -145,7 +152,7 @@ impl FullViewingKey { None => { return Err(io::Error::new( io::ErrorKind::InvalidData, - "nk not of prime order", + "nk not in prime-order subgroup", )); } }; @@ -174,3 +181,38 @@ impl FullViewingKey { result } } + +#[cfg(test)] +mod tests { + use pairing::bls12_381::Bls12; + use sapling_crypto::jubjub::{edwards, FixedGenerators, JubjubParams, PrimeOrder}; + use std::error::Error; + + use super::FullViewingKey; + use crate::JUBJUB; + + #[test] + fn ak_must_be_prime_order() { + let mut buf = [0; 96]; + let identity = edwards::Point::::zero(); + + // Set both ak and nk to the identity. + identity.write(&mut buf[0..32]).unwrap(); + identity.write(&mut buf[32..64]).unwrap(); + + // ak is not allowed to be the identity. + assert_eq!( + FullViewingKey::::read(&buf[..], &JUBJUB) + .unwrap_err() + .description(), + "ak not of prime order" + ); + + // Set ak to a basepoint. + let basepoint = JUBJUB.generator(FixedGenerators::SpendingKeyGenerator); + basepoint.write(&mut buf[0..32]).unwrap(); + + // nk is allowed to be the identity. + assert!(FullViewingKey::::read(&buf[..], &JUBJUB).is_ok()); + } +}