Skip to content

feat: add BLAKE3 support - #172

Closed
thevilledev wants to merge 2 commits into
mirage:mainfrom
thevilledev:feat/blake3
Closed

thevilledev wants to merge 2 commits into
mirage:mainfrom
thevilledev:feat/blake3

Conversation

@thevilledev

@thevilledev thevilledev commented Sep 13, 2026 •

Copy link
Copy Markdown

Summary

Add Digestif.BLAKE3 to the C and pure OCaml backends.

Fixes #93.

Changes

  • Standard Digestif hashing, keyed mode, derive-key mode, and seekable XOF.
  • Portable BLAKE3 1.8.7 C code (CC0) under src-c/native, with marked upstream/Digestif sections.
  • Existing hash selectors, conversions, and bigstring runtime-lock handling.

Tests

  • Formatting, package lint, build/install, and documentation build passed.
  • Tests passed on OCaml 4.13.1 and 5.4.1.
  • Ran fuzzing for some time.
  • C ASan/UBSan and threaded/GC checks passed.

Tested locally on macOS.

Make BLAKE3 available through Digestif's existing backend selection so
Mirage and TLS users do not need a separate hashing package. Support
keyed hashing, key derivation, and extensible output in both backends.

Keep the imported C code auditable with pinned upstream provenance and
a clear separation from the Digestif-specific integration.

Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
@thevilledev
thevilledev marked this pull request as ready for review September 13, 2026 17:51
@dinosaure

Copy link
Copy Markdown
Member

The PR seems ok from a quick view, I need time to look into the OCaml implementation but as far as I can tell, I can give a green flag.

Comment thread src-c/native/stubs.c Outdated
__define_hash (blake2s, BLAKE2S)
__define_hash (rmd160, RMD160)

CAMLprim value

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you have a reason of not using __define_hash? blake2{b,s} is particular because it has multiple parameters when we would like to initialize it but I don't see (quickly) a particular case regarding blake3.

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, definitely a better approach. I initially kept it separate because of minor differences in the upstream API (like different context type). I can look into this later today!

@dinosaure dinosaure left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I can see a certain merge path between BLAKE2 and BLAKE3, I need more time to figure out how to organize all of that but I think we can save some lines via functors.

Route BLAKE3's standard operations through the shared hash definition.
A small adapter preserves the upstream API differences while keeping
keyed and extensible-output operations explicit.

Keep the fuzzing change focused on registering BLAKE3 by retaining
Crowbar's existing failure-formatting helper.

Signed-off-by: Ville Vesilehto <ville@vesilehto.fi>
Comment thread src-c/native/stubs.c
return Val_int (upper ## _CTX_SIZE); \
}

struct blake3_ctx {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand such indirection, why we need to wrap the hasher into a struct. Can we just use the digetif_blake3_hasher directly?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To your previous comment #172 (comment): if we want to use __define__hash and not wrap digestif_blake3_hasher we would have to add an explicit third parameter to __define_hash. To demonstrate:

-#define __define_hash(name, upper)
+#define __define_hash(name, upper, ctx_type)

And then something like this:

__define_hash (md5, MD5, struct md5_ctx)
__define_hash (sha1, SHA1, struct sha1_ctx)
__define_hash (sha224, SHA224, struct sha224_ctx)
__define_hash (sha256, SHA256, struct sha256_ctx)
__define_hash (sha384, SHA384, struct sha384_ctx)
__define_hash (sha512, SHA512, struct sha512_ctx)
__define_hash (whirlpool, WHIRLPOOL, struct whirlpool_ctx)
__define_hash (blake2b, BLAKE2B, struct blake2b_ctx)
__define_hash (blake2s, BLAKE2S, struct blake2s_ctx)
__define_hash (blake3, BLAKE3, digestif_blake3_hasher)
__define_hash (rmd160, RMD160, struct rmd160_ctx)

The blake3_ctx is there simply to be aligned with the macro & not refactor at this point. Which way do we go?

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

#174 should help, I'm waiting the CI and see if everything is correct but your PR should just define a typedef then to rename blake3_hasher to blake3_ctx.

@dinosaure dinosaure mentioned this pull request Sep 25, 2026
@dinosaure

Copy link
Copy Markdown
Member

Replaced by #180 where the diff is much more smaller.

@dinosaure dinosaure closed this Sep 25, 2026
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.

BLAKE3

2 participants