orchard/src/spec/prf_expand.rs

76 lines
2.4 KiB
Rust

use blake2b_simd::Params;
const PRF_EXPAND_PERSONALIZATION: &[u8; 16] = b"Zcash_ExpandSeed";
/// The set of domains in which $PRF^\mathsf{expand}$ is defined.
pub(crate) enum PrfExpand {
Esk,
Rcm,
OrchardAsk,
OrchardNk,
OrchardRivk,
Psi,
OrchardZip32Child,
OrchardDkOvk,
OrchardRivkInternal,
}
impl PrfExpand {
fn domain_separator(&self) -> u8 {
match self {
Self::Esk => 0x04,
Self::Rcm => 0x05,
Self::OrchardAsk => 0x06,
Self::OrchardNk => 0x07,
Self::OrchardRivk => 0x08,
Self::Psi => 0x09,
Self::OrchardZip32Child => 0x81,
Self::OrchardDkOvk => 0x82,
Self::OrchardRivkInternal => 0x83,
}
}
/// Expands the given secret key in this domain, with no additional data.
///
/// $PRF^\mathsf{expand}(sk, dst) := BLAKE2b-512("Zcash_ExpandSeed", sk || dst)$
///
/// Defined in [Zcash Protocol Spec § 5.4.2: Pseudo Random Functions][concreteprfs].
///
/// [concreteprfs]: https://zips.z.cash/protocol/nu5.pdf#concreteprfs
pub(crate) fn expand(self, sk: &[u8]) -> [u8; 64] {
self.with_ad_slices(sk, &[])
}
/// Expands the given secret key in this domain, with the given additional data.
///
/// $PRF^\mathsf{expand}(sk, dst, t) := BLAKE2b-512("Zcash_ExpandSeed", sk || dst || t)$
///
/// Defined in [Zcash Protocol Spec § 5.4.2: Pseudo Random Functions][concreteprfs].
///
/// [concreteprfs]: https://zips.z.cash/protocol/nu5.pdf#concreteprfs
pub(crate) fn with_ad(self, sk: &[u8], t: &[u8]) -> [u8; 64] {
self.with_ad_slices(sk, &[t])
}
/// Expands the given secret key in this domain, with additional data concatenated
/// from the given slices.
///
/// $PRF^\mathsf{expand}(sk, dst, a, b, ...) := BLAKE2b-512("Zcash_ExpandSeed", sk || dst || a || b || ...)$
///
/// Defined in [Zcash Protocol Spec § 5.4.2: Pseudo Random Functions][concreteprfs].
///
/// [concreteprfs]: https://zips.z.cash/protocol/nu5.pdf#concreteprfs
pub(crate) fn with_ad_slices(self, sk: &[u8], ts: &[&[u8]]) -> [u8; 64] {
let mut h = Params::new()
.hash_length(64)
.personal(PRF_EXPAND_PERSONALIZATION)
.to_state();
h.update(sk);
h.update(&[self.domain_separator()]);
for t in ts {
h.update(t);
}
*h.finalize().as_array()
}
}