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. 24 import Base 25 import bend-osdev-bytes@0.1.0.0/bytes.bend as B 26 27 def 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 35 def 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 39 def 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 44 def 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))