adler32.ha (2145B)
1 // SPDX-License-Identifier: MPL-2.0 2 // (c) Hare authors <https://harelang.org> 3 4 use endian; 5 use hash; 6 use io; 7 use strings; 8 9 // The size, in bytes, of an Adler-32 checksum. 10 export def SZ: size = 4; 11 12 export type state = struct { 13 hash::hash, 14 a: u32, 15 b: u32, 16 }; 17 18 const adler32_vtable: io::vtable = io::vtable { 19 writer = &write, 20 ... 21 }; 22 23 // Creates a [[hash::hash]] which computes the Adler-32 checksum algorithm. This 24 // hash does not allocate any state, so you do not need to call [[hash::close]] 25 // when you are done with it. 26 export fn adler32() state = state { 27 stream = &adler32_vtable, 28 sum = &sum, 29 reset = &reset, 30 sz = 4, 31 a = 1, 32 b = 0, 33 ... 34 }; 35 36 fn write(s: *io::stream, buf: const []u8) (size | io::error) = { 37 let s = s: *state; 38 for (let i = 0z; i < len(buf); i += 1) { 39 s.a = (s.a + buf[i]) % 65521; 40 s.b = (s.b + s.a) % 65521; 41 }; 42 return len(buf); 43 }; 44 45 fn reset(h: *hash::hash) void = { 46 let h = h: *state; 47 h.a = 1; 48 h.b = 0; 49 }; 50 51 fn sum(h: *hash::hash, buf: []u8) void = { 52 let h = h: *state; 53 // RFC 1950 specifies that Adler-32 checksums are stored in network 54 // order. 55 endian::beputu32(buf, (h.b << 16) | h.a); 56 }; 57 58 export fn sum32(h: *hash::hash) u32 = { 59 assert(h.reset == &reset); 60 let h = h: *state; 61 return h.b << 16 | h.a; 62 }; 63 64 @test fn adler32() void = { 65 const vectors: [](str, u32) = [ 66 ("", 1), 67 ("hello world", 436929629), 68 ("Hare is a cool language", 1578567727), 69 ("'UNIX was not designed to stop its users from doing stupid things, as that would also stop them from doing clever things' - Doug Gwyn", 2140876731), 70 ("'Life is too short to run proprietary software' - Bdale Garbee", 3135706652), 71 ("'The central enemy of reliability is complexity.' - Geer et al", 3170309588), 72 ("'A language that doesn’t have everything is actually easier to program in than some that do.' - Dennis Ritchie", 1148528899), 73 74 ]; 75 76 let hash = adler32(); 77 let s: [4]u8 = [0...]; 78 79 for (let i = 0z; i < len(vectors); i += 1) { 80 let vec = vectors[i]; 81 hash::reset(&hash); 82 hash::write(&hash, strings::toutf8(vec.0)); 83 84 hash::sum(&hash, s); 85 86 assert(endian::begetu32(s) == vec.1); 87 assert(sum32(&hash) == vec.1); 88 }; 89 };