From 01fcce53f4b6fd61346cf44e299d2d099f37e729 Mon Sep 17 00:00:00 2001 From: Deirdre Connolly Date: Wed, 12 Feb 2020 20:21:59 -0500 Subject: [PATCH] Move memo to its own module under note_encryption, turn try_from into a match cmp --- zebra-chain/src/note_encryption.rs | 89 +------------------------ zebra-chain/src/note_encryption/memo.rs | 83 +++++++++++++++++++++++ 2 files changed, 84 insertions(+), 88 deletions(-) create mode 100644 zebra-chain/src/note_encryption/memo.rs diff --git a/zebra-chain/src/note_encryption.rs b/zebra-chain/src/note_encryption.rs index 2cde6d5e4..751434a56 100644 --- a/zebra-chain/src/note_encryption.rs +++ b/zebra-chain/src/note_encryption.rs @@ -1,92 +1,5 @@ //! Note encryption types. -use std::{ - convert::{AsRef, From}, - fmt, -}; - +pub mod memo; mod sapling; mod sprout; - -/// A 512-byte _Memo_ field associated with a note, as described in -/// [protocol specification §5.5][ps]. -/// -/// The _Memo- field of a note is a plaintext type; the parent note is -/// what is encrypted and stored on the blockchain. The underlying -/// usage of the memo field is by agreement between the sender and -/// recipient of the note. -/// -/// [ps]: https://zips.z.cash/protocol/protocol.pdf#notept -#[derive(Clone, Copy)] -pub struct Memo([u8; 512]); - -impl> From for Memo { - fn from(input: T) -> Self { - let input_bytes: &[u8] = input.as_ref(); - - let mut full_bytes = [0; 512]; - - if input_bytes.len() < 512 { - full_bytes[0..input_bytes.len()].copy_from_slice(input_bytes); - Memo(full_bytes) - } else if input_bytes.len() == 512 { - full_bytes[..].copy_from_slice(input_bytes); - Memo(full_bytes) - } else { - // Because this is a From impl, we truncate your input - // rather than return any Memo at all. - full_bytes.copy_from_slice(&input_bytes[0..512]); - Memo(full_bytes) - } - } -} - -impl fmt::Debug for Memo { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let output: String; - - // This saves work but if the 'valid utf8 string' is just a - // bunch of numbers, it prints them out like - // 'Memo("\u{0}\u{0}..")', so. ¯\_(ツ)_/¯ - match std::str::from_utf8(&self.0[..]) { - Ok(memo) => output = String::from(memo), - _ => output = hex::encode(&self.0[..]), - } - - f.debug_tuple("Memo").field(&output).finish() - } -} - -#[test] -fn memo_fmt() { - let memo = Memo( - *b"thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ - iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ - aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ - veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \ - looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \ - meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \ - but it's just short enough", - ); - - assert_eq!(format!("{:?}", memo), - "Memo(\"thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo but it\\\'s just short enough\")" - ); - - let mut some_bytes = [0u8; 512]; - some_bytes[0] = 0xF6; - - assert_eq!(format!("{:?}", Memo(some_bytes)), - "Memo(\"f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\")" - ); -} - -#[test] -fn memo_from_string() { - let memo = Memo::from("foo bar baz"); - - let mut bytes = [0; 512]; - bytes[0..11].copy_from_slice(&[102, 111, 111, 32, 98, 97, 114, 32, 98, 97, 122]); - - assert!(memo.0.iter().eq(bytes.iter())); -} diff --git a/zebra-chain/src/note_encryption/memo.rs b/zebra-chain/src/note_encryption/memo.rs new file mode 100644 index 000000000..95e5d6868 --- /dev/null +++ b/zebra-chain/src/note_encryption/memo.rs @@ -0,0 +1,83 @@ +use std::{cmp, convert::TryFrom, fmt}; + +/// A 512-byte _Memo_ field associated with a note, as described in +/// [protocol specification §5.5][ps]. +/// +/// The _Memo_ field of a note is a plaintext type; the parent note is +/// what is encrypted and stored on the blockchain. The underlying +/// usage of the memo field is by agreement between the sender and +/// recipient of the note. +/// +/// [ps]: https://zips.z.cash/protocol/protocol.pdf#notept +#[derive(Clone, Copy)] +pub struct Memo([u8; 512]); + +impl<'a> TryFrom<&'a [u8]> for Memo { + type Error = &'static str; + + fn try_from(input: &'a [u8]) -> Result { + let mut full_bytes = [0; 512]; + + match input.len().cmp(&512) { + cmp::Ordering::Less => { + full_bytes[0..input.len()].copy_from_slice(input); + Ok(Memo(full_bytes)) + } + cmp::Ordering::Equal => { + full_bytes[..].copy_from_slice(input); + Ok(Memo(full_bytes)) + } + cmp::Ordering::Greater => Err("Memos have a max length of 512 bytes."), + } + } +} + +impl fmt::Debug for Memo { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let output: String; + + // This saves work but if the 'valid utf8 string' is just a + // bunch of numbers, it prints them out like + // 'Memo("\u{0}\u{0}..")', so. ¯\_(ツ)_/¯ + match std::str::from_utf8(&self.0[..]) { + Ok(memo) => output = String::from(memo), + _ => output = hex::encode(&self.0[..]), + } + + f.debug_tuple("Memo").field(&output).finish() + } +} + +#[test] +fn memo_fmt() { + let memo = Memo( + *b"thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ + iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ + aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ + veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \ + looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \ + meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \ + but it's just short enough", + ); + + assert_eq!(format!("{:?}", memo), + "Memo(\"thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo but it\\\'s just short enough\")" + ); + + let mut some_bytes = [0u8; 512]; + some_bytes[0] = 0xF6; + + assert_eq!(format!("{:?}", Memo(some_bytes)), + "Memo(\"f600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\")" + ); +} + +#[test] +fn memo_from_string() { + let memo = Memo::try_from("foo bar baz".as_ref()).unwrap(); + + let mut bytes = [0; 512]; + bytes[0..11].copy_from_slice(&[102, 111, 111, 32, 98, 97, 114, 32, 98, 97, 122]); + + assert!(memo.0.iter().eq(bytes.iter())); +}