1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
//! Signature hashes for Zcash transactions
use std::sync::Arc;
use zcash_protocol::value::ZatBalance;
use zcash_transparent::sighash::SighashType;
use super::Transaction;
use crate::parameters::NetworkUpgrade;
use crate::{transparent, Error};
use crate::primitives::zcash_primitives::{sighash, sighash_v4_raw, PrecomputedTxData};
bitflags::bitflags! {
/// The different SigHash types, as defined in <https://zips.z.cash/zip-0143>
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub struct HashType: u32 {
/// Sign all the outputs
const ALL = 0b0000_0001;
/// Sign none of the outputs - anyone can spend
const NONE = 0b0000_0010;
/// Sign one of the outputs - anyone can spend the rest
const SINGLE = Self::ALL.bits() | Self::NONE.bits();
/// Anyone can add inputs to this transaction
const ANYONECANPAY = 0b1000_0000;
/// Sign all the outputs and Anyone can add inputs to this transaction
const ALL_ANYONECANPAY = Self::ALL.bits() | Self::ANYONECANPAY.bits();
/// Sign none of the outputs and Anyone can add inputs to this transaction
const NONE_ANYONECANPAY = Self::NONE.bits() | Self::ANYONECANPAY.bits();
/// Sign one of the outputs and Anyone can add inputs to this transaction
const SINGLE_ANYONECANPAY = Self::SINGLE.bits() | Self::ANYONECANPAY.bits();
}
}
impl TryFrom<HashType> for SighashType {
type Error = ();
fn try_from(hash_type: HashType) -> Result<Self, Self::Error> {
Ok(match hash_type {
HashType::ALL => Self::ALL,
HashType::NONE => Self::NONE,
HashType::SINGLE => Self::SINGLE,
HashType::ALL_ANYONECANPAY => Self::ALL_ANYONECANPAY,
HashType::NONE_ANYONECANPAY => Self::NONE_ANYONECANPAY,
HashType::SINGLE_ANYONECANPAY => Self::SINGLE_ANYONECANPAY,
_other => return Err(()),
})
}
}
/// 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
}
}
impl From<SigHash> for [u8; 32] {
fn from(sighash: SigHash) -> Self {
sighash.0
}
}
/// A SigHasher context which stores precomputed data that is reused
/// between sighash computations for the same transaction.
#[derive(Debug)]
pub struct SigHasher {
precomputed_tx_data: PrecomputedTxData,
}
impl SigHasher {
/// Create a new SigHasher for the given transaction.
///
/// # Panics
///
/// - If `trans` can't be converted to its `librustzcash` equivalent. This could happen, for
/// example, if `trans` contains the `nConsensusBranchId` field, and `nu` doesn't match it.
/// More details in [`PrecomputedTxData::new`].
/// - If `nu` doesn't contain a consensus branch id convertible to its `librustzcash`
/// equivalent.
pub fn new(
trans: &Transaction,
nu: NetworkUpgrade,
all_previous_outputs: Arc<Vec<transparent::Output>>,
) -> Result<Self, Error> {
Ok(SigHasher {
precomputed_tx_data: PrecomputedTxData::new(trans, nu, all_previous_outputs)?,
})
}
/// Calculate the sighash for the current transaction.
///
/// # Details
///
/// The `input_index_script_code` tuple indicates the index of the
/// transparent Input for which we are producing a sighash and the
/// respective script code being validated, or None if it's a shielded
/// input.
///
/// # Panics
///
/// - if the input index is out of bounds for self.inputs()
pub fn sighash(
&self,
hash_type: HashType,
input_index_script_code: Option<(usize, Vec<u8>)>,
) -> SigHash {
sighash(
&self.precomputed_tx_data,
hash_type,
input_index_script_code,
)
}
/// Calculate the sighash for the current pre-V5 (V4) transaction using the
/// raw `hash_type` byte taken directly from the signature.
///
/// This preserves non-canonical bits (e.g. `0x41`) in the preimage so that
/// the resulting digest matches `zcashd`'s pre-V5 sighash semantics.
/// Callers handling V5+ transactions must use [`SigHasher::sighash`].
pub fn sighash_v4_raw(
&self,
raw_hash_type: u8,
input_index_script_code: Option<(usize, Vec<u8>)>,
) -> SigHash {
sighash_v4_raw(
&self.precomputed_tx_data,
raw_hash_type,
input_index_script_code,
)
}
/// Returns the Orchard bundle in the precomputed transaction data.
pub fn orchard_bundle(
&self,
) -> Option<::orchard::bundle::Bundle<::orchard::bundle::Authorized, ZatBalance>> {
self.precomputed_tx_data.orchard_bundle()
}
/// Returns the Sapling bundle in the precomputed transaction data.
pub fn sapling_bundle(
&self,
) -> Option<sapling_crypto::Bundle<sapling_crypto::bundle::Authorized, ZatBalance>> {
self.precomputed_tx_data.sapling_bundle()
}
}