2
$\begingroup$

The Argon2 variable-length hash function uses BLAKE2b directly if the user requests an output less than or equal to 64 bytes in length. However, if the user requests an output longer than this, each BLAKE2b-512 hash is truncated to become BLAKE2b-512-256. From Wikipedia:

   // If the requested digestSize is 64-bytes or lower, then we use Blake2b directly
   if (digestSize <= 64) then
      // concatenate 32-bit little endian digestSize with the message bytes
      return Blake2b(digestSize ∥ message, digestSize)

   // For desired hashes over 64-bytes (e.g. 1024 bytes for Argon2 blocks),
   // we use Blake2b to generate twice the number of needed 64-byte blocks,
   // and then only use 32-bytes from each block

   // Calculate the number of whole blocks (knowing we're only going to use 32-bytes from each)
   r ← Ceil(digestSize/32)-2;

   // Generate r whole blocks.
   // Initial block is generated from message
   V1 ← Blake2b(digestSize ∥ message, 64);
   // Subsequent blocks are generated from previous blocks
   for i ← 2 to r do
      Vi ← Blake2b(Vi-1, 64)
   // Generate the final (possibly partial) block
   partialBytesNeeded ← digestSize – 32*r;
   Vr+1 ← Blake2b(Vr, partialBytesNeeded)

   // Concatenate the first 32-bytes of each block Vi
   // (except the possibly partial last block, which we take the whole thing)
   // Let Ai represent the lower 32-bytes of block Vi
   return A1 ∥ A2 ∥ ... ∥ Ar ∥ Vr+1

I didn't see any rationale for this glancing at the specification and RFC. Why are they not using full BLAKE2b-512 outputs?

$\endgroup$
4
  • $\begingroup$ Because it is designed for password hashing where there is no collision problem so 256-bit is enough for all. $\endgroup$
    – kelalaka
    Commented Jan 21 at 16:07
  • $\begingroup$ @kelalaka Yes, I'm aware of that, but truncation results in more computation (more hashing) for larger outputs. Deriving a short output hasn't been slowed down. It doesn't seem like domain separation when V1 is the same as a digestSize = 64. $\endgroup$ Commented Jan 21 at 16:48
  • 2
    $\begingroup$ A by now classic remark for "why" questions: have you tried to contact the authors? If possible it would be great if they or otherwise you could post the answer here. $\endgroup$
    – Maarten Bodewes
    Commented Jan 21 at 22:30
  • $\begingroup$ @MaartenBodewes I haven't but seeing as nobody has answered, I'll do that. I've had mixed success emailing academics/engineers so it's not my go-to approach. $\endgroup$ Commented Jan 22 at 16:34

1 Answer 1

2
$\begingroup$

Emailing all three authors resulted in no reply, but I realised this is done to prevent you computing subsequent blocks from previous blocks.

Given the first block of output, you don't want someone to be able to compute other blocks of output without knowing the key (or in this case, the final block of the Argon2 operation). Truncation solves this by hiding half the input.

Then if the output length is <= 64 bytes, there's only one output block, meaning there's no need to worry about this problem.

You can think of it like symmetric-key ratchets/KDF chains and how the KDF key and output key must be different/independent:

KDF chain

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.