Skip to main content

zebra_chain/transaction/
auth_digest.rs

1//! Authorizing digests for Zcash transactions.
2
3use std::{array::TryFromSliceError, fmt};
4
5use hex::{FromHex, ToHex};
6
7use crate::serialization::{
8    BytesInDisplayOrder, ReadZcashExt, SerializationError, WriteZcashExt, ZcashDeserialize,
9    ZcashSerialize,
10};
11
12#[cfg(any(test, feature = "proptest-impl"))]
13use proptest_derive::Arbitrary;
14
15/// An authorizing data commitment hash as specified in [ZIP-244].
16///
17/// Note: Zebra displays transaction and block hashes in big-endian byte-order,
18/// following the u256 convention set by Bitcoin and zcashd.
19///
20/// [ZIP-244]: https://zips.z.cash/zip-0244
21#[derive(Copy, Clone, Eq, PartialEq, Hash, serde::Deserialize, serde::Serialize)]
22#[cfg_attr(any(test, feature = "proptest-impl"), derive(Arbitrary))]
23pub struct AuthDigest(pub [u8; 32]);
24
25impl BytesInDisplayOrder<true> for AuthDigest {
26    fn bytes_in_serialized_order(&self) -> [u8; 32] {
27        self.0
28    }
29
30    fn from_bytes_in_serialized_order(bytes: [u8; 32]) -> Self {
31        AuthDigest(bytes)
32    }
33}
34
35// From<&Transaction> for AuthDigest is defined in transaction.rs (TryFrom)
36
37impl From<[u8; 32]> for AuthDigest {
38    fn from(bytes: [u8; 32]) -> Self {
39        Self(bytes)
40    }
41}
42
43impl TryFrom<&[u8]> for AuthDigest {
44    type Error = TryFromSliceError;
45
46    fn try_from(bytes: &[u8]) -> Result<Self, Self::Error> {
47        Ok(AuthDigest(bytes.try_into()?))
48    }
49}
50
51impl From<AuthDigest> for [u8; 32] {
52    fn from(auth_digest: AuthDigest) -> Self {
53        auth_digest.0
54    }
55}
56
57impl From<&AuthDigest> for [u8; 32] {
58    fn from(auth_digest: &AuthDigest) -> Self {
59        (*auth_digest).into()
60    }
61}
62
63impl ToHex for &AuthDigest {
64    fn encode_hex<T: FromIterator<char>>(&self) -> T {
65        self.bytes_in_display_order().encode_hex()
66    }
67
68    fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
69        self.bytes_in_display_order().encode_hex_upper()
70    }
71}
72
73impl ToHex for AuthDigest {
74    fn encode_hex<T: FromIterator<char>>(&self) -> T {
75        (&self).encode_hex()
76    }
77
78    fn encode_hex_upper<T: FromIterator<char>>(&self) -> T {
79        (&self).encode_hex_upper()
80    }
81}
82
83impl FromHex for AuthDigest {
84    type Error = <[u8; 32] as FromHex>::Error;
85
86    fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
87        let mut hash = <[u8; 32]>::from_hex(hex)?;
88        hash.reverse();
89
90        Ok(hash.into())
91    }
92}
93
94impl fmt::Display for AuthDigest {
95    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
96        f.write_str(&self.encode_hex::<String>())
97    }
98}
99
100impl fmt::Debug for AuthDigest {
101    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102        f.debug_tuple("AuthDigest")
103            .field(&self.encode_hex::<String>())
104            .finish()
105    }
106}
107
108impl std::str::FromStr for AuthDigest {
109    type Err = SerializationError;
110
111    fn from_str(s: &str) -> Result<Self, Self::Err> {
112        let mut bytes = [0; 32];
113        if hex::decode_to_slice(s, &mut bytes[..]).is_err() {
114            Err(SerializationError::Parse("hex decoding error"))
115        } else {
116            bytes.reverse();
117            Ok(AuthDigest(bytes))
118        }
119    }
120}
121
122impl ZcashSerialize for AuthDigest {
123    fn zcash_serialize<W: std::io::Write>(&self, mut writer: W) -> Result<(), std::io::Error> {
124        writer.write_32_bytes(&self.into())
125    }
126}
127
128impl ZcashDeserialize for AuthDigest {
129    fn zcash_deserialize<R: std::io::Read>(mut reader: R) -> Result<Self, SerializationError> {
130        Ok(reader.read_32_bytes()?.into())
131    }
132}