Skip to content

feat: Implement BLAKE2X XOF (Blake2Xb and Blake2Xs) #704

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from

Conversation

huitseeker
Copy link

@huitseeker huitseeker commented Jul 15, 2025

This PR introduces an implementation of Blake2X – inspired from, but greatly extends on #677. This contributes to #1.

Category Lines
Test Vector Files 6148
Unit Tests 762
Dependency Management 124
Implementation 631

This is a complete implementation of the Blake2X extensible-output function (XOF) for both its 64-bit (Blake2Xb) and 32-bit (Blake2Xs) variants. This new functionality is gated behind the blake2x cargo feature flag.

1. Implementation and Design

The implementation follows the design principles of the existing crate, utilizing a macro-driven approach to provide generic logic for both Blake2Xb and Blake2Xs, which minimizes code duplication.

  • Core Logic (macros.rs): A new macro, blake2x_impl!, has been introduced.

  • Algorithm (blake2x.rs): The implementation follows the two-phase process specified by the Blake2X algorithm:

    1. Root Hash Generation: It first computes a root hash (H₀) using the underlying Blake2bVarCore or Blake2sVarCore. Crucially, it incorporates the total desired output length (xof_len) into the parameter block during this phase. This ensures that outputs of different lengths are cryptographically distinct, a key security feature of Blake2X.
    2. Output Expansion: The finalize_xof() method returns a Reader struct. This reader generates the final hash output incrementally. For each block of output requested, it computes a new hash by feeding the root hash H₀ into the base BLAKE2 function, but with a unique parameter block for each "expansion node" (differentiated by an incrementing node_offset). This logic is encapsulated in the expand_node helper function.
  • Public API: New public-facing structs Blake2xb, Blake2xs, and their corresponding Reader types are exposed.

2. Testing and Validation

The implementation is supported by a comprehensive test suite in tests/blake2x.rs that validates correctness through two primary resources: official test vectors and a reference implementation.

  • Test Vectors:

    • The tests/data/ directory now includes blake2xb-kat.json and blake2xs-kat.json. These are the test vectors sourced directly from the BLAKE2 RFC repository.
    • The tests parse these JSON files and validate the implementation against a wide range of input and output sizes for both keyed and unkeyed hashing.
  • Reference Implementation (b2rs):

    • To further ensure correctness, the test suite now uses the b2rs crate as a reference implementation. This crate is maintained on GitHub by Jean-Philippe Aumasson (@veorq), one of the original authors of the BLAKE2 algorithm.
    • The tests use b2rs in two ways:
      1. Fuzz-like comparison: Random inputs and output lengths are generated, and the output of our implementation is compared against the output of b2rs.
      2. Internal State Validation: The tests go a step further by using b2rs to verify intermediate values of the Blake2X computation, such as the value of the root hash (H₀) and the output of the first expansion node. This confirms that our internal parameter block construction and hashing logic are correct, not just the final result.

All tests, including functional checks for progressive reads and constructor behavior, are passing.


Edit: the last 2 commits of the PR respectively fix a typo-detection CI false positive, and unrelated clippy warnings.

@huitseeker huitseeker force-pushed the blake2x-pr branch 4 times, most recently from 29d8e5a to 80960a4 Compare July 15, 2025 21:21
This commit introduces an implementation of Blake2X, the extensible-output
function (XOF) variant of the BLAKE2 hash function. Blake2X is specified
in the official BLAKE2 paper and is designed to produce hash outputs of
arbitrary length.

It is useful for applications requiring digests longer than the standard
BLAKE2 output sizes, such as in certain digital signature schemes (e.g.,
EdDSA with large curves) or as a Key Derivation Function (KDF).

The implementation provides `Blake2xb` (64-bit) and `Blake2xs` (32-bit)
variants, along with their corresponding `XofReader`s. Both are accessible
under a new `blake2x` feature flag.

The core logic is consolidated within a `blake2x_impl!` macro to generate
the necessary structures and trait implementations for both variants,
minimizing code duplication. The implementation correctly handles the
Blake2X tree-hashing mode:
- The initial root hash is computed using a standard BLAKE2 core with the
  XOF output length encoded in the parameter block.
- Subsequent output blocks are generated by creating and hashing expansion
  nodes using the root hash as input, as per the specification.

Keyed hashing is supported through `new_with_key` constructors for both
`Blake2xb` and `Blake2xs`.

A comprehensive test suite has been added, including:
- Test vectors) for both keyed and unkeyed hashing, sourced
  from new JSON test vector files.
- Comparison tests against the `b2rs` reference implementation to ensure
  correctness.
- Functional tests for progressive output reads and constructor
  parameterization.
@huitseeker
Copy link
Author

@newpavlov Happy to add a CHANGELOG line as part of this PR, or remove the b2rs unit tests, or anything else you might think needs adapting.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant