Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions .github/workflows/sha2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft"
- run: cargo test --all-features
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft-compact"
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft" --cfg sha2_backend_soft="compact"

# macOS tests
macos:
Expand All @@ -112,7 +112,7 @@ jobs:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft"
- run: cargo test --all-features
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft-compact"
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft" --cfg sha2_backend_soft="compact"

# Windows tests
windows:
Expand All @@ -139,7 +139,7 @@ jobs:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft"
- run: cargo test --all-features
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft-compact"
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft" --cfg sha2_backend_soft="compact"

# Cross-compiled tests
cross:
Expand Down Expand Up @@ -186,16 +186,16 @@ jobs:
toolchain: nightly
- run: cross test --package sha2 --all-features --target riscv64gc-unknown-linux-gnu
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft" -C target-feature=+zknh,+zbkb
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft"
- run: cross test --package sha2 --all-features --target riscv64gc-unknown-linux-gnu
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft-compact" -C target-feature=+zknh,+zbkb
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft" --cfg sha2_backend_soft="compact"
- run: cross test --package sha2 --all-features --target riscv64gc-unknown-linux-gnu
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="riscv-zknh" -C target-feature=+zknh,+zbkb
- run: cross test --package sha2 --all-features --target riscv64gc-unknown-linux-gnu
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="riscv-zknh-compact" -C target-feature=+zknh,+zbkb
RUSTFLAGS: -Dwarnings --cfg sha2_backend="riscv-zknh" --cfg sha2_backend_riscv_zknh="compact" -C target-feature=+zknh,+zbkb

riscv32-zknh:
runs-on: ubuntu-latest
Expand All @@ -208,16 +208,16 @@ jobs:
components: rust-src
- run: cargo build --all-features --target riscv32gc-unknown-linux-gnu -Z build-std
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft" -C target-feature=+zknh,+zbkb
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft"
- run: cargo build --all-features --target riscv32gc-unknown-linux-gnu -Z build-std
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft-compact" -C target-feature=+zknh,+zbkb
RUSTFLAGS: -Dwarnings --cfg sha2_backend="soft" --cfg sha2_backend_soft="compact"
- run: cargo build --all-features --target riscv32gc-unknown-linux-gnu -Z build-std
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="riscv-zknh" -C target-feature=+zknh,+zbkb
- run: cargo build --all-features --target riscv32gc-unknown-linux-gnu -Z build-std
env:
RUSTFLAGS: -Dwarnings --cfg sha2_backend="riscv-zknh-compact" -C target-feature=+zknh,+zbkb
RUSTFLAGS: -Dwarnings --cfg sha2_backend="riscv-zknh" --cfg sha2_backend_riscv_zknh="compact" -C target-feature=+zknh,+zbkb

# wasmtime tests
wasm:
Expand Down
7 changes: 3 additions & 4 deletions sha2/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,13 +13,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Replace type aliases with newtypes ([#678])
- `compress256` and `compress512` are moved to the `block_api` module ([#678])
- Implementation of the `SerializableState` trait ([#716])
- Configuration flags for backend selection ([#614], [#615], [#686], [#802])

### Added
- `alloc` crate feature ([#678])
- RISC-V scalar crypto extension support gated behind `sha2_backend = "riscv-zknh"` or
`sha2_backend = "riscv-zknh-compact"` configuration flags ([#614])
- `sha2_backend = "soft"` configuration flag ([#615])
- `sha2_backend = "soft-compact"` configuration flag ([#686])
- RISC-V scalar crypto extension support ([#614])

### Removed
- `asm`, `asm-aarch64`, `loongarch64_asm`, and `compress` crate features ([#542])
Expand All @@ -34,6 +32,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#678]: https://github.com/RustCrypto/hashes/pull/678
[#686]: https://github.com/RustCrypto/hashes/pull/686
[#716]: https://github.com/RustCrypto/hashes/pull/716
[#802]: https://github.com/RustCrypto/hashes/pull/802

## 0.10.9 (2025-04-30)
### Added
Expand Down
6 changes: 5 additions & 1 deletion sha2/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,11 @@ oid = ["digest/oid"]
[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = [
'cfg(sha2_backend, values("soft", "soft-compact", "riscv-zknh", "riscv-zknh-compact"))',
'cfg(sha2_backend, values("soft", "riscv-zknh"))',
'cfg(sha2_256_backend, values("aarch64-sha2", "soft", "riscv-zknh", "x86-sha"))',
'cfg(sha2_512_backend, values("aarch64-sha3", "soft", "riscv-zknh", "x86-avx2"))',
'cfg(sha2_backend_soft, values("compact"))',
'cfg(sha2_backend_riscv_zknh, values("compact"))',
]

[package.metadata.docs.rs]
Expand Down
56 changes: 41 additions & 15 deletions sha2/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,51 @@ See the [`digest`] crate docs for additional examples.

## Backends

This crate supports the following backends:
- `soft`: portable implementation with fully unrolled rounds
- `soft-compact`: portable implementation which produces smaller binaries
- `aarch64-sha2`: uses the AArch64 `sha2` extension, fallbacks to the `soft` backend
if the extension is not available
This crate supports a number of different backends.

SHA-256 and SHA-512 backends:
- `soft`: portable software implementation
- `loongarch64-asm`: `asm!`-based implementation for LoongArch64 targets
- `riscv-zknh`: uses the RISC-V `Zknh` scalar crypto extension. Experimental,
requires Nightly compiler and to enable `Zknh` and `Zbkb` (or `Zbb`)
target features at compile time.
- `riscv-zknh-compact`: same as `riscv-zknh` but does not unroll rounds.
- `wasm32-simd`: uses the WASM `simd128` extension
- `x86-shani`: uses the x86 SHA-NI extension, fallbacks to the `soft` backend
if the extension is not available (SHA-256 only)
- `x86-avx2`: uses the x86 AVX2 extension, fallbacks to the `soft` backend
if the extension is not available (SHA-512 only)

You can force backend selection using the `sha2_backend` configuration flag. It can be enabled
using either environment variable (e.g. `RUSTFLAGS='--cfg sha2_backend="soft"'`),
or by modifying your `.cargo/config.toml` file.
- `wasm32-simd128`: uses the WASM `simd128` extension.

SHA-256 only backends:
- `aarch64-sha2`: uses the AArch64 `sha2` extension.
- `x86-sha`: uses the x86 SHA-NI extension.

SHA-512 only backends:
- `aarch64-sha3`: uses the AArch64 `sha3` extension.
- `x86-avx2`: uses the x86 AVX2 extension.

By default the following backends are used:
- `target_arch = "aarch64"`: use `aarch64-sha2` and `aarch64-sha3` when the required
target features are detected at runtime; otherwise fall back to `soft`.
- `any(target_arch = "x86", target_arch = "x86_64")`: use `x86-sha` and `x86-avx` when
the required target features are detected at runtime; otherwise fall back to `soft`.
- `target_arch = "loongarch64"`: use `loongarch64-asm`.
- `all(target_arch = "wasm32", target_feature = "simd128")`: use `wasm32-simd128`.
- All other targets: use `soft`.

You can force backend selection using the following configuration flags:
- `sha2_backend`: select SHA-256 and SHA-512 backends. Supported values: `soft`, `riscv-zknh`.
- `sha2_256_backend`: select SHA-256 backend. Supported values: `aarch64-sha2`, `soft`,
`riscv-zknh`, `x86-sha`.
- `sha2_512_backend`: select SHA-512 backend. Supported values: `aarch64-sha3`, `soft`,
`riscv-zknh`, `x86-avx2`.

They can be enabled using either the `RUSTFLAGS` environment variable
(e.g. `RUSTFLAGS='--cfg sha2_backend="soft"'`), or by modifying your `.cargo/config.toml` file.

Note that `sha2_backend` has higher priority than `sha2_256_backend` and `sha2_512_backend`.
In other words, using `--cfg sha2_backend="soft" --cfg sha2_256_backend="x86_sha"` will result
in selection of the software backend for SHA-256.

By default `soft` and `riscv-zknh` backends unroll round loops, which results in a better
performance at the cost of a bigger resulting binary. You can disable unrolling in the backends
by using `sha2_backend_soft = "compact"` and `sha2_backend_riscv_zknh = "compact"` configuration
flags respectively.

## License

Expand Down
12 changes: 5 additions & 7 deletions sha2/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,15 @@
#![cfg_attr(docsrs, feature(doc_cfg))]
#![warn(missing_docs, unreachable_pub)]
#![cfg_attr(
any(sha2_backend = "riscv-zknh", sha2_backend = "riscv-zknh-compact"),
any(
sha2_backend = "riscv-zknh",
sha2_256_backend = "riscv-zknh",
sha2_256_backend = "riscv-zknh",
),
feature(riscv_ext_intrinsics)
)]
#![allow(clippy::needless_range_loop)]

#[cfg(all(
any(sha2_backend = "riscv-zknh", sha2_backend = "riscv-zknh-compact"),
not(any(any(target_arch = "riscv32", target_arch = "riscv64")))
))]
compile_error!("The Zknh backends can be enabled only for RISC-V targets");

pub use digest::{self, Digest};

use digest::{
Expand Down
99 changes: 65 additions & 34 deletions sha2/src/sha256.rs
Original file line number Diff line number Diff line change
@@ -1,32 +1,45 @@
cfg_if::cfg_if! {
if #[cfg(sha2_backend = "soft")] {
if #[cfg(any(sha2_backend = "soft", sha2_256_backend = "soft"))] {
mod soft;
use soft::compress;
} else if #[cfg(sha2_backend = "soft-compact")] {
mod soft_compact;
use soft_compact::compress;
} else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
mod soft;
mod x86_shani;
use x86_shani::compress;
} else if #[cfg(all(
any(target_arch = "riscv32", target_arch = "riscv64"),
sha2_backend = "riscv-zknh"
))] {
} else if #[cfg(any(sha2_backend = "riscv-zknh", sha2_256_backend = "riscv-zknh"))] {
mod riscv_zknh;
mod riscv_zknh_utils;
use riscv_zknh::compress;
} else if #[cfg(all(
any(target_arch = "riscv32", target_arch = "riscv64"),
sha2_backend = "riscv-zknh-compact"
))] {
mod riscv_zknh_compact;
mod riscv_zknh_utils;
use riscv_zknh_compact::compress;
} else if #[cfg(target_arch = "aarch64")] {
mod soft;

#[cfg(not(all(
target_feature = "zknh",
any(target_feature = "zbb", target_feature = "zbkb")
)))]
compile_error!("riscv-zknh backend requires zknh and zbkb (or zbb) target features");

fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) {
// SAFETY: we checked above that the required target features are enabled
unsafe { riscv_zknh::compress(state, blocks) }
}
} else if #[cfg(sha2_256_backend = "x86-sha")] {
mod x86_sha;

#[cfg(not(all(
target_feature = "sha",
target_feature = "sse2",
target_feature = "ssse3",
target_feature = "sse4.1",
)))]
compile_error!("x86-sha backend requires sha, sse2, ssse3, sse4.1 target features");

fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) {
// SAFETY: we checked above that the required target features are enabled
unsafe { x86_sha::compress(state, blocks) }
}
} else if #[cfg(sha2_256_backend = "aarch64-sha2")] {
mod aarch64_sha2;
use aarch64_sha2::compress;

#[cfg(not(target_feature = "sha2"))]
compile_error!("aarch64-sha2 backend requires sha2 target feature");

fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) {
// SAFETY: we checked above that the required target features are enabled
unsafe { aarch64_sha2::compress(state, blocks) }
}
} else if #[cfg(target_arch = "loongarch64")] {
mod loongarch64_asm;
use loongarch64_asm::compress;
Expand All @@ -35,17 +48,35 @@ cfg_if::cfg_if! {
use wasm32_simd128::compress;
} else {
mod soft;
use soft::compress;
}
}

#[inline(always)]
#[allow(dead_code)]
fn to_u32s(block: &[u8; 64]) -> [u32; 16] {
core::array::from_fn(|i| {
let chunk = block[4 * i..][..4].try_into().unwrap();
u32::from_be_bytes(chunk)
})
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
mod x86_sha;
cpufeatures::new!(shani_cpuid, "sha", "sse2", "ssse3", "sse4.1");
} else if #[cfg(target_arch = "aarch64")] {
mod aarch64_sha2;
cpufeatures::new!(sha2_hwcap, "sha2");
}
}

fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) {
cfg_if::cfg_if! {
if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] {
if shani_cpuid::get() {
// SAFETY: we checked that required target features are available
return unsafe { x86_sha::compress(state, blocks) };
}
} else if #[cfg(target_arch = "aarch64")] {
if sha2_hwcap::get() {
// SAFETY: we checked that `sha2` target feature is available
return unsafe { aarch64_sha2::compress(state, blocks) };
}
}
}

soft::compress(state, blocks);
}
}
}

/// Raw SHA-256 compression function.
Expand Down
22 changes: 6 additions & 16 deletions sha2/src/sha256/aarch64_sha2.rs
Original file line number Diff line number Diff line change
@@ -1,26 +1,16 @@
//! SHA-256 `aarch64` backend.
//!
//! Implementation adapted from mbedtls.
#![allow(unsafe_op_in_unsafe_fn)]

// Implementation adapted from mbedtls.

use core::arch::aarch64::*;
#[cfg(not(target_arch = "aarch64"))]
compile_error!("aarch64-sha2 backend can be used only aarch64 target arches");

use crate::consts::K32;

cpufeatures::new!(sha2_hwcap, "sha2");

pub(super) fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) {
// TODO: Replace with https://github.com/rust-lang/rfcs/pull/2725
// after stabilization
if sha2_hwcap::get() {
unsafe { sha256_compress(state, blocks) }
} else {
super::soft::compress(state, blocks);
}
}
use core::arch::aarch64::*;

#[target_feature(enable = "sha2")]
unsafe fn sha256_compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) {
pub(super) unsafe fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) {
// SAFETY: Requires the sha2 feature.

// Load state into vectors.
Expand Down
3 changes: 3 additions & 0 deletions sha2/src/sha256/loongarch64_asm.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
//! LoongArch64 assembly backend

#[cfg(not(target_arch = "loongarch64"))]
compile_error!("loongarch-asm backend can be used only on loongarch64 target arches");

macro_rules! c {
($($l:expr)*) => {
concat!($($l ,)*)
Expand Down
Loading
Loading