1use byteorder::{ByteOrder, BE};
2use lazy_static::lazy_static;
3
4use crate::{consts::H256, platform::Implementation};
5
6lazy_static! {
7 static ref IMPL: Implementation = Implementation::detect();
8}
9
10#[derive(Clone)]
11pub struct Sha256 {
12 len: u64,
13 state: [u32; 8],
14}
15
16impl Default for Sha256 {
17 fn default() -> Self {
18 Sha256 {
19 len: 0,
20 state: H256,
21 }
22 }
23}
24
25impl Sha256 {
26 pub fn new() -> Self {
27 Sha256::default()
28 }
29
30 pub fn digest(blocks: &[&[u8]]) -> [u8; 32] {
31 let mut sha = Sha256::new();
32 sha.input(blocks);
33 sha.finish()
34 }
35
36 pub fn input(&mut self, blocks: &[&[u8]]) {
37 debug_assert_eq!(blocks.len() % 2, 0, "invalid block length");
38
39 self.len += (blocks.len() as u64) << 8;
40
41 IMPL.compress256(&mut self.state, blocks);
42 }
43
44 pub fn finish(mut self) -> [u8; 32] {
45 let mut block0 = [0u8; 32];
46 let mut block1 = [0u8; 32];
47
48 block0[0] = 0b1000_0000;
50
51 let l = self.len;
53 block1[32 - 8..].copy_from_slice(&l.to_be_bytes()[..]);
54
55 IMPL.compress256(&mut self.state, &[&block0[..], &block1[..]][..]);
56
57 let mut out = [0u8; 32];
58 BE::write_u32_into(&self.state, &mut out);
59 out
60 }
61
62 pub fn finish_with(mut self, block0: &[u8]) -> [u8; 32] {
63 debug_assert_eq!(block0.len(), 32);
64
65 let mut block1 = [0u8; 32];
66
67 block1[0] = 0b1000_0000;
69
70 let l = self.len + 256;
72 block1[32 - 8..].copy_from_slice(&l.to_be_bytes()[..]);
73
74 IMPL.compress256(&mut self.state, &[block0, &block1[..]][..]);
75
76 let mut out = [0u8; 32];
77 BE::write_u32_into(&self.state, &mut out);
78 out
79 }
80}
81
82opaque_debug::implement!(Sha256);
83
84#[cfg(test)]
85mod tests {
86 use super::*;
87
88 use rand::{RngCore, SeedableRng};
89 use rand_xorshift::XorShiftRng;
90 use sha2::{Digest, Sha256 as Original};
91
92 #[test]
93 fn test_fuzz_simple() {
94 fuzz(10);
95 }
96
97 #[test]
98 #[ignore]
99 fn test_fuzz_long() {
100 fuzz(1_000);
101 }
102
103 fn fuzz(n: usize) {
104 let rng = &mut XorShiftRng::from_seed([
105 0x59, 0x62, 0xbe, 0x5d, 0x76, 0x3d, 0x31, 0x8d, 0x17, 0xdb, 0x37, 0x32, 0x54, 0x06,
106 0xbc, 0xe5,
107 ]);
108 for k in 1..n {
109 for _ in 0..100 {
110 let mut input = vec![0u8; 64 * k];
111 rng.fill_bytes(&mut input);
112 let chunked = input.chunks(32).collect::<Vec<_>>();
113 assert_eq!(&Sha256::digest(&chunked)[..], &Original::digest(&input)[..])
114 }
115 }
116
117 for k in (1..n).step_by(2) {
118 for _ in 0..100 {
119 let mut input = vec![0u8; 32 * k];
120 rng.fill_bytes(&mut input);
121 let mut hasher = Sha256::new();
122 for chunk in input.chunks(64) {
123 if chunk.len() == 64 {
124 hasher.input(&[&chunk[..32], &chunk[32..]]);
125 }
126 }
127 assert_eq!(input.len() % 64, 32);
128 let hash = hasher.finish_with(&input[input.len() - 32..]);
129
130 assert_eq!(
131 &hash[..],
132 &Original::digest(&input)[..],
133 "input: {:?}",
134 &input
135 );
136 }
137 }
138 }
139}