Move sapling key tests to own module, test key derivation against test vectors
Impl a few From<[u8; 32]>'s for a few key types.
This commit is contained in:
parent
ce1415a8ee
commit
e508d09e9b
|
@ -144,7 +144,7 @@ mod tests {
|
|||
let authorizing_key = sapling::AuthorizingKey::from(spend_authorizing_key);
|
||||
let nullifier_deriving_key = sapling::NullifierDerivingKey::from(proof_authorizing_key);
|
||||
let incoming_viewing_key =
|
||||
sapling::IncomingViewingKey::from(authorizing_key, nullifier_deriving_key);
|
||||
sapling::IncomingViewingKey::from_keys(authorizing_key, nullifier_deriving_key);
|
||||
|
||||
let diversifier = sapling::Diversifier::new(&mut OsRng);
|
||||
let transmission_key = sapling::TransmissionKey::from(incoming_viewing_key, diversifier);
|
||||
|
|
|
@ -8,6 +8,11 @@
|
|||
//! [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
||||
//! [3.1]: https://zips.z.cash/protocol/protocol.pdf#addressesandkeys
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_vectors;
|
||||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
use std::{
|
||||
convert::{From, Into, TryFrom},
|
||||
fmt,
|
||||
|
@ -22,8 +27,8 @@ use jubjub;
|
|||
use rand_core::{CryptoRng, RngCore};
|
||||
use redjubjub::{self, SpendAuth};
|
||||
|
||||
#[cfg(test)]
|
||||
use proptest::{array, prelude::*};
|
||||
// #[cfg(test)]
|
||||
// use proptest::{array, prelude::*};
|
||||
#[cfg(test)]
|
||||
use proptest_derive::Arbitrary;
|
||||
|
||||
|
@ -339,6 +344,12 @@ impl From<[u8; 32]> for OutgoingViewingKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<OutgoingViewingKey> for [u8; 32] {
|
||||
fn from(nk: OutgoingViewingKey) -> [u8; 32] {
|
||||
nk.0
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SpendingKey> for OutgoingViewingKey {
|
||||
/// For this invocation of Blake2b-512 as _PRF^expand_, t=2.
|
||||
///
|
||||
|
@ -407,6 +418,12 @@ impl From<[u8; 32]> for NullifierDerivingKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<NullifierDerivingKey> for [u8; 32] {
|
||||
fn from(nk: NullifierDerivingKey) -> [u8; 32] {
|
||||
nk.0.to_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for NullifierDerivingKey {
|
||||
type Target = jubjub::AffinePoint;
|
||||
|
||||
|
@ -465,6 +482,8 @@ pub struct IncomingViewingKey {
|
|||
scalar: Scalar,
|
||||
}
|
||||
|
||||
// TODO: impl a top-level to_bytes or PartialEq between this and [u8; 32]
|
||||
|
||||
// TODO: impl a From that accepts a Network?
|
||||
|
||||
impl Deref for IncomingViewingKey {
|
||||
|
@ -475,6 +494,32 @@ impl Deref for IncomingViewingKey {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<[u8; 32]> for IncomingViewingKey {
|
||||
/// Generate an _IncomingViewingKey_ from existing bytes.
|
||||
fn from(mut bytes: [u8; 32]) -> Self {
|
||||
// Drop the most significant five bits, so it can be interpreted
|
||||
// as a scalar.
|
||||
//
|
||||
// I don't want to put this inside crh_ivk, but does it belong
|
||||
// inside Scalar/Fr::from_bytes()? That seems the better
|
||||
// place...
|
||||
//
|
||||
// https://github.com/zcash/librustzcash/blob/master/zcash_primitives/src/primitives.rs#L86
|
||||
bytes[31] &= 0b0000_0111;
|
||||
|
||||
Self {
|
||||
network: Network::default(),
|
||||
scalar: Scalar::from_bytes(&bytes).unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<IncomingViewingKey> for [u8; 32] {
|
||||
fn from(ivk: IncomingViewingKey) -> [u8; 32] {
|
||||
ivk.scalar.to_bytes()
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for IncomingViewingKey {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
f.debug_tuple("IncomingViewingKey")
|
||||
|
@ -530,26 +575,15 @@ impl IncomingViewingKey {
|
|||
// [spending key]." - [§4.2.2][ps]
|
||||
//
|
||||
// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
||||
pub fn from(
|
||||
//
|
||||
// TODO: won't let me name this `from(arg1, arg2)` when I have From impl'd above?
|
||||
pub fn from_keys(
|
||||
authorizing_key: AuthorizingKey,
|
||||
nullifier_deriving_key: NullifierDerivingKey,
|
||||
) -> IncomingViewingKey {
|
||||
let mut hash_bytes = crh_ivk(authorizing_key.into(), nullifier_deriving_key.to_bytes());
|
||||
) -> Self {
|
||||
let hash_bytes = crh_ivk(authorizing_key.into(), nullifier_deriving_key.to_bytes());
|
||||
|
||||
// Drop the most significant five bits, so it can be interpreted
|
||||
// as a scalar.
|
||||
//
|
||||
// I don't want to put this inside crh_ivk, but does it belong
|
||||
// inside Scalar/Fr::from_bytes()? That seems the better
|
||||
// place...
|
||||
//
|
||||
// https://github.com/zcash/librustzcash/blob/master/zcash_primitives/src/primitives.rs#L86
|
||||
hash_bytes[31] &= 0b0000_0111;
|
||||
|
||||
Self {
|
||||
network: Network::default(),
|
||||
scalar: Scalar::from_bytes(&hash_bytes).unwrap(),
|
||||
}
|
||||
IncomingViewingKey::from(hash_bytes)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -563,6 +597,8 @@ impl 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")
|
||||
|
@ -650,25 +686,6 @@ impl TransmissionKey {
|
|||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Arbitrary for TransmissionKey {
|
||||
type Parameters = ();
|
||||
|
||||
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
|
||||
(array::uniform32(any::<u8>()))
|
||||
.prop_map(|_transmission_key_bytes| {
|
||||
// TODO: actually generate something better than the identity.
|
||||
//
|
||||
// return Self::from_bytes(transmission_key_bytes);
|
||||
|
||||
return Self(jubjub::AffinePoint::identity());
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
||||
type Strategy = BoxedStrategy<Self>;
|
||||
}
|
||||
|
||||
/// Magic human-readable strings used to identify what networks
|
||||
/// Sapling FullViewingKeys are associated with when encoded/decoded
|
||||
/// with bech32.
|
||||
|
@ -754,47 +771,3 @@ impl std::str::FromStr for FullViewingKey {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use rand_core::OsRng;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn derive() {
|
||||
let spending_key = SpendingKey::new(&mut OsRng);
|
||||
|
||||
let spend_authorizing_key = SpendAuthorizingKey::from(spending_key);
|
||||
let proof_authorizing_key = ProofAuthorizingKey::from(spending_key);
|
||||
let outgoing_viewing_key = OutgoingViewingKey::from(spending_key);
|
||||
|
||||
let authorizing_key = AuthorizingKey::from(spend_authorizing_key);
|
||||
let nullifier_deriving_key = NullifierDerivingKey::from(proof_authorizing_key);
|
||||
// "If ivk = 0, discard this key and start over with a new
|
||||
// [spending key]."
|
||||
// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
||||
let incoming_viewing_key =
|
||||
IncomingViewingKey::from(authorizing_key, nullifier_deriving_key);
|
||||
|
||||
let diversifier = Diversifier::new(&mut OsRng);
|
||||
let _transmission_key = TransmissionKey::from(incoming_viewing_key, diversifier);
|
||||
|
||||
let _full_viewing_key = FullViewingKey {
|
||||
network: Network::default(),
|
||||
authorizing_key,
|
||||
nullifier_deriving_key,
|
||||
outgoing_viewing_key,
|
||||
};
|
||||
}
|
||||
|
||||
// TODO: test vectors, not just random data
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
proptest! {
|
||||
|
||||
//#[test]
|
||||
// fn test() {}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,110 @@
|
|||
#[cfg(test)]
|
||||
use proptest::{array, prelude::*};
|
||||
#[cfg(test)]
|
||||
use proptest_derive::Arbitrary;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[cfg(test)]
|
||||
impl Arbitrary for TransmissionKey {
|
||||
type Parameters = ();
|
||||
|
||||
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
|
||||
(array::uniform32(any::<u8>()))
|
||||
.prop_map(|_transmission_key_bytes| {
|
||||
// TODO: actually generate something better than the identity.
|
||||
//
|
||||
// return Self::from_bytes(transmission_key_bytes);
|
||||
|
||||
return Self(jubjub::AffinePoint::identity());
|
||||
})
|
||||
.boxed()
|
||||
}
|
||||
|
||||
type Strategy = BoxedStrategy<Self>;
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
|
||||
use rand_core::OsRng;
|
||||
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn derive() {
|
||||
let spending_key = SpendingKey::new(&mut OsRng);
|
||||
|
||||
let spend_authorizing_key = SpendAuthorizingKey::from(spending_key);
|
||||
let proof_authorizing_key = ProofAuthorizingKey::from(spending_key);
|
||||
let outgoing_viewing_key = OutgoingViewingKey::from(spending_key);
|
||||
|
||||
let authorizing_key = AuthorizingKey::from(spend_authorizing_key);
|
||||
let nullifier_deriving_key = NullifierDerivingKey::from(proof_authorizing_key);
|
||||
// "If ivk = 0, discard this key and start over with a new
|
||||
// [spending key]."
|
||||
// https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
||||
let incoming_viewing_key =
|
||||
IncomingViewingKey::from_keys(authorizing_key, nullifier_deriving_key);
|
||||
|
||||
let diversifier = Diversifier::new(&mut OsRng);
|
||||
let _transmission_key = TransmissionKey::from(incoming_viewing_key, diversifier);
|
||||
|
||||
let _full_viewing_key = FullViewingKey {
|
||||
network: Network::default(),
|
||||
authorizing_key,
|
||||
nullifier_deriving_key,
|
||||
outgoing_viewing_key,
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn derive_for_each_test_vector() {
|
||||
for test_vector in test_vectors::TEST_VECTORS.iter() {
|
||||
let spending_key = SpendingKey::from(test_vector.sk);
|
||||
|
||||
let spend_authorizing_key = SpendAuthorizingKey::from(spending_key);
|
||||
assert_eq!(spend_authorizing_key.to_bytes(), test_vector.ask);
|
||||
let proof_authorizing_key = ProofAuthorizingKey::from(spending_key);
|
||||
assert_eq!(proof_authorizing_key.to_bytes(), test_vector.nsk);
|
||||
let outgoing_viewing_key = OutgoingViewingKey::from(spending_key);
|
||||
assert_eq!(
|
||||
Into::<[u8; 32]>::into(outgoing_viewing_key),
|
||||
test_vector.ovk
|
||||
);
|
||||
|
||||
let authorizing_key = AuthorizingKey::from(spend_authorizing_key);
|
||||
assert_eq!(Into::<[u8; 32]>::into(authorizing_key), test_vector.ak);
|
||||
let nullifier_deriving_key = NullifierDerivingKey::from(proof_authorizing_key);
|
||||
assert_eq!(
|
||||
Into::<[u8; 32]>::into(nullifier_deriving_key),
|
||||
test_vector.nk
|
||||
);
|
||||
let incoming_viewing_key =
|
||||
IncomingViewingKey::from_keys(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);
|
||||
assert_eq!(diversifier.0, test_vector.default_d);
|
||||
|
||||
let transmission_key = TransmissionKey::from(incoming_viewing_key, diversifier);
|
||||
assert_eq!(transmission_key.to_bytes(), test_vector.default_pk_d);
|
||||
|
||||
let _full_viewing_key = FullViewingKey {
|
||||
network: Network::default(),
|
||||
authorizing_key,
|
||||
nullifier_deriving_key,
|
||||
outgoing_viewing_key,
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
proptest! {
|
||||
|
||||
//#[test]
|
||||
// fn test() {}
|
||||
}
|
Loading…
Reference in New Issue