1unsafe extern "C" {
37 fn hash_one(
38 header_hash_bytes: *const u8,
39 nonce64_ptr: *const u64,
40 block_height: i32,
41 mix_out_bytes: *const u8,
42 hash_out_bytes: *const u8,
43 );
44
45 fn verify(
46 header_hash_bytes: *const u8,
47 nonce64_ptr: *const u64,
48 block_height: i32,
49 mix_out_bytes: *const u8,
50 hash_out_bytes: *const u8,
51 ) -> bool;
52}
53
54pub fn hash_kawpow(header_hash: &[u8; 32], nonce: &u64, block_height: i32) -> ([u8; 32], [u8; 32]) {
86 let mut mix_out = [0u8; 32];
87 let mut hash_out = [0u8; 32];
88 unsafe {
89 hash_one(
90 header_hash.as_ptr(),
91 nonce,
92 block_height,
93 mix_out.as_mut_ptr(),
94 hash_out.as_mut_ptr(),
95 );
96 }
97 (mix_out, hash_out)
98}
99
100pub fn verify_kawpow(
136 header_hash: &[u8; 32],
137 nonce: &u64,
138 block_height: i32,
139 mix_out: &[u8; 32],
140 hash_out: &[u8; 32],
141) -> bool {
142 let valid;
143 unsafe {
144 valid = verify(
145 header_hash.as_ptr(),
146 nonce,
147 block_height,
148 mix_out.as_ptr(),
149 hash_out.as_ptr(),
150 );
151 }
152
153 valid
154}
155
156#[cfg(test)]
157mod tests {
158 use super::*;
159 use std::time::Instant;
160
161 fn hex_to_bytes(hexstr: &str) -> Vec<u8> {
163 let mut bytes = Vec::with_capacity(hexstr.len() / 2);
164 let chars: Vec<_> = hexstr.chars().collect();
165 for i in (0..hexstr.len()).step_by(2) {
166 let byte = u8::from_str_radix(&format!("{}{}", chars[i], chars[i + 1]), 16)
167 .expect("valid hex");
168 bytes.push(byte);
169 }
170 bytes
171 }
172
173 fn hex_to_le_u64(hexstr: &str) -> u64 {
175 let mut bytes = hex_to_bytes(hexstr);
176 bytes.reverse();
177 let mut arr = [0u8; 8];
178 arr.copy_from_slice(&bytes);
179 u64::from_le_bytes(arr)
180 }
181
182 fn bytes_to_hex(bytes: &[u8]) -> String {
184 bytes
185 .iter()
186 .map(|b| format!("{:02x}", b))
187 .collect::<String>()
188 }
189
190 #[test]
191 fn test_hash_kawpow_matches_expected() {
192 let header_hash =
193 hex_to_bytes("63543d3913fe56e6720c5e61e8d208d05582875822628f483279a3e8d9c9a8b3");
194 let nonce = hex_to_le_u64("88a23b0033eb959b");
195 let block_height = 262523i32;
196 let expected_mix_hash = "89732e5ff8711c32558a308fc4b8ee77416038a70995670e3eb84cbdead2e337";
197 let expected_hash = "0000000718ba5143286c46f44eee668fdf59b8eba810df21e4e2f4ec9538fc20";
198
199 let header_hash_arr: [u8; 32] = header_hash.try_into().unwrap();
200 let (mix, hash) = hash_kawpow(&header_hash_arr, &nonce, block_height);
201
202 let mix_hex = bytes_to_hex(&mix);
203 let hash_hex = bytes_to_hex(&hash);
204
205 println!("Mix Hash: {}", mix_hex);
206 println!("Expected: {}\n", expected_mix_hash);
207 println!("Hash: {}", hash_hex);
208 println!("Expected: {}\n", expected_hash);
209
210 assert_eq!(mix_hex, expected_mix_hash, "Got invalid mix hash");
211 assert_eq!(hash_hex, expected_hash, "Got invalid hash");
212 }
213
214 #[test]
215 fn test_verify_kawpow_matches_expected() {
216 let header_hash =
217 hex_to_bytes("63543d3913fe56e6720c5e61e8d208d05582875822628f483279a3e8d9c9a8b3");
218 let nonce = hex_to_le_u64("88a23b0033eb959b");
219 let block_height = 262523i32;
220 let expected_hash = "0000000718ba5143286c46f44eee668fdf59b8eba810df21e4e2f4ec9538fc20";
221
222 let header_hash_arr: [u8; 32] = header_hash.try_into().unwrap();
223 let (mix, hash) = hash_kawpow(&header_hash_arr, &nonce, block_height);
224
225 let valid = verify_kawpow(&header_hash_arr, &nonce, block_height, &mix, &hash);
226 assert!(valid, "Verification failed");
227 assert_eq!(
228 bytes_to_hex(&hash),
229 expected_hash,
230 "Verified hash output does not match original hash"
231 );
232 }
233
234 #[test]
235 fn test_verify_kawpow_benchmark() {
236 let header_hash =
237 hex_to_bytes("63543d3913fe56e6720c5e61e8d208d05582875822628f483279a3e8d9c9a8b3");
238 let nonce = hex_to_le_u64("88a23b0033eb959b");
239 let block_height = 262523i32;
240
241 let header_hash_arr: [u8; 32] = header_hash.try_into().unwrap();
242 let (mix, _hash) = hash_kawpow(&header_hash_arr, &nonce, block_height);
243 let hash_out_arr: [u8; 32] = [0u8; 32];
244
245 let iterations = 1000;
246 let start = Instant::now();
247 for _ in 0..iterations {
248 let valid = verify_kawpow(&header_hash_arr, &nonce, block_height, &mix, &hash_out_arr);
249 assert!(valid, "Verification failed");
250 }
251 let elapsed = start.elapsed().as_millis();
252 let verify_ps = (iterations as f64) / (elapsed as f64) * 1000.0;
253 println!("verify/sec = {}", verify_ps);
254 }
255}