Skip to content

Commit

Permalink
Render byte slices as hex more often in Debug impls
Browse files Browse the repository at this point in the history
This is more generally useful for debugging purposes than the default
`Debug` impl for `&[u8]`.

We also provide an alternate `Debug` impl for `legacy::Script` that
parses and renders known opcodes. Note that we only parse a subset of
the full opcode set.
  • Loading branch information
str4d committed Aug 30, 2023
1 parent 57a3914 commit c8e2d81
Show file tree
Hide file tree
Showing 4 changed files with 102 additions and 4 deletions.
23 changes: 22 additions & 1 deletion components/zcash_note_encryption/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down Expand Up @@ -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
Expand Down
59 changes: 58 additions & 1 deletion zcash_primitives/src/legacy.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand All @@ -10,6 +12,7 @@ use zcash_encoding::Vector;
pub mod keys;

/// Minimal subset of script opcodes.
#[derive(Debug)]
enum OpCode {
// push value
PushData1 = 0x4c,
Expand All @@ -28,10 +31,64 @@ enum OpCode {
CheckSig = 0xac,
}

impl OpCode {
fn parse(b: u8) -> Option<Self> {
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<u8>);

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<String> = 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<R: Read>(mut reader: R) -> io::Result<Self> {
let script = Vector::read(&mut reader, |r| r.read_u8())?;
Expand Down
11 changes: 10 additions & 1 deletion zcash_primitives/src/sapling/note/nullifier.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use std::array::TryFromSliceError;
use std::fmt;

use subtle::{Choice, ConstantTimeEq};

Expand All @@ -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<Nullifier, TryFromSliceError> {
bytes.try_into().map(Nullifier)
Expand Down
13 changes: 12 additions & 1 deletion zcash_primitives/src/sapling/redjubjub.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};

Expand All @@ -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)]
Expand Down

0 comments on commit c8e2d81

Please sign in to comment.