Skip to content
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

Make portable implementation const #439

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

Conversation

nazar-pc
Copy link

@nazar-pc nazar-pc commented Jan 5, 2025

I was going to use BLAKE3 in const environment, but it doesn't support such use case yet.

This relatively small PR refactors portable implementation to make it work in const environment.

There is a bit of trivially verifiable unsafe due to nicer APIs not yet available in const environment, but these all work on stable.

arrayref were hard to read and used slicing that is not compatible with const, so I replaced it with a couple simple macros where it was necessary and left other usages as is.


UPD: I decided to implement the whole thing, added const_hash, const_keyed_hash and const_derive_key functions by copying the originals and modifying them to use const fn portable implementation.

I didn't add ConstHasher, though it is possible too if someone needs it.

Resolves #440

Copy link

@devinrsmith devinrsmith left a comment

Choose a reason for hiding this comment

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

FYI: I'm not a maintainer of this library, but I do like to keep up to date with some of the going-ons.

@@ -120,7 +119,7 @@ pub fn compress_xof(
crate::platform::le_bytes_from_words_64(&state)
}

pub fn hash1<const N: usize>(
const fn hash1<const N: usize>(

Choose a reason for hiding this comment

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

Removal of pub intended?

Copy link
Author

Choose a reason for hiding this comment

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

Not really, but since there are a few other backends with the same function and in all cases it is internal implementation without pub (here too), I decided to remove it for consistency too. Happy to restore if maintainers have strong opinion on this one.

Copy link
Author

@nazar-pc nazar-pc left a comment

Choose a reason for hiding this comment

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

Thanks for review, appreciate it!

@@ -120,7 +119,7 @@ pub fn compress_xof(
crate::platform::le_bytes_from_words_64(&state)
}

pub fn hash1<const N: usize>(
const fn hash1<const N: usize>(
Copy link
Author

Choose a reason for hiding this comment

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

Not really, but since there are a few other backends with the same function and in all cases it is internal implementation without pub (here too), I decided to remove it for consistency too. Happy to restore if maintainers have strong opinion on this one.

@nazar-pc
Copy link
Author

@oconnor663 it'd be great to get your attention here, especially since the changes are fairly simple

@nazar-pc
Copy link
Author

Ping 🙂

@nazar-pc
Copy link
Author

nazar-pc commented Mar 9, 2025

I have implemented public const functions too and added them to tests against reference implementation, everything passes. Just rebased against master to pull Rust 1.78.0 to get some of the features that were previously unstable on older version of Rust.

@oconnor663 would be great if you can find time to look at this, especially since all tests are passing.

@nazar-pc
Copy link
Author

nazar-pc commented Mar 9, 2025

Hm... I see a31e519 says that true MSRV is 1.66.0, if that is the case I can put new features behind feature flag or maybe MSRV can be increased (1.77.0 is what is needed here I believe, which was released almost a year ago).

UPD: 1.83.0 is needed actually.

@oconnor663
Copy link
Member

Apologies for not reviewing this more promptly. You might already have noticed that I just pushed the CI-tested MSRV to 1.78 (for the ignore crate).

@nazar-pc
Copy link
Author

nazar-pc commented Mar 9, 2025

Just discovered 1.83.0 is what is needed for ptr::copy_to_nonoverlapping()

@nazar-pc
Copy link
Author

nazar-pc commented Mar 9, 2025

Okay, so &mut is not allowed in const fn until current stable 1.85.0. Sorry for the noise here, I added const feature that enabled these new APIs, retaining support for older versions of Rust.

@oconnor663
Copy link
Member

I'm leaning against taking these changes. It looks like a lot of complicated logic has to be duplicated, and much of that logic (like compress_subtree_wide) is only as complicated as it is because it supports SIMD parallelism, which the const version gets no benefit from. I wonder if it could make more sense to fork the reference_impl rather than the highly optimized implementation?

That said, my gut level, haven't-spent-much-time-with-the-feature impression of const generics is that it's still too early to rely heavily on them. Errors like this feel silly to me:

error[E0015]: cannot use `for` loop on `std::ops::Range<usize>` in constant functions
  --> reference_impl.rs:68:14
   |
68 |     for i in 0..16 {
   |              ^^^^^

Another minimim-viable-feature for me would be basic arithmetic in const parameters, which doesn't work today:

struct Hasher<const LEN: usize> {
    state: [u8; LEN * 2],  // error: generic parameters may not be used in const operations
}

Does all that sound reasonable?

@nazar-pc
Copy link
Author

The bigger problem is not SIMD, but rather lack of generics support, which means there is no way to avoid duplication. This is also the reason why you can't use basic iterators with for loops.

Another minimim-viable-feature for me would be basic arithmetic in const parameters, which doesn't work today:

It works on Nightly, this is one ofthe many features I enjoy on Nightly for a long time. But it is not really required here.

While code duplication is unfortunate and undesirable, there is a substantial benefit for having the same functions available in the official crate with const feature rather than relying on lesser known crates from third-party authors.

In the latest revision I have feature-gates most of the new code, so it is easier to review and const code passes tests against reference implementation, so it should works correctly.

I understand if you're not going to accept this, but I am hopeful that there is a way to get it in.

Raising MSRV to 1.85.0 and bumping major version would immediately remove the feature flag and all conditional compilation, but I'm not sure if you want everyone to be able to use older Rust versions with the latest versions of the crate.

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 in const environment
3 participants