Skip to content

Commit

Permalink
test(kyberlib): ✅ tests covering the main functions in the `symmetric…
Browse files Browse the repository at this point in the history
….rs`
  • Loading branch information
sebastienrousseau committed May 8, 2024
1 parent 5d3317b commit 524278e
Show file tree
Hide file tree
Showing 4 changed files with 166 additions and 23 deletions.
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,7 @@ mod avx2;
use avx2::*;

#[cfg(any(not(target_arch = "x86_64"), not(feature = "avx2")))]
mod reference;
pub mod reference;
#[cfg(any(not(target_arch = "x86_64"), not(feature = "avx2")))]
use reference::*;

Expand All @@ -169,6 +169,7 @@ pub mod kex;
pub mod macros;
/// Parameters for the KyberLib library.
pub mod params;

/// Random number generators for the KyberLib library.
pub mod rng;
/// Symmetric key encapsulation module for the KyberLib library.
Expand Down
8 changes: 4 additions & 4 deletions src/reference/fips202.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@
use crate::symmetric::KeccakState;

pub(crate) const SHAKE128_RATE: usize = 168;
const SHAKE256_RATE: usize = 136;
const SHA3_256_RATE: usize = 136;
const SHA3_512_RATE: usize = 72;
const NROUNDS: usize = 24;
pub(crate) const SHAKE256_RATE: usize = 136;
pub(crate) const SHA3_256_RATE: usize = 136;
pub(crate) const SHA3_512_RATE: usize = 72;
pub(crate) const NROUNDS: usize = 24;

fn rol(a: u64, offset: u64) -> u64 {
(a << offset) ^ (a >> (64 - offset))
Expand Down
36 changes: 18 additions & 18 deletions src/symmetric.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,50 +21,50 @@ pub const AES256CTR_BLOCKBYTES: usize = 64;

/// Block size for AES256CTR in bytes.
#[cfg(not(feature = "90s"))]
pub(crate) const AES256CTR_BLOCKBYTES: usize = 64;
pub const AES256CTR_BLOCKBYTES: usize = 64;

/// Block size for XOF (Extendable Output Function) in bytes.
#[cfg(feature = "90s")]
pub const XOF_BLOCKBYTES: usize = AES256CTR_BLOCKBYTES;

/// Block size for XOF (Extendable Output Function) in bytes.
#[cfg(not(feature = "90s"))]
pub(crate) const XOF_BLOCKBYTES: usize = SHAKE128_RATE;
pub const XOF_BLOCKBYTES: usize = SHAKE128_RATE;

/// Type alias for the XOF (Extendable Output Function) state.
#[cfg(not(feature = "90s"))]
pub(crate) type XofState = KeccakState;
pub type XofState = KeccakState;

/// Type alias for the XOF (Extendable Output Function) state in 90s mode.
#[cfg(feature = "90s")]
pub type XofState = Aes256CtrCtx;

/// Keccak state for absorbing data
#[derive(Copy, Clone)]
pub(crate) struct KeccakState {
pub(crate) s: [u64; 25],
pub(crate) pos: usize,
#[derive(Copy, Clone, Debug, Default)]

Check warning on line 43 in src/symmetric.rs

View check run for this annotation

Codecov / codecov/patch

src/symmetric.rs#L43

Added line #L43 was not covered by tests
pub struct KeccakState {
pub s: [u64; 25],
pub pos: usize,

Check warning on line 46 in src/symmetric.rs

View check run for this annotation

Codecov / codecov/patch

src/symmetric.rs#L45-L46

Added lines #L45 - L46 were not covered by tests
}

impl KeccakState {
/// Creates a new KeccakState
pub(crate) fn new() -> Self {
pub fn new() -> Self {
KeccakState {
s: [0u64; 25],
pos: 0usize,
}
}

/// Resets the KeccakState
pub(crate) fn reset(&mut self) {
pub fn reset(&mut self) {

Check warning on line 59 in src/symmetric.rs

View check run for this annotation

Codecov / codecov/patch

src/symmetric.rs#L59

Added line #L59 was not covered by tests
self.s = [0u64; 25];
self.pos = 0;
}
}

/// Computes SHA3-256 hash
#[cfg(not(feature = "90s"))]
pub(crate) fn hash_h(out: &mut [u8], input: &[u8], inlen: usize) {
pub fn hash_h(out: &mut [u8], input: &[u8], inlen: usize) {
sha3_256(out, input, inlen);
}

Expand All @@ -79,7 +79,7 @@ pub fn hash_h(out: &mut [u8], input: &[u8], inlen: usize) {

/// Computes SHA3-512 hash
#[cfg(not(feature = "90s"))]
pub(crate) fn hash_g(out: &mut [u8], input: &[u8], inlen: usize) {
pub fn hash_g(out: &mut [u8], input: &[u8], inlen: usize) {
sha3_512(out, input, inlen);
}

Expand All @@ -94,7 +94,7 @@ pub fn hash_g(out: &mut [u8], input: &[u8], inlen: usize) {

/// Absorbs input data into the XOF state in non-90s mode
#[cfg(not(feature = "90s"))]
pub(crate) fn xof_absorb(state: &mut XofState, input: &[u8], x: u8, y: u8) {
pub fn xof_absorb(state: &mut XofState, input: &[u8], x: u8, y: u8) {
kyber_shake128_absorb(state, input, x, y);
}

Expand All @@ -109,7 +109,7 @@ pub fn xof_absorb(state: &mut XofState, input: &[u8], x: u8, y: u8) {

/// Squeezes XOF data into output in non-90s mode
#[cfg(not(feature = "90s"))]
pub(crate) fn xof_squeezeblocks(out: &mut [u8], outblocks: usize, state: &mut XofState) {
pub fn xof_squeezeblocks(out: &mut [u8], outblocks: usize, state: &mut XofState) {
kyber_shake128_squeezeblocks(out, outblocks, state);
}

Expand All @@ -121,7 +121,7 @@ pub fn xof_squeezeblocks(out: &mut [u8], outblocks: usize, state: &mut XofState)

/// Pseudo-random function (PRF) in non-90s mode
#[cfg(not(feature = "90s"))]
pub(crate) fn prf(out: &mut [u8], outbytes: usize, key: &[u8], nonce: u8) {
pub fn prf(out: &mut [u8], outbytes: usize, key: &[u8], nonce: u8) {
shake256_prf(out, outbytes, key, nonce);
}

Expand All @@ -145,7 +145,7 @@ pub fn prf(out: &mut [u8], _outbytes: usize, key: &[u8], nonce: u8) {

/// Key derivation function (KDF) in non-90s mode
#[cfg(not(feature = "90s"))]
pub(crate) fn kdf(out: &mut [u8], input: &[u8], inlen: usize) {
pub fn kdf(out: &mut [u8], input: &[u8], inlen: usize) {
shake256(out, KYBER_SHARED_SECRET_BYTES, input, inlen);
}

Expand All @@ -160,7 +160,7 @@ pub fn kdf(out: &mut [u8], input: &[u8], inlen: usize) {

/// Absorb step of the SHAKE128 specialized for the Kyber context
#[cfg(not(feature = "90s"))]
fn kyber_shake128_absorb(s: &mut KeccakState, input: &[u8], x: u8, y: u8) {
pub fn kyber_shake128_absorb(s: &mut KeccakState, input: &[u8], x: u8, y: u8) {
let mut extseed = [0u8; KYBER_SYM_BYTES + 2];
extseed[..KYBER_SYM_BYTES].copy_from_slice(input);
extseed[KYBER_SYM_BYTES] = x;
Expand All @@ -170,13 +170,13 @@ fn kyber_shake128_absorb(s: &mut KeccakState, input: &[u8], x: u8, y: u8) {

/// Squeeze step of SHAKE128 XOF in non-90s mode
#[cfg(not(feature = "90s"))]
fn kyber_shake128_squeezeblocks(output: &mut [u8], nblocks: usize, s: &mut KeccakState) {
pub fn kyber_shake128_squeezeblocks(output: &mut [u8], nblocks: usize, s: &mut KeccakState) {
shake128_squeezeblocks(output, nblocks, s);
}

/// Usage of SHAKE256 as a PRF in non-90s mode
#[cfg(not(feature = "90s"))]
fn shake256_prf(output: &mut [u8], outlen: usize, key: &[u8], nonce: u8) {
pub fn shake256_prf(output: &mut [u8], outlen: usize, key: &[u8], nonce: u8) {
let mut extkey = [0u8; KYBER_SYM_BYTES + 1];
extkey[..KYBER_SYM_BYTES].copy_from_slice(key);
extkey[KYBER_SYM_BYTES] = nonce;
Expand Down
142 changes: 142 additions & 0 deletions tests/test_symmetric.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
// Copyright © 2023 kyberlib. All rights reserved.
// SPDX-License-Identifier: Apache-2.0 OR MIT

#[cfg(test)]
mod tests {
// Import necessary items
use kyberlib::{
symmetric::{hash_g, hash_h, kdf, prf},
KYBER_SHARED_SECRET_BYTES,
};

// Test the hash_h function
#[test]
fn test_hash_h() {
let input = b"test input";
let inlen = input.len();
let mut out = [0u8; 32];

// Call the hash_h function
hash_h(&mut out, input, inlen);

// Assert that the output is not all zeros
assert_ne!(out, [0u8; 32]);
}

// Test the hash_g function
#[test]
fn test_hash_g() {
let input = b"test input";
let inlen = input.len();
let mut out = [0u8; 64];

// Call the hash_g function
hash_g(&mut out, input, inlen);

// Assert that the output is not all zeros
assert_ne!(out, [0u8; 64]);
}

// Test the xof_absorb and xof_squeezeblocks functions
#[test]
fn test_xof_absorb_squeeze() {
use kyberlib::params::KYBER_SYM_BYTES;
use kyberlib::symmetric::KeccakState;
use kyberlib::symmetric::{kyber_shake128_absorb, kyber_shake128_squeezeblocks};

const SHAKE128_RATE: usize = 168;

let mut state = KeccakState::new();
let input = [1u8; KYBER_SYM_BYTES];
let x = 1;
let y = 2;
let mut out = [0u8; SHAKE128_RATE];

// Absorb input data into the Kyber-specific SHAKE128 state
kyber_shake128_absorb(&mut state, &input, x, y);
let nblocks = out.len() / SHAKE128_RATE;
kyber_shake128_squeezeblocks(&mut out, nblocks, &mut state);
let outlen = out.len();
let mut idx = 0;
for i in 0..outlen {

Check failure on line 61 in tests/test_symmetric.rs

View workflow job for this annotation

GitHub Actions / Lint

the loop variable `i` is only used to index `out`
assert_ne!(out[i], 0);
idx += 1;
}
assert_eq!(idx, outlen);
}

// Test the prf function
#[test]
fn test_prf() {
use kyberlib::params::KYBER_SYM_BYTES;
let mut key = [0u8; KYBER_SYM_BYTES];
key[..8].copy_from_slice(b"test key");
let nonce = 42;
let mut out = [0u8; 64];
let outbytes = out.len();

// Call the prf function
prf(&mut out, outbytes, &key, nonce);

// Assert that the output is not all zeros
assert_ne!(out, [0u8; 64]);
}

// Test the kdf function
#[test]
fn test_kdf() {
let input = b"test input";
let inlen = input.len();
let mut out = [0u8; KYBER_SHARED_SECRET_BYTES];

// Call the kdf function
kdf(&mut out, input, inlen);

// Assert that the output is not all zeros
assert_ne!(out, [0u8; KYBER_SHARED_SECRET_BYTES]);
}

#[cfg(not(feature = "90s"))]
#[test]
fn test_kyber_shake128_absorb_squeeze() {
use kyberlib::params::KYBER_SYM_BYTES;
use kyberlib::symmetric::KeccakState;
use kyberlib::symmetric::{kyber_shake128_absorb, kyber_shake128_squeezeblocks};

const SHAKE128_RATE: usize = 168;

let mut state = KeccakState::new();
let input = [1u8; KYBER_SYM_BYTES];
let x = 1;
let y = 2;
let mut out = [0u8; SHAKE128_RATE];

// Absorb input data into the Kyber-specific SHAKE128 state
kyber_shake128_absorb(&mut state, &input, x, y);

// Squeeze Kyber-specific SHAKE128 data into output
kyber_shake128_squeezeblocks(&mut out, 1, &mut state);

// Assert that the output is not all zeros
assert_ne!(out, [0u8; SHAKE128_RATE]);
}

#[cfg(not(feature = "90s"))]
#[test]
fn test_shake256_prf() {
use kyberlib::params::KYBER_SYM_BYTES;
use kyberlib::symmetric::shake256_prf;

let mut key = [0u8; KYBER_SYM_BYTES];
key.copy_from_slice(&[0u8; KYBER_SYM_BYTES]);
let nonce = 42;
let mut out = [0u8; 32]; // Output length of SHAKE256 is 32 bytes
let outlen = out.len();

// Call the SHAKE256 PRF function
shake256_prf(&mut out, outlen, &key, nonce);

// Assert that the output is not all zeros
assert_ne!(out, [0u8; 32]);
}
}

0 comments on commit 524278e

Please sign in to comment.