diff --git a/components/zcash_note_encryption/src/lib.rs b/components/zcash_note_encryption/src/lib.rs index fb8049d40..16c089bba 100644 --- a/components/zcash_note_encryption/src/lib.rs +++ b/components/zcash_note_encryption/src/lib.rs @@ -19,6 +19,8 @@ #![deny(unsafe_code)] // TODO: #![deny(missing_docs)] +use core::fmt::{self, Write}; + #[cfg(feature = "alloc")] extern crate alloc; #[cfg(feature = "alloc")] @@ -72,9 +74,28 @@ impl AsRef<[u8]> for OutgoingCipherKey { /// Newtype representing the byte encoding of an [`EphemeralPublicKey`]. /// /// [`EphemeralPublicKey`]: Domain::EphemeralPublicKey -#[derive(Clone, Debug)] +#[derive(Clone)] pub struct EphemeralKeyBytes(pub [u8; 32]); +impl fmt::Debug for EphemeralKeyBytes { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + struct HexFmt<'b>(&'b [u8]); + impl<'b> fmt::Debug for HexFmt<'b> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_char('"')?; + for b in self.0 { + f.write_fmt(format_args!("{:02x}", b))?; + } + f.write_char('"') + } + } + + f.debug_tuple("EphemeralKeyBytes") + .field(&HexFmt(&self.0)) + .finish() + } +} + impl AsRef<[u8]> for EphemeralKeyBytes { fn as_ref(&self) -> &[u8] { &self.0 diff --git a/zcash_primitives/src/legacy.rs b/zcash_primitives/src/legacy.rs index e1d12a766..cdbbc2512 100644 --- a/zcash_primitives/src/legacy.rs +++ b/zcash_primitives/src/legacy.rs @@ -1,6 +1,8 @@ //! Support for legacy transparent addresses and scripts. use byteorder::{ReadBytesExt, WriteBytesExt}; + +use std::fmt; use std::io::{self, Read, Write}; use std::ops::Shl; @@ -10,6 +12,7 @@ use zcash_encoding::Vector; pub mod keys; /// Minimal subset of script opcodes. +#[derive(Debug)] enum OpCode { // push value PushData1 = 0x4c, @@ -28,10 +31,64 @@ enum OpCode { CheckSig = 0xac, } +impl OpCode { + fn parse(b: u8) -> Option { + match b { + 0x4c => Some(OpCode::PushData1), + 0x4d => Some(OpCode::PushData2), + 0x4e => Some(OpCode::PushData4), + 0x76 => Some(OpCode::Dup), + 0x87 => Some(OpCode::Equal), + 0x88 => Some(OpCode::EqualVerify), + 0xa9 => Some(OpCode::Hash160), + 0xac => Some(OpCode::CheckSig), + _ => None, + } + } +} + /// A serialized script, used inside transparent inputs and outputs of a transaction. -#[derive(Clone, Debug, Default, PartialEq, Eq)] +#[derive(Clone, Default, PartialEq, Eq)] pub struct Script(pub Vec); +impl fmt::Debug for Script { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + struct ScriptPrinter<'s>(&'s [u8]); + impl<'s> fmt::Debug for ScriptPrinter<'s> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + let mut l = f.debug_list(); + let mut unknown: Option = None; + for b in self.0 { + if let Some(opcode) = OpCode::parse(*b) { + if let Some(s) = unknown.take() { + l.entry(&s); + } + l.entry(&opcode); + } else { + let encoded = format!("{:02x}", b); + if let Some(s) = &mut unknown { + s.push_str(&encoded); + } else { + unknown = Some(encoded); + } + } + } + l.finish() + } + } + + if f.alternate() { + f.debug_tuple("Script") + .field(&ScriptPrinter(&self.0)) + .finish() + } else { + f.debug_tuple("Script") + .field(&hex::encode(&self.0)) + .finish() + } + } +} + impl Script { pub fn read(mut reader: R) -> io::Result { let script = Vector::read(&mut reader, |r| r.read_u8())?; diff --git a/zcash_primitives/src/sapling/note/nullifier.rs b/zcash_primitives/src/sapling/note/nullifier.rs index 86f7bf946..6fd212de4 100644 --- a/zcash_primitives/src/sapling/note/nullifier.rs +++ b/zcash_primitives/src/sapling/note/nullifier.rs @@ -1,4 +1,5 @@ use std::array::TryFromSliceError; +use std::fmt; use subtle::{Choice, ConstantTimeEq}; @@ -9,9 +10,17 @@ use crate::sapling::{ }; /// Typesafe wrapper for nullifier values. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[derive(Copy, Clone, PartialEq, Eq)] pub struct Nullifier(pub [u8; 32]); +impl fmt::Debug for Nullifier { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Nullifier") + .field(&hex::encode(self.0)) + .finish() + } +} + impl Nullifier { pub fn from_slice(bytes: &[u8]) -> Result { bytes.try_into().map(Nullifier) diff --git a/zcash_primitives/src/sapling/redjubjub.rs b/zcash_primitives/src/sapling/redjubjub.rs index 74b7b6e0d..695098681 100644 --- a/zcash_primitives/src/sapling/redjubjub.rs +++ b/zcash_primitives/src/sapling/redjubjub.rs @@ -7,6 +7,8 @@ use ff::{Field, PrimeField}; use group::GroupEncoding; use jubjub::{AffinePoint, ExtendedPoint, SubgroupPoint}; use rand_core::RngCore; + +use std::fmt; use std::io::{self, Read, Write}; use std::ops::{AddAssign, MulAssign, Neg}; @@ -28,12 +30,21 @@ fn h_star(a: &[u8], b: &[u8]) -> jubjub::Fr { hash_to_scalar(b"Zcash_RedJubjubH", a, b) } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone)] pub struct Signature { rbar: [u8; 32], sbar: [u8; 32], } +impl fmt::Debug for Signature { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Signature") + .field("rbar", &hex::encode(self.rbar)) + .field("sbar", &hex::encode(self.sbar)) + .finish() + } +} + pub struct PrivateKey(pub jubjub::Fr); #[derive(Debug, Clone)]