zebra_chain/transaction/
sighash.rs

1//! Signature hashes for Zcash transactions
2
3use std::sync::Arc;
4
5use zcash_transparent::sighash::SighashType;
6
7use super::Transaction;
8
9use crate::parameters::NetworkUpgrade;
10use crate::{transparent, Error};
11
12use crate::primitives::zcash_primitives::{sighash, PrecomputedTxData};
13
14bitflags::bitflags! {
15    /// The different SigHash types, as defined in <https://zips.z.cash/zip-0143>
16    #[derive(Copy, Clone, Debug, PartialEq, Eq)]
17    pub struct HashType: u32 {
18        /// Sign all the outputs
19        const ALL = 0b0000_0001;
20        /// Sign none of the outputs - anyone can spend
21        const NONE = 0b0000_0010;
22        /// Sign one of the outputs - anyone can spend the rest
23        const SINGLE = Self::ALL.bits() | Self::NONE.bits();
24        /// Anyone can add inputs to this transaction
25        const ANYONECANPAY = 0b1000_0000;
26
27        /// Sign all the outputs and Anyone can add inputs to this transaction
28        const ALL_ANYONECANPAY = Self::ALL.bits() | Self::ANYONECANPAY.bits();
29        /// Sign none of the outputs and Anyone can add inputs to this transaction
30        const NONE_ANYONECANPAY = Self::NONE.bits() | Self::ANYONECANPAY.bits();
31        /// Sign one of the outputs and Anyone can add inputs to this transaction
32        const SINGLE_ANYONECANPAY = Self::SINGLE.bits() | Self::ANYONECANPAY.bits();
33    }
34}
35
36impl TryFrom<HashType> for SighashType {
37    type Error = ();
38
39    fn try_from(hash_type: HashType) -> Result<Self, Self::Error> {
40        Ok(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}
51
52/// 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]);
56
57impl AsRef<[u8; 32]> for SigHash {
58    fn as_ref(&self) -> &[u8; 32] {
59        &self.0
60    }
61}
62
63impl AsRef<[u8]> for SigHash {
64    fn as_ref(&self) -> &[u8] {
65        &self.0
66    }
67}
68
69/// 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}
75
76impl 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.
86    pub fn new(
87        trans: &Transaction,
88        nu: NetworkUpgrade,
89        all_previous_outputs: Arc<Vec<transparent::Output>>,
90    ) -> Result<Self, Error> {
91        Ok(SigHasher {
92            precomputed_tx_data: PrecomputedTxData::new(trans, nu, all_previous_outputs)?,
93        })
94    }
95
96    /// 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()
108    pub 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}