#![allow(non_snake_case)]
use core::fmt::Debug;
use cfg_if::cfg_if;
use subtle::Choice;
use subtle::ConditionallyNegatable;
use subtle::ConditionallySelectable;
use subtle::ConstantTimeEq;
use crate::traits::Identity;
use crate::backend::serial::curve_models::AffineNielsPoint;
use crate::backend::serial::curve_models::ProjectiveNielsPoint;
use crate::edwards::EdwardsPoint;
#[cfg(feature = "zeroize")]
use zeroize::Zeroize;
macro_rules! impl_lookup_table {
(Name = $name:ident, Size = $size:expr, SizeNeg = $neg:expr, SizeRange = $range:expr, ConversionRange = $conv_range:expr) => {
#[derive(Copy, Clone)]
pub struct $name<T>(pub(crate) [T; $size]);
impl<T> $name<T>
where
T: Identity + ConditionallySelectable + ConditionallyNegatable,
{
pub fn select(&self, x: i8) -> T {
debug_assert!(x >= $neg);
debug_assert!(x as i16 <= $size as i16); let xmask = x as i16 >> 7;
let xabs = (x as i16 + xmask) ^ xmask;
let mut t = T::identity();
for j in $range {
let c = (xabs as u16).ct_eq(&(j as u16));
t.conditional_assign(&self.0[j - 1], c);
}
let neg_mask = Choice::from((xmask & 1) as u8);
t.conditional_negate(neg_mask);
t
}
}
impl<T: Copy + Default> Default for $name<T> {
fn default() -> $name<T> {
$name([T::default(); $size])
}
}
impl<T: Debug> Debug for $name<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}(", stringify!($name))?;
for x in self.0.iter() {
write!(f, "{:?}", x)?;
}
write!(f, ")")
}
}
impl<'a> From<&'a EdwardsPoint> for $name<ProjectiveNielsPoint> {
fn from(P: &'a EdwardsPoint) -> Self {
let mut points = [P.as_projective_niels(); $size];
for j in $conv_range {
points[j + 1] = (P + &points[j]).as_extended().as_projective_niels();
}
$name(points)
}
}
impl<'a> From<&'a EdwardsPoint> for $name<AffineNielsPoint> {
fn from(P: &'a EdwardsPoint) -> Self {
let mut points = [P.as_affine_niels(); $size];
for j in $conv_range {
points[j + 1] = (P + &points[j]).as_extended().as_affine_niels()
}
$name(points)
}
}
#[cfg(feature = "zeroize")]
impl<T> Zeroize for $name<T>
where
T: Copy + Default + Zeroize,
{
fn zeroize(&mut self) {
self.0.iter_mut().zeroize();
}
}
};
} impl_lookup_table! {
Name = LookupTable,
Size = 8,
SizeNeg = -8,
SizeRange = 1..9,
ConversionRange = 0..7
}
cfg_if! {
if #[cfg(feature = "precomputed-tables")] {
impl_lookup_table! {
Name = LookupTableRadix32,
Size = 16,
SizeNeg = -16,
SizeRange = 1..17,
ConversionRange = 0..15
}
impl_lookup_table! {
Name = LookupTableRadix64,
Size = 32,
SizeNeg = -32,
SizeRange = 1..33,
ConversionRange = 0..31
}
impl_lookup_table! {
Name = LookupTableRadix128,
Size = 64,
SizeNeg = -64,
SizeRange = 1..65,
ConversionRange = 0..63
}
impl_lookup_table! {
Name = LookupTableRadix256,
Size = 128,
SizeNeg = -128,
SizeRange = 1..129,
ConversionRange = 0..127
}
pub(crate) type LookupTableRadix16<T> = LookupTable<T>;
}
}
#[derive(Copy, Clone)]
pub(crate) struct NafLookupTable5<T>(pub(crate) [T; 8]);
impl<T: Copy> NafLookupTable5<T> {
pub fn select(&self, x: usize) -> T {
debug_assert_eq!(x & 1, 1);
debug_assert!(x < 16);
self.0[x / 2]
}
}
impl<T: Debug> Debug for NafLookupTable5<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "NafLookupTable5({:?})", self.0)
}
}
impl<'a> From<&'a EdwardsPoint> for NafLookupTable5<ProjectiveNielsPoint> {
fn from(A: &'a EdwardsPoint) -> Self {
let mut Ai = [A.as_projective_niels(); 8];
let A2 = A.double();
for i in 0..7 {
Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_projective_niels();
}
NafLookupTable5(Ai)
}
}
impl<'a> From<&'a EdwardsPoint> for NafLookupTable5<AffineNielsPoint> {
fn from(A: &'a EdwardsPoint) -> Self {
let mut Ai = [A.as_affine_niels(); 8];
let A2 = A.double();
for i in 0..7 {
Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_affine_niels();
}
NafLookupTable5(Ai)
}
}
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
#[derive(Copy, Clone)]
pub(crate) struct NafLookupTable8<T>(pub(crate) [T; 64]);
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
impl<T: Copy> NafLookupTable8<T> {
pub fn select(&self, x: usize) -> T {
debug_assert_eq!(x & 1, 1);
debug_assert!(x < 128);
self.0[x / 2]
}
}
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
impl<T: Debug> Debug for NafLookupTable8<T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
writeln!(f, "NafLookupTable8([")?;
for i in 0..64 {
writeln!(f, "\t{:?},", &self.0[i])?;
}
write!(f, "])")
}
}
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
impl<'a> From<&'a EdwardsPoint> for NafLookupTable8<ProjectiveNielsPoint> {
fn from(A: &'a EdwardsPoint) -> Self {
let mut Ai = [A.as_projective_niels(); 64];
let A2 = A.double();
for i in 0..63 {
Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_projective_niels();
}
NafLookupTable8(Ai)
}
}
#[cfg(any(feature = "precomputed-tables", feature = "alloc"))]
impl<'a> From<&'a EdwardsPoint> for NafLookupTable8<AffineNielsPoint> {
fn from(A: &'a EdwardsPoint) -> Self {
let mut Ai = [A.as_affine_niels(); 64];
let A2 = A.double();
for i in 0..63 {
Ai[i + 1] = (&A2 + &Ai[i]).as_extended().as_affine_niels();
}
NafLookupTable8(Ai)
}
}