1 | const MOD: u32 = 65521; |
2 | const NMAX: usize = 5552; |
3 | |
4 | pub fn update(a: u16, b: u16, data: &[u8]) -> (u16, u16) { |
5 | let mut a = a as u32; |
6 | let mut b = b as u32; |
7 | |
8 | let chunks = data.chunks_exact(NMAX); |
9 | let remainder = chunks.remainder(); |
10 | |
11 | for chunk in chunks { |
12 | for byte in chunk { |
13 | a = a.wrapping_add(*byte as _); |
14 | b = b.wrapping_add(a); |
15 | } |
16 | |
17 | a %= MOD; |
18 | b %= MOD; |
19 | } |
20 | |
21 | for byte in remainder { |
22 | a = a.wrapping_add(*byte as _); |
23 | b = b.wrapping_add(a); |
24 | } |
25 | |
26 | a %= MOD; |
27 | b %= MOD; |
28 | |
29 | (a as u16, b as u16) |
30 | } |
31 | |
32 | #[cfg (test)] |
33 | mod tests { |
34 | #[test ] |
35 | fn zeroes() { |
36 | assert_eq!(adler32(&[]), 1); |
37 | assert_eq!(adler32(&[0]), 1 | 1 << 16); |
38 | assert_eq!(adler32(&[0, 0]), 1 | 2 << 16); |
39 | assert_eq!(adler32(&[0; 100]), 0x00640001); |
40 | assert_eq!(adler32(&[0; 1024]), 0x04000001); |
41 | assert_eq!(adler32(&[0; 1024 * 1024]), 0x00f00001); |
42 | } |
43 | |
44 | #[test ] |
45 | fn ones() { |
46 | assert_eq!(adler32(&[0xff; 1024]), 0x79a6fc2e); |
47 | assert_eq!(adler32(&[0xff; 1024 * 1024]), 0x8e88ef11); |
48 | } |
49 | |
50 | #[test ] |
51 | fn mixed() { |
52 | assert_eq!(adler32(&[1]), 2 | 2 << 16); |
53 | assert_eq!(adler32(&[40]), 41 | 41 << 16); |
54 | |
55 | assert_eq!(adler32(&[0xA5; 1024 * 1024]), 0xd5009ab1); |
56 | } |
57 | |
58 | /// Example calculation from https://en.wikipedia.org/wiki/Adler-32. |
59 | #[test ] |
60 | fn wiki() { |
61 | assert_eq!(adler32(b"Wikipedia" ), 0x11E60398); |
62 | } |
63 | |
64 | fn adler32(data: &[u8]) -> u32 { |
65 | let (a, b) = super::update(1, 0, data); |
66 | |
67 | u32::from(b) << 16 | u32::from(a) |
68 | } |
69 | } |
70 | |