assemble_core/
cryptography.rs1use generic_array::GenericArray;
4use serde::de::Error;
5use serde::{Deserialize, Deserializer, Serialize, Serializer};
6use sha2::digest::{OutputSizeUser, Update};
7use sha2::Digest;
8use sha2::Sha256 as Sha2_Sha256;
9use std::fmt::{Display, Formatter};
10use std::io;
11use std::num::ParseIntError;
12use std::path::Path;
13use std::str::FromStr;
14use thiserror::Error;
15
16type Sha256Length = <Sha2_Sha256 as OutputSizeUser>::OutputSize;
17
18pub const SHA256_BYTES: usize = 256 / 8;
20
21#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)]
23pub struct Sha256([u8; SHA256_BYTES]);
24impl Sha256 {
25 fn from(array: &GenericArray<u8, Sha256Length>) -> Self {
26 let slice = array.as_slice();
27 assert_eq!(slice.len(), SHA256_BYTES);
28 let mut output_array = [0_u8; SHA256_BYTES];
29 output_array.clone_from_slice(slice);
30 Self(output_array)
31 }
32}
33
34#[derive(Debug, Error)]
35pub enum ParseSha256Error {
36 #[error("Expected a string of 64 chars (len = {0})")]
37 WrongSize(usize),
38 #[error(transparent)]
39 ParseIntError(#[from] ParseIntError),
40}
41
42impl FromStr for Sha256 {
43 type Err = ParseSha256Error;
44
45 fn from_str(s: &str) -> Result<Self, Self::Err> {
46 if s.chars().count() != 64 {
47 return Err(ParseSha256Error::WrongSize(s.chars().count()));
48 }
49
50 let mut bytes = [0_u8; SHA256_BYTES];
51 for index in 0..SHA256_BYTES {
52 let byte_str = &s[(index * 2)..][..2];
53 let byte = u8::from_str_radix(byte_str, 16)?;
54 bytes[index] = byte;
55 }
56 Ok(Self(bytes))
57 }
58}
59
60impl Display for Sha256 {
61 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
62 write!(
63 f,
64 "{}",
65 self.0
66 .iter()
67 .map(|b| format!("{:02x}", b))
68 .collect::<String>()
69 )
70 }
71}
72
73impl Serialize for Sha256 {
74 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
75 where
76 S: Serializer,
77 {
78 self.to_string().serialize(serializer)
79 }
80}
81
82impl<'de> Deserialize<'de> for Sha256 {
83 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
84 where
85 D: Deserializer<'de>,
86 {
87 let string = String::deserialize(deserializer)?;
88 Sha256::from_str(&string).map_err(D::Error::custom)
89 }
90}
91
92pub struct Sha256Hasher {
94 hasher: Sha2_Sha256,
95}
96
97impl Sha256Hasher {
98 pub fn new() -> Self {
100 Self {
101 hasher: Sha2_Sha256::new(),
102 }
103 }
104
105 pub fn finalize(self) -> Sha256 {
107 Sha256::from(&self.hasher.finalize())
108 }
109
110 pub fn update<B: Sha256Hashable + ?Sized>(&mut self, value: &B) {
112 value.hash(self);
113 }
114}
115
116pub trait Sha256Hashable {
118 fn hash(&self, hasher: &mut Sha256Hasher);
119}
120
121impl<B: AsRef<[u8]> + ?Sized> Sha256Hashable for B {
122 fn hash(&self, hasher: &mut Sha256Hasher) {
123 Digest::update(&mut hasher.hasher, self)
124 }
125}
126
127pub fn hash_sha256<S: Sha256Hashable + ?Sized>(value: &S) -> Sha256 {
129 let mut hasher = Sha256Hasher::new();
130 hasher.update(value);
131 hasher.finalize()
132}
133
134pub fn hash_file_sha256<P: AsRef<Path> + ?Sized>(value: &P) -> io::Result<Sha256> {
136 let read = std::fs::read(value)?;
137 Ok(hash_sha256(&read))
138}
139
140#[cfg(test)]
141mod tests {
142 use crate::cryptography::{hash_sha256, Sha256};
143 use std::str::FromStr;
144
145 #[test]
146 fn parse_string() {
147 let string = "design patterns is a really long and boring book";
148 let value = hash_sha256(string);
149 let value_as_string = value.to_string();
150 let str_hash = Sha256::from_str(&value_as_string).unwrap();
151 assert_eq!(value, str_hash, "value was parsed incorrectly");
152 }
153
154 #[test]
155 fn hash_string() {
156 let string1 = "Hello, World!";
157 let string2 = "Hello, World!".to_string();
158 let value1 = hash_sha256(string1);
159 let value2 = hash_sha256(&string2);
160 println!("{}", value1);
161 assert_eq!(
162 value1,
163 Sha256::from_str("dffd6021bb2bd5b0af676290809ec3a53191dd81c7f70a4b28688a362182986f")
164 .unwrap()
165 );
166 assert_eq!(
167 value1, value2,
168 "Hashing of equivalent bytes should be equal"
169 );
170 }
171}