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
4 changes: 2 additions & 2 deletions keccak/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ name = "keccak"
version = "0.1.1"
authors = ["RustCrypto Developers"]
license = "CC0-1.0"
description = "Keccak-f sponge function"
description = "Keccak sponge function"
documentation = "https://docs.rs/keccak"
repository = "https://github.com/RustCrypto/sponges"
keywords = ["crypto", "sponge", "keccak-f"]
keywords = ["crypto", "sponge", "keccak", "keccak-f", "keccak-p"]
categories = ["cryptography", "no-std"]

[features]
Expand Down
19 changes: 15 additions & 4 deletions keccak/benches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,19 @@
extern crate keccak;
extern crate test;

#[bench]
fn f1600(b: &mut test::Bencher) {
let mut data = [0u64; 25];
b.iter(|| keccak::f1600(&mut data));
use keccak::{f1600, f200, f400, f800};

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));
}
};
}

impl_bench!(b_f200, f200, 0u8);
impl_bench!(b_f400, f400, 0u16);
impl_bench!(b_f800, f800, 0u32);
impl_bench!(b_f1600, f1600, 0u64);
229 changes: 217 additions & 12 deletions keccak/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@
#![no_std]
#![allow(non_upper_case_globals)]

use core::{
convert::TryInto,
fmt::Debug,
mem::size_of,
ops::{BitAnd, BitAndAssign, BitXor, BitXorAssign, Not},
};

#[rustfmt::skip]
mod unroll;

Expand Down Expand Up @@ -78,34 +85,101 @@ const RC: [u64; 24] = [
0x8000000080008008,
];

pub trait LaneSize:
Copy
+ Clone
+ Debug
+ Default
+ PartialEq
+ BitAndAssign
+ BitAnd<Output = Self>
+ BitXorAssign
+ BitXor<Output = Self>
+ Not<Output = Self>
{
const KECCAK_F_ROUND_COUNT: usize;

fn truncate_rc(rc: u64) -> Self;
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();
Self::from_le_bytes(tmp[..size_of::<Self>()].try_into().unwrap())
});
impl_lanesize!(u32, 22, |rc: u64| {
let tmp = rc.to_le_bytes();
Self::from_le_bytes(tmp[..size_of::<Self>()].try_into().unwrap())
});
impl_lanesize!(u64, 24, |rc: u64| { rc });

macro_rules! impl_keccak {
($name:ident, $type:ty) => {
/// Keccak-$name sponge function
pub fn $name(state: &mut [$type; PLEN]) {
keccak_p(state, <$type>::KECCAK_F_ROUND_COUNT);
}
};
}

impl_keccak!(f200, u8);
impl_keccak!(f400, u16);
impl_keccak!(f800, u32);
impl_keccak!(f1600, u64);

#[allow(unused_assignments)]
/// Keccak-f[1600] sponge function
pub fn f1600(a: &mut [u64; PLEN]) {
/// Generic Keccak-p sponge function
pub fn keccak_p<L: LaneSize>(state: &mut [L; PLEN], round_count: usize) {
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 &RC {
let mut array = [0u64; 5];
for &rc in round_consts {
let mut array = [L::default(); 5];

// Theta
unroll5!(x, {
unroll5!(y, {
array[x] ^= a[5 * y + x];
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);
a[5 * y + x] ^= t1 ^ t2;
state[5 * y + x] ^= t1 ^ t2;
});
});

// Rho and pi
let mut last = a[1];
let mut last = state[1];
unroll24!(x, {
array[0] = a[PI[x]];
a[PI[x]] = last.rotate_left(RHO[x]);
array[0] = state[PI[x]];
state[PI[x]] = last.rotate_left(RHO[x]);
last = array[0];
});

Expand All @@ -114,17 +188,148 @@ pub fn f1600(a: &mut [u64; PLEN]) {
let y = 5 * y_step;

unroll5!(x, {
array[x] = a[y + x];
array[x] = state[y + x];
});

unroll5!(x, {
let t1 = !array[(x + 1) % 5];
let t2 = array[(x + 2) % 5];
a[y + x] = array[x] ^ (t1 & t2);
state[y + x] = array[x] ^ (t1 & t2);
});
});

// Iota
a[0] ^= rc;
state[0] ^= L::truncate_rc(rc);
}
}

#[cfg(test)]
mod tests {
use {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 = [
0x3C, 0x28, 0x26, 0x84, 0x1C, 0xB3, 0x5C, 0x17, 0x1E, 0xAA, 0xE9, 0xB8, 0x11, 0x13,
0x4C, 0xEA, 0xA3, 0x85, 0x2C, 0x69, 0xD2, 0xC5, 0xAB, 0xAF, 0xEA,
];
let state_second = [
0x1B, 0xEF, 0x68, 0x94, 0x92, 0xA8, 0xA5, 0x43, 0xA5, 0x99, 0x9F, 0xDB, 0x83, 0x4E,
0x31, 0x66, 0xA1, 0x4B, 0xE8, 0x27, 0xD9, 0x50, 0x40, 0x47, 0x9E,
];

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 = [
0x09F5, 0x40AC, 0x0FA9, 0x14F5, 0xE89F, 0xECA0, 0x5BD1, 0x7870, 0xEFF0, 0xBF8F, 0x0337,
0x6052, 0xDC75, 0x0EC9, 0xE776, 0x5246, 0x59A1, 0x5D81, 0x6D95, 0x6E14, 0x633E, 0x58EE,
0x71FF, 0x714C, 0xB38E,
];
let state_second = [
0xE537, 0xD5D6, 0xDBE7, 0xAAF3, 0x9BC7, 0xCA7D, 0x86B2, 0xFDEC, 0x692C, 0x4E5B, 0x67B1,
0x15AD, 0xA7F7, 0xA66F, 0x67FF, 0x3F8A, 0x2F99, 0xE2C2, 0x656B, 0x5F31, 0x5BA6, 0xCA29,
0xC224, 0xB85C, 0x097C,
];

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 = [
0xE531D45D, 0xF404C6FB, 0x23A0BF99, 0xF1F8452F, 0x51FFD042, 0xE539F578, 0xF00B80A7,
0xAF973664, 0xBF5AF34C, 0x227A2424, 0x88172715, 0x9F685884, 0xB15CD054, 0x1BF4FC0E,
0x6166FA91, 0x1A9E599A, 0xA3970A1F, 0xAB659687, 0xAFAB8D68, 0xE74B1015, 0x34001A98,
0x4119EFF3, 0x930A0E76, 0x87B28070, 0x11EFE996,
];
let state_second = [
0x75BF2D0D, 0x9B610E89, 0xC826AF40, 0x64CD84AB, 0xF905BDD6, 0xBC832835, 0x5F8001B9,
0x15662CCE, 0x8E38C95E, 0x701FE543, 0x1B544380, 0x89ACDEFF, 0x51EDB5DE, 0x0E9702D9,
0x6C19AA16, 0xA2913EEE, 0x60754E9A, 0x9819063C, 0xF4709254, 0xD09F9084, 0x772DA259,
0x1DB35DF7, 0x5AA60162, 0x358825D5, 0xB3783BAB,
];

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 = [
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,
];
let state_second = [
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,
];

keccak_f::<u64>(state_first, state_second);
}
}