| 1 | // Copyright (c) 2019-2024 Alexander Medvednikov. All rights reserved. |
| 2 | // Use of this source code is governed by an MIT license |
| 3 | // that can be found in the LICENSE file. |
| 4 | |
| 5 | // This is a pure V implementation of Adler-32 from RFC 1950. |
| 6 | // Parameters: BASE=65521, init=1, output=(s2 << 16) | s1. |
| 7 | module adler32 |
| 8 | |
| 9 | // base is the largest prime smaller than 2^16, mandated by RFC 1950. |
| 10 | pub const base = u32(65521) |
| 11 | // nmax is the largest chunk size that keeps intermediate sums inside u32. |
| 12 | // See RFC 1950 Appendix and zlib's adler32 implementation. |
| 13 | pub const nmax = 5552 |
| 14 | |
| 15 | // update_state updates an Adler-32 state with `data`. |
| 16 | // For RFC-1950 compliant checksums, use state `1` for a new stream. |
| 17 | @[direct_array_access] |
| 18 | pub fn update_state(state u32, data []u8) u32 { |
| 19 | mut s1 := state & u32(0xffff) |
| 20 | mut s2 := state >> 16 |
| 21 | mut pos := 0 |
| 22 | for pos < data.len { |
| 23 | block_len := if data.len - pos > nmax { nmax } else { data.len - pos } |
| 24 | for _ in 0 .. block_len { |
| 25 | s1 += data[pos] |
| 26 | if s1 >= base { |
| 27 | s1 -= base |
| 28 | } |
| 29 | s2 += s1 |
| 30 | pos++ |
| 31 | } |
| 32 | s2 %= base |
| 33 | } |
| 34 | return (s2 << 16) | s1 |
| 35 | } |
| 36 | |
| 37 | // checksum returns the RFC-1950 Adler-32 checksum for `data`. |
| 38 | pub fn checksum(data []u8) u32 { |
| 39 | return update_state(u32(1), data) |
| 40 | } |
| 41 | |
| 42 | // update extends an existing Adler-32 checksum `adler` with `data`. |
| 43 | // Use `adler = 1` for a fresh checksum. |
| 44 | pub fn update(adler u32, data []u8) u32 { |
| 45 | return update_state(adler, data) |
| 46 | } |
| 47 | |
| 48 | // sum is an alias for checksum. |
| 49 | pub fn sum(data []u8) u32 { |
| 50 | return checksum(data) |
| 51 | } |
| 52 | |