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:
mixis G,columns_then_diagonalsthe index sets,initandfinalizethe 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
@spec hash(binary()) :: <<_::256>>
Returns the 32-byte BLAKE2b-256 digest of data.
iex> Rexd.Blake2b.hash("abc") |> Base.encode16(case: :lower)
"bddd813c634239723171ef3fee98579b94964e3bb1cb3e427262c8c068d52319"