zebra_chain/transaction/
auth_digest.rs

1//! Authorizing digests for Zcash transactions.
2
3use std::{fmt, sync::Arc};
4
5use hex::{FromHex, ToHex};
6
7use crate::{
8    primitives::zcash_primitives::auth_digest,
9    serialization::{
10        ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize, ZcashSerialize,
11    },
12};
13
14use super::Transaction;
15
16#[cfg(any(test, feature = "proptest-impl"))]
17use proptest_derive::Arbitrary;
18
19/// An authorizing data commitment hash as specified in [ZIP-244].
20///
21/// Note: Zebra displays transaction and block hashes in big-endian byte-order,
22/// following the u256 convention set by Bitcoin and zcashd.
23///
24/// [ZIP-244]: https://zips.z.cash/zip-0244
25#[derive(Copy, Clone, Eq, PartialEq, Hash)]
26#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
27pub struct AuthDigest(pub [u8; 32]);
28
29impl AuthDigest {
30    /// Return the hash bytes in big-endian byte-order suitable for printing out byte by byte.
31    ///
32    /// Zebra displays transaction and block hashes in big-endian byte-order,
33    /// following the u256 convention set by Bitcoin and zcashd.
34    pub fn bytes_in_display_order(&self) -> [u8; 32] {
35        let mut reversed_bytes = self.0;
36        reversed_bytes.reverse();
37        reversed_bytes
38    }
39
40    /// Convert bytes in big-endian byte-order into a [`transaction::AuthDigest`](crate::transaction::AuthDigest).
41    ///
42    /// Zebra displays transaction and block hashes in big-endian byte-order,
43    /// following the u256 convention set by Bitcoin and zcashd.
44    pub fn from_bytes_in_display_order(bytes_in_display_order: &[u8; 32]) -> AuthDigest {
45        let mut internal_byte_order = *bytes_in_display_order;
46        internal_byte_order.reverse();
47
48        AuthDigest(internal_byte_order)
49    }
50}
51
52impl From<Transaction> for AuthDigest {
53    /// Computes the authorizing data commitment for a transaction.
54    ///
55    /// # Panics
56    ///
57    /// If passed a pre-v5 transaction.
58    fn from(transaction: Transaction) -> Self {
59        // use the ref implementation, to avoid cloning the transaction
60        AuthDigest::from(&transaction)
61    }
62}
63
64impl From<&Transaction> for AuthDigest {
65    /// Computes the authorizing data commitment for a transaction.
66    ///
67    /// # Panics
68    ///
69    /// If passed a pre-v5 transaction.
70    fn from(transaction: &Transaction) -> Self {
71        auth_digest(transaction)
72    }
73}
74
75impl From<Arc<Transaction>> for AuthDigest {
76    /// Computes the authorizing data commitment for a transaction.
77    ///
78    /// # Panics
79    ///
80    /// If passed a pre-v5 transaction.
81    fn from(transaction: Arc<Transaction>) -> Self {
82        transaction.as_ref().into()
83    }
84}
85
86impl From<[u8; 32]> for AuthDigest {
87    fn from(bytes: [u8; 32]) -> Self {
88        Self(bytes)
89    }
90}
91
92impl From<AuthDigest> for [u8; 32] {
93    fn from(auth_digest: AuthDigest) -> Self {
94        auth_digest.0
95    }
96}
97
98impl From<&AuthDigest> for [u8; 32] {
99    fn from(auth_digest: &AuthDigest) -> Self {
100        (*auth_digest).into()
101    }
102}
103
104impl ToHex for &AuthDigest {
105    fn encode_hex<T: FromIterator<char>>(&self) -> T {
106        self.bytes_in_display_order().encode_hex()
107    }
108
109    fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
110        self.bytes_in_display_order().encode_hex_upper()
111    }
112}
113
114impl ToHex for AuthDigest {
115    fn encode_hex<T: FromIterator<char>>(&self) -> T {
116        (&self).encode_hex()
117    }
118
119    fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
120        (&self).encode_hex_upper()
121    }
122}
123
124impl FromHex for AuthDigest {
125    type Error = <[u8; 32] as FromHex>::Error;
126
127    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
128        let mut hash = <[u8; 32]>::from_hex(hex)?;
129        hash.reverse();
130
131        Ok(hash.into())
132    }
133}
134
135impl fmt::Display for AuthDigest {
136    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
137        f.write_str(&self.encode_hex::<String>())
138    }
139}
140
141impl fmt::Debug for AuthDigest {
142    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
143        f.debug_tuple("AuthDigest")
144            .field(&self.encode_hex::<String>())
145            .finish()
146    }
147}
148
149impl std::str::FromStr for AuthDigest {
150    type Err = SerializationError;
151
152    fn from_str(s: &str) -> Result<Self, Self::Err> {
153        let mut bytes = [0; 32];
154        if hex::decode_to_slice(s, &mut bytes[..]).is_err() {
155            Err(SerializationError::Parse("hex decoding error"))
156        } else {
157            bytes.reverse();
158            Ok(AuthDigest(bytes))
159        }
160    }
161}
162
163impl ZcashSerialize for AuthDigest {
164    fn zcash_serialize<W: std::io::Write>(&self, mut writer: W) -> Result<(), std::io::Error> {
165        writer.write_32_bytes(&self.into())
166    }
167}
168
169impl ZcashDeserialize for AuthDigest {
170    fn zcash_deserialize<R: std::io::Read>(mut reader: R) -> Result<Self, SerializationError> {
171        Ok(reader.read_32_bytes()?.into())
172    }
173}