Rexd.Blake2b (Rexd v1.0.0)

Copy Markdown View Source

BLAKE2b-256 (RFC 7693, unkeyed, digest length 32), the strong hash of librsync RS_*_BLAKE2_SIG_MAGIC signatures.

librsync initialises BLAKE2b with a 32-byte digest length and truncates the result to the signature's strong_sum_len. BLAKE2b-256 is not a prefix of BLAKE2b-512: the digest length is part of the parameter block mixed into the initial state. :crypto only provides BLAKE2b-512, hence this module.

Why the code looks like this

The straightforward implementation (64-bit words in a tuple, a g/7 function applied per round) is about 18 times slower, and the strong hash bounds the speed of Rexd.signature/2. Two choices trade readability for that factor:

  • Split words. BEAM small integers hold 60 bits, so 64-bit additions and rotations allocate a bignum almost every time. Each word is carried as two 32-bit halves (hi, lo) with the carry propagated by hand, so nothing allocates.
  • Compile-time unrolling. The twelve rounds are generated as one function body of plain variable bindings, avoiding tuple reads and writes and per-round calls. The generator below mirrors RFC 7693 section 3: mix is G, columns_then_diagonals the index sets, init and finalize the state set-up and feed-forward.

Correctness is checked against b2sum -l 256 and committed digests. See NOTES.md, "Code shaped by performance", for measurements.

Summary

Functions

Returns the 32-byte BLAKE2b-256 digest of data.

Functions

hash(data)

@spec hash(binary()) :: <<_::256>>

Returns the 32-byte BLAKE2b-256 digest of data.

iex> Rexd.Blake2b.hash("abc") |> Base.encode16(case: :lower)
"bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319"