1use crate::arith::{Word64, rotr};
2use crate::hash_state;
3use crate::hash_state::HashState;
4use crate::traits::*;
5use crate::consts::*;
6
7pub struct Sha512 {
9 h: [Word64; 8],
11 message_len: u128,
13 block_len: usize,
15 current_block: [u8; SHA512_BLOCK_SIZE],
17}
18
19impl Sha512 {
20 pub fn new() -> Self {
22 Self {
23 h: SHA512_H,
24 current_block: [0u8; SHA512_BLOCK_SIZE],
25 block_len: 0usize,
26 message_len: 0u128,
27 }
28 }
29 fn process_block(&mut self) {
31 if self.block_len != SHA512_BLOCK_SIZE {
32 panic!("block is not filled");
33 }
34 let mut w = [Word64(0); 80];
35 for t in 0..16 {
36 w[t] = self.get_word64_in_block(t)
37 }
38 for t in 16..80 {
39 w[t] = Self::lsigma1(w[t - 2]) + w[t - 7] + Self::lsigma0(w[t - 15]) + w[t - 16];
40 }
41 let mut a = self.h[0];
42 let mut b = self.h[1];
43 let mut c = self.h[2];
44 let mut d = self.h[3];
45 let mut e = self.h[4];
46 let mut f = self.h[5];
47 let mut g = self.h[6];
48 let mut h = self.h[7];
49
50 for t in 0..80 {
51 let t1 = h + Self::sigma1(e) + Self::ch(e, f, g) + SHA512_K[t] + w[t];
52 let t2 = Self::sigma0(a) + Self::maj(a, b, c);
53 h = g;
54 g = f;
55 f = e;
56 e = d + t1;
57 d = c;
58 c = b;
59 b = a;
60 a = t1 + t2;
61 }
62 self.h[0] = a + self.h[0];
63 self.h[1] = b + self.h[1];
64 self.h[2] = c + self.h[2];
65 self.h[3] = d + self.h[3];
66 self.h[4] = e + self.h[4];
67 self.h[5] = f + self.h[5];
68 self.h[6] = g + self.h[6];
69 self.h[7] = h + self.h[7];
70
71 self.current_block = [0u8; SHA512_BLOCK_SIZE]; self.block_len = 0; }
74
75 const fn get_word64_in_block(&self, i: usize) -> Word64 {
77 let m: u64 =
78 ((self.current_block[i * 8] as u64) << 56)
79 + ((self.current_block[i * 8 + 1] as u64) << 48)
80 + ((self.current_block[i * 8 + 2] as u64) << 40)
81 + ((self.current_block[i * 8 + 3] as u64) << 32)
82 + ((self.current_block[i * 8 + 4] as u64) << 24)
83 + ((self.current_block[i * 8 + 5] as u64) << 16)
84 + ((self.current_block[i * 8 + 6] as u64) << 8)
85 + (self.current_block[i * 8 + 7] as u64);
86 Word64(m)
87 }
88}
89
90impl Sha512 {
92 fn sigma0(x: Word64) -> Word64 {
93 rotr(x, 28) ^ rotr(x, 34) ^ rotr(x, 39)
94 }
95 fn sigma1(x: Word64) -> Word64 {
96 rotr(x, 14) ^ rotr(x, 18) ^ rotr(x, 41)
97 }
98 fn lsigma0(x: Word64) -> Word64 {
99 rotr(x, 1) ^ rotr(x, 8) ^ (x >> 7)
100 }
101 fn lsigma1(x: Word64) -> Word64 {
102 rotr(x, 19) ^ rotr(x, 61) ^ (x >> 6)
103 }
104 fn ch(x: Word64, y: Word64, z: Word64) -> Word64 {
105 (x & y) ^ (!x & z)
106 }
107 fn maj(x: Word64, y: Word64, z: Word64) -> Word64 {
108 (x & y) ^ (x & z) ^ (y & z)
109 }
110}
111impl StreamHasher for Sha512 {
112 type Output = [u8; 64];
113 const BLOCK_SIZE: usize = SHA512_BLOCK_SIZE;
114 fn update(&mut self, buf: &[u8]) -> usize {
115 let len = buf.len();
116 if len == 0 {
117 return 0;
119 }
120 let writable_len = Self::BLOCK_SIZE - self.block_len;
121 let writable_area = &mut self.current_block[self.block_len..];
122
123 if len >= writable_len {
124 writable_area.clone_from_slice(&buf[0..writable_len]); self.block_len += writable_len;
127 self.message_len += writable_len as u128;
128 self.process_block(); self.update(&buf[writable_len..]); } else {
131 let write_area = &mut self.current_block[self.block_len..self.block_len + len];
133 write_area.clone_from_slice(&buf[..]);
134 self.block_len += len;
135 self.message_len += len as u128;
136 }
137 len
138 }
139 fn finish(mut self) -> Self::Output {
140 self.current_block[self.block_len] = 0x80;
141 if self.block_len + 1 + 16 > Self::BLOCK_SIZE {
142 self.block_len = Self::BLOCK_SIZE;
145 self.process_block(); }
147 let writable_area = &mut self.current_block[Self::BLOCK_SIZE - 16..Self::BLOCK_SIZE];
148 let len_bits = self.message_len * 8;
149 writable_area.clone_from_slice(&len_bits.to_be_bytes());
150 self.block_len = Self::BLOCK_SIZE;
151 self.process_block();
152 let mut final_hash: Self::Output = [0; 64];
153 for i in 0..8 {
154 let word_area = &mut final_hash[i * 8..i * 8 + 8];
155 word_area.clone_from_slice(&self.h[i].0.to_be_bytes());
156 }
157 return final_hash;
158 }
159
160}
161impl Resumable for Sha512 {
162 fn pause(self) -> HashState {
163 let h: [u64; 8] = [
164 self.h[0].0,
165 self.h[1].0,
166 self.h[2].0,
167 self.h[3].0,
168 self.h[4].0,
169 self.h[5].0,
170 self.h[6].0,
171 self.h[7].0,
172 ];
173 HashState::Sha512(hash_state::Sha512HashState {
174 h,
175 message_len: self.message_len,
176 block_len: self.block_len,
177 current_block: self.current_block,
178 })
179 }
180 fn resume(hash_state: HashState) -> Result<Self, hash_state::Error> {
181 match hash_state {
182 HashState::Sha512(hs) => Ok(Self {
183 h: arr64![hs.h[0], hs.h[1], hs.h[2], hs.h[3], hs.h[4], hs.h[5], hs.h[6], hs.h[7]],
184 message_len: hs.message_len,
185 block_len: hs.block_len,
186 current_block: hs.current_block,
187 }),
188 _ => Err(hash_state::Error::HashTypeNotMatch),
189 }
190 }
191}
192impl Default for Sha512 {
193 fn default() -> Self {
194 Self::new()
195 }
196}