Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
284 changes: 282 additions & 2 deletions 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 @@ -9,29 +11,307 @@ use zcash_encoding::Vector;
#[cfg(feature = "transparent-inputs")]
pub mod keys;

/// Minimal subset of script opcodes.
/// Defined script opcodes.
///
/// Most of the opcodes are unused by this crate, but we define them so that the alternate
/// `Debug` impl for [`Script`] renders correctly for unexpected scripts.
#[derive(Debug)]
enum OpCode {
// push value
Op0 = 0x00, // False
PushData1 = 0x4c,
PushData2 = 0x4d,
PushData4 = 0x4e,
Negative1 = 0x4f,
Reserved = 0x50,
Op1 = 0x51, // True
Op2 = 0x52,
Op3 = 0x53,
Op4 = 0x54,
Op5 = 0x55,
Op6 = 0x56,
Op7 = 0x57,
Op8 = 0x58,
Op9 = 0x59,
Op10 = 0x5a,
Op11 = 0x5b,
Op12 = 0x5c,
Op13 = 0x5d,
Op14 = 0x5e,
Op15 = 0x5f,
Op16 = 0x60,

// control
Nop = 0x61,
Ver = 0x62,
If = 0x63,
NotIf = 0x64,
VerIf = 0x65,
VerNotIf = 0x66,
Else = 0x67,
EndIf = 0x68,
Verify = 0x69,
Return = 0x6a,

// stack ops
ToAltStack = 0x6b,
FromAltStack = 0x6c,
Drop2 = 0x6d,
Dup2 = 0x6e,
Dup3 = 0x6f,
Over2 = 0x70,
Rot2 = 0x71,
Swap2 = 0x72,
IfDup = 0x73,
Depth = 0x74,
Drop = 0x75,
Dup = 0x76,
Nip = 0x77,
Over = 0x78,
Pick = 0x79,
Roll = 0x7a,
Rot = 0x7b,
Swap = 0x7c,
Tuck = 0x7d,

// splice ops
Cat = 0x7e, // Disabled
Substr = 0x7f, // Disabled
Left = 0x80, // Disabled
Right = 0x81, // Disabled
Size = 0x82,

// bit logic
Invert = 0x83, // Disabled
And = 0x84, // Disabled
Or = 0x85, // Disabled
Xor = 0x86, // Disabled
Equal = 0x87,
EqualVerify = 0x88,
Reserved1 = 0x89,
Reserved2 = 0x8a,

// numeric
Add1 = 0x8b,
Sub1 = 0x8c,
Mul2 = 0x8d, // Disabled
Div2 = 0x8e, // Disabled
Negate = 0x8f,
Abs = 0x90,
Not = 0x91,
NotEqual0 = 0x92,

Add = 0x93,
Sub = 0x94,
Mul = 0x95, // Disabled
Div = 0x96, // Disabled
Mod = 0x97, // Disabled
LShift = 0x98, // Disabled
RShift = 0x99, // Disabled

BoolAnd = 0x9a,
BoolOr = 0x9b,
NumEqual = 0x9c,
NumEqualVerify = 0x9d,
NumNotEqual = 0x9e,
LessThan = 0x9f,
GreaterThan = 0xa0,
LessThanOrEqual = 0xa1,
GreaterThanOrEqual = 0xa2,
Min = 0xa3,
Max = 0xa4,

Within = 0xa5,

// crypto
Ripemd160 = 0xa6,
Sha1 = 0xa7,
Sha256 = 0xa8,
Hash160 = 0xa9,
Hash256 = 0xaa,
CodeSeparator = 0xab, // Disabled
CheckSig = 0xac,
CheckSigVerify = 0xad,
CheckMultisig = 0xae,
CheckMultisigVerify = 0xaf,

// expansion
Nop1 = 0xb0,
CheckLockTimeVerify = 0xb1,
Nop3 = 0xb2,
Nop4 = 0xb3,
Nop5 = 0xb4,
Nop6 = 0xb5,
Nop7 = 0xb6,
Nop8 = 0xb7,
Nop9 = 0xb8,
Nop10 = 0xb9,

InvalidOpCode = 0xff,
}

impl OpCode {
fn parse(b: u8) -> Option<Self> {
match b {
0x00 => Some(OpCode::Op0),
0x4c => Some(OpCode::PushData1),
0x4d => Some(OpCode::PushData2),
0x4e => Some(OpCode::PushData4),
0x4f => Some(OpCode::Negative1),
0x50 => Some(OpCode::Reserved),
0x51 => Some(OpCode::Op1),
0x52 => Some(OpCode::Op2),
0x53 => Some(OpCode::Op3),
0x54 => Some(OpCode::Op4),
0x55 => Some(OpCode::Op5),
0x56 => Some(OpCode::Op6),
0x57 => Some(OpCode::Op7),
0x58 => Some(OpCode::Op8),
0x59 => Some(OpCode::Op9),
0x5a => Some(OpCode::Op10),
0x5b => Some(OpCode::Op11),
0x5c => Some(OpCode::Op12),
0x5d => Some(OpCode::Op13),
0x5e => Some(OpCode::Op14),
0x5f => Some(OpCode::Op15),
0x60 => Some(OpCode::Op16),
0x61 => Some(OpCode::Nop),
0x62 => Some(OpCode::Ver),
0x63 => Some(OpCode::If),
0x64 => Some(OpCode::NotIf),
0x65 => Some(OpCode::VerIf),
0x66 => Some(OpCode::VerNotIf),
0x67 => Some(OpCode::Else),
0x68 => Some(OpCode::EndIf),
0x69 => Some(OpCode::Verify),
0x6a => Some(OpCode::Return),
0x6b => Some(OpCode::ToAltStack),
0x6c => Some(OpCode::FromAltStack),
0x6d => Some(OpCode::Drop2),
0x6e => Some(OpCode::Dup2),
0x6f => Some(OpCode::Dup3),
0x70 => Some(OpCode::Over2),
0x71 => Some(OpCode::Rot2),
0x72 => Some(OpCode::Swap2),
0x73 => Some(OpCode::IfDup),
0x74 => Some(OpCode::Depth),
0x75 => Some(OpCode::Drop),
0x76 => Some(OpCode::Dup),
0x77 => Some(OpCode::Nip),
0x78 => Some(OpCode::Over),
0x79 => Some(OpCode::Pick),
0x7a => Some(OpCode::Roll),
0x7b => Some(OpCode::Rot),
0x7c => Some(OpCode::Swap),
0x7d => Some(OpCode::Tuck),
0x7e => Some(OpCode::Cat),
0x7f => Some(OpCode::Substr),
0x80 => Some(OpCode::Left),
0x81 => Some(OpCode::Right),
0x82 => Some(OpCode::Size),
0x83 => Some(OpCode::Invert),
0x84 => Some(OpCode::And),
0x85 => Some(OpCode::Or),
0x86 => Some(OpCode::Xor),
0x87 => Some(OpCode::Equal),
0x88 => Some(OpCode::EqualVerify),
0x89 => Some(OpCode::Reserved1),
0x8a => Some(OpCode::Reserved2),
0x8b => Some(OpCode::Add1),
0x8c => Some(OpCode::Sub1),
0x8d => Some(OpCode::Mul2),
0x8e => Some(OpCode::Div2),
0x8f => Some(OpCode::Negate),
0x90 => Some(OpCode::Abs),
0x91 => Some(OpCode::Not),
0x92 => Some(OpCode::NotEqual0),
0x93 => Some(OpCode::Add),
0x94 => Some(OpCode::Sub),
0x95 => Some(OpCode::Mul),
0x96 => Some(OpCode::Div),
0x97 => Some(OpCode::Mod),
0x98 => Some(OpCode::LShift),
0x99 => Some(OpCode::RShift),
0x9a => Some(OpCode::BoolAnd),
0x9b => Some(OpCode::BoolOr),
0x9c => Some(OpCode::NumEqual),
0x9d => Some(OpCode::NumEqualVerify),
0x9e => Some(OpCode::NumNotEqual),
0x9f => Some(OpCode::LessThan),
0xa0 => Some(OpCode::GreaterThan),
0xa1 => Some(OpCode::LessThanOrEqual),
0xa2 => Some(OpCode::GreaterThanOrEqual),
0xa3 => Some(OpCode::Min),
0xa4 => Some(OpCode::Max),
0xa5 => Some(OpCode::Within),
0xa6 => Some(OpCode::Ripemd160),
0xa7 => Some(OpCode::Sha1),
0xa8 => Some(OpCode::Sha256),
0xa9 => Some(OpCode::Hash160),
0xaa => Some(OpCode::Hash256),
0xab => Some(OpCode::CodeSeparator),
0xac => Some(OpCode::CheckSig),
0xad => Some(OpCode::CheckSigVerify),
0xae => Some(OpCode::CheckMultisig),
0xaf => Some(OpCode::CheckMultisigVerify),
0xb0 => Some(OpCode::Nop1),
0xb1 => Some(OpCode::CheckLockTimeVerify),
0xb2 => Some(OpCode::Nop3),
0xb3 => Some(OpCode::Nop4),
0xb4 => Some(OpCode::Nop5),
0xb5 => Some(OpCode::Nop6),
0xb6 => Some(OpCode::Nop7),
0xb7 => Some(OpCode::Nop8),
0xb8 => Some(OpCode::Nop9),
0xb9 => Some(OpCode::Nop10),
0xff => Some(OpCode::InvalidOpCode),
_ => 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
Loading