clock_bigint/
ct.rs

1//! Constant-time primitives for cryptographic operations.
2//!
3//! All functions in this module execute in constant time regardless of input values,
4//! preventing timing side-channel attacks.
5
6/// Constant-time conditional selection.
7///
8/// Returns `a` if `choice == 1`, otherwise returns `b`.
9/// Executes in constant time regardless of the value of `choice`.
10///
11/// Note: `choice` should be 0 or 1. Other values may produce unexpected results.
12#[inline(always)]
13pub fn ct_select(choice: u64, a: u64, b: u64) -> u64 {
14    ct_select_u64(choice, a, b)
15}
16
17/// Constant-time selection for u64.
18#[inline(always)]
19pub fn ct_select_u64(choice: u64, a: u64, b: u64) -> u64 {
20    let mask = choice.wrapping_neg();
21    (a & mask) | (b & !mask)
22}
23
24/// Constant-time selection for u32.
25#[inline(always)]
26pub fn ct_select_u32(choice: u32, a: u32, b: u32) -> u32 {
27    let mask = choice.wrapping_neg();
28    (a & mask) | (b & !mask)
29}
30
31/// Constant-time less-than comparison.
32///
33/// Returns `1` if `a < b`, otherwise returns `0`.
34/// Executes in constant time.
35#[inline(always)]
36pub fn ct_lt(a: u64, b: u64) -> u64 {
37    let a128 = a as i128;
38    let b128 = b as i128;
39    let diff = a128 - b128;
40    ((diff >> 127) & 1) as u64
41}
42
43/// Constant-time equality comparison.
44///
45/// Returns `1` if `a == b`, otherwise returns `0`.
46/// Executes in constant time.
47#[inline(always)]
48pub fn ct_eq(a: u64, b: u64) -> u64 {
49    let diff = a ^ b;
50    ((diff.wrapping_sub(1)) & !diff) >> 63
51}
52
53/// Constant-time greater-than comparison.
54///
55/// Returns `1` if `a > b`, otherwise returns `0`.
56/// Executes in constant time.
57#[inline(always)]
58pub fn ct_gt(a: u64, b: u64) -> u64 {
59    ct_lt(b, a)
60}
61
62/// Constant-time less-than-or-equal comparison.
63///
64/// Returns `1` if `a <= b`, otherwise returns `0`.
65/// Executes in constant time.
66#[inline(always)]
67pub fn ct_le(a: u64, b: u64) -> u64 {
68    !ct_gt(a, b)
69}
70
71/// Constant-time greater-than-or-equal comparison.
72///
73/// Returns `1` if `a >= b`, otherwise returns `0`.
74/// Executes in constant time.
75#[inline(always)]
76pub fn ct_ge(a: u64, b: u64) -> u64 {
77    !ct_lt(a, b)
78}
79
80/// Constant-time masking utility.
81///
82/// Returns `value` if `mask == 0xFFFFFFFF...`, otherwise returns `0`.
83#[inline(always)]
84pub fn ct_mask(mask: u64, value: u64) -> u64 {
85    mask & value
86}
87
88/// Constant-time conditional swap.
89///
90/// Swaps `a` and `b` if `choice == 1`, otherwise leaves them unchanged.
91/// Executes in constant time.
92#[inline(always)]
93pub fn ct_swap(choice: u64, a: &mut u64, b: &mut u64) {
94    let mask = choice.wrapping_neg();
95    let diff = *a ^ *b;
96    *a ^= diff & mask;
97    *b ^= diff & mask;
98}
99
100/// Constant-time conditional swap for arrays.
101///
102/// Swaps corresponding elements of `a` and `b` if `choice == 1`.
103#[inline(always)]
104pub fn ct_swap_slice(choice: u64, a: &mut [u64], b: &mut [u64]) {
105    let mask = choice.wrapping_neg();
106    let len = a.len().min(b.len());
107    for i in 0..len {
108        let diff = a[i] ^ b[i];
109        a[i] ^= diff & mask;
110        b[i] ^= diff & mask;
111    }
112}
113
114#[cfg(test)]
115mod tests {
116    use super::*;
117
118    #[test]
119    fn test_ct_select() {
120        assert_eq!(ct_select_u64(0, 10, 20), 20);
121        assert_eq!(ct_select_u64(1, 10, 20), 10);
122        assert_eq!(ct_select_u64(0, 0xFFFF, 0x0000), 0x0000);
123        assert_eq!(ct_select_u64(1, 0xFFFF, 0x0000), 0xFFFF);
124    }
125
126    #[test]
127    fn test_ct_lt() {
128        assert_eq!(ct_lt(5, 10), 1);
129        assert_eq!(ct_lt(10, 5), 0);
130        assert_eq!(ct_lt(10, 10), 0);
131        assert_eq!(ct_lt(0, u64::MAX), 1);
132    }
133
134    #[test]
135    fn test_ct_eq() {
136        assert_eq!(ct_eq(5, 5), 1);
137        assert_eq!(ct_eq(5, 10), 0);
138        assert_eq!(ct_eq(0, 0), 1);
139        assert_eq!(ct_eq(u64::MAX, u64::MAX), 1);
140    }
141
142    #[test]
143    fn test_ct_swap() {
144        let mut a = 10u64;
145        let mut b = 20u64;
146        ct_swap(0, &mut a, &mut b);
147        assert_eq!(a, 10);
148        assert_eq!(b, 20);
149
150        let mut a = 10u64;
151        let mut b = 20u64;
152        ct_swap(1, &mut a, &mut b);
153        assert_eq!(a, 20);
154        assert_eq!(b, 10);
155    }
156}