From a93e2db44b26806c5dd3070189bccb01063e846c Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Mon, 27 Jan 2020 23:25:17 -0500 Subject: [PATCH] Add and use OutCiphertext Instead of [u64; 10]. --- zebra-chain/src/transaction/serialize.rs | 27 +------- zebra-chain/src/transaction/shielded_data.rs | 68 ++++++++++++++++++-- 2 files changed, 67 insertions(+), 28 deletions(-) diff --git a/zebra-chain/src/transaction/serialize.rs b/zebra-chain/src/transaction/serialize.rs index b54580d3..8c204947 100644 --- a/zebra-chain/src/transaction/serialize.rs +++ b/zebra-chain/src/transaction/serialize.rs @@ -2,7 +2,7 @@ //! transaction types, so that all of the serialization logic is in one place. use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; -use std::io::{self, Read}; +use std::io; use crate::proofs::ZkSnarkProof; use crate::serialization::{ @@ -177,21 +177,8 @@ impl ZcashSerialize for OutputDescription { writer.write_all(&self.cv[..])?; writer.write_all(&self.cmu[..])?; writer.write_all(&self.ephemeral_key[..])?; - // assert_eq!(self.enc_ciphertext.len(), 580); self.enc_ciphertext.zcash_serialize(&mut writer)?; - // XXX remove this assertion when types are refined - assert_eq!(self.out_ciphertext.len(), 80); - // XXX very ugly, this happens because we used a [u64; 10] instead of - // [u8; 80] to get trait impls and it will disappear when we refine to - // a note ciphertext type - writer.write_all( - &{ - use byteorder::ByteOrder; - let mut bytes = [0u8; 80]; - LittleEndian::write_u64_into(&self.out_ciphertext[..], &mut bytes); - bytes - }[..], - )?; + self.out_ciphertext.zcash_serialize(&mut writer)?; self.zkproof.zcash_serialize(&mut writer)?; Ok(()) } @@ -204,15 +191,7 @@ impl ZcashDeserialize for OutputDescription { cmu: reader.read_32_bytes()?, ephemeral_key: reader.read_32_bytes()?, enc_ciphertext: shielded_data::EncryptedCiphertext::zcash_deserialize(&mut reader)?, - out_ciphertext: { - // XXX this is horrible, see above, will be removed with type refinement - use byteorder::ByteOrder; - let mut bytes = [0u8; 80]; - reader.read_exact(&mut bytes[..])?; - let mut u64s = [0u64; 10]; - LittleEndian::read_u64_into(&bytes, &mut u64s[..]); - u64s - }, + out_ciphertext: shielded_data::OutCiphertext::zcash_deserialize(&mut reader)?, zkproof: Groth16Proof::zcash_deserialize(&mut reader)?, }) } diff --git a/zebra-chain/src/transaction/shielded_data.rs b/zebra-chain/src/transaction/shielded_data.rs index 82a7b37a..deb4c565 100644 --- a/zebra-chain/src/transaction/shielded_data.rs +++ b/zebra-chain/src/transaction/shielded_data.rs @@ -91,10 +91,7 @@ pub struct OutputDescription { /// A ciphertext component for the encrypted output note. pub enc_ciphertext: EncryptedCiphertext, /// A ciphertext component for the encrypted output note. - /// - /// XXX refine to a specific type. - /// XXX this is a [u64; 10] rather than a [u8; 80] to get trait impls - pub out_ciphertext: [u64; 10], + pub out_ciphertext: OutCiphertext, /// The ZK output proof. pub zkproof: Groth16Proof, } @@ -267,3 +264,66 @@ impl Arbitrary for EncryptedCiphertext { type Strategy = BoxedStrategy; } + +/// A ciphertext component for encrypted output notes. +pub struct OutCiphertext(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<(), SerializationError> { + 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()); + return Self(bytes); + }) + .boxed() + } + + type Strategy = BoxedStrategy; +}