use {
crate::{
ecc::{Curve, Point},
util,
},
docext::docext,
std::{cmp, iter, mem, ops},
};
#[derive(Debug, Default, Clone, Copy, PartialEq, Eq)]
pub struct Num([u64; Self::WIDTH]);
impl Num {
pub const ZERO: Num = Num([0, 0, 0, 0]);
pub const ONE: Num = Num([1, 0, 0, 0]);
pub const TWO: Num = Num([2, 0, 0, 0]);
pub const THREE: Num = Num([3, 0, 0, 0]);
pub const SEVEN: Num = Num([7, 0, 0, 0]);
pub const WIDTH: usize = 4;
pub const BITS: usize = Self::WIDTH * u64::BITS as usize;
pub const BYTES: usize = Self::BITS / 8;
pub const fn from_le_words(n: [u64; Self::WIDTH]) -> Self {
Self(n)
}
pub fn from_le_bytes(b: [u8; Self::BYTES]) -> Self {
const S: usize = mem::size_of::<u64>();
Self::from_le_words([
u64::from_le_bytes(b[..S].try_into().unwrap()),
u64::from_le_bytes(b[S..2 * S].try_into().unwrap()),
u64::from_le_bytes(b[2 * S..3 * S].try_into().unwrap()),
u64::from_le_bytes(b[3 * S..4 * S].try_into().unwrap()),
])
}
pub fn to_le_bytes(&self) -> [u8; Self::BYTES] {
let mut result = [0u8; Self::BYTES];
result
.iter_mut()
.zip(self.0.iter().flat_map(|n| n.to_le_bytes()))
.for_each(|(a, b)| *a = b);
result
}
#[must_use]
pub fn add(&self, n: Self, p: Self) -> Self {
let (n, carry) = add(self.0, n.0);
if carry.0 {
let mut ext = [0; Self::WIDTH + 1];
ext.iter_mut()
.zip(n.into_iter().chain(iter::once(1)))
.for_each(|(a, b)| *a = b);
Self(reduce(ext, p.0))
} else {
Self(reduce(n, p.0))
}
}
#[must_use]
pub fn sub(self, n: Self, p: Self) -> Self {
let (n, borrow) = sub(self.0, n.0);
if borrow.0 {
let (add, carry) = add(n, p.0);
assert!(carry.0);
Self(add)
} else {
Self(n)
}
}
#[must_use]
pub fn mul(self, n: Self, p: Self) -> Self {
let mut prod = [0; Self::WIDTH * 2];
for (i, a) in self.0.into_iter().enumerate() {
let mut carry = 0u128;
for (j, b) in n.0.into_iter().enumerate() {
let m = prod[i + j] as u128 + a as u128 * b as u128 + carry;
carry = (m & ((u64::MAX as u128) << u64::BITS)) >> u64::BITS;
prod[i + j] = u64::try_from(m & u64::MAX as u128).unwrap();
}
prod[i + Self::WIDTH] = u64::try_from(carry).unwrap();
}
Self(reduce(prod, p.0))
}
pub fn eq(self, n: Self, p: Self) -> bool {
reduce(self.0, p.0) == reduce(n.0, p.0)
}
pub fn reduce(self, p: Self) -> Self {
Self(reduce(self.0, p.0))
}
#[docext]
#[must_use]
pub fn inv(&self, p: Self) -> Option<Self> {
if *self == Self::ZERO {
return None;
}
let mut u = reduce(self.0, p.0);
let mut v = p.0;
let mut x1 = Self::ONE;
let mut x2 = Self::ZERO;
while u != Self::ZERO.0 {
let (q, r) = div(v, u);
v = u;
u = r.0;
let x = x2.sub(Self(q).mul(x1, p), p);
x2 = x1;
x1 = x;
}
Some(x2)
}
pub fn get_bit(&self, i: usize) -> bool {
get_bit(self.0, i)
}
}
impl cmp::PartialOrd for Num {
fn partial_cmp(&self, other: &Self) -> Option<cmp::Ordering> {
Some(self.cmp(other))
}
}
impl cmp::Ord for Num {
fn cmp(&self, other: &Self) -> cmp::Ordering {
for (a, b) in self.0.iter().zip(other.0.iter()).rev() {
match a.cmp(b) {
cmp::Ordering::Less => return cmp::Ordering::Less,
cmp::Ordering::Equal => {}
cmp::Ordering::Greater => return cmp::Ordering::Greater,
}
}
cmp::Ordering::Equal
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Borrow(bool);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Carry(bool);
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
struct Rem<const N: usize>([u64; N]);
#[must_use]
fn sub<const N: usize>(a: [u64; N], b: [u64; N]) -> ([u64; N], Borrow) {
let mut borrow = false;
let mut result = [0; N];
for ((a, b), r) in a.iter().zip(&b).zip(result.iter_mut()) {
let (sub, overflow) = a.overflowing_sub(*b);
*r = sub;
if overflow {
if borrow {
*r -= 1;
}
borrow = true;
} else {
let (sub, overflow) = r.overflowing_sub(borrow as u64);
*r = sub;
if overflow {
} else {
borrow = false;
}
}
}
(result, Borrow(borrow))
}
#[must_use]
fn add<const N: usize>(a: [u64; N], b: [u64; N]) -> ([u64; N], Carry) {
let mut carry = false;
let mut result = [0; N];
for ((a, b), r) in a.iter().zip(&b).zip(result.iter_mut()) {
let (add, overflow) = a.overflowing_add(*b);
*r = add;
if carry {
let (add, overflow) = r.overflowing_add(1);
*r = add;
carry = overflow;
}
if overflow {
carry = true;
}
}
(result, Carry(carry))
}
#[must_use]
fn div<const N: usize>(n: [u64; N], d: [u64; N]) -> ([u64; N], Rem<N>) {
let mut q = [0; N];
let mut r = [0; N];
for i in (0..N * u64::BITS as usize).rev() {
r = shl(r);
if get_bit(n, i) {
r = set_bit(r, 0);
}
let (sub, borrow) = sub(r, d);
if !borrow.0 {
r = sub;
q = set_bit(q, i);
}
}
(q, Rem(r))
}
#[must_use]
fn reduce<const N: usize, const P: usize>(n: [u64; N], p: [u64; P]) -> [u64; P] {
assert!(N >= P);
let (_div, rem) = div(n, util::resize(p));
util::resize(rem.0)
}
#[must_use]
fn shl<const N: usize>(n: [u64; N]) -> [u64; N] {
let mut res = [0; N];
let mut msb = false;
for (i, digit) in n.into_iter().enumerate() {
res[i] = digit.wrapping_shl(1);
if msb {
res[i] |= 1;
}
msb = digit & (1 << (u64::BITS - 1)) != 0;
}
res
}
#[must_use]
fn get_bit<const N: usize>(n: [u64; N], i: usize) -> bool {
let digit = i / u64::BITS as usize;
let i = i % u64::BITS as usize;
n[digit] & (1 << i) != 0
}
#[must_use]
fn set_bit<const N: usize>(mut n: [u64; N], i: usize) -> [u64; N] {
let digit = i / u64::BITS as usize;
let i = i % u64::BITS as usize;
n[digit] |= 1 << i;
n
}
#[docext]
impl<C: Curve> ops::Mul<Point<C>> for Num {
type Output = Point<C>;
fn mul(self, rhs: Point<C>) -> Self::Output {
rhs.scale(self)
}
}