stacks_core/crypto/
sha256.rs1pub use bdk::bitcoin::secp256k1;
2use serde::{Deserialize, Serialize};
3use sha2::{Digest, Sha256};
4
5use crate::{
6 crypto::{Hasher, Hashing, Hex},
7 StacksError, StacksResult,
8};
9
10pub(crate) const SHA256_LENGTH: usize = 32;
11
12#[derive(
13 Serialize, Deserialize, Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord,
14)]
15#[serde(try_from = "Hex")]
16#[serde(into = "Hex")]
17pub struct Sha256Hashing([u8; SHA256_LENGTH]);
19
20impl Hashing<SHA256_LENGTH> for Sha256Hashing {
21 fn hash(data: &[u8]) -> Self {
22 Self(Sha256::digest(data).into())
23 }
24
25 fn as_bytes(&self) -> &[u8] {
26 &self.0
27 }
28
29 fn from_bytes(bytes: &[u8]) -> StacksResult<Self> {
30 Ok(Self(bytes.try_into()?))
31 }
32}
33
34#[allow(clippy::from_over_into)]
36impl Into<Hex> for Sha256Hashing {
37 fn into(self) -> Hex {
38 Hex(hex::encode(self.as_bytes()))
39 }
40}
41
42impl TryFrom<Hex> for Sha256Hashing {
43 type Error = StacksError;
44
45 fn try_from(value: Hex) -> Result<Self, Self::Error> {
46 Self::from_bytes(&hex::decode(value.0)?)
47 }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
51pub struct DoubleSha256Hashing(Sha256Hashing);
53
54impl Hashing<SHA256_LENGTH> for DoubleSha256Hashing {
55 fn hash(data: &[u8]) -> Self {
56 Self(Sha256Hashing::hash(Sha256Hashing::hash(data).as_bytes()))
57 }
58
59 fn as_bytes(&self) -> &[u8] {
60 self.0.as_bytes()
61 }
62
63 fn from_bytes(bytes: &[u8]) -> StacksResult<Self> {
64 Ok(Self(Sha256Hashing::from_bytes(bytes)?))
65 }
66}
67
68#[allow(clippy::from_over_into)]
70impl Into<Hex> for DoubleSha256Hashing {
71 fn into(self) -> Hex {
72 Hex(hex::encode(self.as_bytes()))
73 }
74}
75
76impl TryFrom<Hex> for DoubleSha256Hashing {
77 type Error = StacksError;
78
79 fn try_from(value: Hex) -> Result<Self, Self::Error> {
80 Self::from_bytes(&hex::decode(value.0)?)
81 }
82}
83
84pub type Sha256Hasher = Hasher<Sha256Hashing, SHA256_LENGTH>;
86pub type DoubleSha256Hasher = Hasher<DoubleSha256Hashing, SHA256_LENGTH>;
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92 use crate::uint::Uint256;
93
94 #[test]
95 fn should_sha256_hash_correctly() {
96 let plaintext = "Hello world";
97 let expected_hash_hex =
98 "64ec88ca00b268e5ba1a35678a1b5316d212f4f366b2477232534a8aeca37f3c";
99
100 assert_eq!(
101 hex::encode(Sha256Hasher::hash(plaintext.as_bytes())),
102 expected_hash_hex
103 );
104 }
105
106 #[test]
107 fn should_sha256_checksum_correctly() {
108 let plaintext = "Hello world";
109 let expected_checksum_hex = "64ec88ca";
110
111 assert_eq!(
112 hex::encode(Sha256Hasher::hash(plaintext.as_bytes()).checksum()),
113 expected_checksum_hex
114 );
115 }
116
117 #[test]
118 fn should_double_sha256_hash_correctly() {
119 let plaintext = "Hello world";
120 let expected_hash_hex =
121 "f6dc724d119649460e47ce719139e521e082be8a9755c5bece181de046ee65fe";
122
123 assert_eq!(
124 hex::encode(
125 DoubleSha256Hasher::hash(plaintext.as_bytes()).as_bytes()
126 ),
127 expected_hash_hex
128 );
129 }
130
131 #[test]
132 fn should_double_sha256_checksum_correctly() {
133 let plaintext = "Hello world";
134 let expected_checksum_hex = "f6dc724d";
135
136 assert_eq!(
137 hex::encode(
138 DoubleSha256Hasher::hash(plaintext.as_bytes()).checksum()
139 ),
140 expected_checksum_hex
141 );
142 }
143
144 #[test]
145 fn should_convert_to_uint_correctly() {
146 let expected_num = Uint256::from(0xDEADBEEFDEADBEEF_u64) << 64
147 | Uint256::from(0x0102030405060708_u64);
148 let num_bytes = hex::decode(
149 "0807060504030201efbeaddeefbeadde00000000000000000000000000000000",
150 )
151 .unwrap();
152
153 let hash = Sha256Hashing(num_bytes.try_into().unwrap());
154
155 assert_eq!(
156 expected_num,
157 Uint256::from_le_bytes(hash.as_bytes()).unwrap()
158 );
159 }
160}