Add ZIP-244 signature hash support (#2165)
* ZIP-244 sighash implementation using librustzcash * ZIP-244: fix sighash test; add roundtrip test; update vectors * Improvements from review; renamed sighash::Hash to SigHash
This commit is contained in:
parent
d430e951c2
commit
fdfa3cbdc6
|
@ -15,4 +15,4 @@ pub use x25519_dalek as x25519;
|
|||
pub use proofs::{Bctv14Proof, Groth16Proof, Halo2Proof, ZkSnarkProof};
|
||||
|
||||
pub mod zcash_history;
|
||||
mod zcash_primitives;
|
||||
pub(crate) mod zcash_primitives;
|
||||
|
|
|
@ -4,9 +4,16 @@
|
|||
use std::{
|
||||
convert::{TryFrom, TryInto},
|
||||
io,
|
||||
ops::Deref,
|
||||
};
|
||||
|
||||
use crate::{serialization::ZcashSerialize, transaction::Transaction};
|
||||
use crate::{
|
||||
amount::{Amount, NonNegative},
|
||||
parameters::NetworkUpgrade,
|
||||
serialization::ZcashSerialize,
|
||||
transaction::{HashType, SigHash, Transaction},
|
||||
transparent::{self, Script},
|
||||
};
|
||||
|
||||
impl TryFrom<&Transaction> for zcash_primitives::transaction::Transaction {
|
||||
type Error = io::Error;
|
||||
|
@ -28,19 +35,92 @@ impl TryFrom<&Transaction> for zcash_primitives::transaction::Transaction {
|
|||
| Transaction::V4 { .. } => panic!("Zebra only uses librustzcash for V5 transactions"),
|
||||
};
|
||||
|
||||
let serialized_tx = trans.zcash_serialize_to_vec()?;
|
||||
// The `read` method currently ignores the BranchId for V5 transactions;
|
||||
// but we use the correct BranchId anyway.
|
||||
let branch_id: u32 = network_upgrade
|
||||
.branch_id()
|
||||
.expect("Network upgrade must have a Branch ID")
|
||||
.into();
|
||||
// We've already parsed this transaction, so its network upgrade must be valid.
|
||||
let branch_id: zcash_primitives::consensus::BranchId = branch_id
|
||||
.try_into()
|
||||
.expect("zcash_primitives and Zebra have the same branch ids");
|
||||
let alt_tx =
|
||||
zcash_primitives::transaction::Transaction::read(&serialized_tx[..], branch_id)?;
|
||||
Ok(alt_tx)
|
||||
convert_tx_to_librustzcash(trans, *network_upgrade)
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_tx_to_librustzcash(
|
||||
trans: &Transaction,
|
||||
network_upgrade: NetworkUpgrade,
|
||||
) -> Result<zcash_primitives::transaction::Transaction, io::Error> {
|
||||
let serialized_tx = trans.zcash_serialize_to_vec()?;
|
||||
let branch_id: u32 = network_upgrade
|
||||
.branch_id()
|
||||
.expect("Network upgrade must have a Branch ID")
|
||||
.into();
|
||||
// We've already parsed this transaction, so its network upgrade must be valid.
|
||||
let branch_id: zcash_primitives::consensus::BranchId = branch_id
|
||||
.try_into()
|
||||
.expect("zcash_primitives and Zebra have the same branch ids");
|
||||
let alt_tx = zcash_primitives::transaction::Transaction::read(&serialized_tx[..], branch_id)?;
|
||||
Ok(alt_tx)
|
||||
}
|
||||
|
||||
/// Convert a Zebra Amount into a librustzcash one.
|
||||
impl TryFrom<Amount<NonNegative>> for zcash_primitives::transaction::components::Amount {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(amount: Amount<NonNegative>) -> Result<Self, Self::Error> {
|
||||
zcash_primitives::transaction::components::Amount::from_u64(amount.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a Zebra Script into a librustzcash one.
|
||||
impl From<&Script> for zcash_primitives::legacy::Script {
|
||||
fn from(script: &Script) -> Self {
|
||||
zcash_primitives::legacy::Script(script.as_raw_bytes().to_vec())
|
||||
}
|
||||
}
|
||||
|
||||
/// Compute a signature hash using librustzcash.
|
||||
///
|
||||
/// # Inputs
|
||||
///
|
||||
/// - `transaction`: the transaction whose signature hash to compute.
|
||||
/// - `hash_type`: the type of hash (SIGHASH) being used.
|
||||
/// - `network_upgrade`: the network upgrade of the block containing the transaction.
|
||||
/// - `input`: information about the transparent input for which this signature
|
||||
/// hash is being computed, if any. A tuple with the matching output of the
|
||||
/// previous transaction, the input itself, and the index of the input in
|
||||
/// the transaction.
|
||||
pub(crate) fn sighash(
|
||||
trans: &Transaction,
|
||||
hash_type: HashType,
|
||||
network_upgrade: NetworkUpgrade,
|
||||
input: Option<(&transparent::Output, &transparent::Input, usize)>,
|
||||
) -> SigHash {
|
||||
let alt_tx = convert_tx_to_librustzcash(trans, network_upgrade)
|
||||
.expect("zcash_primitives and Zebra transaction formats must be compatible");
|
||||
|
||||
let script: zcash_primitives::legacy::Script;
|
||||
let signable_input = match input {
|
||||
Some((output, _, idx)) => {
|
||||
script = (&output.lock_script).into();
|
||||
zcash_primitives::transaction::sighash::SignableInput::Transparent(
|
||||
zcash_primitives::transaction::sighash::TransparentInput::new(
|
||||
idx,
|
||||
&script,
|
||||
output
|
||||
.value
|
||||
.try_into()
|
||||
.expect("amount was previously validated"),
|
||||
),
|
||||
)
|
||||
}
|
||||
None => zcash_primitives::transaction::sighash::SignableInput::Shielded,
|
||||
};
|
||||
|
||||
let txid_parts = alt_tx
|
||||
.deref()
|
||||
.digest(zcash_primitives::transaction::txid::TxIdDigester);
|
||||
|
||||
SigHash(
|
||||
*zcash_primitives::transaction::sighash::signature_hash(
|
||||
alt_tx.deref(),
|
||||
hash_type.bits(),
|
||||
&signable_input,
|
||||
&txid_parts,
|
||||
)
|
||||
.as_ref(),
|
||||
)
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ pub use lock_time::LockTime;
|
|||
pub use memo::Memo;
|
||||
pub use sapling::FieldNotPresent;
|
||||
pub use sighash::HashType;
|
||||
pub use sighash::SigHash;
|
||||
|
||||
use crate::{
|
||||
amount, block, orchard,
|
||||
|
@ -146,7 +147,7 @@ impl Transaction {
|
|||
network_upgrade: NetworkUpgrade,
|
||||
hash_type: sighash::HashType,
|
||||
input: Option<(u32, transparent::Output)>,
|
||||
) -> blake2b_simd::Hash {
|
||||
) -> SigHash {
|
||||
sighash::SigHasher::new(self, hash_type, network_upgrade, input).sighash()
|
||||
}
|
||||
|
||||
|
|
|
@ -12,10 +12,14 @@ use crate::{
|
|||
transparent,
|
||||
};
|
||||
|
||||
use blake2b_simd::Hash;
|
||||
use byteorder::{LittleEndian, WriteBytesExt};
|
||||
|
||||
use std::io::{self, Write};
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
io::{self, Write},
|
||||
};
|
||||
|
||||
use crate::primitives::zcash_primitives::sighash;
|
||||
|
||||
static ZIP143_EXPLANATION: &str = "Invalid transaction version: after Overwinter activation transaction versions 1 and 2 are rejected";
|
||||
static ZIP243_EXPLANATION: &str = "Invalid transaction version: after Sapling activation transaction versions 1, 2, and 3 are rejected";
|
||||
|
@ -48,6 +52,23 @@ impl HashType {
|
|||
}
|
||||
}
|
||||
|
||||
/// A Signature Hash (or SIGHASH) as specified in
|
||||
/// https://zips.z.cash/protocol/protocol.pdf#sighash
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub struct SigHash(pub [u8; 32]);
|
||||
|
||||
impl AsRef<[u8; 32]> for SigHash {
|
||||
fn as_ref(&self) -> &[u8; 32] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<[u8]> for SigHash {
|
||||
fn as_ref(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) struct SigHasher<'a> {
|
||||
trans: &'a Transaction,
|
||||
hash_type: HashType,
|
||||
|
@ -79,7 +100,7 @@ impl<'a> SigHasher<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn sighash(self) -> Hash {
|
||||
pub(super) fn sighash(self) -> SigHash {
|
||||
use NetworkUpgrade::*;
|
||||
let mut hash = blake2b_simd::Params::new()
|
||||
.hash_length(32)
|
||||
|
@ -94,12 +115,10 @@ impl<'a> SigHasher<'a> {
|
|||
Sapling | Blossom | Heartwood | Canopy => self
|
||||
.hash_sighash_zip243(&mut hash)
|
||||
.expect("serialization into hasher never fails"),
|
||||
Nu5 => unimplemented!(
|
||||
"Nu5 upgrade uses a new transaction digest algorithm, as specified in ZIP-244"
|
||||
),
|
||||
Nu5 => return self.hash_sighash_zip244(),
|
||||
}
|
||||
|
||||
hash.finalize()
|
||||
SigHash(hash.finalize().as_ref().try_into().unwrap())
|
||||
}
|
||||
|
||||
fn consensus_branch_id(&self) -> ConsensusBranchId {
|
||||
|
@ -107,7 +126,7 @@ impl<'a> SigHasher<'a> {
|
|||
}
|
||||
|
||||
/// Sighash implementation for the overwinter network upgrade
|
||||
fn hash_sighash_zip143<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_sighash_zip143<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
self.hash_header(&mut writer)?;
|
||||
self.hash_groupid(&mut writer)?;
|
||||
self.hash_prevouts(&mut writer)?;
|
||||
|
@ -131,7 +150,7 @@ impl<'a> SigHasher<'a> {
|
|||
personal
|
||||
}
|
||||
|
||||
fn hash_header<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_header<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
let overwintered_flag = 1 << 31;
|
||||
|
||||
writer.write_u32::<LittleEndian>(match &self.trans {
|
||||
|
@ -142,7 +161,7 @@ impl<'a> SigHasher<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn hash_groupid<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_groupid<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_u32::<LittleEndian>(match &self.trans {
|
||||
Transaction::V1 { .. } | Transaction::V2 { .. } => unreachable!(ZIP143_EXPLANATION),
|
||||
Transaction::V3 { .. } => OVERWINTER_VERSION_GROUP_ID,
|
||||
|
@ -151,7 +170,7 @@ impl<'a> SigHasher<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
fn hash_prevouts<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_prevouts<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
if self.hash_type.contains(HashType::ANYONECANPAY) {
|
||||
return writer.write_all(&[0; 32]);
|
||||
}
|
||||
|
@ -173,7 +192,7 @@ impl<'a> SigHasher<'a> {
|
|||
writer.write_all(hash.finalize().as_ref())
|
||||
}
|
||||
|
||||
fn hash_sequence<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_sequence<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
if self.hash_type.contains(HashType::ANYONECANPAY)
|
||||
|| self.hash_type.masked() == HashType::SINGLE
|
||||
|| self.hash_type.masked() == HashType::NONE
|
||||
|
@ -199,7 +218,7 @@ impl<'a> SigHasher<'a> {
|
|||
}
|
||||
|
||||
/// Writes the u256 hash of the transactions outputs to the provided Writer
|
||||
fn hash_outputs<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_outputs<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
if self.hash_type.masked() != HashType::SINGLE && self.hash_type.masked() != HashType::NONE
|
||||
{
|
||||
self.outputs_hash(writer)
|
||||
|
@ -249,7 +268,7 @@ impl<'a> SigHasher<'a> {
|
|||
writer.write_all(hash.finalize().as_ref())
|
||||
}
|
||||
|
||||
fn hash_joinsplits<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_joinsplits<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
let has_joinsplits = match self.trans {
|
||||
Transaction::V1 { .. } | Transaction::V2 { .. } => unreachable!(ZIP143_EXPLANATION),
|
||||
Transaction::V3 { joinsplit_data, .. } => joinsplit_data.is_some(),
|
||||
|
@ -318,19 +337,19 @@ impl<'a> SigHasher<'a> {
|
|||
writer.write_all(hash.finalize().as_ref())
|
||||
}
|
||||
|
||||
fn hash_lock_time<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_lock_time<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
self.trans.lock_time().zcash_serialize(&mut writer)
|
||||
}
|
||||
|
||||
fn hash_expiry_height<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_expiry_height<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_u32::<LittleEndian>(self.trans.expiry_height().expect(ZIP143_EXPLANATION).0)
|
||||
}
|
||||
|
||||
fn hash_hash_type<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_hash_type<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
writer.write_u32::<LittleEndian>(self.hash_type.bits())
|
||||
}
|
||||
|
||||
fn hash_input<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_input<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
if self.input.is_some() {
|
||||
self.hash_input_prevout(&mut writer)?;
|
||||
self.hash_input_script_code(&mut writer)?;
|
||||
|
@ -341,7 +360,7 @@ impl<'a> SigHasher<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn hash_input_prevout<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_input_prevout<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
let (_, input, _) = self
|
||||
.input
|
||||
.as_ref()
|
||||
|
@ -359,7 +378,10 @@ impl<'a> SigHasher<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn hash_input_script_code<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_input_script_code<W: io::Write>(
|
||||
&self,
|
||||
mut writer: W,
|
||||
) -> Result<(), io::Error> {
|
||||
let (transparent::Output { lock_script, .. }, _, _) = self
|
||||
.input
|
||||
.as_ref()
|
||||
|
@ -370,7 +392,7 @@ impl<'a> SigHasher<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn hash_input_amount<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_input_amount<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
let (transparent::Output { value, .. }, _, _) = self
|
||||
.input
|
||||
.as_ref()
|
||||
|
@ -381,7 +403,7 @@ impl<'a> SigHasher<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn hash_input_sequence<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_input_sequence<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
let (_, input, _) = self
|
||||
.input
|
||||
.as_ref()
|
||||
|
@ -405,7 +427,7 @@ impl<'a> SigHasher<'a> {
|
|||
|
||||
/// Sighash implementation for the sapling network upgrade and every
|
||||
/// subsequent network upgrade
|
||||
fn hash_sighash_zip243<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_sighash_zip243<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
self.hash_header(&mut writer)?;
|
||||
self.hash_groupid(&mut writer)?;
|
||||
self.hash_prevouts(&mut writer)?;
|
||||
|
@ -423,7 +445,10 @@ impl<'a> SigHasher<'a> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn hash_shielded_spends<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_shielded_spends<W: io::Write>(
|
||||
&self,
|
||||
mut writer: W,
|
||||
) -> Result<(), io::Error> {
|
||||
use Transaction::*;
|
||||
|
||||
let sapling_shielded_data = match self.trans {
|
||||
|
@ -462,7 +487,10 @@ impl<'a> SigHasher<'a> {
|
|||
writer.write_all(hash.finalize().as_ref())
|
||||
}
|
||||
|
||||
fn hash_shielded_outputs<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_shielded_outputs<W: io::Write>(
|
||||
&self,
|
||||
mut writer: W,
|
||||
) -> Result<(), io::Error> {
|
||||
use Transaction::*;
|
||||
|
||||
let sapling_shielded_data = match self.trans {
|
||||
|
@ -499,7 +527,7 @@ impl<'a> SigHasher<'a> {
|
|||
writer.write_all(hash.finalize().as_ref())
|
||||
}
|
||||
|
||||
fn hash_value_balance<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
pub(super) fn hash_value_balance<W: io::Write>(&self, mut writer: W) -> Result<(), io::Error> {
|
||||
use crate::amount::Amount;
|
||||
use std::convert::TryFrom;
|
||||
use Transaction::*;
|
||||
|
@ -520,466 +548,13 @@ impl<'a> SigHasher<'a> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::{amount::Amount, serialization::ZcashDeserializeInto, transaction::Transaction};
|
||||
use color_eyre::eyre;
|
||||
use eyre::Result;
|
||||
use transparent::Script;
|
||||
use zebra_test::vectors::{ZIP143_1, ZIP143_2, ZIP243_1, ZIP243_2, ZIP243_3};
|
||||
|
||||
macro_rules! assert_hash_eq {
|
||||
($expected:literal, $hasher:expr, $f:ident) => {
|
||||
let mut buf = vec![];
|
||||
$hasher
|
||||
.$f(&mut buf)
|
||||
.expect("hashing into a vec never fails");
|
||||
let expected = $expected;
|
||||
let result = hex::encode(buf);
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_vecs",
|
||||
expected.len = expected.len(),
|
||||
result.len = result.len(),
|
||||
hash_fn = stringify!($f)
|
||||
);
|
||||
let guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
drop(guard);
|
||||
};
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec143_1() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
let transaction = ZIP143_1.zcash_deserialize_into::<Transaction>()?;
|
||||
|
||||
let hasher = SigHasher {
|
||||
trans: &transaction,
|
||||
hash_type: HashType::ALL,
|
||||
network_upgrade: NetworkUpgrade::Overwinter,
|
||||
input: None,
|
||||
};
|
||||
|
||||
assert_hash_eq!("03000080", hasher, hash_header);
|
||||
|
||||
assert_hash_eq!("7082c403", hasher, hash_groupid);
|
||||
|
||||
assert_hash_eq!(
|
||||
"d53a633bbecf82fe9e9484d8a0e727c73bb9e68c96e72dec30144f6a84afa136",
|
||||
hasher,
|
||||
hash_prevouts
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"a5f25f01959361ee6eb56a7401210ee268226f6ce764a4f10b7f29e54db37272",
|
||||
hasher,
|
||||
hash_sequence
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"ab6f7f6c5ad6b56357b5f37e16981723db6c32411753e28c175e15589172194a",
|
||||
hasher,
|
||||
hash_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_joinsplits
|
||||
);
|
||||
|
||||
assert_hash_eq!("481cdd86", hasher, hash_lock_time);
|
||||
|
||||
assert_hash_eq!("b3cc4318", hasher, hash_expiry_height);
|
||||
|
||||
assert_hash_eq!("01000000", hasher, hash_hash_type);
|
||||
|
||||
assert_hash_eq!(
|
||||
"030000807082c403d53a633bbecf82fe9e9484d8a0e727c73bb9e68c96e72dec30144f6a84afa136a5f25f01959361ee6eb56a7401210ee268226f6ce764a4f10b7f29e54db37272ab6f7f6c5ad6b56357b5f37e16981723db6c32411753e28c175e15589172194a0000000000000000000000000000000000000000000000000000000000000000481cdd86b3cc431801000000",
|
||||
hasher,
|
||||
hash_sighash_zip143
|
||||
);
|
||||
|
||||
let hash = hasher.sighash();
|
||||
let expected = "a1f1a4e5cd9bd522322d661edd2af1bf2a7019cfab94ece18f4ba935b0a19073";
|
||||
let result = hex::encode(hash.as_bytes());
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_final",
|
||||
expected.len = expected.len(),
|
||||
buf.len = result.len()
|
||||
);
|
||||
let _guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec143_2() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
let transaction = ZIP143_2.zcash_deserialize_into::<Transaction>()?;
|
||||
|
||||
let value = hex::decode("2f6e04963b4c0100")?.zcash_deserialize_into::<Amount<_>>()?;
|
||||
let lock_script = Script::new(&hex::decode("53")?);
|
||||
let input_ind = 1;
|
||||
|
||||
let hasher = SigHasher::new(
|
||||
&transaction,
|
||||
HashType::SINGLE,
|
||||
NetworkUpgrade::Overwinter,
|
||||
Some((input_ind, transparent::Output { value, lock_script })),
|
||||
);
|
||||
|
||||
assert_hash_eq!("03000080", hasher, hash_header);
|
||||
|
||||
assert_hash_eq!("7082c403", hasher, hash_groupid);
|
||||
|
||||
assert_hash_eq!(
|
||||
"92b8af1f7e12cb8de105af154470a2ae0a11e64a24a514a562ff943ca0f35d7f",
|
||||
hasher,
|
||||
hash_prevouts
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_sequence
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"edc32cce530f836f7c31c53656f859f514c3ff8dcae642d3e17700fdc6e829a4",
|
||||
hasher,
|
||||
hash_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"f59e41b40f3a60be90bee2be11b0956dfff06a6d8e22668c4f215bd87b20d514",
|
||||
hasher,
|
||||
hash_joinsplits
|
||||
);
|
||||
|
||||
assert_hash_eq!("97b0e4e4", hasher, hash_lock_time);
|
||||
|
||||
assert_hash_eq!("c705fc05", hasher, hash_expiry_height);
|
||||
|
||||
assert_hash_eq!("03000000", hasher, hash_hash_type);
|
||||
|
||||
assert_hash_eq!(
|
||||
"378af1e40f64e125946f62c2fa7b2fecbcb64b6968912a6381ce3dc166d56a1d62f5a8d7",
|
||||
hasher,
|
||||
hash_input_prevout
|
||||
);
|
||||
|
||||
assert_hash_eq!("0153", hasher, hash_input_script_code);
|
||||
|
||||
assert_hash_eq!("2f6e04963b4c0100", hasher, hash_input_amount);
|
||||
|
||||
assert_hash_eq!("e8c7203d", hasher, hash_input_sequence);
|
||||
|
||||
let hash = hasher.sighash();
|
||||
let expected = "23652e76cb13b85a0e3363bb5fca061fa791c40c533eccee899364e6e60bb4f7";
|
||||
let result = hash.as_bytes();
|
||||
let result = hex::encode(result);
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_final",
|
||||
expected.len = expected.len(),
|
||||
buf.len = result.len()
|
||||
);
|
||||
let _guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec243_1() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
let transaction = ZIP243_1.zcash_deserialize_into::<Transaction>()?;
|
||||
|
||||
let hasher = SigHasher {
|
||||
trans: &transaction,
|
||||
hash_type: HashType::ALL,
|
||||
network_upgrade: NetworkUpgrade::Sapling,
|
||||
input: None,
|
||||
};
|
||||
|
||||
assert_hash_eq!("04000080", hasher, hash_header);
|
||||
|
||||
assert_hash_eq!("85202f89", hasher, hash_groupid);
|
||||
|
||||
assert_hash_eq!(
|
||||
"d53a633bbecf82fe9e9484d8a0e727c73bb9e68c96e72dec30144f6a84afa136",
|
||||
hasher,
|
||||
hash_prevouts
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"a5f25f01959361ee6eb56a7401210ee268226f6ce764a4f10b7f29e54db37272",
|
||||
hasher,
|
||||
hash_sequence
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"ab6f7f6c5ad6b56357b5f37e16981723db6c32411753e28c175e15589172194a",
|
||||
hasher,
|
||||
hash_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_joinsplits
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"3fd9edb96dccf5b9aeb71e3db3710e74be4f1dfb19234c1217af26181f494a36",
|
||||
hasher,
|
||||
hash_shielded_spends
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"dafece799f638ba7268bf8fe43f02a5112f0bb32a84c4a8c2f508c41ff1c78b5",
|
||||
hasher,
|
||||
hash_shielded_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!("481cdd86", hasher, hash_lock_time);
|
||||
|
||||
assert_hash_eq!("b3cc4318", hasher, hash_expiry_height);
|
||||
|
||||
assert_hash_eq!("442117623ceb0500", hasher, hash_value_balance);
|
||||
|
||||
assert_hash_eq!("01000000", hasher, hash_hash_type);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0400008085202f89d53a633bbecf82fe9e9484d8a0e727c73bb9e68c96e72dec30144f6a84afa136a5f25f01959361ee6eb56a7401210ee268226f6ce764a4f10b7f29e54db37272ab6f7f6c5ad6b56357b5f37e16981723db6c32411753e28c175e15589172194a00000000000000000000000000000000000000000000000000000000000000003fd9edb96dccf5b9aeb71e3db3710e74be4f1dfb19234c1217af26181f494a36dafece799f638ba7268bf8fe43f02a5112f0bb32a84c4a8c2f508c41ff1c78b5481cdd86b3cc4318442117623ceb050001000000",
|
||||
hasher,
|
||||
hash_sighash_zip243
|
||||
);
|
||||
|
||||
let hash = hasher.sighash();
|
||||
let expected = "63d18534de5f2d1c9e169b73f9c783718adbef5c8a7d55b5e7a37affa1dd3ff3";
|
||||
let result = hex::encode(hash.as_bytes());
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_final",
|
||||
expected.len = expected.len(),
|
||||
buf.len = result.len()
|
||||
);
|
||||
let _guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec243_2() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
let transaction = ZIP243_2.zcash_deserialize_into::<Transaction>()?;
|
||||
|
||||
let value = hex::decode("adedf02996510200")?.zcash_deserialize_into::<Amount<_>>()?;
|
||||
let lock_script = Script::new(&[]);
|
||||
let input_ind = 1;
|
||||
|
||||
let hasher = SigHasher::new(
|
||||
&transaction,
|
||||
HashType::NONE,
|
||||
NetworkUpgrade::Sapling,
|
||||
Some((input_ind, transparent::Output { value, lock_script })),
|
||||
);
|
||||
|
||||
assert_hash_eq!("04000080", hasher, hash_header);
|
||||
|
||||
assert_hash_eq!("85202f89", hasher, hash_groupid);
|
||||
|
||||
assert_hash_eq!(
|
||||
"cacf0f5210cce5fa65a59f314292b3111d299e7d9d582753cf61e1e408552ae4",
|
||||
hasher,
|
||||
hash_prevouts
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_sequence
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_joinsplits
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_shielded_spends
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"b79530fcec83211d21e3c355db538c138d625784c27370e9d1039a8515a23f87",
|
||||
hasher,
|
||||
hash_shielded_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!("d7034302", hasher, hash_lock_time);
|
||||
|
||||
assert_hash_eq!("011b9a07", hasher, hash_expiry_height);
|
||||
|
||||
assert_hash_eq!("6620edc067ff0200", hasher, hash_value_balance);
|
||||
|
||||
assert_hash_eq!("02000000", hasher, hash_hash_type);
|
||||
|
||||
assert_hash_eq!(
|
||||
"090f47a068e227433f9e49d3aa09e356d8d66d0c0121e91a3c4aa3f27fa1b63396e2b41d",
|
||||
hasher,
|
||||
hash_input_prevout
|
||||
);
|
||||
|
||||
assert_hash_eq!("00", hasher, hash_input_script_code);
|
||||
|
||||
assert_hash_eq!("adedf02996510200", hasher, hash_input_amount);
|
||||
|
||||
assert_hash_eq!("4e970568", hasher, hash_input_sequence);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0400008085202f89cacf0f5210cce5fa65a59f314292b3111d299e7d9d582753cf61e1e408552ae40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b79530fcec83211d21e3c355db538c138d625784c27370e9d1039a8515a23f87d7034302011b9a076620edc067ff020002000000090f47a068e227433f9e49d3aa09e356d8d66d0c0121e91a3c4aa3f27fa1b63396e2b41d00adedf029965102004e970568",
|
||||
hasher,
|
||||
hash_sighash_zip243
|
||||
);
|
||||
|
||||
let hash = hasher.sighash();
|
||||
let expected = "bbe6d84f57c56b29b914c694baaccb891297e961de3eb46c68e3c89c47b1a1db";
|
||||
let result = hex::encode(hash.as_bytes());
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_final",
|
||||
expected.len = expected.len(),
|
||||
buf.len = result.len()
|
||||
);
|
||||
let _guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec243_3() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
let transaction = ZIP243_3.zcash_deserialize_into::<Transaction>()?;
|
||||
|
||||
let value = hex::decode("80f0fa0200000000")?.zcash_deserialize_into::<Amount<_>>()?;
|
||||
let lock_script = Script::new(&hex::decode(
|
||||
"76a914507173527b4c3318a2aecd793bf1cfed705950cf88ac",
|
||||
)?);
|
||||
let input_ind = 0;
|
||||
|
||||
let hasher = SigHasher::new(
|
||||
&transaction,
|
||||
HashType::ALL,
|
||||
NetworkUpgrade::Sapling,
|
||||
Some((input_ind, transparent::Output { value, lock_script })),
|
||||
);
|
||||
|
||||
assert_hash_eq!("04000080", hasher, hash_header);
|
||||
|
||||
assert_hash_eq!("85202f89", hasher, hash_groupid);
|
||||
|
||||
assert_hash_eq!(
|
||||
"fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f11",
|
||||
hasher,
|
||||
hash_prevouts
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"6c80d37f12d89b6f17ff198723e7db1247c4811d1a695d74d930f99e98418790",
|
||||
hasher,
|
||||
hash_sequence
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"d2b04118469b7810a0d1cc59568320aad25a84f407ecac40b4f605a4e6868454",
|
||||
hasher,
|
||||
hash_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_joinsplits
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_shielded_spends
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_shielded_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!("29b00400", hasher, hash_lock_time);
|
||||
|
||||
assert_hash_eq!("48b00400", hasher, hash_expiry_height);
|
||||
|
||||
assert_hash_eq!("0000000000000000", hasher, hash_value_balance);
|
||||
|
||||
assert_hash_eq!("01000000", hasher, hash_hash_type);
|
||||
|
||||
assert_hash_eq!(
|
||||
"a8c685478265f4c14dada651969c45a65e1aeb8cd6791f2f5bb6a1d9952104d901000000",
|
||||
hasher,
|
||||
hash_input_prevout
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"1976a914507173527b4c3318a2aecd793bf1cfed705950cf88ac",
|
||||
hasher,
|
||||
hash_input_script_code
|
||||
);
|
||||
|
||||
assert_hash_eq!("80f0fa0200000000", hasher, hash_input_amount);
|
||||
|
||||
assert_hash_eq!("feffffff", hasher, hash_input_sequence);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0400008085202f89fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f116c80d37f12d89b6f17ff198723e7db1247c4811d1a695d74d930f99e98418790d2b04118469b7810a0d1cc59568320aad25a84f407ecac40b4f605a4e686845400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000029b0040048b00400000000000000000001000000a8c685478265f4c14dada651969c45a65e1aeb8cd6791f2f5bb6a1d9952104d9010000001976a914507173527b4c3318a2aecd793bf1cfed705950cf88ac80f0fa0200000000feffffff",
|
||||
hasher,
|
||||
hash_sighash_zip243
|
||||
);
|
||||
|
||||
let hash = hasher.sighash();
|
||||
let expected = "f3148f80dfab5e573d5edfe7a850f5fd39234f80b5429d3a57edcc11e34c585b";
|
||||
let result = hex::encode(hash.as_bytes());
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_final",
|
||||
expected.len = expected.len(),
|
||||
buf.len = result.len()
|
||||
);
|
||||
let _guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
|
||||
Ok(())
|
||||
/// Compute a signature hash for V5 transactions according to ZIP-244.
|
||||
fn hash_sighash_zip244(&self) -> SigHash {
|
||||
let input = self
|
||||
.input
|
||||
.as_ref()
|
||||
.map(|(output, input, idx)| (output, *input, *idx));
|
||||
sighash(&self.trans, self.hash_type, self.network_upgrade, input)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,9 +10,35 @@ use crate::{
|
|||
block::{Block, Height, MAX_BLOCK_BYTES},
|
||||
parameters::{Network, NetworkUpgrade},
|
||||
serialization::{SerializationError, ZcashDeserialize, ZcashDeserializeInto, ZcashSerialize},
|
||||
transaction::txid::TxIdBuilder,
|
||||
transaction::{sighash::SigHasher, txid::TxIdBuilder},
|
||||
};
|
||||
|
||||
use crate::{amount::Amount, transaction::Transaction};
|
||||
|
||||
use transparent::Script;
|
||||
use zebra_test::vectors::{ZIP143_1, ZIP143_2, ZIP243_1, ZIP243_2, ZIP243_3};
|
||||
|
||||
macro_rules! assert_hash_eq {
|
||||
($expected:literal, $hasher:expr, $f:ident) => {
|
||||
let mut buf = vec![];
|
||||
$hasher
|
||||
.$f(&mut buf)
|
||||
.expect("hashing into a vec never fails");
|
||||
let expected = $expected;
|
||||
let result = hex::encode(buf);
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_vecs",
|
||||
expected.len = expected.len(),
|
||||
result.len = result.len(),
|
||||
hash_fn = stringify!($f)
|
||||
);
|
||||
let guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
drop(guard);
|
||||
};
|
||||
}
|
||||
|
||||
lazy_static! {
|
||||
pub static ref EMPTY_V5_TX: Transaction = Transaction::V5 {
|
||||
network_upgrade: NetworkUpgrade::Nu5,
|
||||
|
@ -431,6 +457,23 @@ fn fake_v5_librustzcash_round_trip_for_network(network: Network) {
|
|||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zip244_round_trip() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
for test in zip0244::TEST_VECTORS.iter() {
|
||||
let transaction = test.tx.zcash_deserialize_into::<Transaction>()?;
|
||||
let reencoded = transaction.zcash_serialize_to_vec()?;
|
||||
assert_eq!(test.tx, reencoded);
|
||||
|
||||
let _alt_tx: zcash_primitives::transaction::Transaction = (&transaction)
|
||||
.try_into()
|
||||
.expect("librustzcash deserialization must work for zebra serialized transactions");
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zip244_txid() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
@ -444,3 +487,547 @@ fn zip244_txid() -> Result<()> {
|
|||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec143_1() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
let transaction = ZIP143_1.zcash_deserialize_into::<Transaction>()?;
|
||||
|
||||
let hasher = SigHasher::new(
|
||||
&transaction,
|
||||
HashType::ALL,
|
||||
NetworkUpgrade::Overwinter,
|
||||
None,
|
||||
);
|
||||
|
||||
assert_hash_eq!("03000080", hasher, hash_header);
|
||||
|
||||
assert_hash_eq!("7082c403", hasher, hash_groupid);
|
||||
|
||||
assert_hash_eq!(
|
||||
"d53a633bbecf82fe9e9484d8a0e727c73bb9e68c96e72dec30144f6a84afa136",
|
||||
hasher,
|
||||
hash_prevouts
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"a5f25f01959361ee6eb56a7401210ee268226f6ce764a4f10b7f29e54db37272",
|
||||
hasher,
|
||||
hash_sequence
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"ab6f7f6c5ad6b56357b5f37e16981723db6c32411753e28c175e15589172194a",
|
||||
hasher,
|
||||
hash_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_joinsplits
|
||||
);
|
||||
|
||||
assert_hash_eq!("481cdd86", hasher, hash_lock_time);
|
||||
|
||||
assert_hash_eq!("b3cc4318", hasher, hash_expiry_height);
|
||||
|
||||
assert_hash_eq!("01000000", hasher, hash_hash_type);
|
||||
|
||||
assert_hash_eq!(
|
||||
"030000807082c403d53a633bbecf82fe9e9484d8a0e727c73bb9e68c96e72dec30144f6a84afa136a5f25f01959361ee6eb56a7401210ee268226f6ce764a4f10b7f29e54db37272ab6f7f6c5ad6b56357b5f37e16981723db6c32411753e28c175e15589172194a0000000000000000000000000000000000000000000000000000000000000000481cdd86b3cc431801000000",
|
||||
hasher,
|
||||
hash_sighash_zip143
|
||||
);
|
||||
|
||||
let hash = hasher.sighash();
|
||||
let expected = "a1f1a4e5cd9bd522322d661edd2af1bf2a7019cfab94ece18f4ba935b0a19073";
|
||||
let result = hex::encode(hash);
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_final",
|
||||
expected.len = expected.len(),
|
||||
buf.len = result.len()
|
||||
);
|
||||
let _guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec143_2() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
let transaction = ZIP143_2.zcash_deserialize_into::<Transaction>()?;
|
||||
|
||||
let value = hex::decode("2f6e04963b4c0100")?.zcash_deserialize_into::<Amount<_>>()?;
|
||||
let lock_script = Script::new(&hex::decode("53")?);
|
||||
let input_ind = 1;
|
||||
|
||||
let hasher = SigHasher::new(
|
||||
&transaction,
|
||||
HashType::SINGLE,
|
||||
NetworkUpgrade::Overwinter,
|
||||
Some((input_ind, transparent::Output { value, lock_script })),
|
||||
);
|
||||
|
||||
assert_hash_eq!("03000080", hasher, hash_header);
|
||||
|
||||
assert_hash_eq!("7082c403", hasher, hash_groupid);
|
||||
|
||||
assert_hash_eq!(
|
||||
"92b8af1f7e12cb8de105af154470a2ae0a11e64a24a514a562ff943ca0f35d7f",
|
||||
hasher,
|
||||
hash_prevouts
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_sequence
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"edc32cce530f836f7c31c53656f859f514c3ff8dcae642d3e17700fdc6e829a4",
|
||||
hasher,
|
||||
hash_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"f59e41b40f3a60be90bee2be11b0956dfff06a6d8e22668c4f215bd87b20d514",
|
||||
hasher,
|
||||
hash_joinsplits
|
||||
);
|
||||
|
||||
assert_hash_eq!("97b0e4e4", hasher, hash_lock_time);
|
||||
|
||||
assert_hash_eq!("c705fc05", hasher, hash_expiry_height);
|
||||
|
||||
assert_hash_eq!("03000000", hasher, hash_hash_type);
|
||||
|
||||
assert_hash_eq!(
|
||||
"378af1e40f64e125946f62c2fa7b2fecbcb64b6968912a6381ce3dc166d56a1d62f5a8d7",
|
||||
hasher,
|
||||
hash_input_prevout
|
||||
);
|
||||
|
||||
assert_hash_eq!("0153", hasher, hash_input_script_code);
|
||||
|
||||
assert_hash_eq!("2f6e04963b4c0100", hasher, hash_input_amount);
|
||||
|
||||
assert_hash_eq!("e8c7203d", hasher, hash_input_sequence);
|
||||
|
||||
let hash = hasher.sighash();
|
||||
let expected = "23652e76cb13b85a0e3363bb5fca061fa791c40c533eccee899364e6e60bb4f7";
|
||||
let result: &[u8] = hash.as_ref();
|
||||
let result = hex::encode(result);
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_final",
|
||||
expected.len = expected.len(),
|
||||
buf.len = result.len()
|
||||
);
|
||||
let _guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec243_1() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
let transaction = ZIP243_1.zcash_deserialize_into::<Transaction>()?;
|
||||
|
||||
let hasher = SigHasher::new(&transaction, HashType::ALL, NetworkUpgrade::Sapling, None);
|
||||
|
||||
assert_hash_eq!("04000080", hasher, hash_header);
|
||||
|
||||
assert_hash_eq!("85202f89", hasher, hash_groupid);
|
||||
|
||||
assert_hash_eq!(
|
||||
"d53a633bbecf82fe9e9484d8a0e727c73bb9e68c96e72dec30144f6a84afa136",
|
||||
hasher,
|
||||
hash_prevouts
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"a5f25f01959361ee6eb56a7401210ee268226f6ce764a4f10b7f29e54db37272",
|
||||
hasher,
|
||||
hash_sequence
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"ab6f7f6c5ad6b56357b5f37e16981723db6c32411753e28c175e15589172194a",
|
||||
hasher,
|
||||
hash_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_joinsplits
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"3fd9edb96dccf5b9aeb71e3db3710e74be4f1dfb19234c1217af26181f494a36",
|
||||
hasher,
|
||||
hash_shielded_spends
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"dafece799f638ba7268bf8fe43f02a5112f0bb32a84c4a8c2f508c41ff1c78b5",
|
||||
hasher,
|
||||
hash_shielded_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!("481cdd86", hasher, hash_lock_time);
|
||||
|
||||
assert_hash_eq!("b3cc4318", hasher, hash_expiry_height);
|
||||
|
||||
assert_hash_eq!("442117623ceb0500", hasher, hash_value_balance);
|
||||
|
||||
assert_hash_eq!("01000000", hasher, hash_hash_type);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0400008085202f89d53a633bbecf82fe9e9484d8a0e727c73bb9e68c96e72dec30144f6a84afa136a5f25f01959361ee6eb56a7401210ee268226f6ce764a4f10b7f29e54db37272ab6f7f6c5ad6b56357b5f37e16981723db6c32411753e28c175e15589172194a00000000000000000000000000000000000000000000000000000000000000003fd9edb96dccf5b9aeb71e3db3710e74be4f1dfb19234c1217af26181f494a36dafece799f638ba7268bf8fe43f02a5112f0bb32a84c4a8c2f508c41ff1c78b5481cdd86b3cc4318442117623ceb050001000000",
|
||||
hasher,
|
||||
hash_sighash_zip243
|
||||
);
|
||||
|
||||
let hash = hasher.sighash();
|
||||
let expected = "63d18534de5f2d1c9e169b73f9c783718adbef5c8a7d55b5e7a37affa1dd3ff3";
|
||||
let result = hex::encode(hash);
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_final",
|
||||
expected.len = expected.len(),
|
||||
buf.len = result.len()
|
||||
);
|
||||
let _guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
|
||||
let alt_sighash = crate::primitives::zcash_primitives::sighash(
|
||||
&transaction,
|
||||
HashType::ALL,
|
||||
NetworkUpgrade::Sapling,
|
||||
None,
|
||||
);
|
||||
let result = hex::encode(alt_sighash);
|
||||
assert_eq!(expected, result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec243_2() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
let transaction = ZIP243_2.zcash_deserialize_into::<Transaction>()?;
|
||||
|
||||
let value = hex::decode("adedf02996510200")?.zcash_deserialize_into::<Amount<_>>()?;
|
||||
let lock_script = Script::new(&[]);
|
||||
let input_ind = 1;
|
||||
|
||||
let hasher = SigHasher::new(
|
||||
&transaction,
|
||||
HashType::NONE,
|
||||
NetworkUpgrade::Sapling,
|
||||
Some((input_ind, transparent::Output { value, lock_script })),
|
||||
);
|
||||
|
||||
assert_hash_eq!("04000080", hasher, hash_header);
|
||||
|
||||
assert_hash_eq!("85202f89", hasher, hash_groupid);
|
||||
|
||||
assert_hash_eq!(
|
||||
"cacf0f5210cce5fa65a59f314292b3111d299e7d9d582753cf61e1e408552ae4",
|
||||
hasher,
|
||||
hash_prevouts
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_sequence
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_joinsplits
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_shielded_spends
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"b79530fcec83211d21e3c355db538c138d625784c27370e9d1039a8515a23f87",
|
||||
hasher,
|
||||
hash_shielded_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!("d7034302", hasher, hash_lock_time);
|
||||
|
||||
assert_hash_eq!("011b9a07", hasher, hash_expiry_height);
|
||||
|
||||
assert_hash_eq!("6620edc067ff0200", hasher, hash_value_balance);
|
||||
|
||||
assert_hash_eq!("02000000", hasher, hash_hash_type);
|
||||
|
||||
assert_hash_eq!(
|
||||
"090f47a068e227433f9e49d3aa09e356d8d66d0c0121e91a3c4aa3f27fa1b63396e2b41d",
|
||||
hasher,
|
||||
hash_input_prevout
|
||||
);
|
||||
|
||||
assert_hash_eq!("00", hasher, hash_input_script_code);
|
||||
|
||||
assert_hash_eq!("adedf02996510200", hasher, hash_input_amount);
|
||||
|
||||
assert_hash_eq!("4e970568", hasher, hash_input_sequence);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0400008085202f89cacf0f5210cce5fa65a59f314292b3111d299e7d9d582753cf61e1e408552ae40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b79530fcec83211d21e3c355db538c138d625784c27370e9d1039a8515a23f87d7034302011b9a076620edc067ff020002000000090f47a068e227433f9e49d3aa09e356d8d66d0c0121e91a3c4aa3f27fa1b63396e2b41d00adedf029965102004e970568",
|
||||
hasher,
|
||||
hash_sighash_zip243
|
||||
);
|
||||
|
||||
let hash = hasher.sighash();
|
||||
let expected = "bbe6d84f57c56b29b914c694baaccb891297e961de3eb46c68e3c89c47b1a1db";
|
||||
let result = hex::encode(hash);
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_final",
|
||||
expected.len = expected.len(),
|
||||
buf.len = result.len()
|
||||
);
|
||||
let _guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
|
||||
let lock_script = Script::new(&[]);
|
||||
let prevout = transparent::Output { value, lock_script };
|
||||
let index = input_ind as usize;
|
||||
let inputs = transaction.inputs();
|
||||
let input = Some((&prevout, &inputs[index], index));
|
||||
|
||||
let alt_sighash = crate::primitives::zcash_primitives::sighash(
|
||||
&transaction,
|
||||
HashType::NONE,
|
||||
NetworkUpgrade::Sapling,
|
||||
input,
|
||||
);
|
||||
let result = hex::encode(alt_sighash);
|
||||
assert_eq!(expected, result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_vec243_3() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
let transaction = ZIP243_3.zcash_deserialize_into::<Transaction>()?;
|
||||
|
||||
let value = hex::decode("80f0fa0200000000")?.zcash_deserialize_into::<Amount<_>>()?;
|
||||
let lock_script = Script::new(&hex::decode(
|
||||
"76a914507173527b4c3318a2aecd793bf1cfed705950cf88ac",
|
||||
)?);
|
||||
let input_ind = 0;
|
||||
|
||||
let hasher = SigHasher::new(
|
||||
&transaction,
|
||||
HashType::ALL,
|
||||
NetworkUpgrade::Sapling,
|
||||
Some((input_ind, transparent::Output { value, lock_script })),
|
||||
);
|
||||
|
||||
assert_hash_eq!("04000080", hasher, hash_header);
|
||||
|
||||
assert_hash_eq!("85202f89", hasher, hash_groupid);
|
||||
|
||||
assert_hash_eq!(
|
||||
"fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f11",
|
||||
hasher,
|
||||
hash_prevouts
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"6c80d37f12d89b6f17ff198723e7db1247c4811d1a695d74d930f99e98418790",
|
||||
hasher,
|
||||
hash_sequence
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"d2b04118469b7810a0d1cc59568320aad25a84f407ecac40b4f605a4e6868454",
|
||||
hasher,
|
||||
hash_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_joinsplits
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_shielded_spends
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0000000000000000000000000000000000000000000000000000000000000000",
|
||||
hasher,
|
||||
hash_shielded_outputs
|
||||
);
|
||||
|
||||
assert_hash_eq!("29b00400", hasher, hash_lock_time);
|
||||
|
||||
assert_hash_eq!("48b00400", hasher, hash_expiry_height);
|
||||
|
||||
assert_hash_eq!("0000000000000000", hasher, hash_value_balance);
|
||||
|
||||
assert_hash_eq!("01000000", hasher, hash_hash_type);
|
||||
|
||||
assert_hash_eq!(
|
||||
"a8c685478265f4c14dada651969c45a65e1aeb8cd6791f2f5bb6a1d9952104d901000000",
|
||||
hasher,
|
||||
hash_input_prevout
|
||||
);
|
||||
|
||||
assert_hash_eq!(
|
||||
"1976a914507173527b4c3318a2aecd793bf1cfed705950cf88ac",
|
||||
hasher,
|
||||
hash_input_script_code
|
||||
);
|
||||
|
||||
assert_hash_eq!("80f0fa0200000000", hasher, hash_input_amount);
|
||||
|
||||
assert_hash_eq!("feffffff", hasher, hash_input_sequence);
|
||||
|
||||
assert_hash_eq!(
|
||||
"0400008085202f89fae31b8dec7b0b77e2c8d6b6eb0e7e4e55abc6574c26dd44464d9408a8e33f116c80d37f12d89b6f17ff198723e7db1247c4811d1a695d74d930f99e98418790d2b04118469b7810a0d1cc59568320aad25a84f407ecac40b4f605a4e686845400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000029b0040048b00400000000000000000001000000a8c685478265f4c14dada651969c45a65e1aeb8cd6791f2f5bb6a1d9952104d9010000001976a914507173527b4c3318a2aecd793bf1cfed705950cf88ac80f0fa0200000000feffffff",
|
||||
hasher,
|
||||
hash_sighash_zip243
|
||||
);
|
||||
|
||||
let hash = hasher.sighash();
|
||||
let expected = "f3148f80dfab5e573d5edfe7a850f5fd39234f80b5429d3a57edcc11e34c585b";
|
||||
let result = hex::encode(hash);
|
||||
let span = tracing::span!(
|
||||
tracing::Level::ERROR,
|
||||
"compare_final",
|
||||
expected.len = expected.len(),
|
||||
buf.len = result.len()
|
||||
);
|
||||
let _guard = span.enter();
|
||||
assert_eq!(expected, result);
|
||||
|
||||
let lock_script = Script::new(&hex::decode(
|
||||
"76a914507173527b4c3318a2aecd793bf1cfed705950cf88ac",
|
||||
)?);
|
||||
let prevout = transparent::Output { value, lock_script };
|
||||
let index = input_ind as usize;
|
||||
let inputs = transaction.inputs();
|
||||
let input = Some((&prevout, &inputs[index], index));
|
||||
|
||||
let alt_sighash = crate::primitives::zcash_primitives::sighash(
|
||||
&transaction,
|
||||
HashType::ALL,
|
||||
NetworkUpgrade::Sapling,
|
||||
input,
|
||||
);
|
||||
let result = hex::encode(alt_sighash);
|
||||
assert_eq!(expected, result);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn zip244_sighash() -> Result<()> {
|
||||
zebra_test::init();
|
||||
|
||||
for (i, test) in zip0244::TEST_VECTORS.iter().enumerate() {
|
||||
let transaction = test.tx.zcash_deserialize_into::<Transaction>()?;
|
||||
let input = match test.amount {
|
||||
Some(amount) => Some((
|
||||
test.transparent_input
|
||||
.expect("test vector must have transparent_input when it has amount"),
|
||||
transparent::Output {
|
||||
value: amount.try_into()?,
|
||||
lock_script: transparent::Script::new(
|
||||
test.script_code
|
||||
.as_ref()
|
||||
.expect("test vector must have script_code when it has amount"),
|
||||
),
|
||||
},
|
||||
)),
|
||||
None => None,
|
||||
};
|
||||
let result = hex::encode(transaction.sighash(NetworkUpgrade::Nu5, HashType::ALL, input));
|
||||
let expected = hex::encode(test.sighash_all);
|
||||
assert_eq!(expected, result, "test #{}: sighash does not match", i);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Use librustzcash to compute sighashes and compare with zebra sighashes.
|
||||
#[test]
|
||||
fn librustzcash_sighash() {
|
||||
zebra_test::init();
|
||||
|
||||
librustzcash_sighash_for_network(Network::Mainnet);
|
||||
librustzcash_sighash_for_network(Network::Testnet);
|
||||
}
|
||||
|
||||
fn librustzcash_sighash_for_network(network: Network) {
|
||||
let block_iter = match network {
|
||||
Network::Mainnet => zebra_test::vectors::MAINNET_BLOCKS.iter(),
|
||||
Network::Testnet => zebra_test::vectors::TESTNET_BLOCKS.iter(),
|
||||
};
|
||||
|
||||
for (height, original_bytes) in block_iter {
|
||||
let original_block = original_bytes
|
||||
.zcash_deserialize_into::<Block>()
|
||||
.expect("block is structurally valid");
|
||||
|
||||
// skip blocks that are before overwinter as they will not have a valid consensus branch id
|
||||
if *height
|
||||
< NetworkUpgrade::Overwinter
|
||||
.activation_height(network)
|
||||
.expect("a valid height")
|
||||
.0
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let network_upgrade = NetworkUpgrade::current(network, Height(*height));
|
||||
|
||||
// Test each transaction. Skip the coinbase transaction
|
||||
for original_tx in original_block.transactions.iter().skip(1) {
|
||||
let original_sighash = original_tx.sighash(network_upgrade, HashType::ALL, None);
|
||||
|
||||
let alt_sighash = crate::primitives::zcash_primitives::sighash(
|
||||
original_tx,
|
||||
HashType::ALL,
|
||||
network_upgrade,
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(original_sighash, alt_sighash);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -19,7 +19,7 @@ use zebra_chain::{
|
|||
parameters::{Network, NetworkUpgrade},
|
||||
primitives::Groth16Proof,
|
||||
sapling,
|
||||
transaction::{self, HashType, Transaction},
|
||||
transaction::{self, HashType, SigHash, Transaction},
|
||||
transparent,
|
||||
};
|
||||
|
||||
|
@ -398,7 +398,7 @@ where
|
|||
/// Verifies a transaction's Sprout shielded join split data.
|
||||
fn verify_sprout_shielded_data(
|
||||
joinsplit_data: &Option<transaction::JoinSplitData<Groth16Proof>>,
|
||||
shielded_sighash: &blake2b_simd::Hash,
|
||||
shielded_sighash: &SigHash,
|
||||
) -> AsyncChecks {
|
||||
let mut checks = AsyncChecks::new();
|
||||
|
||||
|
@ -434,7 +434,7 @@ where
|
|||
/// Verifies a transaction's Sapling shielded data.
|
||||
fn verify_sapling_shielded_data<A>(
|
||||
sapling_shielded_data: &Option<sapling::ShieldedData<A>>,
|
||||
shielded_sighash: &blake2b_simd::Hash,
|
||||
shielded_sighash: &SigHash,
|
||||
) -> Result<AsyncChecks, TransactionError>
|
||||
where
|
||||
A: sapling::AnchorVariant + Clone,
|
||||
|
|
|
@ -620,7 +620,7 @@ fn v4_with_signed_sprout_transfer_is_accepted() {
|
|||
Transaction::V4 {
|
||||
joinsplit_data: Some(joinsplit_data),
|
||||
..
|
||||
} => joinsplit_data.sig = signing_key.sign(sighash.as_bytes()),
|
||||
} => joinsplit_data.sig = signing_key.sign(sighash.as_ref()),
|
||||
_ => unreachable!("Mock transaction was created incorrectly"),
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@ pub struct TestVector {
|
|||
pub tx: Vec<u8>,
|
||||
/// The expected transaction ID.
|
||||
pub txid: [u8; 32],
|
||||
/// The expected auth digest.
|
||||
pub auth_digest: [u8; 32],
|
||||
/// Which transparent input the ID refers to, if any.
|
||||
pub transparent_input: Option<u32>,
|
||||
/// The script code for the given transparent input, if any.
|
||||
|
@ -288,6 +290,11 @@ lazy_static! {
|
|||
0x8b, 0x3c, 0x87, 0xc7, 0x4a, 0x2a, 0x63, 0xa2, 0x89, 0xd3, 0x00, 0x05, 0xda, 0xd6,
|
||||
0x98, 0x3d, 0x95, 0x44,
|
||||
],
|
||||
auth_digest: [
|
||||
0x1c, 0xbb, 0xe0, 0xd7, 0x25, 0x4c, 0xa6, 0x52, 0xcd, 0xda, 0xa7, 0xa9, 0xd2, 0x91,
|
||||
0x5a, 0x60, 0x9e, 0x35, 0x73, 0xc0, 0x3d, 0x27, 0x05, 0xe9, 0xad, 0xd4, 0xe3, 0x2e,
|
||||
0xec, 0x0d, 0x76, 0x9e,
|
||||
],
|
||||
transparent_input: Some(0),
|
||||
script_code: Some(vec![0x65, 0x00, 0x51]),
|
||||
amount: Some(570688904498311),
|
||||
|
@ -459,6 +466,11 @@ lazy_static! {
|
|||
0xa5, 0xe4, 0xfc, 0xb7, 0xbf, 0xa7, 0xda, 0x79, 0x29, 0xbf, 0xb7, 0x31, 0xac, 0x10,
|
||||
0xa5, 0x8a, 0xb0, 0x03,
|
||||
],
|
||||
auth_digest: [
|
||||
0x64, 0xed, 0x51, 0x50, 0x16, 0x96, 0xf1, 0x14, 0x32, 0xb8, 0xa1, 0xe2, 0xe6, 0x87,
|
||||
0xb8, 0x9e, 0x61, 0x25, 0x97, 0xfd, 0x47, 0x49, 0xf9, 0x2c, 0x0f, 0x5f, 0x51, 0x71,
|
||||
0xfc, 0xad, 0x78, 0xbe,
|
||||
],
|
||||
transparent_input: None,
|
||||
script_code: None,
|
||||
amount: None,
|
||||
|
@ -483,6 +495,11 @@ lazy_static! {
|
|||
0xf9, 0x57, 0x6a, 0xb7, 0x6b, 0xff, 0xc7, 0x1b, 0xcd, 0x98, 0x5b, 0x62, 0xdd, 0xd6,
|
||||
0x9d, 0x29, 0x97, 0xcd,
|
||||
],
|
||||
auth_digest: [
|
||||
0x04, 0xda, 0x78, 0xb6, 0x64, 0x11, 0x1d, 0xe8, 0xe4, 0xfc, 0xfc, 0x14, 0x93, 0x3d,
|
||||
0x79, 0xf6, 0xd9, 0x60, 0xda, 0xd8, 0xf1, 0x08, 0xf1, 0xe0, 0xb4, 0x26, 0xcc, 0x20,
|
||||
0x36, 0x29, 0x22, 0xed,
|
||||
],
|
||||
transparent_input: None,
|
||||
script_code: None,
|
||||
amount: None,
|
||||
|
@ -508,6 +525,11 @@ lazy_static! {
|
|||
0xe3, 0x4f, 0xd5, 0xf9, 0xc7, 0x9c, 0x9f, 0x78, 0xdc, 0x65, 0x05, 0x1a, 0x9a, 0x14,
|
||||
0xca, 0xc2, 0xb1, 0xbf,
|
||||
],
|
||||
auth_digest: [
|
||||
0x04, 0xda, 0x78, 0xb6, 0x64, 0x11, 0x1d, 0xe8, 0xe4, 0xfc, 0xfc, 0x14, 0x93, 0x3d,
|
||||
0x79, 0xf6, 0xd9, 0x60, 0xda, 0xd8, 0xf1, 0x08, 0xf1, 0xe0, 0xb4, 0x26, 0xcc, 0x20,
|
||||
0x36, 0x29, 0x22, 0xed,
|
||||
],
|
||||
transparent_input: None,
|
||||
script_code: None,
|
||||
amount: None,
|
||||
|
@ -544,6 +566,11 @@ lazy_static! {
|
|||
0x90, 0x93, 0x03, 0xd4, 0x58, 0x0e, 0x72, 0x3a, 0xd3, 0x16, 0x2c, 0x06, 0x09, 0x66,
|
||||
0x48, 0xa2, 0x5b, 0x1e,
|
||||
],
|
||||
auth_digest: [
|
||||
0x9e, 0x7c, 0x68, 0x39, 0xb3, 0x1f, 0xb3, 0xe9, 0x12, 0xb6, 0x93, 0xd1, 0x87, 0x9f,
|
||||
0xbb, 0xad, 0xdb, 0xe7, 0xa7, 0x4a, 0x50, 0x8e, 0x7b, 0x6d, 0x1f, 0xe1, 0x93, 0x82,
|
||||
0x68, 0xc0, 0x4a, 0xb3,
|
||||
],
|
||||
transparent_input: Some(1),
|
||||
script_code: Some(vec![0xac, 0x00, 0x00]),
|
||||
amount: Some(693972628630138),
|
||||
|
@ -800,6 +827,11 @@ lazy_static! {
|
|||
0x1f, 0x14, 0x12, 0xe3, 0x8f, 0x89, 0x13, 0x07, 0x52, 0x80, 0xcd, 0x2b, 0x38, 0x02,
|
||||
0xf5, 0xb2, 0x70, 0x4e,
|
||||
],
|
||||
auth_digest: [
|
||||
0xee, 0x3a, 0x4a, 0x6d, 0xd3, 0x89, 0xf2, 0x81, 0xb6, 0xd6, 0xe3, 0xd8, 0xe0, 0xf7,
|
||||
0x97, 0xa3, 0xd4, 0xfa, 0x01, 0x4e, 0x3f, 0x41, 0x6a, 0x0e, 0x47, 0x68, 0x4f, 0x76,
|
||||
0x02, 0x15, 0x44, 0x58,
|
||||
],
|
||||
transparent_input: None,
|
||||
script_code: None,
|
||||
amount: None,
|
||||
|
@ -831,6 +863,11 @@ lazy_static! {
|
|||
0xbc, 0xdf, 0x2d, 0x35, 0xd0, 0x13, 0x55, 0x80, 0x4b, 0xf0, 0xe3, 0xee, 0x1b, 0x17,
|
||||
0xde, 0x9e, 0x46, 0xcd,
|
||||
],
|
||||
auth_digest: [
|
||||
0x2c, 0xbe, 0xf7, 0x5b, 0x3e, 0x2c, 0xff, 0x88, 0xb6, 0xf1, 0x20, 0xbf, 0x70, 0xcb,
|
||||
0x3e, 0xc7, 0x57, 0xec, 0x25, 0xd3, 0x11, 0xfa, 0xca, 0xfd, 0xfe, 0x2d, 0xb4, 0x2e,
|
||||
0xd3, 0x42, 0x04, 0x0f,
|
||||
],
|
||||
transparent_input: Some(0),
|
||||
script_code: Some(vec![0x63, 0x52, 0x51, 0x63, 0x53]),
|
||||
amount: Some(107504874564564),
|
||||
|
@ -1092,6 +1129,11 @@ lazy_static! {
|
|||
0x2a, 0xd9, 0x06, 0x50, 0x34, 0x22, 0x5d, 0xad, 0x9c, 0x89, 0xbf, 0xcb, 0x73, 0x32,
|
||||
0x8d, 0x3d, 0x4f, 0xe6,
|
||||
],
|
||||
auth_digest: [
|
||||
0xbb, 0x48, 0xcf, 0x27, 0x71, 0x54, 0x6c, 0x2c, 0x15, 0x57, 0x7d, 0xb2, 0x0d, 0x04,
|
||||
0x86, 0x5a, 0x8c, 0xc0, 0x0c, 0x9c, 0x02, 0xec, 0xb3, 0x10, 0x24, 0x94, 0x31, 0x0f,
|
||||
0x18, 0x68, 0x50, 0xcf,
|
||||
],
|
||||
transparent_input: None,
|
||||
script_code: None,
|
||||
amount: None,
|
||||
|
@ -1200,6 +1242,11 @@ lazy_static! {
|
|||
0x01, 0x54, 0xeb, 0x2d, 0xeb, 0x76, 0x78, 0x74, 0xa3, 0x1b, 0x5d, 0x10, 0xaa, 0xf7,
|
||||
0x6b, 0xa8, 0x4f, 0xae,
|
||||
],
|
||||
auth_digest: [
|
||||
0xf1, 0x58, 0x29, 0x64, 0xb8, 0xc9, 0xec, 0x20, 0x29, 0xab, 0x97, 0xa2, 0x55, 0x98,
|
||||
0xdb, 0xff, 0x28, 0x35, 0x23, 0xe6, 0xf3, 0x7a, 0xdb, 0x19, 0xcc, 0x57, 0x69, 0xb5,
|
||||
0x13, 0xc7, 0x33, 0xc0,
|
||||
],
|
||||
transparent_input: None,
|
||||
script_code: None,
|
||||
amount: None,
|
||||
|
@ -1497,6 +1544,11 @@ lazy_static! {
|
|||
0xde, 0x07, 0x15, 0x27, 0x5d, 0x15, 0x6c, 0xda, 0xb9, 0x6f, 0x68, 0xdc, 0x70, 0x10,
|
||||
0x58, 0x3b, 0x02, 0xaa,
|
||||
],
|
||||
auth_digest: [
|
||||
0x87, 0x46, 0xc9, 0x9d, 0x98, 0x57, 0x86, 0xb1, 0xb7, 0x7c, 0x40, 0x5f, 0x6e, 0xe8,
|
||||
0x31, 0xe2, 0x98, 0x71, 0xca, 0x9d, 0x68, 0xe7, 0x72, 0x4f, 0xb7, 0xf8, 0x78, 0x6f,
|
||||
0x28, 0x18, 0x42, 0xa6,
|
||||
],
|
||||
transparent_input: Some(0),
|
||||
script_code: Some(vec![]),
|
||||
amount: Some(1405243945822387),
|
||||
|
|
Loading…
Reference in New Issue