tc_constant_time 0.1.0

Constant-time selection, comparison, and conditional arithmetic primitives.
Documentation
use tc_constant_time::{Choice, ConditionallyNegatable, ConditionallySelectable, ConstantTimeEq};

#[test]
fn arrays_select_and_compare_every_position() {
    let original = [0_u64, 1, 1 << 63, u64::MAX];
    assert_eq!(original.ct_eq(&original).unwrap_u8(), 1);
    for index in 0..original.len() {
        let mut changed = original;
        changed[index] ^= 1;
        assert_eq!(original.ct_eq(&changed).unwrap_u8(), 0);
        assert_eq!(changed.ct_eq(&original).unwrap_u8(), 0);
        assert_eq!(
            <[u64; 4]>::conditional_select(&original, &changed, Choice::from_lsb(0)),
            original
        );
        assert_eq!(
            <[u64; 4]>::conditional_select(&original, &changed, Choice::from_lsb(1)),
            changed
        );
    }
    let empty: [u64; 0] = [];
    assert_eq!(empty.ct_eq(&empty).unwrap_u8(), 1);
    for bit in 0..=1 {
        assert_eq!(
            <[u64; 0]>::conditional_select(&empty, &empty, Choice::from_lsb(bit)),
            empty
        );
    }
}

#[test]
fn arrays_support_in_place_operations_and_zero_length() {
    let left = [i32::MIN, -1, 0, i32::MAX];
    let right = [7, 11, -13, 17];
    for bit in 0..=1 {
        let choice = Choice::from_lsb(bit);
        let mut assigned = left;
        assigned.conditional_assign(&right, choice);
        assert_eq!(assigned, if bit == 0 { left } else { right });
        let (mut a, mut b) = (left, right);
        <[i32; 4]>::conditional_swap(&mut a, &mut b, choice);
        assert_eq!(
            (a, b),
            if bit == 0 {
                (left, right)
            } else {
                (right, left)
            }
        );
        let mut negated = left;
        negated.conditional_negate(choice);
        assert_eq!(
            negated,
            if bit == 0 {
                left
            } else {
                left.map(i32::wrapping_neg)
            }
        );
        let (mut empty_a, mut empty_b): ([i32; 0], [i32; 0]) = ([], []);
        empty_a.conditional_assign(&empty_b, choice);
        <[i32; 0]>::conditional_swap(&mut empty_a, &mut empty_b, choice);
        empty_a.conditional_negate(choice);
        assert_eq!(empty_a.ct_eq(&empty_b).unwrap_u8(), 1);
    }
}