pallas_crypto/hash/
hash.rs1use pallas_codec::minicbor;
2use std::{fmt, ops::Deref, str::FromStr};
3
4#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
9pub struct Hash<const BYTES: usize>([u8; BYTES]);
10
11impl<const BYTES: usize> Hash<BYTES> {
12 #[inline]
13 pub const fn new(bytes: [u8; BYTES]) -> Self {
14 Self(bytes)
15 }
16}
17
18impl<const BYTES: usize> From<[u8; BYTES]> for Hash<BYTES> {
19 #[inline]
20 fn from(bytes: [u8; BYTES]) -> Self {
21 Self::new(bytes)
22 }
23}
24
25impl<const BYTES: usize> From<&[u8]> for Hash<BYTES> {
26 fn from(value: &[u8]) -> Self {
27 let mut hash = [0; BYTES];
28 hash.copy_from_slice(value);
29 Self::new(hash)
30 }
31}
32
33impl<const BYTES: usize> AsRef<[u8]> for Hash<BYTES> {
34 #[inline]
35 fn as_ref(&self) -> &[u8] {
36 &self.0
37 }
38}
39
40impl<const BYTES: usize> Deref for Hash<BYTES> {
41 type Target = [u8; BYTES];
42
43 #[inline]
44 fn deref(&self) -> &Self::Target {
45 &self.0
46 }
47}
48
49impl<const BYTES: usize> PartialEq<[u8]> for Hash<BYTES> {
50 fn eq(&self, other: &[u8]) -> bool {
51 self.0.eq(other)
52 }
53}
54
55impl<const BYTES: usize> fmt::Debug for Hash<BYTES> {
56 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
57 f.debug_tuple(&format!("Hash<{BYTES}>"))
58 .field(&hex::encode(self))
59 .finish()
60 }
61}
62
63impl<const BYTES: usize> fmt::Display for Hash<BYTES> {
64 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
65 f.write_str(&hex::encode(self))
66 }
67}
68
69impl<const BYTES: usize> FromStr for Hash<BYTES> {
70 type Err = hex::FromHexError;
71 fn from_str(s: &str) -> Result<Self, Self::Err> {
72 let mut bytes = [0; BYTES];
73 hex::decode_to_slice(s, &mut bytes)?;
74 Ok(Self::new(bytes))
75 }
76}
77
78impl<C, const BYTES: usize> minicbor::Encode<C> for Hash<BYTES> {
79 fn encode<W: minicbor::encode::Write>(
80 &self,
81 e: &mut minicbor::Encoder<W>,
82 _ctx: &mut C,
83 ) -> Result<(), minicbor::encode::Error<W::Error>> {
84 e.bytes(&self.0)?.ok()
85 }
86}
87
88impl<'a, C, const BYTES: usize> minicbor::Decode<'a, C> for Hash<BYTES> {
89 fn decode(
90 d: &mut minicbor::Decoder<'a>,
91 _ctx: &mut C,
92 ) -> Result<Self, minicbor::decode::Error> {
93 let bytes = d.bytes()?;
94 if bytes.len() == BYTES {
95 let mut hash = [0; BYTES];
96 hash.copy_from_slice(bytes);
97 Ok(Self::new(hash))
98 } else {
99 Err(minicbor::decode::Error::message("Invalid hash size"))
102 }
103 }
104}
105
106#[cfg(test)]
107mod tests {
108 use super::*;
109
110 #[test]
111 fn from_str() {
112 let _digest: Hash<28> = "276fd18711931e2c0e21430192dbeac0e458093cd9d1fcd7210f64b3"
113 .parse()
114 .unwrap();
115
116 let _digest: Hash<32> = "0d8d00cdd4657ac84d82f0a56067634a7adfdf43da41cb534bcaa45060973d21"
117 .parse()
118 .unwrap();
119 }
120
121 #[test]
122 #[should_panic]
123 fn from_str_fail_1() {
124 let _digest: Hash<28> = "27".parse().unwrap();
125 }
126
127 #[test]
128 #[should_panic]
129 fn from_str_fail_2() {
130 let _digest: Hash<32> = "0d8d00cdd465".parse().unwrap();
131 }
132}