|
|
@ -12,14 +12,49 @@ use sapling_crypto::{ |
|
|
|
}, |
|
|
|
primitives::{Diversifier, Note, PaymentAddress}, |
|
|
|
}; |
|
|
|
use std::fmt; |
|
|
|
use std::str; |
|
|
|
|
|
|
|
use crate::{keys::OutgoingViewingKey, JUBJUB}; |
|
|
|
|
|
|
|
pub const KDF_SAPLING_PERSONALIZATION: &'static [u8; 16] = b"Zcash_SaplingKDF"; |
|
|
|
pub const PRF_OCK_PERSONALIZATION: &'static [u8; 16] = b"Zcash_Derive_ock"; |
|
|
|
|
|
|
|
/// Format a byte array as a colon-delimited hex string.
|
|
|
|
///
|
|
|
|
/// Source: https://github.com/tendermint/signatory
|
|
|
|
/// License: MIT / Apache 2.0
|
|
|
|
fn fmt_colon_delimited_hex<B>(f: &mut fmt::Formatter<'_>, bytes: B) -> fmt::Result |
|
|
|
where |
|
|
|
B: AsRef<[u8]>, |
|
|
|
{ |
|
|
|
let len = bytes.as_ref().len(); |
|
|
|
|
|
|
|
for (i, byte) in bytes.as_ref().iter().enumerate() { |
|
|
|
write!(f, "{:02x}", byte)?; |
|
|
|
|
|
|
|
if i != len - 1 { |
|
|
|
write!(f, ":")?; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
Ok(()) |
|
|
|
} |
|
|
|
|
|
|
|
#[derive(Clone)] |
|
|
|
pub struct Memo([u8; 512]); |
|
|
|
|
|
|
|
impl fmt::Debug for Memo { |
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
|
|
|
write!(f, "Memo(")?; |
|
|
|
match self.to_utf8() { |
|
|
|
Some(Ok(memo)) => write!(f, "{}", memo)?, |
|
|
|
_ => fmt_colon_delimited_hex(f, &self.0[..])?, |
|
|
|
} |
|
|
|
write!(f, ")") |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl Default for Memo { |
|
|
|
fn default() -> Self { |
|
|
|
// Empty memo field indication per ZIP 302
|
|
|
@ -29,6 +64,58 @@ impl Default for Memo { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl PartialEq for Memo { |
|
|
|
fn eq(&self, rhs: &Memo) -> bool { |
|
|
|
&self.0[..] == &rhs.0[..] |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
impl Memo { |
|
|
|
/// Returns a Memo containing the given slice, appending with zero bytes if necessary,
|
|
|
|
/// or None if the slice is too long. If the slice is empty, Memo::default() is
|
|
|
|
/// returned.
|
|
|
|
pub fn from_bytes(memo: &[u8]) -> Option<Memo> { |
|
|
|
if memo.is_empty() { |
|
|
|
Some(Memo::default()) |
|
|
|
} else if memo.len() <= 512 { |
|
|
|
let mut data = [0; 512]; |
|
|
|
data[0..memo.len()].copy_from_slice(memo); |
|
|
|
Some(Memo(data)) |
|
|
|
} else { |
|
|
|
// memo is too long
|
|
|
|
None |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// Returns a Memo containing the given string, or None if the string is too long.
|
|
|
|
pub fn from_str(memo: &str) -> Option<Memo> { |
|
|
|
Memo::from_bytes(memo.as_bytes()) |
|
|
|
} |
|
|
|
|
|
|
|
pub fn as_bytes(&self) -> &[u8] { |
|
|
|
&self.0[..] |
|
|
|
} |
|
|
|
|
|
|
|
/// Returns:
|
|
|
|
/// - None if the memo is not text
|
|
|
|
/// - Some(Ok(memo)) if the memo contains a valid UTF8 string
|
|
|
|
/// - Some(Err(e)) if the memo contains invalid UTF8
|
|
|
|
pub fn to_utf8(&self) -> Option<Result<String, str::Utf8Error>> { |
|
|
|
// Check if it is a text or binary memo
|
|
|
|
if self.0[0] < 0xF5 { |
|
|
|
// Drop trailing zeroes
|
|
|
|
let mut data = &self.0[..]; |
|
|
|
while let Some((0, next)) = data.split_last() { |
|
|
|
data = next; |
|
|
|
} |
|
|
|
// Check if it is valid UTF8
|
|
|
|
Some(str::from_utf8(data).map(|memo| memo.to_owned())) |
|
|
|
} else { |
|
|
|
None |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fn generate_esk() -> Fs { |
|
|
|
// create random 64 byte buffer
|
|
|
|
let mut rng = OsRng::new().expect("should be able to construct RNG"); |
|
|
@ -359,6 +446,120 @@ mod tests { |
|
|
|
}; |
|
|
|
use crate::{keys::OutgoingViewingKey, JUBJUB}; |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn memo_from_str() { |
|
|
|
assert_eq!( |
|
|
|
Memo::from_str("").unwrap(), |
|
|
|
Memo([ |
|
|
|
0xf6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
|
|
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 |
|
|
|
]) |
|
|
|
); |
|
|
|
assert_eq!( |
|
|
|
Memo::from_str( |
|
|
|
"thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ |
|
|
|
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ |
|
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ |
|
|
|
veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \ |
|
|
|
looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \ |
|
|
|
meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \ |
|
|
|
but it's just short enough" |
|
|
|
) |
|
|
|
.unwrap(), |
|
|
|
Memo([ |
|
|
|
0x74, 0x68, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x73, 0x20, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x69, |
|
|
|
0x69, 0x69, 0x69, 0x69, 0x69, 0x69, 0x73, 0x20, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, |
|
|
|
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, |
|
|
|
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, |
|
|
|
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, |
|
|
|
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, |
|
|
|
0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, 0x61, |
|
|
|
0x61, 0x61, 0x61, 0x61, 0x20, 0x76, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, |
|
|
|
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, |
|
|
|
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, |
|
|
|
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, |
|
|
|
0x65, 0x65, 0x72, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, |
|
|
|
0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, 0x79, |
|
|
|
0x79, 0x20, 0x6c, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, |
|
|
|
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, |
|
|
|
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, |
|
|
|
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, |
|
|
|
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, |
|
|
|
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6e, 0x67, 0x20, 0x6d, |
|
|
|
0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, 0x65, |
|
|
|
0x65, 0x65, 0x65, 0x65, 0x65, 0x6d, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, |
|
|
|
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, |
|
|
|
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, |
|
|
|
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, |
|
|
|
0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x6f, 0x20, 0x62, 0x75, 0x74, 0x20, |
|
|
|
0x69, 0x74, 0x27, 0x73, 0x20, 0x6a, 0x75, 0x73, 0x74, 0x20, 0x73, 0x68, 0x6f, 0x72, |
|
|
|
0x74, 0x20, 0x65, 0x6e, 0x6f, 0x75, 0x67, 0x68 |
|
|
|
]) |
|
|
|
); |
|
|
|
assert!(Memo::from_str( |
|
|
|
"thiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ |
|
|
|
iiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiiis \ |
|
|
|
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \ |
|
|
|
veeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeryyyyyyyyyyyyyyyyyyyyyyyyyy \ |
|
|
|
looooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooong \ |
|
|
|
meeeeeeeeeeeeeeeeeeemooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo \ |
|
|
|
but it's now a bit too long" |
|
|
|
) |
|
|
|
.is_none()); |
|
|
|
} |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn memo_to_utf8() { |
|
|
|
let memo = Memo::from_str("Test memo").unwrap(); |
|
|
|
assert_eq!(memo.to_utf8(), Some(Ok("Test memo".to_owned()))); |
|
|
|
assert_eq!(Memo::default().to_utf8(), None); |
|
|
|
} |
|
|
|
|
|
|
|
#[test] |
|
|
|
fn test_vectors() { |
|
|
|
let test_vectors = crate::test_vectors::note_encryption::make_test_vectors(); |
|
|
|