neo3/neo_crypto/
hash.rs

1use hmac::{Hmac, Mac};
2use ripemd::{Digest as RipemdDigest, Ripemd160};
3use sha2::{Digest, Sha256, Sha512};
4
5pub trait HashableForVec {
6	fn hash256(&self) -> Vec<u8>;
7	fn ripemd160(&self) -> Vec<u8>;
8	fn sha256_ripemd160(&self) -> Vec<u8>;
9	fn hmac_sha512(&self, key: &[u8]) -> Vec<u8>;
10}
11
12impl HashableForVec for [u8] {
13	fn hash256(&self) -> Vec<u8> {
14		let mut hasher = Sha256::new();
15		hasher.update(self);
16		hasher.finalize().to_vec()
17	}
18
19	fn ripemd160(&self) -> Vec<u8> {
20		let mut hasher = Ripemd160::new();
21		hasher.update(self);
22		hasher.finalize().to_vec()
23	}
24
25	fn sha256_ripemd160(&self) -> Vec<u8> {
26		let mut sha256 = Sha256::new();
27		sha256.update(self);
28		let sha_result = sha256.finalize();
29
30		let mut ripemd = Ripemd160::new();
31		ripemd.update(&sha_result);
32		ripemd.finalize().to_vec()
33	}
34
35	fn hmac_sha512(&self, key: &[u8]) -> Vec<u8> {
36		type HmacSha512 = Hmac<Sha512>;
37		let mut mac = HmacSha512::new_from_slice(key).expect("HMAC can take key of any size");
38		mac.update(self);
39		mac.finalize().into_bytes().to_vec()
40	}
41}
42
43impl HashableForVec for Vec<u8> {
44	fn hash256(&self) -> Vec<u8> {
45		self.as_slice().hash256()
46	}
47
48	fn ripemd160(&self) -> Vec<u8> {
49		self.as_slice().ripemd160()
50	}
51
52	fn sha256_ripemd160(&self) -> Vec<u8> {
53		self.as_slice().sha256_ripemd160()
54	}
55
56	fn hmac_sha512(&self, key: &[u8]) -> Vec<u8> {
57		self.as_slice().hmac_sha512(key)
58	}
59}
60
61fn hex_encode(bytes: &[u8]) -> String {
62	hex::encode(bytes)
63}
64
65pub trait HashableForString {
66	fn hash256(&self) -> String;
67	fn ripemd160(&self) -> String;
68	fn sha256_ripemd160(&self) -> String;
69	fn hmac_sha512(&self, key: &str) -> String;
70	fn hash160(&self) -> String;
71}
72
73impl HashableForString for String {
74	fn hash256(&self) -> String {
75		hex_encode(&self.as_bytes().hash256())
76	}
77
78	fn ripemd160(&self) -> String {
79		hex_encode(&self.as_bytes().ripemd160())
80	}
81
82	fn sha256_ripemd160(&self) -> String {
83		hex_encode(&self.as_bytes().sha256_ripemd160())
84	}
85
86	fn hmac_sha512(&self, key: &str) -> String {
87		hex_encode(&self.as_bytes().hmac_sha512(key.as_bytes()))
88	}
89
90	fn hash160(&self) -> String {
91		let hash = self.as_bytes().sha256_ripemd160();
92		bs58::encode(&hash[..]).into_string()
93	}
94}
95
96#[cfg(test)]
97mod tests {
98	use super::*;
99
100	#[test]
101	fn test_hash256_for_bytes() {
102		let data = b"hello world";
103		let expected = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
104		let result = data.hash256();
105		assert_eq!(hex_encode(&result), expected);
106	}
107
108	#[test]
109	fn test_hash256_for_string() {
110		let data = String::from("hello world");
111		let expected = "b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9";
112		assert_eq!(data.hash256(), expected);
113	}
114
115	#[test]
116	fn test_ripemd160_for_bytes() {
117		let data = b"hello world";
118		// Use the expected hash value for "hello world" using RIPEMD160
119		let expected = "98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f";
120		let result = data.ripemd160();
121		assert_eq!(hex_encode(&result), expected);
122	}
123
124	#[test]
125	fn test_ripemd160_for_string() {
126		let data = String::from("hello world");
127		let expected = "98c615784ccb5fe5936fbc0cbe9dfdb408d92f0f";
128		assert_eq!(data.ripemd160(), expected);
129	}
130
131	#[test]
132	fn test_sha256_ripemd160_for_bytes() {
133		let data = b"hello world";
134		// Use the expected hash value for "hello world" using SHA256 followed by RIPEMD160
135		let expected = "d7d5ee7824ff93f94c3055af9382c86c68b5ca92";
136		let result = data.sha256_ripemd160();
137		assert_eq!(hex_encode(&result), expected);
138	}
139
140	#[test]
141	fn test_sha256_ripemd160_for_string() {
142		let data = String::from("hello world");
143		let expected = "d7d5ee7824ff93f94c3055af9382c86c68b5ca92"; // fill this in
144		assert_eq!(data.sha256_ripemd160(), expected);
145	}
146
147	#[test]
148	fn test_hmac_sha512_for_bytes() {
149		let data = b"hello world";
150		let key = b"secret";
151		// Use the expected HMAC-SHA512 value for "hello world" with key "secret"
152		let expected = "6d32239b01dd1750557211629313d95e4f4fcb8ee517e443990ac1afc7562bfd74ffa6118387efd9e168ff86d1da5cef4a55edc63cc4ba289c4c3a8b4f7bdfc2";
153		let result = data.hmac_sha512(key);
154		assert_eq!(hex_encode(&result), expected);
155	}
156
157	#[test]
158	fn test_hmac_sha512_for_string() {
159		let data = String::from("hello world");
160		let key = "secret";
161		let expected = "6d32239b01dd1750557211629313d95e4f4fcb8ee517e443990ac1afc7562bfd74ffa6118387efd9e168ff86d1da5cef4a55edc63cc4ba289c4c3a8b4f7bdfc2";
162		assert_eq!(data.hmac_sha512(key), expected);
163	}
164
165	#[test]
166	fn test_hash160_for_string() {
167		let data = String::from("hello world");
168		// Use the expected hash value for "hello world" using SHA256 followed by RIPEMD160 and then base58 encoded
169		let expected = "41QPk1SP3NZmiQxd5jY6HWh1tRcD";
170		assert_eq!(data.hash160(), expected);
171	}
172
173	#[test]
174	fn test_ripemd160_test_vectors() {
175		let test_vectors: &[(&str, &str)] = &[
176			("", "9c1185a5c5e9fc54612808977ee8f548b2258d31"),
177			("a", "0bdc9d2d256b3ee9daae347be6f4dc835a467ffe"),
178			("abc", "8eb208f7e05d987a9b044a8e98c6b087f15a0bfc"),
179			("message digest", "5d0689ef49d2fae572b881b123a85ffa21595f36"),
180			("abcdefghijklmnopqrstuvwxyz", "f71c27109c692c1b56bbdceb5b9d2865b3708dbc"),
181			(
182				"abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq",
183				"12a053384a9c0c88e405a06c27dcf49ada62eb2b",
184			),
185			(
186				"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
187				"b0e20b6e3116640286ed3a87a5713079b21f5189",
188			),
189			// For the large repeating strings, directly include them in the test
190			(
191				"12345678901234567890123456789012345678901234567890123456789012345678901234567890",
192				"9b752e45573d4b39f4dbd3323cab82bf63326bfb",
193			),
194			(&"a".repeat(1_000_000), "52783243c1697bdbe16d37f97f68f08325dc1528"),
195		];
196
197		for &(input, expected_hash) in test_vectors {
198			let hash = input.as_bytes().ripemd160();
199			let hex_string = to_hex_string(&hash);
200			assert_eq!(hex_string, expected_hash);
201		}
202	}
203
204	// Helper function to convert bytes to hex string
205	// Define this or replace it with your actual hex string conversion function
206	fn to_hex_string(bytes: &[u8]) -> String {
207		bytes.iter().map(|byte| format!("{byte:02x}")).collect()
208	}
209}