Skip to content
Open
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
49 changes: 34 additions & 15 deletions .github/workflows/keccak.yml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,9 @@ jobs:
toolchain: ${{ matrix.rust }}
targets: ${{ matrix.target }}
- run: cargo build --target ${{ matrix.target }}
- run: cargo build --target ${{ matrix.target }} --features parallel
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="soft-compact"'
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="soft"'
run: cargo build --target ${{ matrix.target }}

minimal-versions:
Expand Down Expand Up @@ -80,25 +81,36 @@ jobs:
targets: ${{ matrix.target }}
- run: cargo check --target ${{ matrix.target }}
- run: cargo test --target ${{ matrix.target }}
- run: cargo test --release --target ${{ matrix.target }}
- run: cargo test --target ${{ matrix.target }} --features parallel
- run: cargo test --release --target ${{ matrix.target }} --features parallel
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="armv8_asm"'
RUSTFLAGS: '-Dwarnings --cfg keccak_soft_compact'
run: cargo test --release --target ${{ matrix.target }}
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="soft-compact"'
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="soft"'
run: cargo test --release --target ${{ matrix.target }}
- if: contains(matrix.target, 'aarch64')
env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="aarch64_sha3"'
run: cargo test --release --target ${{ matrix.target }}

test-simd:
runs-on: ubuntu-latest
env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="simd"'
steps:
- uses: actions/checkout@v4
- uses: RustCrypto/actions/cargo-cache@master
- uses: dtolnay/rust-toolchain@master
with:
toolchain: nightly
- run: cargo test
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="simd128"'
run: cargo test --features parallel
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="simd256"'
run: cargo test --features parallel
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="simd512"'
run: cargo test --features parallel

test-miri:
runs-on: ubuntu-latest
Expand All @@ -117,15 +129,22 @@ jobs:
components: miri
- run: cargo miri setup
- run: cargo miri test --target ${{ matrix.target }}
- run: cargo miri test --target ${{ matrix.target }} --features parallel
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_soft_compact'
run: cargo miri test --release --target ${{ matrix.target }} --features parallel
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="simd128"'
run: cargo miri test --release --target ${{ matrix.target }} --features parallel
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="armv8_asm"'
run: cargo miri test --release --target ${{ matrix.target }}
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="simd256"'
run: cargo miri test --release --target ${{ matrix.target }} --features parallel
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="simd"'
run: cargo miri test --release --target ${{ matrix.target }}
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="simd512"'
run: cargo miri test --release --target ${{ matrix.target }} --features parallel
- env:
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="soft-compact"'
run: cargo miri test --release --target ${{ matrix.target }}
RUSTFLAGS: '-Dwarnings --cfg keccak_backend="soft"'
run: cargo miri test --release --target ${{ matrix.target }} --features parallel

aarch64-sha3:
needs: set-msrv
Expand Down Expand Up @@ -154,8 +173,8 @@ jobs:
mv /tmp/cross ~/.cargo/bin
shell: bash
- env:
RUSTFLAGS: '-C target-feature=+sha3 --cfg keccak_backend="armv8_asm"'
RUSTFLAGS: '-C target-feature=+sha3 --cfg keccak_backend="aarch64_sha3"'
run: |
cd keccak
# Cross doesn't enable `sha3` by default, but QEMU supports it.
cross test --target aarch64-unknown-linux-gnu --no-default-features
cross test --target aarch64-unknown-linux-gnu --features parallel
27 changes: 25 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

12 changes: 11 additions & 1 deletion keccak/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,16 @@ readme = "README.md"
edition = "2024"
rust-version = "1.85"

[dependencies]
cfg-if = "1"
hybrid-array = { version = "0.4", optional = true }

[target.'cfg(target_arch = "aarch64")'.dependencies]
cpufeatures = "0.3"

[features]
parallel = ["dep:hybrid-array"]

[lints.rust]
missing_debug_implementations = "warn"
missing_docs = "warn"
Expand All @@ -29,7 +36,10 @@ unused_qualifications = "warn"

[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = ['cfg(keccak_backend, values("simd", "soft-compact"))']
check-cfg = [
'cfg(keccak_soft_compact)',
'cfg(keccak_backend, values("aarch64_sha3", "simd128", "simd256", "simd512", "soft"))',
]

[lints.clippy]
borrow_as_ptr = "warn"
Expand Down
59 changes: 44 additions & 15 deletions keccak/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,8 @@
![Rust Version][rustc-image]
[![Project Chat][chat-image]][chat-link]

Pure Rust implementation of the [Keccak Sponge Function][keccak] including the keccak-f
and keccak-p variants.

[Documentation][docs-link]
Pure Rust implementation of the [Keccak Sponge Function][keccak] including the `keccak-f`
and `keccak-p` variants.

## About

Expand All @@ -20,17 +18,48 @@ cryptographic functions are built.
For the SHA-3 family including the SHAKE XOFs, see the [`sha3`] crate, which
is built on this crate.

## Minimum Supported Rust Version

Rust **1.85** or higher.

Minimum supported Rust version can be changed in the future, but it will be
done with a minor version bump.

## SemVer Policy

- All on-by-default features of this library are covered by SemVer
- MSRV is considered exempt from SemVer as noted above
## Examples

```rust
// Test vector from KeccakCodePackage
let mut state = [0u64; 25];

keccak::Keccak::new().with_f1600(|f1600| {
f1600(&mut state);
assert_eq!(state, [
0xF1258F7940E1DDE7, 0x84D5CCF933C0478A, 0xD598261EA65AA9EE, 0xBD1547306F80494D,
0x8B284E056253D057, 0xFF97A42D7F8E6FD4, 0x90FEE5A0A44647C4, 0x8C5BDA0CD6192E76,
0xAD30A6F71B19059C, 0x30935AB7D08FFC64, 0xEB5AA93F2317D635, 0xA9A6E6260D712103,
0x81A57C16DBCF555F, 0x43B831CD0347C826, 0x01F22F1A11A5569F, 0x05E5635A21D9AE61,
0x64BEFEF28CC970F2, 0x613670957BC46611, 0xB87C5A554FD00ECB, 0x8C3EE88A1CCF32C8,
0x940C7922AE3A2614, 0x1841F924A2C509E4, 0x16F53526E70465C2, 0x75F644E97F30A13B,
0xEAF1FF7B5CECA249,
]);

f1600(&mut state);
assert_eq!(state, [
0x2D5C954DF96ECB3C, 0x6A332CD07057B56D, 0x093D8D1270D76B6C, 0x8A20D9B25569D094,
0x4F9C4F99E5E7F156, 0xF957B9A2DA65FB38, 0x85773DAE1275AF0D, 0xFAF4F247C3D810F7,
0x1F1B9EE6F79A8759, 0xE4FECC0FEE98B425, 0x68CE61B6B9CE68A1, 0xDEEA66C4BA8F974F,
0x33C43D836EAFB1F5, 0xE00654042719DBD9, 0x7CF8A9F009831265, 0xFD5449A6BF174743,
0x97DDAD33D8994B40, 0x48EAD5FC5D0BE774, 0xE3B8C8EE55B7B03C, 0x91A0226E649E42E9,
0x900E3129E7BADD7B, 0x202A9EC5FAA3CCE8, 0x5B3402464E1C3DB6, 0x609F4E62A44C1059,
0x20D06CD26A8FBF5C,
]);
});
```

## Configuration flags

You can modify crate using the following configuration flags:

- `keccak_backend`: select the specified backend. Supported values:
`aarch64_sha3`, `simd128`, `simd256`, `simd512`, `soft`.
- `keccak_soft_compact`: do not unroll loops in the software backend.
Reduces performance, but results in a more compact binary code.

The flags can be enabled using `RUSTFLAGS` environment variable
(e.g. `RUSTFLAGS="--cfg aes_compact"`) or by modifying `.cargo/config`.

## License

Expand Down
39 changes: 8 additions & 31 deletions keccak/benches/mod.rs
Original file line number Diff line number Diff line change
@@ -1,45 +1,22 @@
//! keccak benchmarks

#![feature(test)]
#![cfg_attr(keccak_backend = "simd", feature(portable_simd))]

extern crate keccak;
extern crate test;

use keccak::{f200, f400, f800, f1600, p1600};
use core::hint::black_box;
use keccak::Keccak;

macro_rules! impl_bench {
($name:ident, $fn:ident, $type:expr) => {
#[bench]
fn $name(b: &mut test::Bencher) {
let mut data = [$type; 25];
b.iter(|| $fn(&mut data));
let mut data = black_box([0; 25]);
Keccak::new().$fn(|f| b.iter(|| black_box(f(&mut data))))
}
};
}

impl_bench!(b_f200, f200, 0u8);
impl_bench!(b_f400, f400, 0u16);
impl_bench!(b_f800, f800, 0u32);
impl_bench!(b_f1600, f1600, 0u64);

#[bench]
fn b_p1600_24(b: &mut test::Bencher) {
let mut data = [0u64; 25];
b.iter(|| p1600(&mut data, 24));
}

#[bench]
fn b_p1600_16(b: &mut test::Bencher) {
let mut data = [0u64; 25];
b.iter(|| p1600(&mut data, 16));
}

#[cfg(keccak_backend = "simd")]
mod simd {
use keccak::simd::{f1600x2, f1600x4, f1600x8, u64x2, u64x4, u64x8};

impl_bench!(b_f1600x2, f1600x2, u64x2::splat(0));
impl_bench!(b_f1600x4, f1600x4, u64x4::splat(0));
impl_bench!(b_f1600x8, f1600x8, u64x8::splat(0));
}
impl_bench!(keccak_f200, with_f200, 0u8);
impl_bench!(keccak_f400, with_f400, 0u16);
impl_bench!(keccak_f800, with_f800, 0u32);
impl_bench!(keccak_f1600, with_f1600, 0u64);
60 changes: 60 additions & 0 deletions keccak/src/backends.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
//! Keccak backend implementations.
use crate::consts::F1600_ROUNDS;
use crate::types::*;
#[cfg(feature = "parallel")]
use hybrid_array::ArraySize;

#[cfg(target_arch = "aarch64")]
pub(crate) mod aarch64_sha3;
#[cfg(any(
keccak_backend = "simd128",
keccak_backend = "simd256",
keccak_backend = "simd512",
))]
pub(crate) mod simd;
pub(crate) mod soft;

/// Trait used to define a closure which operates over Keccak backends.
pub trait BackendClosure {
/// Execute closure with the provided backend.
fn call_once<B: Backend>(self);
Copy link
Member Author

Choose a reason for hiding this comment

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

We could modify it to return a result (i.e. fn call_once<B: Backend>(self) -> Self::Output) and modify the Keccak methods accordingly, but I am not sure it's worth the trouble.

}

/// Trait implemented by a Keccak backend.
pub trait Backend {
/// Parallelism width supported by the backend for [`State1600`].
#[cfg(feature = "parallel")]
type ParSize1600: ArraySize;

/// Get scalar `p1600` function with the specified number of rounds.
///
/// # Panics
/// If `ROUNDS` is bigger than [`F1600_ROUNDS`].
#[must_use]
fn get_p1600<const ROUNDS: usize>() -> Fn1600;

/// Get parallel `p1600` function with the specified number of rounds.
///
/// # Panics
/// If `ROUNDS` is bigger than [`F1600_ROUNDS`].
#[cfg(feature = "parallel")]
#[inline]
#[must_use]
fn get_par_p1600<const ROUNDS: usize>() -> ParFn1600<Self> {
|par_state| par_state.iter_mut().for_each(Self::get_p1600::<ROUNDS>())
}

/// Get scalar `f1600` function.
#[must_use]
fn get_f1600() -> Fn1600 {
Self::get_p1600::<F1600_ROUNDS>()
}

/// Get parallel `f1600` function.
#[cfg(feature = "parallel")]
#[inline]
#[must_use]
fn get_par_f1600() -> ParFn1600<Self> {
Self::get_par_p1600::<F1600_ROUNDS>()
}
}
Loading
Loading