// Implements the Adler-32 checksum algorithm. It is a non-cryptographic // checksum. use endian; use hash; use io; use strings; type state = struct { hash: hash::hash, a: u32, b: u32, }; // Creates a [hash::hash] which computes the Adler-32 checksum algorithm. export fn adler32() *hash::hash = alloc(state { hash = hash::hash { stream = io::stream { writer = &write, closer = &close, ... }, sum = &sum, reset = &reset, sz = 4, }, a = 1, b = 0, }): *hash::hash; fn close(s: *io::stream) void = free(s); fn write(s: *io::stream, buf: const []u8) (size | io::error) = { let s = s: *state; for (let i = 0z; i < len(buf); i += 1) { s.a = (s.a + buf[i]) % 65521; s.b = (s.b + s.a) % 65521; }; return len(buf); }; fn reset(h: *hash::hash) void = { let h = h: *state; h.a = 1; h.b = 0; }; fn sum(h: *hash::hash) []u8 = { let h = h: *state; let buf: [4]u8 = [0...]; // RFC 1950 specifies that Adler-32 checksums are stored in network // order. endian::beputu32(buf, (h.b << 16) | h.a); return alloc(buf); }; export fn sum32(h: *hash::hash) u32 = { assert(h.reset == &reset); let h = h: *state; return h.b << 16 | h.a; }; @test fn adler32() void = { const vectors: [](str, u32) = [ ("", 1), ("hello world", 436929629), ("Hare is a cool language", 1578567727), ("'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), ("'Life is too short to run proprietary software' - Bdale Garbee", 3135706652), ("'The central enemy of reliability is complexity.' - Geer et al", 3170309588), ("'A language that doesn’t have everything is actually easier to program in than some that do.' - Dennis Ritchie", 1148528899), ]; let hash = adler32(); defer hash::close(hash); for (let i = 0z; i < len(vectors); i += 1) { let vec = vectors[i]; hash::reset(hash); hash::write(hash, strings::toutf8(vec.0)); let s = hash::sum(hash); defer free(s); assert(endian::begetu32(s) == vec.1); assert(sum32(hash) == vec.1); }; };