commit
7421d85cc0
|
@ -19,6 +19,8 @@
|
||||||
#![deny(unsafe_code)]
|
#![deny(unsafe_code)]
|
||||||
// TODO: #![deny(missing_docs)]
|
// TODO: #![deny(missing_docs)]
|
||||||
|
|
||||||
|
use core::fmt::{self, Write};
|
||||||
|
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
extern crate alloc;
|
extern crate alloc;
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
|
@ -72,9 +74,28 @@ impl AsRef<[u8]> for OutgoingCipherKey {
|
||||||
/// Newtype representing the byte encoding of an [`EphemeralPublicKey`].
|
/// Newtype representing the byte encoding of an [`EphemeralPublicKey`].
|
||||||
///
|
///
|
||||||
/// [`EphemeralPublicKey`]: Domain::EphemeralPublicKey
|
/// [`EphemeralPublicKey`]: Domain::EphemeralPublicKey
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone)]
|
||||||
pub struct EphemeralKeyBytes(pub [u8; 32]);
|
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 {
|
impl AsRef<[u8]> for EphemeralKeyBytes {
|
||||||
fn as_ref(&self) -> &[u8] {
|
fn as_ref(&self) -> &[u8] {
|
||||||
&self.0
|
&self.0
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
//! Support for legacy transparent addresses and scripts.
|
//! Support for legacy transparent addresses and scripts.
|
||||||
|
|
||||||
use byteorder::{ReadBytesExt, WriteBytesExt};
|
use byteorder::{ReadBytesExt, WriteBytesExt};
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::ops::Shl;
|
use std::ops::Shl;
|
||||||
|
|
||||||
|
@ -9,29 +11,307 @@ use zcash_encoding::Vector;
|
||||||
#[cfg(feature = "transparent-inputs")]
|
#[cfg(feature = "transparent-inputs")]
|
||||||
pub mod keys;
|
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 {
|
enum OpCode {
|
||||||
// push value
|
// push value
|
||||||
|
Op0 = 0x00, // False
|
||||||
PushData1 = 0x4c,
|
PushData1 = 0x4c,
|
||||||
PushData2 = 0x4d,
|
PushData2 = 0x4d,
|
||||||
PushData4 = 0x4e,
|
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
|
// 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,
|
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
|
// bit logic
|
||||||
|
Invert = 0x83, // Disabled
|
||||||
|
And = 0x84, // Disabled
|
||||||
|
Or = 0x85, // Disabled
|
||||||
|
Xor = 0x86, // Disabled
|
||||||
Equal = 0x87,
|
Equal = 0x87,
|
||||||
EqualVerify = 0x88,
|
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
|
// crypto
|
||||||
|
Ripemd160 = 0xa6,
|
||||||
|
Sha1 = 0xa7,
|
||||||
|
Sha256 = 0xa8,
|
||||||
Hash160 = 0xa9,
|
Hash160 = 0xa9,
|
||||||
|
Hash256 = 0xaa,
|
||||||
|
CodeSeparator = 0xab, // Disabled
|
||||||
CheckSig = 0xac,
|
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.
|
/// 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>);
|
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 {
|
impl Script {
|
||||||
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
pub fn read<R: Read>(mut reader: R) -> io::Result<Self> {
|
||||||
let script = Vector::read(&mut reader, |r| r.read_u8())?;
|
let script = Vector::read(&mut reader, |r| r.read_u8())?;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
use std::array::TryFromSliceError;
|
use std::array::TryFromSliceError;
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use subtle::{Choice, ConstantTimeEq};
|
use subtle::{Choice, ConstantTimeEq};
|
||||||
|
|
||||||
|
@ -9,9 +10,17 @@ use crate::sapling::{
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Typesafe wrapper for nullifier values.
|
/// Typesafe wrapper for nullifier values.
|
||||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
#[derive(Copy, Clone, PartialEq, Eq)]
|
||||||
pub struct Nullifier(pub [u8; 32]);
|
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 {
|
impl Nullifier {
|
||||||
pub fn from_slice(bytes: &[u8]) -> Result<Nullifier, TryFromSliceError> {
|
pub fn from_slice(bytes: &[u8]) -> Result<Nullifier, TryFromSliceError> {
|
||||||
bytes.try_into().map(Nullifier)
|
bytes.try_into().map(Nullifier)
|
||||||
|
|
|
@ -7,6 +7,8 @@ use ff::{Field, PrimeField};
|
||||||
use group::GroupEncoding;
|
use group::GroupEncoding;
|
||||||
use jubjub::{AffinePoint, ExtendedPoint, SubgroupPoint};
|
use jubjub::{AffinePoint, ExtendedPoint, SubgroupPoint};
|
||||||
use rand_core::RngCore;
|
use rand_core::RngCore;
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::io::{self, Read, Write};
|
use std::io::{self, Read, Write};
|
||||||
use std::ops::{AddAssign, MulAssign, Neg};
|
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)
|
hash_to_scalar(b"Zcash_RedJubjubH", a, b)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Signature {
|
pub struct Signature {
|
||||||
rbar: [u8; 32],
|
rbar: [u8; 32],
|
||||||
sbar: [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);
|
pub struct PrivateKey(pub jubjub::Fr);
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
use blake2b_simd::{Hash as Blake2bHash, Params as Blake2bParams};
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
|
||||||
use ff::PrimeField;
|
use ff::PrimeField;
|
||||||
|
|
||||||
use crate::consensus::BranchId;
|
use crate::consensus::BranchId;
|
||||||
|
@ -22,13 +21,6 @@ const ZCASH_JOINSPLITS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashJSplitsHash";
|
||||||
const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashSSpendsHash";
|
const ZCASH_SHIELDED_SPENDS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashSSpendsHash";
|
||||||
const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashSOutputHash";
|
const ZCASH_SHIELDED_OUTPUTS_HASH_PERSONALIZATION: &[u8; 16] = b"ZcashSOutputHash";
|
||||||
|
|
||||||
macro_rules! update_u32 {
|
|
||||||
($h:expr, $value:expr, $tmp:expr) => {
|
|
||||||
(&mut $tmp[..4]).write_u32::<LittleEndian>($value).unwrap();
|
|
||||||
$h.update(&$tmp[..4]);
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
macro_rules! update_hash {
|
macro_rules! update_hash {
|
||||||
($h:expr, $cond:expr, $value:expr) => {
|
($h:expr, $cond:expr, $value:expr) => {
|
||||||
if $cond {
|
if $cond {
|
||||||
|
@ -53,7 +45,7 @@ fn prevout_hash<TA: transparent::Authorization>(vin: &[TxIn<TA>]) -> Blake2bHash
|
||||||
fn sequence_hash<TA: transparent::Authorization>(vin: &[TxIn<TA>]) -> Blake2bHash {
|
fn sequence_hash<TA: transparent::Authorization>(vin: &[TxIn<TA>]) -> Blake2bHash {
|
||||||
let mut data = Vec::with_capacity(vin.len() * 4);
|
let mut data = Vec::with_capacity(vin.len() * 4);
|
||||||
for t_in in vin {
|
for t_in in vin {
|
||||||
data.write_u32::<LittleEndian>(t_in.sequence).unwrap();
|
data.extend_from_slice(&t_in.sequence.to_le_bytes());
|
||||||
}
|
}
|
||||||
Blake2bParams::new()
|
Blake2bParams::new()
|
||||||
.hash_length(32)
|
.hash_length(32)
|
||||||
|
@ -145,18 +137,15 @@ pub fn v4_signature_hash<
|
||||||
if tx.version.has_overwinter() {
|
if tx.version.has_overwinter() {
|
||||||
let mut personal = [0; 16];
|
let mut personal = [0; 16];
|
||||||
personal[..12].copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX);
|
personal[..12].copy_from_slice(ZCASH_SIGHASH_PERSONALIZATION_PREFIX);
|
||||||
(&mut personal[12..])
|
personal[12..].copy_from_slice(&u32::from(tx.consensus_branch_id).to_le_bytes());
|
||||||
.write_u32::<LittleEndian>(tx.consensus_branch_id.into())
|
|
||||||
.unwrap();
|
|
||||||
|
|
||||||
let mut h = Blake2bParams::new()
|
let mut h = Blake2bParams::new()
|
||||||
.hash_length(32)
|
.hash_length(32)
|
||||||
.personal(&personal)
|
.personal(&personal)
|
||||||
.to_state();
|
.to_state();
|
||||||
let mut tmp = [0; 8];
|
|
||||||
|
|
||||||
update_u32!(h, tx.version.header(), tmp);
|
h.update(&tx.version.header().to_le_bytes());
|
||||||
update_u32!(h, tx.version.version_group_id(), tmp);
|
h.update(&tx.version.version_group_id().to_le_bytes());
|
||||||
update_hash!(
|
update_hash!(
|
||||||
h,
|
h,
|
||||||
hash_type & SIGHASH_ANYONECANPAY == 0,
|
hash_type & SIGHASH_ANYONECANPAY == 0,
|
||||||
|
@ -231,12 +220,12 @@ pub fn v4_signature_hash<
|
||||||
shielded_outputs_hash(tx.sapling_bundle.as_ref().unwrap().shielded_outputs())
|
shielded_outputs_hash(tx.sapling_bundle.as_ref().unwrap().shielded_outputs())
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
update_u32!(h, tx.lock_time, tmp);
|
h.update(&tx.lock_time.to_le_bytes());
|
||||||
update_u32!(h, tx.expiry_height.into(), tmp);
|
h.update(&u32::from(tx.expiry_height).to_le_bytes());
|
||||||
if tx.version.has_sapling() {
|
if tx.version.has_sapling() {
|
||||||
h.update(&tx.sapling_value_balance().to_i64_le_bytes());
|
h.update(&tx.sapling_value_balance().to_i64_le_bytes());
|
||||||
}
|
}
|
||||||
update_u32!(h, hash_type.into(), tmp);
|
h.update(&u32::from(hash_type).to_le_bytes());
|
||||||
|
|
||||||
match signable_input {
|
match signable_input {
|
||||||
SignableInput::Shielded => (),
|
SignableInput::Shielded => (),
|
||||||
|
@ -251,8 +240,7 @@ pub fn v4_signature_hash<
|
||||||
bundle.vin[*index].prevout.write(&mut data).unwrap();
|
bundle.vin[*index].prevout.write(&mut data).unwrap();
|
||||||
script_code.write(&mut data).unwrap();
|
script_code.write(&mut data).unwrap();
|
||||||
data.extend_from_slice(&value.to_i64_le_bytes());
|
data.extend_from_slice(&value.to_i64_le_bytes());
|
||||||
data.write_u32::<LittleEndian>(bundle.vin[*index].sequence)
|
data.extend_from_slice(&bundle.vin[*index].sequence.to_le_bytes());
|
||||||
.unwrap();
|
|
||||||
h.update(&data);
|
h.update(&data);
|
||||||
} else {
|
} else {
|
||||||
panic!(
|
panic!(
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
use blake2b_simd::{Hash as Blake2bHash, Params, State};
|
use blake2b_simd::{Hash as Blake2bHash, Params, State};
|
||||||
use byteorder::{LittleEndian, WriteBytesExt};
|
|
||||||
use zcash_encoding::Array;
|
use zcash_encoding::Array;
|
||||||
|
|
||||||
use crate::transaction::{
|
use crate::transaction::{
|
||||||
|
@ -17,6 +16,9 @@ use crate::transaction::{
|
||||||
Authorization, TransactionData, TransparentDigests, TxDigests,
|
Authorization, TransactionData, TransparentDigests, TxDigests,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(feature = "zfuture")]
|
||||||
|
use byteorder::WriteBytesExt;
|
||||||
|
|
||||||
#[cfg(feature = "zfuture")]
|
#[cfg(feature = "zfuture")]
|
||||||
use zcash_encoding::{CompactSize, Vector};
|
use zcash_encoding::{CompactSize, Vector};
|
||||||
|
|
||||||
|
@ -121,7 +123,7 @@ fn transparent_sig_digest<A: TransparentAuthorizingContext>(
|
||||||
txin.prevout.write(&mut ch).unwrap();
|
txin.prevout.write(&mut ch).unwrap();
|
||||||
ch.write_all(&value.to_i64_le_bytes()).unwrap();
|
ch.write_all(&value.to_i64_le_bytes()).unwrap();
|
||||||
script_pubkey.write(&mut ch).unwrap();
|
script_pubkey.write(&mut ch).unwrap();
|
||||||
ch.write_u32::<LittleEndian>(txin.sequence).unwrap();
|
ch.write_all(&txin.sequence.to_le_bytes()).unwrap();
|
||||||
}
|
}
|
||||||
let txin_sig_digest = ch.finalize();
|
let txin_sig_digest = ch.finalize();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue