use elliptic_curve::{
group::Group,
subtle::{Choice, ConditionallySelectable, ConstantTimeEq},
};
const LUT_SIZE: usize = 8;
#[derive(Clone, Copy, Debug, Default)]
pub struct LookupTable<Point> {
points: [Point; LUT_SIZE],
}
impl<Point> LookupTable<Point>
where
Point: ConditionallySelectable + Group,
{
pub const SIZE: usize = LUT_SIZE;
#[inline]
pub fn new(p: Point) -> Self {
let mut points = [p; LUT_SIZE];
for j in 0..(LUT_SIZE - 1) {
points[j + 1] = p + points[j];
}
Self { points }
}
#[allow(clippy::cast_sign_loss)]
#[inline]
pub fn select(&self, x: i8) -> Point {
debug_assert!((-8..=8).contains(&x));
let xmask = x >> 7;
let xabs = (x + xmask) ^ xmask;
let mut t = Point::identity();
#[allow(clippy::cast_possible_truncation)]
for j in 1..(LUT_SIZE + 1) {
let c = (xabs as u8).ct_eq(&(j as u8));
t.conditional_assign(&self.points[j - 1], c);
}
let neg_mask = Choice::from((xmask & 1) as u8);
t.conditional_assign(&-t, neg_mask);
t
}
#[allow(clippy::cast_sign_loss)]
#[inline]
pub fn select_vartime(&self, x: i8) -> Point {
debug_assert!((-8..=8).contains(&x));
let xabs = x.unsigned_abs();
let t = if xabs == 0 {
Point::identity()
} else {
self.points[xabs as usize - 1]
};
if x < 0 { -t } else { t }
}
}