//! Keccak [sponge function](https://en.wikipedia.org/wiki/Sponge_function).
//!
//! If you are looking for SHA-3 hash functions take a look at [`sha3`][1] and
//! [`tiny-keccak`][2] crates.
//!
//! To disable loop unrolling (e.g. for constraint targets) use `no_unroll`
//! feature.
//!
//! ```
//! // Test vectors are from KeccakCodePackage
//! let mut data = [0u64; 25];
//!
//! keccak::f1600(&mut data);
//! assert_eq!(data, [
//! 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,
//! ]);
//!
//! keccak::f1600(&mut data);
//! assert_eq!(data, [
//! 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,
//! ]);
//! ```
//!
//! [1]: https://docs.rs/sha3
//! [2]: https://docs.rs/tiny-keccak
#! [no_std]
#! [cfg_attr(docsrs, feature(doc_auto_cfg))]
#! [cfg_attr(feature =
"simd" , feature(portable_simd))]
#! [doc(
html_logo_url =
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg ",
html_favicon_url =
"https://raw.githubusercontent.com/RustCrypto/meta/master/logo.svg "
)]
#! [allow(non_upper_case_globals)]
#! [warn(
clippy::mod_module_files,
clippy::unwrap_used,
missing_docs,
rust_2018_idioms,
unused_lifetimes,
unused_qualifications
)]
use core::{
convert::TryInto,
fmt::Debug,
mem::size_of,
ops::{BitAnd, BitAndAssign, BitXor, BitXorAssign, Not},
};
#[ rustfmt::skip]
mod unroll;
#[ cfg(all(target_arch =
"aarch64" , feature =
"asm" ))]
mod armv8;
#[ cfg(all(target_arch =
"aarch64" , feature =
"asm" ))]
cpufeatures::new!(armv8_sha3_intrinsics,
"sha3" );
const PLEN: usize =
25 ;
const RHO: [u32;
24 ] = [
1 ,
3 ,
6 ,
10 ,
15 ,
21 ,
28 ,
36 ,
45 ,
55 ,
2 ,
14 ,
27 ,
41 ,
56 ,
8 ,
25 ,
43 ,
62 ,
18 ,
39 ,
61 ,
20 ,
44 ,
];
const PI: [usize;
24 ] = [
10 ,
7 ,
11 ,
17 ,
18 ,
3 ,
5 ,
16 ,
8 ,
21 ,
24 ,
4 ,
15 ,
23 ,
19 ,
13 ,
12 ,
2 ,
20 ,
14 ,
22 ,
9 ,
6 ,
1 ,
];
const RC: [u64;
24 ] = [
0 x0000000000000001,
0 x0000000000008082,
0 x800000000000808a,
0 x8000000080008000,
0 x000000000000808b,
0 x0000000080000001,
0 x8000000080008081,
0 x8000000000008009,
0 x000000000000008a,
0 x0000000000000088,
0 x0000000080008009,
0 x000000008000000a,
0 x000000008000808b,
0 x800000000000008b,
0 x8000000000008089,
0 x8000000000008003,
0 x8000000000008002,
0 x8000000000000080,
0 x000000000000800a,
0 x800000008000000a,
0 x8000000080008081,
0 x8000000000008080,
0 x0000000080000001,
0 x8000000080008008,
];
/// Keccak is a permutation over an array of lanes which comprise the sponge
/// construction.
pub trait LaneSize:
Copy
+ Clone
+ Debug
+ Default
+ PartialEq
+ BitAndAssign
+ BitAnd<Output =
Self >
+ BitXorAssign
+ BitXor<Output =
Self >
+ Not<Output =
Self >
{
/// Number of rounds of the Keccak-f permutation.
const KECCAK_F_ROUND_COUNT: usize;
/// Truncate function.
fn truncate_rc(rc: u64) ->
Self ;
/// Rotate left function.
fn rotate_left(
self , n: u32) ->
Self ;
}
macro_rules! impl_lanesize {
($
type :ty, $round:expr, $truncate:expr) => {
impl LaneSize
for $
type {
const KECCAK_F_ROUND_COUNT: usize = $round;
fn truncate_rc(rc: u64) ->
Self {
$truncate(rc)
}
fn rotate_left(
self , n: u32) ->
Self {
self .rotate_left(n)
}
}
};
}
impl_lanesize!(u8,
18 , |rc: u64| { rc.to_le_bytes()[
0 ] });
impl_lanesize!(u16,
20 , |rc: u64| {
let tmp = rc.to_le_bytes();
#[ allow(clippy::unwrap_used)]
Self ::from_le_bytes(tmp[..size_of::<
Self >()].try_into().unwrap())
});
impl_lanesize!(u32,
22 , |rc: u64| {
let tmp = rc.to_le_bytes();
#[ allow(clippy::unwrap_used)]
Self ::from_le_bytes(tmp[..size_of::<
Self >()].try_into().unwrap())
});
impl_lanesize!(u64,
24 , |rc: u64| { rc });
macro_rules! impl_keccak {
($pname:ident, $fname:ident, $
type :ty) => {
/// Keccak-p sponge function
pub fn $pname(state: &
mut [$
type ; PLEN], round_count: usize) {
keccak_p(state, round_count);
}
/// Keccak-f sponge function
pub fn $fname(state: &
mut [$
type ; PLEN]) {
keccak_p(state, <$
type >::KECCAK_F_ROUND_COUNT);
}
};
}
impl_keccak!(p200, f200, u8);
impl_keccak!(p400, f400, u16);
impl_keccak!(p800, f800, u32);
#[ cfg(not(all(target_arch =
"aarch64" , feature =
"asm" )))]
impl_keccak!(p1600, f1600, u64);
/// Keccak-p[1600, rc] permutation.
#[ cfg(all(target_arch =
"aarch64" , feature =
"asm" ))]
pub fn p1600(state: &
mut [u64; PLEN], round_count: usize) {
keccak_p(state, round_count);
}
/// Keccak-f[1600] permutation.
#[ cfg(all(target_arch =
"aarch64" , feature =
"asm" ))]
pub fn f1600(state: &
mut [u64; PLEN]) {
if armv8_sha3_intrinsics::get() {
unsafe { armv8::f1600_armv8_sha3_asm(state) }
}
else {
keccak_p(state, u64::KECCAK_F_ROUND_COUNT);
}
}
#[ cfg(feature =
"simd" )]
/// SIMD implementations for Keccak-f1600 sponge function
pub mod simd {
use crate ::{keccak_p, LaneSize, PLEN};
pub use core::simd::{u64x2, u64x4, u64x8};
macro_rules! impl_lanesize_simd_u64xn {
($
type :ty) => {
impl LaneSize
for $
type {
const KECCAK_F_ROUND_COUNT: usize =
24 ;
fn truncate_rc(rc: u64) ->
Self {
Self ::splat(rc)
}
fn rotate_left(
self , n: u32) ->
Self {
self <<
Self ::splat(n.into()) |
self >>
Self ::splat((
64 - n).into())
}
}
};
}
impl_lanesize_simd_u64xn!(u64x2);
impl_lanesize_simd_u64xn!(u64x4);
impl_lanesize_simd_u64xn!(u64x8);
impl_keccak!(p1600x2, f1600x2, u64x2);
impl_keccak!(p1600x4, f1600x4, u64x4);
impl_keccak!(p1600x8, f1600x8, u64x8);
}
#[ allow(unused_assignments)]
/// Generic Keccak-p sponge function
pub fn keccak_p<L: LaneSize>(state: &
mut [L; PLEN], round_count: usi
ze) {
if round_count > L::KECCAK_F_ROUND_COUNT {
panic!("A round_count greater than KECCAK_F_ROUND_COUNT is not supported!" );
}
// https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.202.pdf#page=25
// "the rounds of KECCAK-p[b, nr] match the last rounds of KECCAK-f[b]"
let round_consts = &RC[(L::KECCAK_F_ROUND_COUNT - round_count)..L::KECCAK_F_ROUND_COUNT];
// not unrolling this loop results in a much smaller function, plus
// it positively influences performance due to the smaller load on I-cache
for &rc in round_consts {
let mut array = [L::default(); 5 ];
// Theta
unroll5!(x, {
unroll5!(y, {
array[x] ^= state[5 * y + x];
});
});
unroll5!(x, {
unroll5!(y, {
let t1 = array[(x + 4 ) % 5 ];
let t2 = array[(x + 1 ) % 5 ].rotate_left(1 );
state[5 * y + x] ^= t1 ^ t2;
});
});
// Rho and pi
let mut last = state[1 ];
unroll24!(x, {
array[0 ] = state[PI[x]];
state[PI[x]] = last.rotate_left(RHO[x]);
last = array[0 ];
});
// Chi
unroll5!(y_step, {
let y = 5 * y_step;
unroll5!(x, {
array[x] = state[y + x];
});
unroll5!(x, {
let t1 = !array[(x + 1 ) % 5 ];
let t2 = array[(x + 2 ) % 5 ];
state[y + x] = array[x] ^ (t1 & t2);
});
});
// Iota
state[0 ] ^= L::truncate_rc(rc);
}
}
#[ cfg(test)]
mod tests {
use crate ::{keccak_p, LaneSize, PLEN};
fn keccak_f<L: LaneSize>(state_first: [L; PLEN], state_second: [L; PLEN]) {
let mut state = [L::default(); PLEN];
keccak_p(&mut state, L::KECCAK_F_ROUND_COUNT);
assert_eq!(state, state_first);
keccak_p(&mut state, L::KECCAK_F_ROUND_COUNT);
assert_eq!(state, state_second);
}
#[ test]
fn keccak_f200() {
// Test vectors are copied from XKCP (eXtended Keccak Code Package)
// https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KeccakF-200-IntermediateValues.txt
let state_first = [
0 x3C, 0 x28, 0 x26, 0 x84, 0 x1C, 0 xB3, 0 x5C, 0 x17, 0 x1E, 0 xAA, 0 xE9, 0 xB8, 0 x11, 0 x13,
0 x4C, 0 xEA, 0 xA3, 0 x85, 0 x2C, 0 x69, 0 xD2, 0 xC5, 0 xAB, 0 xAF, 0 xEA,
];
let state_second = [
0 x1B, 0 xEF, 0 x68, 0 x94, 0 x92, 0 xA8, 0 xA5, 0 x43, 0 xA5, 0 x99, 0 x9F, 0 xDB, 0 x83, 0 x4E,
0 x31, 0 x66, 0 xA1, 0 x4B, 0 xE8, 0 x27, 0 xD9, 0 x50, 0 x40, 0 x47, 0 x9E,
];
keccak_f::<u8>(state_first, state_second);
}
#[ test]
fn keccak_f400() {
// Test vectors are copied from XKCP (eXtended Keccak Code Package)
// https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KeccakF-400-IntermediateValues.txt
let state_first = [
0 x09F5, 0 x40AC, 0 x0FA9, 0 x14F5, 0 xE89F, 0 xECA0, 0 x5BD1, 0 x7870, 0 xEFF0, 0 xBF8F, 0 x0337,
0 x6052, 0 xDC75, 0 x0EC9, 0 xE776, 0 x5246, 0 x59A1, 0 x5D81, 0 x6D95, 0 x6E14, 0 x633E, 0 x58EE,
0 x71FF, 0 x714C, 0 xB38E,
];
let state_second = [
0 xE537, 0 xD5D6, 0 xDBE7, 0 xAAF3, 0 x9BC7, 0 xCA7D, 0 x86B2, 0 xFDEC, 0 x692C, 0 x4E5B, 0 x67B1,
0 x15AD, 0 xA7F7, 0 xA66F, 0 x67FF, 0 x3F8A, 0 x2F99, 0 xE2C2, 0 x656B, 0 x5F31, 0 x5BA6, 0 xCA29,
0 xC224, 0 xB85C, 0 x097C,
];
keccak_f::<u16>(state_first, state_second);
}
#[ test]
fn keccak_f800() {
// Test vectors are copied from XKCP (eXtended Keccak Code Package)
// https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KeccakF-800-IntermediateValues.txt
let state_first = [
0 xE531D45D, 0 xF404C6FB, 0 x23A0BF99, 0 xF1F8452F, 0 x51FFD042, 0 xE539F578, 0 xF00B80A7,
0 xAF973664, 0 xBF5AF34C, 0 x227A2424, 0 x88172715, 0 x9F685884, 0 xB15CD054, 0 x1BF4FC0E,
0 x6166FA91, 0 x1A9E599A, 0 xA3970A1F, 0 xAB659687, 0 xAFAB8D68, 0 xE74B1015, 0 x34001A98,
0 x4119EFF3, 0 x930A0E76, 0 x87B28070, 0 x11EFE996,
];
let state_second = [
0 x75BF2D0D, 0 x9B610E89, 0 xC826AF40, 0 x64CD84AB, 0 xF905BDD6, 0 xBC832835, 0 x5F8001B9,
0 x15662CCE, 0 x8E38C95E, 0 x701FE543, 0 x1B544380, 0 x89ACDEFF, 0 x51EDB5DE, 0 x0E9702D9,
0 x6C19AA16, 0 xA2913EEE, 0 x60754E9A, 0 x9819063C, 0 xF4709254, 0 xD09F9084, 0 x772DA259,
0 x1DB35DF7, 0 x5AA60162, 0 x358825D5, 0 xB3783BAB,
];
keccak_f::<u32>(state_first, state_second);
}
#[ test]
fn keccak_f1600() {
// Test vectors are copied from XKCP (eXtended Keccak Code Package)
// https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KeccakF-1600-IntermediateValues.txt
let state_first = [
0 xF1258F7940E1DDE7,
0 x84D5CCF933C0478A,
0 xD598261EA65AA9EE,
0 xBD1547306F80494D,
0 x8B284E056253D057,
0 xFF97A42D7F8E6FD4,
0 x90FEE5A0A44647C4,
0 x8C5BDA0CD6192E76,
0 xAD30A6F71B19059C,
0 x30935AB7D08FFC64,
0 xEB5AA93F2317D635,
0 xA9A6E6260D712103,
0 x81A57C16DBCF555F,
0 x43B831CD0347C826,
0 x01F22F1A11A5569F,
0 x05E5635A21D9AE61,
0 x64BEFEF28CC970F2,
0 x613670957BC46611,
0 xB87C5A554FD00ECB,
0 x8C3EE88A1CCF32C8,
0 x940C7922AE3A2614,
0 x1841F924A2C509E4,
0 x16F53526E70465C2,
0 x75F644E97F30A13B,
0 xEAF1FF7B5CECA249,
];
let state_second = [
0 x2D5C954DF96ECB3C,
0 x6A332CD07057B56D,
0 x093D8D1270D76B6C,
0 x8A20D9B25569D094,
0 x4F9C4F99E5E7F156,
0 xF957B9A2DA65FB38,
0 x85773DAE1275AF0D,
0 xFAF4F247C3D810F7,
0 x1F1B9EE6F79A8759,
0 xE4FECC0FEE98B425,
0 x68CE61B6B9CE68A1,
0 xDEEA66C4BA8F974F,
0 x33C43D836EAFB1F5,
0 xE00654042719DBD9,
0 x7CF8A9F009831265,
0 xFD5449A6BF174743,
0 x97DDAD33D8994B40,
0 x48EAD5FC5D0BE774,
0 xE3B8C8EE55B7B03C,
0 x91A0226E649E42E9,
0 x900E3129E7BADD7B,
0 x202A9EC5FAA3CCE8,
0 x5B3402464E1C3DB6,
0 x609F4E62A44C1059,
0 x20D06CD26A8FBF5C,
];
keccak_f::<u64>(state_first, state_second);
}
#[ cfg(feature = "simd" )]
mod simd {
use super ::keccak_f;
use core::simd::{u64x2, u64x4, u64x8};
macro_rules! impl_keccak_f1600xn {
($name:ident, $type :ty) => {
#[ test]
fn $name() {
// Test vectors are copied from XKCP (eXtended Keccak Code Package)
// https://github.com/XKCP/XKCP/blob/master/tests/TestVectors/KeccakF-1600-IntermediateValues.txt
let state_first = [
<$type >::splat(0 xF1258F7940E1DDE7),
<$type >::splat(0 x84D5CCF933C0478A),
<$type >::splat(0 xD598261EA65AA9EE),
<$type >::splat(0 xBD1547306F80494D),
<$type >::splat(0 x8B284E056253D057),
<$type >::splat(0 xFF97A42D7F8E6FD4),
<$type >::splat(0 x90FEE5A0A44647C4),
<$type >::splat(0 x8C5BDA0CD6192E76),
<$type >::splat(0 xAD30A6F71B19059C),
<$type >::splat(0 x30935AB7D08FFC64),
<$type >::splat(0 xEB5AA93F2317D635),
<$type >::splat(0 xA9A6E6260D712103),
<$type >::splat(0 x81A57C16DBCF555F),
<$type >::splat(0 x43B831CD0347C826),
<$type >::splat(0 x01F22F1A11A5569F),
<$type >::splat(0 x05E5635A21D9AE61),
<$type >::splat(0 x64BEFEF28CC970F2),
<$type >::splat(0 x613670957BC46611),
<$type >::splat(0 xB87C5A554FD00ECB),
<$type >::splat(0 x8C3EE88A1CCF32C8),
<$type >::splat(0 x940C7922AE3A2614),
<$type >::splat(0 x1841F924A2C509E4),
<$type >::splat(0 x16F53526E70465C2),
<$type >::splat(0 x75F644E97F30A13B),
<$type >::splat(0 xEAF1FF7B5CECA249),
];
let state_second = [
<$type >::splat(0 x2D5C954DF96ECB3C),
<$type >::splat(0 x6A332CD07057B56D),
<$type >::splat(0 x093D8D1270D76B6C),
<$type >::splat(0 x8A20D9B25569D094),
<$type >::splat(0 x4F9C4F99E5E7F156),
<$type >::splat(0 xF957B9A2DA65FB38),
<$type >::splat(0 x85773DAE1275AF0D),
<$type >::splat(0 xFAF4F247C3D810F7),
<$type >::splat(0 x1F1B9EE6F79A8759),
<$type >::splat(0 xE4FECC0FEE98B425),
<$type >::splat(0 x68CE61B6B9CE68A1),
<$type >::splat(0 xDEEA66C4BA8F974F),
<$type >::splat(0 x33C43D836EAFB1F5),
<$type >::splat(0 xE00654042719DBD9),
<$type >::splat(0 x7CF8A9F009831265),
<$type >::splat(0 xFD5449A6BF174743),
<$type >::splat(0 x97DDAD33D8994B40),
<$type >::splat(0 x48EAD5FC5D0BE774),
<$type >::splat(0 xE3B8C8EE55B7B03C),
<$type >::splat(0 x91A0226E649E42E9),
<$type >::splat(0 x900E3129E7BADD7B),
<$type >::splat(0 x202A9EC5FAA3CCE8),
<$type >::splat(0 x5B3402464E1C3DB6),
<$type >::splat(0 x609F4E62A44C1059),
<$type >::splat(0 x20D06CD26A8FBF5C),
];
keccak_f::<$type >(state_first, state_second);
}
};
}
impl_keccak_f1600xn!(keccak_f1600x2, u64x2);
impl_keccak_f1600xn!(keccak_f1600x4, u64x4);
impl_keccak_f1600xn!(keccak_f1600x8, u64x8);
}
}
Messung V0.5 in Prozent C=56 H=100 G=80
¤ Dauer der Verarbeitung: 0.14 Sekunden
(vorverarbeitet am 2026-06-18)
¤
*© Formatika GbR, Deutschland