//! #![allow(clippy::unit_arg)] #![allow(dead_code)] use std::{fmt, io}; #[cfg(test)] use proptest::{arbitrary::Arbitrary, collection::vec, prelude::*}; use super::*; use crate::{ keys::sapling::{Diversifier, TransmissionKey}, serde_helpers, serialization::{ReadZcashExt, SerializationError, ZcashDeserialize, ZcashSerialize}, types::amount::{Amount, NonNegative}, }; /// A Nullifier for Sapling transactions #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[cfg_attr(test, derive(proptest_derive::Arbitrary))] pub struct Nullifier([u8; 32]); impl From<[u8; 32]> for Nullifier { fn from(buf: [u8; 32]) -> Self { Self(buf) } } 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[..]) } } /// A Note represents that a value is spendable by the recipient who /// holds the spending key corresponding to a given shielded payment /// address. pub struct Note { diversifier: Diversifier, transmission_key: TransmissionKey, value: Amount, note_commitment_randomness: NoteCommitmentRandomness, } /// The decrypted form of encrypted Sapling notes on the blockchain. pub struct NotePlaintext { diversifier: Diversifier, value: u64, // TODO: refine as jub-jub appropriate in the base field. note_commitment_randomness: NoteCommitmentRandomness, memo: memo::Memo, } /// A ciphertext component for encrypted output notes. #[derive(Deserialize, Serialize)] pub struct EncryptedCiphertext(#[serde(with = "serde_helpers::BigArray")] pub [u8; 580]); impl fmt::Debug for EncryptedCiphertext { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("EncryptedCiphertext") .field(&hex::encode(&self.0[..])) .finish() } } // These impls all only exist because of array length restrictions. impl Copy for EncryptedCiphertext {} impl Clone for EncryptedCiphertext { fn clone(&self) -> Self { let mut bytes = [0; 580]; bytes[..].copy_from_slice(&self.0[..]); Self(bytes) } } impl PartialEq for EncryptedCiphertext { fn eq(&self, other: &Self) -> bool { self.0[..] == other.0[..] } } impl Eq for EncryptedCiphertext {} impl ZcashSerialize for EncryptedCiphertext { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { writer.write_all(&self.0[..])?; Ok(()) } } impl ZcashDeserialize for EncryptedCiphertext { fn zcash_deserialize(mut reader: R) -> Result { let mut bytes = [0; 580]; reader.read_exact(&mut bytes[..])?; Ok(Self(bytes)) } } #[cfg(test)] impl Arbitrary for EncryptedCiphertext { type Parameters = (); fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { (vec(any::(), 580)) .prop_map(|v| { let mut bytes = [0; 580]; bytes.copy_from_slice(v.as_slice()); Self(bytes) }) .boxed() } type Strategy = BoxedStrategy; } /// A ciphertext component for encrypted output notes. #[derive(Deserialize, Serialize)] pub struct OutCiphertext(#[serde(with = "serde_helpers::BigArray")] pub [u8; 80]); impl fmt::Debug for OutCiphertext { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.debug_tuple("OutCiphertext") .field(&hex::encode(&self.0[..])) .finish() } } // These impls all only exist because of array length restrictions. impl Copy for OutCiphertext {} impl Clone for OutCiphertext { fn clone(&self) -> Self { let mut bytes = [0; 80]; bytes[..].copy_from_slice(&self.0[..]); Self(bytes) } } impl PartialEq for OutCiphertext { fn eq(&self, other: &Self) -> bool { self.0[..] == other.0[..] } } impl Eq for OutCiphertext {} impl ZcashSerialize for OutCiphertext { fn zcash_serialize(&self, mut writer: W) -> Result<(), io::Error> { writer.write_all(&self.0[..])?; Ok(()) } } impl ZcashDeserialize for OutCiphertext { fn zcash_deserialize(mut reader: R) -> Result { let mut bytes = [0; 80]; reader.read_exact(&mut bytes[..])?; Ok(Self(bytes)) } } #[cfg(test)] impl Arbitrary for OutCiphertext { type Parameters = (); fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy { (vec(any::(), 80)) .prop_map(|v| { let mut bytes = [0; 80]; bytes.copy_from_slice(v.as_slice()); Self(bytes) }) .boxed() } type Strategy = BoxedStrategy; } #[cfg(test)] proptest! { #[test] fn encrypted_ciphertext_roundtrip(ec in any::()) { let mut data = Vec::new(); ec.zcash_serialize(&mut data).expect("EncryptedCiphertext should serialize"); let ec2 = EncryptedCiphertext::zcash_deserialize(&data[..]).expect("randomized EncryptedCiphertext should deserialize"); prop_assert_eq![ec, ec2]; } #[test] fn out_ciphertext_roundtrip(oc in any::()) { let mut data = Vec::new(); oc.zcash_serialize(&mut data).expect("OutCiphertext should serialize"); let oc2 = OutCiphertext::zcash_deserialize(&data[..]).expect("randomized OutCiphertext should deserialize"); prop_assert_eq![oc, oc2]; } }