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 authorizing_key = sapling::AuthorizingKey::from(spend_authorizing_key);
|
||||||
let nullifier_deriving_key = sapling::NullifierDerivingKey::from(proof_authorizing_key);
|
let nullifier_deriving_key = sapling::NullifierDerivingKey::from(proof_authorizing_key);
|
||||||
let incoming_viewing_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 diversifier = sapling::Diversifier::new(&mut OsRng);
|
||||||
let transmission_key = sapling::TransmissionKey::from(incoming_viewing_key, diversifier);
|
let transmission_key = sapling::TransmissionKey::from(incoming_viewing_key, diversifier);
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,11 @@
|
||||||
//! [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
//! [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
||||||
//! [3.1]: https://zips.z.cash/protocol/protocol.pdf#addressesandkeys
|
//! [3.1]: https://zips.z.cash/protocol/protocol.pdf#addressesandkeys
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test_vectors;
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests;
|
||||||
|
|
||||||
use std::{
|
use std::{
|
||||||
convert::{From, Into, TryFrom},
|
convert::{From, Into, TryFrom},
|
||||||
fmt,
|
fmt,
|
||||||
|
|
@ -22,8 +27,8 @@ use jubjub;
|
||||||
use rand_core::{CryptoRng, RngCore};
|
use rand_core::{CryptoRng, RngCore};
|
||||||
use redjubjub::{self, SpendAuth};
|
use redjubjub::{self, SpendAuth};
|
||||||
|
|
||||||
#[cfg(test)]
|
// #[cfg(test)]
|
||||||
use proptest::{array, prelude::*};
|
// use proptest::{array, prelude::*};
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
use proptest_derive::Arbitrary;
|
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 {
|
impl From<SpendingKey> for OutgoingViewingKey {
|
||||||
/// For this invocation of Blake2b-512 as _PRF^expand_, t=2.
|
/// 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 {
|
impl Deref for NullifierDerivingKey {
|
||||||
type Target = jubjub::AffinePoint;
|
type Target = jubjub::AffinePoint;
|
||||||
|
|
||||||
|
|
@ -465,6 +482,8 @@ pub struct IncomingViewingKey {
|
||||||
scalar: Scalar,
|
scalar: Scalar,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: impl a top-level to_bytes or PartialEq between this and [u8; 32]
|
||||||
|
|
||||||
// TODO: impl a From that accepts a Network?
|
// TODO: impl a From that accepts a Network?
|
||||||
|
|
||||||
impl Deref for IncomingViewingKey {
|
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 {
|
impl fmt::Debug for IncomingViewingKey {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_tuple("IncomingViewingKey")
|
f.debug_tuple("IncomingViewingKey")
|
||||||
|
|
@ -530,26 +575,15 @@ impl IncomingViewingKey {
|
||||||
// [spending key]." - [§4.2.2][ps]
|
// [spending key]." - [§4.2.2][ps]
|
||||||
//
|
//
|
||||||
// [ps]: https://zips.z.cash/protocol/protocol.pdf#saplingkeycomponents
|
// [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,
|
authorizing_key: AuthorizingKey,
|
||||||
nullifier_deriving_key: NullifierDerivingKey,
|
nullifier_deriving_key: NullifierDerivingKey,
|
||||||
) -> IncomingViewingKey {
|
) -> Self {
|
||||||
let mut hash_bytes = crh_ivk(authorizing_key.into(), nullifier_deriving_key.to_bytes());
|
let hash_bytes = crh_ivk(authorizing_key.into(), nullifier_deriving_key.to_bytes());
|
||||||
|
|
||||||
// Drop the most significant five bits, so it can be interpreted
|
IncomingViewingKey::from(hash_bytes)
|
||||||
// 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(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -563,6 +597,8 @@ impl IncomingViewingKey {
|
||||||
#[cfg_attr(test, derive(Arbitrary))]
|
#[cfg_attr(test, derive(Arbitrary))]
|
||||||
pub struct Diversifier(pub [u8; 11]);
|
pub struct Diversifier(pub [u8; 11]);
|
||||||
|
|
||||||
|
// TODO: _DefaultDiversifier_
|
||||||
|
|
||||||
impl fmt::Debug for Diversifier {
|
impl fmt::Debug for Diversifier {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
f.debug_tuple("Diversifier")
|
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
|
/// Magic human-readable strings used to identify what networks
|
||||||
/// Sapling FullViewingKeys are associated with when encoded/decoded
|
/// Sapling FullViewingKeys are associated with when encoded/decoded
|
||||||
/// with bech32.
|
/// 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