hacspec_lib/math_util/ct_util.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
use crate::prelude::*;
/// Conditional, constant-time swapping.
/// Returns `(x, y)` if `c == 0` and `(y, x)` if `c == 1`.
#[inline]
#[cfg_attr(feature = "use_attributes", not_hacspec)]
pub fn cswap_bit<T: Integer + Copy>(x: T, y: T, c: T) -> (T, T) {
cswap(x, y, T::default().wrap_sub(c))
}
/// Conditional, constant-time swapping.
/// Returns `(x, y)` if `c == 0` and `(y, x)` if `c == T::max`.
/// The return value is undefined if `c` has any other value.
#[inline]
#[cfg_attr(feature = "use_attributes", not_hacspec)]
pub fn cswap<T: Integer + Copy>(x: T, y: T, c: T) -> (T, T) {
let mask = c & (x ^ y);
(x ^ mask, y ^ mask)
}
/// Set bit at position `i` in `x` to `b` if `c` is all 1 and return the restult.
/// Returns `x` if `c` is `0`.
#[inline]
#[cfg_attr(feature = "use_attributes", not_hacspec)]
pub fn cset_bit<T: Integer + Copy>(x: T, b: T, i: usize, c: T) -> T {
let set = x.set_bit(b, i);
let (out, _) = cswap(x, set, c);
out
}
/// Add two numerics if condition `c` is set (all bits 1).
/// Returns `x` if condition `c` is `0`.
/// Note: Addition is always wrapping.
#[inline]
#[cfg_attr(feature = "use_attributes", not_hacspec)]
pub fn cadd<T: Integer + Copy>(x: T, y: T, c: T) -> T {
let sum = x.wrap_add(y);
let (x, _) = cswap(x, sum, c);
x
}
/// Subtract two numerics if condition `c` is set (all bits 1).
/// Returns `x` if condition `c` is `0`.
/// Note: Addition is always wrapping.
#[inline]
#[cfg_attr(feature = "use_attributes", not_hacspec)]
pub fn csub<T: Integer + Copy>(x: T, y: T, c: T) -> T {
let diff = x.wrap_sub(y);
let (x, _) = cswap(x, diff, c);
x
}
/// Multiply two numerics if condition `c` is set (all bits 1).
/// Returns `x` if condition `c` is `0`.
/// Note: Multiplication is always wrapping.
#[inline]
#[cfg_attr(feature = "use_attributes", not_hacspec)]
pub fn cmul<T: Integer + Copy>(x: T, y: T, c: T) -> T {
let prod = x.wrap_mul(y);
let (x, _) = cswap(x, prod, c);
x
}
/// Constant time division for Numerics.
/// Note that this function is only constant time if `T` is a secret integer and
/// hence provides constant time implementations for the used functions.
#[inline]
#[cfg_attr(feature = "use_attributes", not_hacspec)]
pub fn ct_div<T: Integer + Copy>(a: T, d: T) -> (T, T) {
let mut q = T::default();
let mut r = T::default();
for i in (0..T::NUM_BITS).rev() {
r = r << 1;
r = r.set(0, a, i);
// The code below is equivalent to the following.
// if r.greater_than_or_equal(d) {
// r = r - d;
// q = q.set_bit(T::ONE(), i);
// }
let geq = r.greater_than_or_equal_bm(d);
r = csub(r, d, geq);
q = cset_bit(q, T::ONE(), i, geq);
}
(q, r)
}