vole_document/
integrity.rs1use sha2::{Digest, Sha256};
12
13pub struct Sha256Hasher {
15 inner: Sha256,
16}
17
18impl Sha256Hasher {
19 pub fn new() -> Self {
21 Sha256Hasher {
22 inner: Sha256::new(),
23 }
24 }
25
26 pub fn update(&mut self, data: &[u8]) {
28 self.inner.update(data);
29 }
30
31 pub fn finalize(self) -> [u8; 32] {
33 let out = self.inner.finalize();
34 let mut buf = [0u8; 32];
35 buf.copy_from_slice(&out);
36 buf
37 }
38}
39
40impl Default for Sha256Hasher {
41 fn default() -> Self {
42 Self::new()
43 }
44}
45
46pub fn sha256(data: &[u8]) -> [u8; 32] {
48 let mut h = Sha256Hasher::new();
49 h.update(data);
50 h.finalize()
51}
52
53pub fn to_hex(bytes: &[u8]) -> String {
55 const HEX: &[u8; 16] = b"0123456789abcdef";
56 let mut s = String::with_capacity(bytes.len() * 2);
57 for &b in bytes {
58 s.push(HEX[(b >> 4) as usize] as char);
59 s.push(HEX[(b & 0x0F) as usize] as char);
60 }
61 s
62}
63
64pub fn crc32c(data: &[u8]) -> u32 {
68 let mut crc = 0xFFFF_FFFFu32;
69 for &b in data {
70 let idx = ((crc ^ b as u32) & 0xFF) as usize;
71 crc = (crc >> 8) ^ CRC32C_TABLE[idx];
72 }
73 !crc
74}
75
76const fn build_crc32c_table() -> [u32; 256] {
77 let mut table = [0u32; 256];
78 let mut i = 0usize;
79 while i < 256 {
80 let mut crc = i as u32;
81 let mut bit = 0;
82 while bit < 8 {
83 if crc & 1 != 0 {
84 crc = (crc >> 1) ^ 0x82F6_3B78;
85 } else {
86 crc >>= 1;
87 }
88 bit += 1;
89 }
90 table[i] = crc;
91 i += 1;
92 }
93 table
94}
95
96static CRC32C_TABLE: [u32; 256] = build_crc32c_table();
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn crc32c_standard_vector() {
104 assert_eq!(crc32c(b"123456789"), 0xE306_9283);
106 assert_eq!(crc32c(b""), 0x0000_0000);
107 }
108
109 #[test]
110 fn sha256_standard_vectors() {
111 assert_eq!(
112 to_hex(&sha256(b"abc")),
113 "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad"
114 );
115 assert_eq!(
116 to_hex(&sha256(b"")),
117 "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855"
118 );
119 }
120
121 #[test]
122 fn streaming_matches_oneshot() {
123 let data = b"the quick brown fox jumps over the lazy dog";
124 let mut h = Sha256Hasher::new();
125 h.update(&data[..10]);
126 h.update(&data[10..]);
127 assert_eq!(h.finalize(), sha256(data));
128 }
129
130 #[test]
131 fn hex_roundtrip_shape() {
132 assert_eq!(to_hex(&[0x00, 0x0f, 0xff]), "000fff");
133 }
134}