1//! Signature hashes for Zcash transactions
23use std::sync::Arc;
45use zcash_transparent::sighash::SighashType;
67use super::Transaction;
89use crate::parameters::NetworkUpgrade;
10use crate::{transparent, Error};
1112use crate::primitives::zcash_primitives::{sighash, PrecomputedTxData};
1314bitflags::bitflags! {
15/// The different SigHash types, as defined in <https://zips.z.cash/zip-0143>
16#[derive(Copy, Clone, Debug, PartialEq, Eq)]
17pub struct HashType: u32 {
18/// Sign all the outputs
19const ALL = 0b0000_0001;
20/// Sign none of the outputs - anyone can spend
21const NONE = 0b0000_0010;
22/// Sign one of the outputs - anyone can spend the rest
23const SINGLE = Self::ALL.bits() | Self::NONE.bits();
24/// Anyone can add inputs to this transaction
25const ANYONECANPAY = 0b1000_0000;
2627/// Sign all the outputs and Anyone can add inputs to this transaction
28const ALL_ANYONECANPAY = Self::ALL.bits() | Self::ANYONECANPAY.bits();
29/// Sign none of the outputs and Anyone can add inputs to this transaction
30const NONE_ANYONECANPAY = Self::NONE.bits() | Self::ANYONECANPAY.bits();
31/// Sign one of the outputs and Anyone can add inputs to this transaction
32const SINGLE_ANYONECANPAY = Self::SINGLE.bits() | Self::ANYONECANPAY.bits();
33 }
34}
3536impl TryFrom<HashType> for SighashType {
37type Error = ();
3839fn try_from(hash_type: HashType) -> Result<Self, Self::Error> {
40Ok(match hash_type {
41 HashType::ALL => Self::ALL,
42 HashType::NONE => Self::NONE,
43 HashType::SINGLE => Self::SINGLE,
44 HashType::ALL_ANYONECANPAY => Self::ALL_ANYONECANPAY,
45 HashType::NONE_ANYONECANPAY => Self::NONE_ANYONECANPAY,
46 HashType::SINGLE_ANYONECANPAY => Self::SINGLE_ANYONECANPAY,
47 _other => return Err(()),
48 })
49 }
50}
5152/// A Signature Hash (or SIGHASH) as specified in
53/// <https://zips.z.cash/protocol/protocol.pdf#sighash>
54#[derive(Copy, Clone, Eq, PartialEq, Debug)]
55pub struct SigHash(pub [u8; 32]);
5657impl AsRef<[u8; 32]> for SigHash {
58fn as_ref(&self) -> &[u8; 32] {
59&self.0
60}
61}
6263impl AsRef<[u8]> for SigHash {
64fn as_ref(&self) -> &[u8] {
65&self.0
66}
67}
6869/// A SigHasher context which stores precomputed data that is reused
70/// between sighash computations for the same transaction.
71#[derive(Debug)]
72pub struct SigHasher {
73 precomputed_tx_data: PrecomputedTxData,
74}
7576impl SigHasher {
77/// Create a new SigHasher for the given transaction.
78 ///
79 /// # Panics
80 ///
81 /// - If `trans` can't be converted to its `librustzcash` equivalent. This could happen, for
82 /// example, if `trans` contains the `nConsensusBranchId` field, and `nu` doesn't match it.
83 /// More details in [`PrecomputedTxData::new`].
84 /// - If `nu` doesn't contain a consensus branch id convertible to its `librustzcash`
85 /// equivalent.
86pub fn new(
87 trans: &Transaction,
88 nu: NetworkUpgrade,
89 all_previous_outputs: Arc<Vec<transparent::Output>>,
90 ) -> Result<Self, Error> {
91Ok(SigHasher {
92 precomputed_tx_data: PrecomputedTxData::new(trans, nu, all_previous_outputs)?,
93 })
94 }
9596/// Calculate the sighash for the current transaction.
97 ///
98 /// # Details
99 ///
100 /// The `input_index_script_code` tuple indicates the index of the
101 /// transparent Input for which we are producing a sighash and the
102 /// respective script code being validated, or None if it's a shielded
103 /// input.
104 ///
105 /// # Panics
106 ///
107 /// - if the input index is out of bounds for self.inputs()
108pub fn sighash(
109&self,
110 hash_type: HashType,
111 input_index_script_code: Option<(usize, Vec<u8>)>,
112 ) -> SigHash {
113 sighash(
114&self.precomputed_tx_data,
115 hash_type,
116 input_index_script_code,
117 )
118 }
119}