krypteia-silentops 0.1.0

Side-channel countermeasure toolkit: constant-time primitives, dudect-style timing leakage verifier, and shared SCA helpers for the krypteia workspace.
Documentation
//! Validation tests for constant-time primitives.
//!
//! These tests verify correctness of whichever backend is active.
//! Run on each target architecture to validate the asm implementations.

use super::*;

#[test]
fn test_ct_select_u8() {
    assert_eq!(ct_select_u8(0xAA, 0x55, 1), 0xAA);
    assert_eq!(ct_select_u8(0xAA, 0x55, 0), 0x55);
    assert_eq!(ct_select_u8(0xFF, 0x00, 1), 0xFF);
    assert_eq!(ct_select_u8(0xFF, 0x00, 0), 0x00);
    assert_eq!(ct_select_u8(42, 99, 1), 42);
    assert_eq!(ct_select_u8(42, 99, 0), 99);
}

#[test]
fn test_ct_select_i16() {
    assert_eq!(ct_select_i16(1000, -1000, 1), 1000);
    assert_eq!(ct_select_i16(1000, -1000, 0), -1000);
    assert_eq!(ct_select_i16(0, 3328, 1), 0);
    assert_eq!(ct_select_i16(0, 3328, 0), 3328);
    assert_eq!(ct_select_i16(-32768, 32767, 1), -32768);
    assert_eq!(ct_select_i16(-32768, 32767, 0), 32767);
}

#[test]
fn test_ct_select_i32() {
    assert_eq!(ct_select_i32(8380416, 0, 1), 8380416);
    assert_eq!(ct_select_i32(8380416, 0, 0), 0);
    assert_eq!(ct_select_i32(-1, 1, 1), -1);
    assert_eq!(ct_select_i32(-1, 1, 0), 1);
}

#[test]
fn test_ct_eq_equal() {
    let a = [1u8, 2, 3, 4, 5];
    let b = [1u8, 2, 3, 4, 5];
    assert_eq!(ct_eq(&a, &b), 1);
}

#[test]
fn test_ct_eq_different() {
    let a = [1u8, 2, 3, 4, 5];
    let b = [1u8, 2, 3, 4, 6]; // last byte differs
    assert_eq!(ct_eq(&a, &b), 0);
}

#[test]
fn test_ct_eq_different_length() {
    let a = [1u8, 2, 3];
    let b = [1u8, 2, 3, 4];
    assert_eq!(ct_eq(&a, &b), 0);
}

#[test]
fn test_ct_eq_empty() {
    let a: [u8; 0] = [];
    let b: [u8; 0] = [];
    assert_eq!(ct_eq(&a, &b), 1);
}

#[test]
fn test_ct_eq_u32_equal() {
    assert_eq!(ct_eq_u32(0, 0), 1);
    assert_eq!(ct_eq_u32(0xDEADBEEF, 0xDEADBEEF), 1);
    assert_eq!(ct_eq_u32(u32::MAX, u32::MAX), 1);
    assert_eq!(ct_eq_u32(1, 1), 1);
}

#[test]
fn test_ct_eq_u32_different() {
    assert_eq!(ct_eq_u32(0, 1), 0);
    assert_eq!(ct_eq_u32(0xDEADBEEF, 0xDEADBEEE), 0); // low-bit diff
    assert_eq!(ct_eq_u32(0xDEADBEEF, 0x5EADBEEF), 0); // high-bit diff
    assert_eq!(ct_eq_u32(u32::MAX, u32::MAX - 1), 0);
    assert_eq!(ct_eq_u32(0x80000000, 0), 0); // sign-bit only
    assert_eq!(ct_eq_u32(0, 0x80000000), 0);
}

#[test]
fn test_ct_copy_active() {
    let mut dst = [0u8; 4];
    let src = [0xAA, 0xBB, 0xCC, 0xDD];
    ct_copy(&mut dst, &src, 1); // condition = 1 → copy
    assert_eq!(dst, src);
}

#[test]
fn test_ct_copy_inactive() {
    let mut dst = [0x11, 0x22, 0x33, 0x44];
    let original = dst;
    let src = [0xAA, 0xBB, 0xCC, 0xDD];
    ct_copy(&mut dst, &src, 0); // condition = 0 → no copy
    assert_eq!(dst, original);
}

#[test]
fn test_ct_select_bytes_cond_one() {
    let mut out = [0u8; 4];
    let a = [0xAA, 0xBB, 0xCC, 0xDD];
    let b = [0x11, 0x22, 0x33, 0x44];
    ct_select_bytes(&mut out, &a, &b, 1); // condition = 1 → pick `a`
    assert_eq!(out, a);
}

#[test]
fn test_ct_select_bytes_cond_zero() {
    let mut out = [0u8; 4];
    let a = [0xAA, 0xBB, 0xCC, 0xDD];
    let b = [0x11, 0x22, 0x33, 0x44];
    ct_select_bytes(&mut out, &a, &b, 0); // condition = 0 → pick `b`
    assert_eq!(out, b);
}

#[test]
fn test_ct_select_bytes_empty() {
    let mut out: [u8; 0] = [];
    let a: [u8; 0] = [];
    let b: [u8; 0] = [];
    ct_select_bytes(&mut out, &a, &b, 1); // length 0 — no-op
    ct_select_bytes(&mut out, &a, &b, 0);
}

#[test]
fn test_ct_select_bytes_overwrites_destination() {
    // Pre-fill out with a third value: it must be fully overwritten, not
    // XORed against the selected candidate (the key difference vs ct_copy).
    let mut out = [0xFFu8; 8];
    let a = [0x01u8; 8];
    let b = [0x02u8; 8];
    ct_select_bytes(&mut out, &a, &b, 1);
    assert_eq!(out, a);
    let mut out = [0xFFu8; 8];
    ct_select_bytes(&mut out, &a, &b, 0);
    assert_eq!(out, b);
}

#[test]
fn test_ct_select_bytes_64_bytes() {
    // Exercise a length that is realistic for SLH-DSA-SHAKE-256 (N = 32)
    // and the largest single-block FORS node size. Pattern covers all
    // byte values via the seed and confirms the per-byte selection scales.
    let a: [u8; 64] = core::array::from_fn(|i| i as u8);
    let b: [u8; 64] = core::array::from_fn(|i| !(i as u8));
    let mut out = [0u8; 64];
    ct_select_bytes(&mut out, &a, &b, 1);
    assert_eq!(out, a);
    ct_select_bytes(&mut out, &a, &b, 0);
    assert_eq!(out, b);
}

#[test]
fn test_ct_zeroize() {
    let mut buf = [0xAA; 32];
    ct_zeroize(&mut buf);
    assert_eq!(buf, [0u8; 32]);
}

#[test]
fn test_ct_zeroize_i16() {
    let mut buf = [0x7FFF_i16; 16];
    ct_zeroize_i16(&mut buf);
    assert_eq!(buf, [0i16; 16]);
}