#![allow(clippy::unit_arg)] #![allow(dead_code)] use std::io; use byteorder::{ByteOrder, LittleEndian}; use serde::{Deserialize, Serialize}; use crate::{ keys::sprout::SpendingKey, serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}, }; /// PRF^nf is used to derive a Sprout nullifer from the receiver's /// spending key a_sk and a nullifier seed ρ, instantiated using the /// SHA-256 compression function. /// /// https://zips.z.cash/protocol/protocol.pdf#abstractprfs /// https://zips.z.cash/protocol/protocol.pdf#commitmentsandnullifiers fn prf_nf(a_sk: [u8; 32], rho: [u8; 32]) -> [u8; 32] { let mut state = [0u32; 8]; let mut block = [0u8; 64]; block[0..32].copy_from_slice(&a_sk[..]); // The first four bits –i.e. the most signicant four bits of the // first byte– are used to separate distinct uses // of SHA256Compress, ensuring that the functions are independent. block[0] |= 0b1110_0000; block[32..].copy_from_slice(&rho[..]); sha2::compress256(&mut state, &block); let mut derived_bytes = [0u8; 32]; LittleEndian::write_u32_into(&state, &mut derived_bytes); derived_bytes } /// Nullifier seed, named rho in the [spec][ps]. /// /// [ps]: https://zips.z.cash/protocol/protocol.pdf#sproutkeycomponents #[derive(Clone, Copy, Debug)] #[cfg_attr(test, derive(proptest_derive::Arbitrary))] pub struct NullifierSeed(pub(crate) [u8; 32]); impl AsRef<[u8]> for NullifierSeed { fn as_ref(&self) -> &[u8] { &self.0 } } impl From<[u8; 32]> for NullifierSeed { fn from(bytes: [u8; 32]) -> Self { Self(bytes) } } impl From for [u8; 32] { fn from(rho: NullifierSeed) -> Self { rho.0 } } /// A Nullifier for Sprout transactions #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(test, derive(proptest_derive::Arbitrary))] pub struct Nullifier(pub(crate) [u8; 32]); impl From<[u8; 32]> for Nullifier { fn from(bytes: [u8; 32]) -> Self { Self(bytes) } } impl<'a> From<(&'a SpendingKey, NullifierSeed)> for Nullifier { fn from((a_sk, rho): (&'a SpendingKey, NullifierSeed)) -> Self { Self(prf_nf(a_sk.into(), rho.into())) } } impl From for [u8; 32] { fn from(n: Nullifier) -> Self { n.0 } } impl ZcashDeserialize for Nullifier { fn zcash_deserialize(mut reader: R) -> Result { let bytes = reader.read_32_bytes()?; Ok(Self(bytes)) } } impl ZcashSerialize for Nullifier { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { writer.write_all(&self.0[..]) } }