1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
use blake2::Blake2b512;
use sha2::Digest;

trait HashAlgorithm {
    fn calculate_digest(digest: &mut [u8], message: &[u8]);
}

pub const BLAKE2B_DIGEST_SIZE: usize = 64;
pub const SHA512_DIGEST_SIZE: usize = 64;

pub type Blake2bDigest = [u8; BLAKE2B_DIGEST_SIZE];
pub type Sha512Digest = [u8; SHA512_DIGEST_SIZE];

struct Blake2b;

impl HashAlgorithm for Blake2b {
    fn calculate_digest(digest: &mut [u8], message: &[u8]) {
        let mut hasher = Blake2b512::new();
        hasher.update(message);
        digest.copy_from_slice(hasher.finalize().as_slice());
    }
}

struct Sha512;

impl HashAlgorithm for Sha512 {
    fn calculate_digest(digest: &mut [u8], message: &[u8]) {
        let mut hasher = sha2::Sha512::new();
        hasher.update(message);
        digest.copy_from_slice(hasher.finalize().as_slice());
    }
}

fn hash<H: HashAlgorithm>(a: &mut [u8], b: &mut [u8], message: &[u8], iterations: Option<u32>) {
    let iterations = match iterations {
        Some(i) => {
            if i == 0 {
                1
            } else {
                i
            }
        }
        None => 1,
    };
    H::calculate_digest(a, message);
    for _ in 1..iterations {
        H::calculate_digest(b, a);
        a.copy_from_slice(b);
    }
}

pub fn blake2b(message: &[u8], iterations: Option<u32>) -> Blake2bDigest {
    let mut a = [0; BLAKE2B_DIGEST_SIZE];
    let mut b = [0; BLAKE2B_DIGEST_SIZE];
    hash::<Blake2b>(&mut a, &mut b, message, iterations);
    a
}

pub fn sha512(message: &[u8], iterations: Option<u32>) -> Sha512Digest {
    let mut a = [0; SHA512_DIGEST_SIZE];
    let mut b = [0; SHA512_DIGEST_SIZE];
    hash::<Sha512>(&mut a, &mut b, message, iterations);
    a
}

#[cfg(test)]
mod tests {
    use super::*;
    use alloc::vec;

    #[test]
    fn test_blake2b() {
        let message = vec![72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100];
        let digest: Blake2bDigest = [
            67, 134, 160, 138, 38, 81, 17, 201, 137, 111, 86, 69, 110, 44, 182, 26, 100, 35, 145,
            21, 196, 120, 76, 244, 56, 227, 108, 200, 81, 34, 25, 114, 218, 63, 176, 17, 95, 115,
            205, 2, 72, 98, 84, 0, 31, 135, 138, 177, 253, 18, 106, 172, 105, 132, 78, 241, 193,
            202, 21, 35, 121, 208, 169, 189,
        ];
        assert_eq!(blake2b(&message, None), digest);
        assert_eq!(blake2b(&message, Some(1)), digest);
    }

    #[test]
    fn test_blake2b_iterated() {
        let message = vec![72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100];
        let digest: Blake2bDigest = [
            165, 34, 42, 151, 213, 48, 192, 184, 236, 68, 32, 92, 134, 69, 116, 201, 216, 176, 198,
            69, 247, 183, 71, 209, 62, 237, 92, 205, 127, 80, 67, 76, 77, 68, 41, 156, 124, 242,
            193, 50, 113, 106, 77, 72, 213, 109, 152, 34, 164, 26, 112, 6, 94, 255, 25, 175, 162,
            76, 14, 157, 240, 122, 113, 141,
        ];
        assert_eq!(blake2b(&message, Some(5)), digest);
    }

    #[test]
    fn test_sha512() {
        let message = vec![72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100];
        let digest: Sha512Digest = [
            44, 116, 253, 23, 237, 175, 216, 14, 132, 71, 176, 212, 103, 65, 238, 36, 59, 126, 183,
            77, 210, 20, 154, 10, 177, 185, 36, 111, 179, 3, 130, 242, 126, 133, 61, 133, 133, 113,
            158, 14, 103, 203, 218, 13, 170, 143, 81, 103, 16, 100, 97, 93, 100, 90, 226, 122, 203,
            21, 191, 177, 68, 127, 69, 155,
        ];
        assert_eq!(sha512(&message, None), digest);
        assert_eq!(sha512(&message, Some(1)), digest);
    }

    #[test]
    fn test_sha512_iterated() {
        let message = vec![72, 101, 108, 108, 111, 32, 87, 111, 114, 108, 100];
        let digest: Sha512Digest = [
            59, 59, 112, 161, 93, 224, 176, 42, 40, 169, 175, 132, 163, 241, 179, 120, 220, 207, 0,
            170, 218, 103, 148, 139, 233, 16, 231, 222, 149, 188, 207, 62, 79, 243, 230, 180, 11,
            227, 73, 142, 98, 65, 85, 94, 195, 193, 135, 28, 111, 6, 221, 42, 150, 72, 174, 131,
            137, 249, 23, 197, 232, 4, 104, 109,
        ];
        assert_eq!(sha512(&message, Some(5)), digest);
    }
}