hash.bend
1# The hash interface.
2#
3# A hash (template arguments, in this order):
4# ~H: Data the state
5# ~bsize: Nat the block size in bytes (HMAC's B)
6# ~dsize: Nat the digest size in bytes (HMAC's L)
7# ~init: H the state before any byte
8# ~update: H -> B.Octets -> H the state after more bytes
9# ~final: H -> B.Octets the digest of the bytes so far
10# ~digest: B.Octets -> B.Octets the digest in one call
11# Laws (README.md, "Laws"):
12# streaming update(s, a ++ b) == update(update(s, a), b), for every state
13# s, so pieces may be fed in any split
14# split final(update(update(init, a), b)) == digest(a ++ b): the
15# streaming result equals the one-shot result for every split
16# length final(s) has dsize bytes (tested)
17#
18# A hash whose one-shot form is not separate code takes CrHash.digest_of (the
19# streaming form in one call) as its ~digest. The instances: inst_crc.bend
20# (CRC-32 and CRC-64 of any parameter set, non-cryptographic), inst_sha2.bend
21# (SHA-256, SHA-512), and the hashes package's MD4, MD5, SHA-1, RIPEMD-160,
22# SM3 and Streebog (their defs directly; each file's header gives its tuple).
23# Generic algorithms over any hash: hmac.bend, hkdf.bend.
24import Base
25import bend-osdev-bytes@0.1.0.0/bytes.bend as B
26
27def cr.hash.feed(~H: Data, ~update: H -> B.Octets -> H, ps: List<&2, B.Octets>, s: H) -> H:
28 match ps:
29 case Nil{}:
30 s
31 case Con{p, t}:
32 cr.hash.feed(~H, ~update, t, update(s, p))
33
34# the state after each piece in turn
35def CrHash.update_all(~H: Data, ~update: H -> B.Octets -> H, s: H, ps: List<&2, B.Octets>) -> H:
36 cr.hash.feed(~H, ~update, ps, s)
37
38# the digest of the pieces joined, through the streaming interface
39def CrHash.of_pieces(~H: Data, ~init: H, ~update: H -> B.Octets -> H, ~final: H -> B.Octets, ps: List<&2, B.Octets>) -> B.Octets:
40 final(CrHash.update_all(~H, ~update, init, ps))
41
42# the streaming interface in one call: a ~digest for a hash with no one-shot
43# code of its own
44def CrHash.digest_of(~H: Data, ~init: H, ~update: H -> B.Octets -> H, ~final: H -> B.Octets, m: B.Octets) -> B.Octets:
45 final(update(init, m))