zebra_chain/transaction/
sighash.rs

1//! Signature hashes for Zcash transactions
2
3use super::Transaction;
4
5use crate::parameters::NetworkUpgrade;
6use crate::transparent;
7
8use crate::primitives::zcash_primitives::{sighash, PrecomputedTxData};
9
10bitflags::bitflags! {
11    /// The different SigHash types, as defined in <https://zips.z.cash/zip-0143>
12    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
13    pub struct HashType: u32 {
14        /// Sign all the outputs
15        const ALL = 0b0000_0001;
16        /// Sign none of the outputs - anyone can spend
17        const NONE = 0b0000_0010;
18        /// Sign one of the outputs - anyone can spend the rest
19        const SINGLE = Self::ALL.bits() | Self::NONE.bits();
20        /// Anyone can add inputs to this transaction
21        const ANYONECANPAY = 0b1000_0000;
22    }
23}
24
25/// A Signature Hash (or SIGHASH) as specified in
26/// <https://zips.z.cash/protocol/protocol.pdf#sighash>
27#[derive(Copy, Clone, Eq, PartialEq, Debug)]
28pub struct SigHash(pub [u8; 32]);
29
30impl AsRef<[u8; 32]> for SigHash {
31    fn as_ref(&self) -> &[u8; 32] {
32        &self.0
33    }
34}
35
36impl AsRef<[u8]> for SigHash {
37    fn as_ref(&self) -> &[u8] {
38        &self.0
39    }
40}
41
42/// A SigHasher context which stores precomputed data that is reused
43/// between sighash computations for the same transaction.
44#[derive(Debug)]
45pub struct SigHasher<'a> {
46    precomputed_tx_data: PrecomputedTxData<'a>,
47}
48
49impl<'a> SigHasher<'a> {
50    /// Create a new SigHasher for the given transaction.
51    ///
52    /// # Panics
53    ///
54    /// - If `trans` can't be converted to its `librustzcash` equivalent. This could happen, for
55    ///   example, if `trans` contains the `nConsensusBranchId` field, and `nu` doesn't match it.
56    ///   More details in [`PrecomputedTxData::new`].
57    /// - If `nu` doesn't contain a consensus branch id convertible to its `librustzcash`
58    ///   equivalent.
59    pub fn new(
60        trans: &'a Transaction,
61        nu: NetworkUpgrade,
62        all_previous_outputs: &'a [transparent::Output],
63    ) -> Self {
64        SigHasher {
65            precomputed_tx_data: PrecomputedTxData::new(trans, nu, all_previous_outputs),
66        }
67    }
68
69    /// Calculate the sighash for the current transaction.
70    ///
71    /// # Details
72    ///
73    /// The `input_index_script_code` tuple indicates the index of the
74    /// transparent Input for which we are producing a sighash and the
75    /// respective script code being validated, or None if it's a shielded
76    /// input.
77    ///
78    /// # Panics
79    ///
80    /// - if the input index is out of bounds for self.inputs()
81    pub fn sighash(
82        &self,
83        hash_type: HashType,
84        input_index_script_code: Option<(usize, Vec<u8>)>,
85    ) -> SigHash {
86        sighash(
87            &self.precomputed_tx_data,
88            hash_type,
89            input_index_script_code,
90        )
91    }
92}