pub(in super::super) trait Ring {
fn n(&self) -> usize;
unsafe fn sqr(&self, r: *mut u64, a: *const u64, t: *mut u64);
unsafe fn mul(&self, r: *mut u64, a: *const u64, b: *const u64, t: *mut u64);
}
pub(in super::super) trait Registers {
type V: Copy;
fn sqr(&self, a: Self::V) -> Self::V;
fn mul(&self, a: Self::V, b: Self::V) -> Self::V;
}
#[inline]
pub(super) fn window(bits: usize) -> u32 {
const LIMITS: [usize; 9] = [7, 25, 81, 241, 673, 1793, 4609, 11521, 28161];
let mut k = 1;
for limit in LIMITS {
if bits > limit {
k += 1;
}
}
k
}
const MAX_REGISTER_WINDOW: u32 = 6;
#[inline(always)]
unsafe fn bit(e: *const u64, i: usize) -> bool {
unsafe { (*e.add((i - 1) / 64) >> ((i - 1) % 64)) & 1 != 0 }
}
#[inline(always)]
pub(super) unsafe fn bits(e: *const u64, i: usize, k: u32) -> u64 {
let k = k as usize;
unsafe {
if i <= k {
return *e & ((1 << i) - 1);
}
let low = i - k;
let (l, s) = (low / 64, low % 64);
let mut r = *e.add(l) >> s;
if 64 - s < k {
r |= *e.add(l + 1) << (64 - s);
}
r & ((1 << k) - 1)
}
}
pub(super) unsafe fn power<R: Ring>(
ring: &R,
r: *mut u64,
e: *const u64,
ebits: usize,
table: *mut u64,
stride: usize,
t: *mut u64,
) {
let n = ring.n();
let k = window(ebits);
unsafe {
if k > 1 {
ring.sqr(r, table, t);
for i in 1..1usize << (k - 1) {
ring.mul(table.add(i * stride), table.add((i - 1) * stride), r, t);
}
}
let mut i = ebits - k as usize;
let w = bits(e, ebits, k);
let zeros = w.trailing_zeros();
i += zeros as usize;
core::ptr::copy_nonoverlapping(table.add((w >> zeros >> 1) as usize * stride), r, n);
while i != 0 {
if !bit(e, i) {
ring.sqr(r, r, t);
i -= 1;
continue;
}
let w = bits(e, i, k);
let zeros = w.trailing_zeros();
let len = k.min(i as u32) - zeros;
i -= len as usize;
for _ in 0..len {
ring.sqr(r, r, t);
}
ring.mul(r, r, table.add((w >> zeros >> 1) as usize * stride), t);
}
}
}
#[inline(always)]
pub(super) unsafe fn power_in_registers<R: Registers>(
ring: &R,
b: R::V,
e: *const u64,
ebits: usize,
) -> R::V {
let k = window(ebits).min(MAX_REGISTER_WINDOW);
let mut table = [b; 1 << (MAX_REGISTER_WINDOW - 1)];
if k > 1 {
let b2 = ring.sqr(b);
for i in 1..1usize << (k - 1) {
table[i] = ring.mul(table[i - 1], b2);
}
}
unsafe {
let mut i = ebits - k as usize;
let w = bits(e, ebits, k);
let zeros = w.trailing_zeros();
i += zeros as usize;
let mut r = table[(w >> zeros >> 1) as usize];
while i != 0 {
if !bit(e, i) {
r = ring.sqr(r);
i -= 1;
continue;
}
let w = bits(e, i, k);
let zeros = w.trailing_zeros();
let len = k.min(i as u32) - zeros;
i -= len as usize;
for _ in 0..len {
r = ring.sqr(r);
}
r = ring.mul(r, table[(w >> zeros >> 1) as usize]);
}
r
}
}