midnight_base_crypto/
hash.rs1use crate::repr::{BinaryHashRepr, MemWrite};
17use const_hex::ToHexExt;
18use fake::Dummy;
19#[cfg(feature = "proptest")]
20use proptest_derive::Arbitrary;
21use serde::{Deserialize, Serialize};
22use serialize::{Deserializable, Serializable, Tagged, tag_enforcement_test};
23use sha2::{Digest, Sha256};
24use std::fmt::{self, Debug, Display, Formatter};
25use std::io;
26use zeroize::Zeroize;
27
28pub const PERSISTENT_HASH_BYTES: usize = 32;
30
31#[derive(
33 Copy,
34 Clone,
35 Default,
36 PartialOrd,
37 Ord,
38 Hash,
39 BinaryHashRepr,
40 Serializable,
41 Serialize,
42 Deserialize,
43 Dummy,
44 Zeroize,
45)]
46#[cfg_attr(feature = "proptest", derive(Arbitrary))]
47#[allow(clippy::derived_hash_with_manual_eq)]
48pub struct HashOutput(pub [u8; PERSISTENT_HASH_BYTES]);
49tag_enforcement_test!(HashOutput);
50
51impl PartialEq for HashOutput {
52 fn eq(&self, other: &Self) -> bool {
53 subtle::ConstantTimeEq::ct_eq(&self.0[..], &other.0[..]).into()
54 }
55}
56
57impl Eq for HashOutput {}
58
59impl Tagged for HashOutput {
60 fn tag() -> std::borrow::Cow<'static, str> {
61 <[u8; PERSISTENT_HASH_BYTES]>::tag()
62 }
63 fn tag_unique_factor() -> String {
64 <[u8; PERSISTENT_HASH_BYTES]>::tag_unique_factor()
65 }
66}
67
68#[cfg(feature = "proptest")]
69serialize::randomised_serialization_test!(HashOutput);
70
71pub const BLANK_HASH: HashOutput = HashOutput([0u8; PERSISTENT_HASH_BYTES]);
73
74impl rand::distributions::Distribution<HashOutput> for rand::distributions::Standard {
75 fn sample<R: rand::Rng + ?Sized>(&self, rng: &mut R) -> HashOutput {
76 HashOutput(rng.r#gen())
77 }
78}
79
80impl Debug for HashOutput {
81 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
82 write!(formatter, "{}", self.0.encode_hex())
83 }
84}
85
86impl Display for HashOutput {
87 fn fmt(&self, formatter: &mut Formatter) -> fmt::Result {
88 write!(formatter, "{}", &self.0.encode_hex()[..10])
89 }
90}
91
92pub fn persistent_hash(a: &[u8]) -> HashOutput {
94 HashOutput(Sha256::digest(a).into())
95}
96
97pub fn persistent_commit<T: BinaryHashRepr + ?Sized>(value: &T, opening: HashOutput) -> HashOutput {
99 let mut writer = PersistentHashWriter::new();
100 opening.binary_repr(&mut writer);
101 value.binary_repr(&mut writer);
102 writer.finalize()
103}
104
105pub struct PersistentHashWriter(Sha256);
107
108impl MemWrite<u8> for PersistentHashWriter {
109 fn write(&mut self, buf: &[u8]) {
110 self.0.update(buf);
111 }
112}
113
114impl io::Write for PersistentHashWriter {
115 fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
116 self.0.update(buf);
117 Ok(buf.len())
118 }
119
120 fn flush(&mut self) -> io::Result<()> {
121 Ok(())
122 }
123}
124
125impl Default for PersistentHashWriter {
126 fn default() -> Self {
127 PersistentHashWriter(Sha256::new())
128 }
129}
130
131impl PersistentHashWriter {
132 pub fn new() -> Self {
134 Default::default()
135 }
136
137 pub fn finalize(self) -> HashOutput {
139 HashOutput(self.0.finalize().into())
140 }
141}