use core::arch::asm;
use core::convert;
use core::mem;
use core::ops;
pub type LimbType = CfgLimbType;
#[cfg(not(target_arch = "x86_64"))]
#[doc(hidden)]
type CfgLimbType = u32;
#[cfg(target_arch = "x86_64")]
#[doc(hidden)]
type CfgLimbType = u64;
pub const LIMB_BITS: u32 = LimbType::BITS;
pub const LIMB_BYTES: usize = mem::size_of::<LimbType>();
const HALF_LIMB_BITS: u32 = LIMB_BITS / 2;
const HALF_LIMB_MASK: LimbType = ct_lsb_mask_l(HALF_LIMB_BITS);
#[cfg(all(feature = "enable_arch_math_asm", target_arch = "x86_64"))]
mod x86_64_math;
#[inline(always)]
pub fn black_box_l(v: LimbType) -> LimbType {
let result: LimbType;
unsafe {
asm!("/* {v} */", v = inout(reg) v => result, options(pure, nomem, nostack));
}
result
}
#[derive(Clone, Copy, Debug)]
pub struct LimbChoice {
mask: LimbType,
}
impl LimbChoice {
pub const fn new(cond: LimbType) -> Self {
debug_assert!(cond == 0 || cond == 1);
Self {
mask: (0 as LimbType).wrapping_sub(cond),
}
}
pub fn unwrap(&self) -> LimbType {
black_box_l(self.mask & 1)
}
pub const fn select(&self, v0: LimbType, v1: LimbType) -> LimbType {
v0 ^ (self.mask & (v0 ^ v1))
}
pub fn select_usize(&self, v0: usize, v1: usize) -> usize {
let cond = self.unwrap() as usize;
let mask = (0_usize).wrapping_sub(cond);
v0 ^ (mask & (v0 ^ v1))
}
}
impl convert::From<LimbType> for LimbChoice {
fn from(value: LimbType) -> Self {
Self::new(value)
}
}
impl ops::Not for LimbChoice {
type Output = Self;
fn not(self) -> Self::Output {
Self { mask: !self.mask }
}
}
impl ops::BitAnd for LimbChoice {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self {
mask: self.mask & rhs.mask,
}
}
}
impl ops::BitAndAssign for LimbChoice {
fn bitand_assign(&mut self, rhs: Self) {
self.mask &= rhs.mask
}
}
impl ops::BitOr for LimbChoice {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self {
mask: self.mask | rhs.mask,
}
}
}
impl ops::BitOrAssign for LimbChoice {
fn bitor_assign(&mut self, rhs: Self) {
self.mask |= rhs.mask
}
}
#[cfg(feature = "zeroize")]
impl zeroize::Zeroize for LimbChoice {
fn zeroize(&mut self) {
self.mask.zeroize()
}
}
#[allow(unused)]
fn generic_ct_is_nonzero_l(v: LimbType) -> LimbType {
black_box_l((v | v.wrapping_neg()) >> (LIMB_BITS - 1))
}
#[cfg(not(all(feature = "enable_arch_math_asm", target_arch = "x86_64")))]
#[doc(hidden)]
use self::generic_ct_is_nonzero_l as arch_ct_is_nonzero_l;
#[cfg(all(feature = "enable_arch_math_asm", target_arch = "x86_64"))]
#[doc(hidden)]
use x86_64_math::ct_is_nonzero_l as arch_ct_is_nonzero_l;
pub fn ct_is_nonzero_l(v: LimbType) -> LimbType {
arch_ct_is_nonzero_l(v)
}
#[allow(unused)]
fn generic_ct_is_zero_l(v: LimbType) -> LimbType {
(1 as LimbType) ^ ct_is_nonzero_l(v)
}
#[cfg(not(all(feature = "enable_arch_math_asm", target_arch = "x86_64")))]
#[doc(hidden)]
use self::generic_ct_is_zero_l as arch_ct_is_zero_l;
#[cfg(all(feature = "enable_arch_math_asm", target_arch = "x86_64"))]
#[doc(hidden)]
use x86_64_math::ct_is_zero_l as arch_ct_is_zero_l;
pub fn ct_is_zero_l(v: LimbType) -> LimbType {
arch_ct_is_zero_l(v)
}
pub fn ct_eq_l_l(v0: LimbType, v1: LimbType) -> LimbChoice {
LimbChoice::from(ct_is_zero_l(v0 ^ v1))
}
pub fn ct_neq_l_l(v0: LimbType, v1: LimbType) -> LimbChoice {
!ct_eq_l_l(v0, v1)
}
pub fn ct_lt_or_eq_l_l(v0: LimbType, v1: LimbType) -> (LimbType, LimbType) {
let (borrow, diff) = ct_sub_l_l(v0, v1);
debug_assert!(diff != 0 || borrow == 0);
(borrow, ct_is_zero_l(diff))
}
pub fn ct_lt_l_l(v0: LimbType, v1: LimbType) -> LimbChoice {
let (borrow, _) = ct_sub_l_l(v0, v1);
LimbChoice::from(borrow)
}
pub fn ct_leq_l_l(v0: LimbType, v1: LimbType) -> LimbChoice {
!ct_lt_l_l(v1, v0)
}
pub fn ct_gt_l_l(v0: LimbType, v1: LimbType) -> LimbChoice {
ct_lt_l_l(v1, v0)
}
pub fn ct_geq_l_l(v0: LimbType, v1: LimbType) -> LimbChoice {
ct_leq_l_l(v1, v0)
}
pub const fn ct_lsb_mask_l(nbits: u32) -> LimbType {
debug_assert!(nbits <= LIMB_BITS);
let nbits_lo = nbits % LIMB_BITS;
let nbits_hi = nbits / LIMB_BITS;
debug_assert!(nbits_hi <= 1);
debug_assert!(nbits_hi == 0 || nbits_lo == 0);
let mask_for_lo = (1 << nbits_lo) - 1;
let mask_for_hi = (0 as LimbType).wrapping_sub(nbits_hi as LimbType);
mask_for_lo | mask_for_hi
}
#[test]
fn test_ct_lsb_mask_l() {
for i in 0..LIMB_BITS {
let mask = ct_lsb_mask_l(i);
assert_eq!(mask, (1 << i) - 1);
}
assert_eq!(ct_lsb_mask_l(LIMB_BITS), !0);
}
fn ct_l_to_hls(v: LimbType) -> (LimbType, LimbType) {
(
black_box_l(v >> HALF_LIMB_BITS),
black_box_l(v & HALF_LIMB_MASK),
)
}
#[allow(unused)]
fn generic_ct_add_l_l(v0: LimbType, v1: LimbType) -> (LimbType, LimbType) {
let v0 = black_box_l(v0);
let v1 = black_box_l(v1);
let r = v0.wrapping_add(v1);
let carry = black_box_l((((v0 | v1) & !r) | (v0 & v1)) >> (LIMB_BITS - 1));
(carry, r)
}
#[cfg(not(all(feature = "enable_arch_math_asm", target_arch = "x86_64")))]
#[doc(hidden)]
use self::generic_ct_add_l_l as arch_ct_add_l_l;
#[cfg(all(feature = "enable_arch_math_asm", target_arch = "x86_64"))]
#[doc(hidden)]
use x86_64_math::ct_add_l_l as arch_ct_add_l_l;
pub fn ct_add_l_l(v0: LimbType, v1: LimbType) -> (LimbType, LimbType) {
arch_ct_add_l_l(v0, v1)
}
#[test]
fn test_ct_add_l_l() {
assert_eq!(ct_add_l_l(0, 0), (0, 0));
assert_eq!(ct_add_l_l(1, 0), (0, 1));
assert_eq!(ct_add_l_l(!0 - 1, 1), (0, !0));
assert_eq!(ct_add_l_l(!0, 1), (1, 0));
assert_eq!(
ct_add_l_l(1 << (LIMB_BITS - 1), 1 << (LIMB_BITS - 1)),
(1, 0)
);
assert_eq!(
ct_add_l_l(!0, 1 << (LIMB_BITS - 1)),
(1, ct_lsb_mask_l(LIMB_BITS - 1))
);
assert_eq!(ct_add_l_l(!0, !0), (1, !0 - 1));
}
pub fn ct_add_l_l_c(v0: LimbType, v1: LimbType, carry: LimbType) -> (LimbType, LimbType) {
debug_assert!(carry <= 1);
let (carry0, r) = ct_add_l_l(v0, carry);
let (carry1, r) = ct_add_l_l(r, v1);
let carry = carry0 + carry1;
debug_assert!(carry <= 1);
(carry, r)
}
#[allow(unused)]
fn generic_ct_sub_l_l(v0: LimbType, v1: LimbType) -> (LimbType, LimbType) {
let v0 = black_box_l(v0);
let v1 = black_box_l(v1);
let r = v0.wrapping_sub(v1);
let borrow = black_box_l((((r | v1) & !v0) | (v1 & r)) >> (LIMB_BITS - 1));
(borrow, r)
}
#[cfg(not(all(feature = "enable_arch_math_asm", target_arch = "x86_64")))]
#[doc(hidden)]
use self::generic_ct_sub_l_l as arch_ct_sub_l_l;
#[cfg(all(feature = "enable_arch_math_asm", target_arch = "x86_64"))]
#[doc(hidden)]
use x86_64_math::ct_sub_l_l as arch_ct_sub_l_l;
pub fn ct_sub_l_l(v0: LimbType, v1: LimbType) -> (LimbType, LimbType) {
arch_ct_sub_l_l(v0, v1)
}
#[test]
fn test_ct_sub_l_l() {
assert_eq!(ct_sub_l_l(0, 0), (0, 0));
assert_eq!(ct_sub_l_l(1, 0), (0, 1));
assert_eq!(ct_sub_l_l(0, 1), (1, !0));
assert_eq!(
ct_sub_l_l(1 << (LIMB_BITS - 1), 1 << (LIMB_BITS - 1)),
(0, 0)
);
assert_eq!(
ct_sub_l_l(0, 1 << (LIMB_BITS - 1)),
(1, 1 << (LIMB_BITS - 1))
);
assert_eq!(
ct_sub_l_l(1 << (LIMB_BITS - 1), (1 << (LIMB_BITS - 1)) + 1),
(1, !0)
);
}
pub fn ct_sub_l_l_b(v0: LimbType, v1: LimbType, borrow: LimbType) -> (LimbType, LimbType) {
debug_assert!(borrow <= 1);
let (borrow0, r) = ct_sub_l_l(v0, borrow);
let (borrow1, r) = ct_sub_l_l(r, v1);
let borrow = borrow0 + borrow1;
debug_assert!(borrow <= 1);
(borrow, r)
}
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct DoubleLimb {
v: [LimbType; 2],
}
impl DoubleLimb {
pub fn new(h: LimbType, l: LimbType) -> Self {
Self { v: [l, h] }
}
pub fn high(&self) -> LimbType {
self.v[1]
}
pub fn low(&self) -> LimbType {
self.v[0]
}
}
#[allow(unused)]
fn generic_ct_mul_l_l(v0: LimbType, v1: LimbType) -> DoubleLimb {
let (v0h, v0l) = ct_l_to_hls(v0);
let (v1h, v1l) = ct_l_to_hls(v1);
let prod_v0l_v1l = v0l * v1l;
let prod_v0l_v1h = v0l * v1h;
let prod_v0h_v1l = v0h * v1l;
let prod_v0h_v1h = v0h * v1h;
let mut result_low: LimbType = prod_v0l_v1l;
let mut result_high: LimbType = prod_v0h_v1h;
let (prod_v0l_v1h_h, prod_v0l_v1h_l) = ct_l_to_hls(prod_v0l_v1h);
let (prod_v0h_v1l_h, prod_v0h_v1l_l) = ct_l_to_hls(prod_v0h_v1l);
let (result_low_carry, result_low_sum) =
ct_add_l_l(result_low, prod_v0l_v1h_l << HALF_LIMB_BITS);
result_low = result_low_sum;
result_high += result_low_carry;
result_high += prod_v0l_v1h_h;
let (result_low_carry, result_low_sum) =
ct_add_l_l(result_low, prod_v0h_v1l_l << HALF_LIMB_BITS);
result_low = result_low_sum;
result_high += result_low_carry;
result_high += prod_v0h_v1l_h;
DoubleLimb::new(result_high, result_low)
}
#[cfg(not(all(feature = "enable_arch_math_asm", target_arch = "x86_64")))]
#[doc(hidden)]
use self::generic_ct_mul_l_l as arch_ct_mul_l_l;
#[cfg(all(feature = "enable_arch_math_asm", target_arch = "x86_64"))]
#[doc(hidden)]
use x86_64_math::ct_mul_l_l as arch_ct_mul_l_l;
pub fn ct_mul_l_l(v0: LimbType, v1: LimbType) -> DoubleLimb {
arch_ct_mul_l_l(v0, v1)
}
#[test]
fn test_ct_mul_l_l() {
let p = ct_mul_l_l(0, 0);
assert_eq!(p.low(), 0);
assert_eq!(p.high(), 0);
let p = ct_mul_l_l(2, 2);
assert_eq!(p.low(), 4);
assert_eq!(p.high(), 0);
let p = ct_mul_l_l(1 << (LIMB_BITS - 1), 2);
assert_eq!(p.low(), 0);
assert_eq!(p.high(), 1);
let p = ct_mul_l_l(2, 1 << (LIMB_BITS - 1));
assert_eq!(p.low(), 0);
assert_eq!(p.high(), 1);
let p = ct_mul_l_l(1 << (LIMB_BITS - 1), 1 << (LIMB_BITS - 1));
assert_eq!(p.low(), 0);
assert_eq!(p.high(), 1 << (LIMB_BITS - 2));
let p = ct_mul_l_l(!0, !0);
assert_eq!(p.low(), 1);
assert_eq!(p.high(), !1);
}
pub fn ct_mul_add_l_l_l_c(
op0: LimbType,
op10: LimbType,
op11: LimbType,
carry: LimbType,
) -> (LimbType, LimbType) {
let prod = ct_mul_l_l(op10, op11);
debug_assert!(prod.high() < !1 || prod.high() == !1 && prod.low() == 1);
let (carry0, result) = ct_add_l_l(op0, carry);
let (carry1, result) = ct_add_l_l(result, prod.low());
debug_assert!(prod.high() < !1 || carry0 + carry1 <= 1);
let carry = prod.high() + carry0 + carry1;
(carry, result)
}
pub fn ct_mul_sub_l_l_l_b(
op0: LimbType,
op10: LimbType,
op11: LimbType,
borrow: LimbType,
) -> (LimbType, LimbType) {
let prod = ct_mul_l_l(op10, op11);
debug_assert!(prod.high() < !1 || prod.high() == !1 && prod.low() == 1);
let (borrow0, result) = ct_sub_l_l(op0, borrow);
let (borrow1, result) = ct_sub_l_l(result, prod.low());
debug_assert!(prod.high() < !1 || borrow0 + borrow1 <= 1);
let borrow = prod.high() + borrow0 + borrow1;
(borrow, result)
}
pub struct CtLDivisor {
m: LimbType,
v: LimbType,
v_width: u32,
}
#[derive(Debug)]
pub enum CtLDivisorError {
DivisorIsZero,
}
impl CtLDivisor {
pub fn new(v: LimbType) -> Result<Self, CtLDivisorError> {
if ct_is_zero_l(v) != 0 {
return Err(CtLDivisorError::DivisorIsZero);
}
debug_assert_ne!(v, 0);
let v_width = ct_find_last_set_bit_l(v) as u32;
let m = Self::ct_compute_m(v, v_width);
Ok(Self { m, v, v_width })
}
fn ct_compute_m(v: LimbType, v_width: u32) -> LimbType {
debug_assert!(v_width > 0);
let v = v << (LIMB_BITS - v_width);
let mut r_msb = LimbChoice::from(0);
let mut r_h = !0;
let mut r_l = !ct_lsb_mask_l(LIMB_BITS - v_width);
let mut q = 0;
for _ in 0..LIMB_BITS + 1 {
let q_new_lsb = r_msb | ct_geq_l_l(r_h, v);
q = (q << 1) | q_new_lsb.unwrap();
r_h = r_h.wrapping_sub(q_new_lsb.select(0, v));
r_msb = LimbChoice::from(r_h >> (LIMB_BITS - 1));
r_h = (r_h << 1) | (r_l >> (LIMB_BITS - 1));
r_l <<= 1;
}
q
}
pub fn nonct_new(v: LimbType) -> Result<Self, CtLDivisorError> {
if v == 0 {
return Err(CtLDivisorError::DivisorIsZero);
}
let v_width = ct_find_last_set_bit_l(v) as u32;
let m = Self::nonct_compute_m(v, v_width);
Ok(Self { m, v, v_width })
}
fn nonct_compute_m(v: LimbType, v_width: u32) -> LimbType {
NonCtLDivisor::new(v)
.unwrap()
.do_div(&DoubleLimb::new(ct_lsb_mask_l(v_width) - v, !0))
.0
}
}
pub trait LDivisorPrivate {
fn do_div(&self, u: &DoubleLimb) -> (LimbType, LimbType);
fn get_v(&self) -> LimbType;
}
impl LDivisorPrivate for CtLDivisor {
fn do_div(&self, u: &DoubleLimb) -> (LimbType, LimbType) {
let l = self.v_width;
debug_assert!(l > 0 && l <= LIMB_BITS);
let u2 = (u.low() >> (l - 1)) >> 1;
let u2 = u2 | u.high() << (LIMB_BITS - l);
let u10 = u.low() << (LIMB_BITS - l);
let u1 = u10 >> (LIMB_BITS - 1);
let v_norm = self.v << (LIMB_BITS - l);
debug_assert_eq!(v_norm >> (LIMB_BITS - 1), 1);
let n_adj = u10.wrapping_add(LimbChoice::from(u1).select(0, v_norm));
debug_assert!(u2 < !0 || u1 == 0);
let p = ct_mul_l_l(self.m, u2 + u1);
let (carry, _) = ct_add_l_l(p.low(), n_adj);
let (carry, q1) = ct_add_l_l_c(u2, p.high(), carry);
debug_assert_eq!(carry, 0);
let neg_q_plus_one = ct_negate_l(q1.wrapping_add(1));
let p = ct_mul_l_l(neg_q_plus_one, self.v);
let (carry, r_l) = ct_add_l_l(u.low(), p.low());
let (carry, r_h) = ct_add_l_l_c(u.high(), p.high(), carry);
let (borrow, r_h) = ct_sub_l_l(r_h, self.v);
debug_assert!(carry == 0 || borrow != 0);
let borrow = borrow ^ carry;
let is_negative = LimbChoice::from(borrow);
let q = q1 + (!is_negative).select(0, 1);
let (carry, r_l) = ct_add_l_l(r_l, is_negative.select(0, self.v));
debug_assert_eq!(r_h.wrapping_add(carry), 0);
debug_assert!(r_l < self.v);
(q, r_l)
}
fn get_v(&self) -> LimbType {
self.v
}
}
#[test]
fn test_ct_l_divisor() {
fn div_and_check(u: DoubleLimb, v: LimbType) {
let nonct_v = CtLDivisor::nonct_new(v).unwrap();
let v = CtLDivisor::new(v).unwrap();
assert_eq!(v.m, nonct_v.m);
assert_eq!(v.v_width, nonct_v.v_width);
assert_eq!(v.v, nonct_v.v);
let (q, r) = v.do_div(&u);
let prod = ct_mul_l_l(q, v.v);
let (carry, result_l) = ct_add_l_l(prod.low(), r);
let (carry, result_h) = ct_add_l_l(prod.high(), carry);
assert_eq!(carry, 0);
assert_eq!(result_l, u.low());
assert_eq!(result_h, u.high());
}
div_and_check(DoubleLimb::new(!1, !0), !0);
div_and_check(DoubleLimb::new(!1, !1), !0);
div_and_check(DoubleLimb::new(0, 0), !0);
div_and_check(DoubleLimb::new(0, !1), !0);
div_and_check(DoubleLimb::new(0, !0), 1);
div_and_check(DoubleLimb::new(1, !0), 2);
for i in 0..LIMB_BITS {
for j1 in i..LIMB_BITS {
for j2 in 0..j1 + 1 {
let u_h = if i != 0 { !0 >> (LIMB_BITS - i) } else { 0 };
let u = DoubleLimb::new(u_h, !0);
let v = 1 << j1 | 1 << j2;
div_and_check(u, v);
}
}
}
}
#[derive(Debug)]
pub enum NonCtLDivisorError {
DivisorIsZero,
}
#[allow(unused)]
struct GenericNonCtLDivisor {
v: LimbType,
scaling_shift: u32,
scaling_low_src_rshift: u32,
scaling_low_src_mask: LimbType,
}
impl GenericNonCtLDivisor {
#[allow(unused)]
fn new(v: LimbType) -> Result<Self, NonCtLDivisorError> {
if v == 0 {
return Err(NonCtLDivisorError::DivisorIsZero);
}
let scaling_shift = v.leading_zeros();
let scaling_low_src_rshift = (LIMB_BITS - scaling_shift) % LIMB_BITS;
let scaling_low_src_mask = ct_lsb_mask_l(scaling_shift);
Ok(Self {
v,
scaling_shift,
scaling_low_src_rshift,
scaling_low_src_mask,
})
}
}
impl LDivisorPrivate for GenericNonCtLDivisor {
fn do_div(&self, u: &DoubleLimb) -> (LimbType, LimbType) {
let v = self.v << self.scaling_shift;
let v_hl_h = v >> HALF_LIMB_BITS;
let v_hl_l = v & HALF_LIMB_MASK;
let mut u_h = (u.high() << self.scaling_shift)
| ((u.low() >> self.scaling_low_src_rshift) & self.scaling_low_src_mask);
debug_assert_eq!(u_h >> self.scaling_shift, u.high());
let mut u_l = u.low() << self.scaling_shift;
let mut q: LimbType = 0;
for _j in [1, 0] {
let mut cur_q_hl = {
let q = u_h / v_hl_h;
let q = q.min(HALF_LIMB_MASK);
let r = u_h - q * v_hl_h;
let r_ov = r >> HALF_LIMB_BITS != 0;
if !r_ov && q * v_hl_l > (r << HALF_LIMB_BITS) | (u_l >> HALF_LIMB_BITS) {
q - 1
} else {
q
}
};
let u2 = u_h >> HALF_LIMB_BITS;
let u1 = (u_h << HALF_LIMB_BITS) | u_l >> HALF_LIMB_BITS;
let u0 = u_l << HALF_LIMB_BITS;
let (borrow, mut u1) = ct_mul_sub_l_l_l_b(u1, cur_q_hl, v, 0);
let (borrow, mut u2) = ct_sub_l_l(u2, borrow);
if borrow != 0 {
cur_q_hl -= 1;
let carry;
(carry, u1) = ct_add_l_l(u1, v);
(_, u2) = ct_add_l_l(u2, carry);
}
debug_assert_eq!(u2, 0);
u_h = u1;
u_l = u0;
q = (q << HALF_LIMB_BITS) | cur_q_hl
}
debug_assert_eq!(u_l, 0);
(q, u_h >> self.scaling_shift)
}
fn get_v(&self) -> LimbType {
self.v
}
}
#[cfg(not(all(feature = "enable_arch_math_asm", target_arch = "x86_64")))]
#[doc(hidden)]
use self::GenericNonCtLDivisor as ArchNonCtLDivisor;
#[cfg(all(feature = "enable_arch_math_asm", target_arch = "x86_64"))]
#[doc(hidden)]
use x86_64_math::NonCtLDivisor as ArchNonCtLDivisor;
pub struct NonCtLDivisor {
arch: ArchNonCtLDivisor,
}
impl NonCtLDivisor {
pub fn new(v: LimbType) -> Result<Self, NonCtLDivisorError> {
Ok(Self {
arch: ArchNonCtLDivisor::new(v)?,
})
}
}
impl LDivisorPrivate for NonCtLDivisor {
fn do_div(&self, u: &DoubleLimb) -> (LimbType, LimbType) {
self.arch.do_div(u)
}
fn get_v(&self) -> LimbType {
self.arch.get_v()
}
}
#[cfg(test)]
fn nonct_div_dl_l(u: &DoubleLimb, v: &NonCtLDivisor) -> (DoubleLimb, LimbType) {
let (q_h, r_h) = v.do_div(&DoubleLimb::new(0, u.high()));
let (q_l, r_l) = v.do_div(&DoubleLimb::new(r_h, u.low()));
(DoubleLimb::new(q_h, q_l), r_l)
}
#[test]
fn test_nonct_div_dl_l() {
fn div_and_check(u: DoubleLimb, v: LimbType) {
let normalized_v = NonCtLDivisor::new(v).unwrap();
let (q, r) = nonct_div_dl_l(&u.clone(), &normalized_v);
let prod_l = ct_mul_l_l(q.low(), v);
let prod_h = ct_mul_l_l(q.high(), v);
assert_eq!(prod_h.high(), 0);
let (carry, result_l) = ct_add_l_l(prod_l.low(), r);
let (carry, result_h) = ct_add_l_l_c(prod_l.high(), prod_h.low(), carry);
assert_eq!(carry, 0);
assert_eq!(result_l, u.low());
assert_eq!(result_h, u.high());
}
div_and_check(DoubleLimb::new(!1, !0), !0);
div_and_check(DoubleLimb::new(!1, !1), !0);
div_and_check(DoubleLimb::new(0, 0), !0);
div_and_check(DoubleLimb::new(0, !1), !0);
div_and_check(DoubleLimb::new(!0, !0), 1);
div_and_check(DoubleLimb::new(!0, !1), 2);
for i in 0..LIMB_BITS {
for j1 in 0..LIMB_BITS {
for j2 in 0..j1 + 1 {
let u_h = if i != 0 { !0 >> (LIMB_BITS - i) } else { 0 };
let u = DoubleLimb::new(u_h, !0);
let v = 1 << j1 | 1 << j2;
div_and_check(u, v);
}
}
}
}
pub fn ct_inv_mod_l(v: LimbType) -> LimbType {
debug_assert_eq!(v & 1, 1);
let mut k = 1;
let mut r: LimbType = 1;
while k < LIMB_BITS {
r = (r << 1).wrapping_sub(v.wrapping_mul(r).wrapping_mul(r));
k *= 2;
}
r
}
#[test]
fn test_ct_inv_mod_l() {
for j in 0..LIMB_BITS {
let v = ((1 as LimbType) << j) | 1;
assert_eq!(v.wrapping_mul(ct_inv_mod_l(v)), 1);
}
for j in 1..LIMB_BITS {
let v = ((1 as LimbType) << j).wrapping_sub(1);
assert_eq!(v.wrapping_mul(ct_inv_mod_l(v)), 1);
}
let v: LimbType = !0;
assert_eq!(v.wrapping_mul(ct_inv_mod_l(v)), 1);
}
pub fn ct_find_last_set_bit_l(mut v: LimbType) -> usize {
let mut bits = LIMB_BITS as LimbType;
assert!(bits != 0);
assert!(bits & (bits - 1) == 0); let mut count: usize = 0;
let mut lsb_mask = !0;
while bits > 1 {
bits /= 2;
lsb_mask >>= bits;
let v_l = v & lsb_mask;
let v_h = v >> bits;
let upper = ct_neq_l_l(v_h, 0);
count += upper.select(0, bits) as usize;
v = upper.select(v_l, v_h);
}
debug_assert!(v <= 1);
count += v as usize;
count
}
#[test]
fn test_ct_find_last_set_bit_l() {
assert_eq!(ct_find_last_set_bit_l(0), 0);
for i in 0..LIMB_BITS as usize {
let v = 1 << i;
assert_eq!(ct_find_last_set_bit_l(v), i + 1);
assert_eq!(ct_find_last_set_bit_l(v - 1), i);
assert_eq!(ct_find_last_set_bit_l(!(v - 1)), LIMB_BITS as usize);
}
}
pub fn ct_find_last_set_byte_l(v: LimbType) -> usize {
(ct_find_last_set_bit_l(v) + 8 - 1) / 8
}
pub fn ct_find_first_set_bit_l(mut v: LimbType) -> usize {
let mut bits = LIMB_BITS as LimbType;
assert!(bits != 0);
assert!(bits & (bits - 1) == 0); let mut count: usize = LIMB_BITS as usize;
let mut lsb_mask = !0;
while bits > 1 {
bits /= 2;
lsb_mask >>= bits;
let v_l = v & lsb_mask;
let v_h = v >> bits;
let lower = ct_neq_l_l(v_l, 0);
count -= lower.select(0, bits) as usize;
v = lower.select(v_h, v_l);
}
debug_assert!(v <= 1);
count -= v as usize;
count
}
#[test]
fn test_ct_find_first_set_bit_l() {
assert_eq!(ct_find_first_set_bit_l(0), LIMB_BITS as usize);
for i in 0..LIMB_BITS as usize {
let v = 1 << i;
assert_eq!(ct_find_first_set_bit_l(v), i);
if i != 0 {
assert_eq!(ct_find_first_set_bit_l(v - 1), 0);
}
assert_eq!(ct_find_first_set_bit_l(!(v - 1)), i);
}
}
pub fn ct_arithmetic_rshift_l(v: LimbType, rshift: LimbType) -> LimbType {
let rshift_nz_mask = LimbChoice::from(ct_is_nonzero_l(rshift)).select(0, !0);
let sign_extend = (0 as LimbType).wrapping_sub(v >> (LIMB_BITS - 1));
let sign_extend = sign_extend << ((LIMB_BITS as LimbType - rshift) & rshift_nz_mask);
let sign_extend = sign_extend & rshift_nz_mask;
let rshift_lt_max_mask = ct_eq_l_l(rshift, LIMB_BITS as LimbType).select(!0, 0);
sign_extend | ((v >> (rshift & rshift_lt_max_mask)) & rshift_lt_max_mask)
}
#[test]
fn test_ct_arithmetic_shift_l() {
assert_eq!(
ct_arithmetic_rshift_l(ct_lsb_mask_l(LIMB_BITS - 1), 0),
ct_lsb_mask_l(LIMB_BITS - 1)
);
assert_eq!(
ct_arithmetic_rshift_l(ct_lsb_mask_l(LIMB_BITS - 1), (LIMB_BITS - 2) as LimbType),
1
);
assert_eq!(
ct_arithmetic_rshift_l(ct_lsb_mask_l(LIMB_BITS - 1), (LIMB_BITS - 1) as LimbType),
0
);
assert_eq!(
ct_arithmetic_rshift_l(ct_lsb_mask_l(LIMB_BITS - 1), LIMB_BITS as LimbType),
0
);
assert_eq!(ct_arithmetic_rshift_l(!0 ^ 1, 0), !0 ^ 1);
assert_eq!(
ct_arithmetic_rshift_l(!0 ^ 1, (LIMB_BITS - 2) as LimbType),
!0
);
assert_eq!(
ct_arithmetic_rshift_l(!0 ^ 1, (LIMB_BITS - 1) as LimbType),
!0
);
assert_eq!(ct_arithmetic_rshift_l(!0 ^ 1, LIMB_BITS as LimbType), !0);
}
pub fn ct_negate_l(v: LimbType) -> LimbType {
(!v).wrapping_add(1)
}