I'm adding the i32::MAX test case here because I personally screwed it
up while I was working on
https://github.com/BLAKE3-team/BLAKE3/issues/271. The correct
implementation of the carry bit is the ANDNOT of old high bit (1) and
the new high bit (0). Using XOR instead of ANDNOT gives the correct
answer in the overflow case, but it also reports an incorrect "extra"
overflow when the high bit goes from 0 to 1.
Adjust to the following changes that happened in digest:
- The crypto-mac crate has been merged into digest (with "mac" feature
enabled)
- Various traits have been split up
- The Digest and Mac traits now share their update/finalize/reset
implementations
- The BlockInput trait was dropped without replacement apparently (as
long as the low-level core API is not used)
The SSE2 patch introduced xmm10 as a temporary register for one of the
rotations, but xmm6-xmm15 are callee-save registers on Windows, and
SSE4.1 was only saving the registers it used. The minimal fix is to use
one of the saved registers instead of xmm10.
See https://github.com/BLAKE3-team/BLAKE3/issues/206.
These clutter the toplevel API, and their prominence might lead callers
to prefer them as a first resort, which probably isn't a good idea.
Restricting multithreading to `Hasher::update_rayon` feels better,
similar to what we've done with `Hasher::finalize_xof`. (But I think
`update_rayon` is still an improvement over the trait-based interface
that it replaced.)
This is quite hard to trigger, because SSE2 has been guaranteed for a
long time. But you could trigger it this way:
rustup target add i686-unknown-linux-musl
RUSTFLAGS="-C target-cpu=i386" cargo build --target i686-unknown-linux-musl
Note a relevant gotcha though: The `cross` tool will not forward
environment variables like RUSTFLAGS to the container by default, so if
you're testing with `cross` you'll need to use the `rustc` command to
explicitly pass the flag, as I've done here in ci.yml. (Or you could
create a `Cross.toml` file, but I don't want to commit one of those if I
can avoid it.)
Use _mm_and_si128 and _mm_cmpeq_epi16 rather than expensive multiplication _mm_mullo_epi16 with _mm_srai_epi16 that compiler may not be able to optimize.
Use a constant mask to blend according to (mask & b) | ((~mask) & a).
* src/rust_sse2.rs: emulate _mm_blend_epi16 using SSE2 intrinsics
* c/blake3_sse2.c: Likewise.
Wire up basic functions and features for SSE2 support using the SSE4.1 version
as a basis without implementing the SSE2 instructions yet.
* Cargo.toml: add no_sse2 feature
* benches/bench.rs: wire SSE2 benchmarks
* build.rs: add SSE2 rust intrinsics and assembly builds
* c/Makefile.testing: add SSE2 C and assembly targets
* c/README.md: add SSE2 to C build instructions
* c/blake3_c_rust_bindings/build.rs: add SSE2 C rust binding builds
* c/blake3_c_rust_bindings/src/lib.rs: add SSE2 C rust bindings
* c/blake3_dispatch.c: add SSE2 C dispatch
* c/blake3_impl.h: add SSE2 C function prototypes
* c/blake3_sse2.c: add SSE2 C intrinsic file starting with SSE4.1 version
* c/blake3_sse2_x86-64_{unix.S,windows_gnu.S,windows_msvc.asm}: add SSE2
assembly files starting with SSE4.1 version
* src/ffi_sse2.rs: add rust implementation using SSE2 C rust bindings
* src/lib.rs: add SSE2 rust intrinsics and SSE2 C rust binding rust SSE2 module
configurations
* src/platform.rs: add SSE2 rust platform detection and dispatch
* src/rust_sse2.rs: add SSE2 rust intrinsic file starting with SSE4.1 version
* tools/instruction_set_support/src/main.rs: add SSE2 feature detection
It looks like I originally made this mistake when I was copying code
from the baokeshed prototype (a274a9b0fa),
and then it got replicated into the C implementation later.