1use std::array;
6use utils::md5;
7
8#[inline]
9pub(crate) fn knot_rounds(lengths: impl Iterator<Item = u8> + Clone, rounds: u32) -> [u8; 256] {
10 let mut list = array::from_fn(|i| i as u8);
11 let mut position = 0;
12 let mut skip = 0;
13
14 for _ in 0..rounds {
15 for length in lengths.clone() {
16 list[0..length as usize].reverse();
17 list.rotate_left((length as usize + skip) % 256);
18 position = (position + length as usize + skip) % 256;
19 skip += 1;
20 }
21 }
22
23 list.rotate_right(position);
24 list
25}
26
27#[inline]
28pub(crate) fn knot_hash(lengths: impl Iterator<Item = u8> + Clone) -> [u8; 16] {
29 let sparse = knot_rounds(lengths.chain([17, 31, 73, 47, 23]), 64);
30
31 array::from_fn(|i| {
32 sparse[16 * i..16 * (i + 1)]
33 .iter()
34 .fold(0, |acc, x| acc ^ x)
35 })
36}
37
38#[inline]
39pub(crate) fn knot_hash_hex(lengths: impl Iterator<Item = u8> + Clone) -> [u8; 32] {
40 let hash = knot_hash(lengths);
41
42 md5::to_hex(array::from_fn(|i| {
43 u32::from_be_bytes(hash[4 * i..4 * (i + 1)].try_into().unwrap())
44 }))
45}