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
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
use crate::{Sha512Hasher, BYTES_LEN};
use core::{hash::BuildHasher, ops::AddAssign};
use rs_hasher_ctx::ByteArrayWrapper;
use rs_internal_hasher::{GenericPad, HashAlgorithm, U128Size};
use rs_internal_state::{BytesLen, DWords, GenericStateHasher, Sha512BitsState};
use rs_n_bit_words::NBitWord;

const H0: u64 = 0x6A09E667F3BCC908;
const H1: u64 = 0xBB67AE8584CAA73B;
const H2: u64 = 0x3C6EF372FE94F82B;
const H3: u64 = 0xA54FF53A5F1D36F1;
const H4: u64 = 0x510E527FADE682D1;
const H5: u64 = 0x9B05688C2B3E6C1F;
const H6: u64 = 0x1F83D9ABFB41BD6B;
const H7: u64 = 0x5BE0CD19137E2179;

const HX: [u64; 8] = [H0, H1, H2, H3, H4, H5, H6, H7];

/// `Sha512State` represents the state of a SHA-512 hashing process.
///
/// It holds intermediate hash calculations. However, it's important to note that starting a hashing process from an
/// arbitrary `Sha512State` is not equivalent to resuming the original process that produced that state. Instead, it
/// begins a new hashing process with a different set of initial values.
///
/// Therefore, a `Sha512State` extracted from a `Sha512Hasher` should not be used with the expectation of
/// continuing the hashing operation from where it left off in the original `Sha512Hasher`. It is  a snapshot of a
/// particular point in the process, not a means to resume the process.
///
/// # Example
///
/// This example demonstrates how to persist the state of a SHA-512 hash operation:
///
/// ```rust
/// # use std::hash::{BuildHasher, Hash, Hasher};
/// # use rs_sha512::{Sha512Hasher, Sha512State};
/// let hello = b"hello";
/// let world = b" world";
///
/// let mut default_sha512hasher = Sha512State::default().build_hasher();
/// default_sha512hasher.write(hello);
///
/// let intermediate_state: Sha512State = default_sha512hasher.clone().into();
///
/// default_sha512hasher.write(world);
///
/// let mut from_sha512state: Sha512Hasher = intermediate_state.into();
/// from_sha512state.write(world);
///
/// let default_hello_world_result = default_sha512hasher.finish();
/// let from_arbitrary_state_result = from_sha512state.finish();
/// assert_ne!(default_hello_world_result, from_arbitrary_state_result);
/// ```
///
/// ## Note
/// In this example, even though the internal state are the same between `default_sha512hasher` and `from_sha512state`
/// before the `Hasher::finish` call, the results are different due to `from_sha512state` be instantiated with an empty
/// pad while the `default_sha512hasher`'s pad already is populated with `b"hello"`.
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct Sha512State(
    pub NBitWord<u64>,
    pub NBitWord<u64>,
    pub NBitWord<u64>,
    pub NBitWord<u64>,
    pub NBitWord<u64>,
    pub NBitWord<u64>,
    pub NBitWord<u64>,
    pub NBitWord<u64>,
);

impl AddAssign<Sha512BitsState> for Sha512State {
    fn add_assign(&mut self, rhs: Sha512BitsState) {
        self.0 += rhs.0;
        self.1 += rhs.1;
        self.2 += rhs.2;
        self.3 += rhs.3;
        self.4 += rhs.4;
        self.5 += rhs.5;
        self.6 += rhs.6;
        self.7 += rhs.7;
    }
}

impl BuildHasher for Sha512State {
    type Hasher = Sha512Hasher;

    fn build_hasher(&self) -> Self::Hasher {
        Self::Hasher::default()
    }
}

impl BytesLen for Sha512State {
    fn len() -> usize {
        BYTES_LEN
    }
}

impl Default for Sha512State {
    fn default() -> Self {
        Self::from(HX)
    }
}

impl From<[u8; BYTES_LEN]> for Sha512State {
    fn from(v: [u8; BYTES_LEN]) -> Self {
        Self(
            NBitWord::from(u64::from_ne_bytes([v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]])),
            NBitWord::from(u64::from_ne_bytes([v[8], v[9], v[10], v[11], v[12], v[13], v[14], v[15]])),
            NBitWord::from(u64::from_ne_bytes([v[16], v[17], v[18], v[19], v[20], v[21], v[22], v[23]])),
            NBitWord::from(u64::from_ne_bytes([v[24], v[25], v[26], v[27], v[28], v[29], v[30], v[31]])),
            NBitWord::from(u64::from_ne_bytes([v[32], v[33], v[34], v[35], v[36], v[37], v[38], v[39]])),
            NBitWord::from(u64::from_ne_bytes([v[40], v[41], v[42], v[43], v[44], v[45], v[46], v[47]])),
            NBitWord::from(u64::from_ne_bytes([v[48], v[49], v[50], v[51], v[52], v[53], v[54], v[55]])),
            NBitWord::from(u64::from_ne_bytes([v[56], v[57], v[58], v[59], v[60], v[61], v[62], v[63]])),
        )
    }
}

impl From<[u64; 8]> for Sha512State {
    fn from(v: [u64; 8]) -> Self {
        Self(
            NBitWord::from(v[0]),
            NBitWord::from(v[1]),
            NBitWord::from(v[2]),
            NBitWord::from(v[3]),
            NBitWord::from(v[4]),
            NBitWord::from(v[5]),
            NBitWord::from(v[6]),
            NBitWord::from(v[7]),
        )
    }
}

impl From<Sha512State> for ByteArrayWrapper<BYTES_LEN> {
    fn from(value: Sha512State) -> Self {
        let a = u64::to_be_bytes(value.0.into());
        let b = u64::to_be_bytes(value.1.into());
        let c = u64::to_be_bytes(value.2.into());
        let d = u64::to_be_bytes(value.3.into());
        let e = u64::to_be_bytes(value.4.into());
        let f = u64::to_be_bytes(value.5.into());
        let g = u64::to_be_bytes(value.6.into());
        let h = u64::to_be_bytes(value.7.into());

        [
            a[0], a[1], a[2], a[3], a[4], a[5], a[6], a[7], b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7], c[0], c[1],
            c[2], c[3], c[4], c[5], c[6], c[7], d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], e[0], e[1], e[2], e[3],
            e[4], e[5], e[6], e[7], f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7], g[0], g[1], g[2], g[3], g[4], g[5],
            g[6], g[7], h[0], h[1], h[2], h[3], h[4], h[5], h[6], h[7],
        ]
        .into()
    }
}

impl HashAlgorithm for Sha512State {
    type Padding = GenericPad<U128Size, 128, 0x80>;
    type Output = ByteArrayWrapper<BYTES_LEN>;

    fn hash_block(&mut self, bytes: &[u8]) {
        let mut state = Sha512BitsState(
            self.0,
            self.1,
            self.2,
            self.3,
            self.4,
            self.5,
            self.6,
            self.7,
            DWords::<u64>::from(<&[u8; 128]>::try_from(bytes).unwrap()),
        );

        state.block_00_15();
        state.block_16_31();
        state.block_32_47();
        state.block_48_63();
        state.block_64_79();

        *self += state;
    }

    fn state_to_u64(&self) -> u64 {
        self.0.into()
    }
}