year2017/
knot_hash.rs

1//! Knot Hash implementation.
2//!
3//! See [`Day10`](crate::Day10) and [`Day14`](crate::Day14).
4
5use 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}