use super::{HeaplessBigInt, is_zero, zero};
use crate::MachineWord;
use const_num_traits::{Personality, PersonalityTag};
use core::marker::PhantomData;
impl<T: MachineWord, const CAP: usize, P: Personality> PartialEq for HeaplessBigInt<T, CAP, P> {
fn eq(&self, other: &Self) -> bool {
let n = core::cmp::max(self.len, other.len) as usize;
match P::TAG {
PersonalityTag::Nct => {
let mut i = 0;
while i < n {
if self.limbs[i] != other.limbs[i] {
return false;
}
i += 1;
}
true
}
PersonalityTag::Ct => {
let mut diff = zero::<T>();
let mut i = 0;
while i < n {
diff |= self.limbs[i] ^ other.limbs[i];
i += 1;
}
is_zero(&diff)
}
}
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> Eq for HeaplessBigInt<T, CAP, P> {}
impl<T: MachineWord, const CAP: usize, P: Personality> PartialOrd for HeaplessBigInt<T, CAP, P> {
fn partial_cmp(&self, other: &Self) -> Option<core::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T: MachineWord, const CAP: usize, P: Personality> Ord for HeaplessBigInt<T, CAP, P> {
fn cmp(&self, other: &Self) -> core::cmp::Ordering {
let n = core::cmp::max(self.len, other.len) as usize;
match P::TAG {
PersonalityTag::Nct => {
let mut i = n;
while i > 0 {
i -= 1;
match self.limbs[i].cmp(&other.limbs[i]) {
core::cmp::Ordering::Equal => continue,
ord => return ord,
}
}
core::cmp::Ordering::Equal
}
PersonalityTag::Ct => {
let a = self.limbs.get(..n).unwrap_or(&self.limbs);
let b = other.limbs.get(..n).unwrap_or(&other.limbs);
crate::fixeduint::const_cmp_ct(a, b)
}
}
}
}
impl<T: MachineWord + core::hash::Hash, const CAP: usize, P: Personality> core::hash::Hash
for HeaplessBigInt<T, CAP, P>
{
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
let mut top = 0usize;
let mut i = 0;
while i < self.len as usize {
if !super::is_zero(&self.limbs[i]) {
top = i + 1;
}
i += 1;
}
state.write_usize(top);
for limb in &self.limbs[..top] {
limb.hash(state);
}
}
}
impl<T, const CAP: usize, P: Personality> subtle::ConstantTimeEq for HeaplessBigInt<T, CAP, P>
where
T: MachineWord + subtle::ConstantTimeEq,
{
fn ct_eq(&self, other: &Self) -> subtle::Choice {
let n = core::cmp::max(self.len, other.len) as usize;
let mut acc = subtle::Choice::from(1u8);
let mut i = 0;
while i < n {
let per_limb = self.limbs[i].ct_eq(&other.limbs[i]);
acc &= per_limb;
i += 1;
}
subtle::Choice::from(core::hint::black_box(acc.unwrap_u8()))
}
}
impl<T, const CAP: usize, P: Personality> subtle::ConditionallySelectable
for HeaplessBigInt<T, CAP, P>
where
T: MachineWord + subtle::ConditionallySelectable,
{
fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
let out_len = core::cmp::max(a.len, b.len);
let mut limbs = [super::zero::<T>(); CAP];
let mut i = 0;
while i < out_len as usize {
limbs[i] = <T as subtle::ConditionallySelectable>::conditional_select(
&a.limbs[i],
&b.limbs[i],
choice,
);
i += 1;
}
Self {
limbs,
len: out_len,
_p: PhantomData,
}
}
}
#[inline]
pub(crate) fn ct_select<T, const CAP: usize, P: Personality>(
if_false: &HeaplessBigInt<T, CAP, P>,
if_true: &HeaplessBigInt<T, CAP, P>,
flag: bool,
) -> HeaplessBigInt<T, CAP, P>
where
T: MachineWord + subtle::ConditionallySelectable,
{
<HeaplessBigInt<T, CAP, P> as subtle::ConditionallySelectable>::conditional_select(
if_false,
if_true,
subtle::Choice::from(flag as u8),
)
}
impl<T, const CAP: usize, P: Personality> const_num_traits::ops::ct::CtIsZero
for HeaplessBigInt<T, CAP, P>
where
T: MachineWord + subtle::ConstantTimeEq,
{
fn ct_is_zero(&self) -> subtle::Choice {
let n = self.len as usize;
let mut acc = subtle::Choice::from(1u8);
let mut i = 0;
while i < n {
acc &= self.limbs[i].ct_eq(&<T as const_num_traits::ConstZero>::ZERO);
i += 1;
}
subtle::Choice::from(core::hint::black_box(acc.unwrap_u8()))
}
}
impl<T, const CAP: usize, P: Personality> subtle::ConstantTimeGreater for HeaplessBigInt<T, CAP, P>
where
T: MachineWord + subtle::ConstantTimeEq + subtle::ConstantTimeGreater,
{
fn ct_gt(&self, other: &Self) -> subtle::Choice {
let n = core::cmp::max(self.len, other.len) as usize;
let mut gt = subtle::Choice::from(0u8);
let mut undecided = subtle::Choice::from(1u8);
let mut i = n;
while i > 0 {
i -= 1;
let gt_here = self.limbs[i].ct_gt(&other.limbs[i]);
let eq_here = self.limbs[i].ct_eq(&other.limbs[i]);
gt |= undecided & gt_here;
undecided &= eq_here;
}
gt
}
}
impl<T, const CAP: usize, P: Personality> subtle::ConstantTimeLess for HeaplessBigInt<T, CAP, P> where
T: MachineWord + subtle::ConstantTimeEq + subtle::ConstantTimeGreater
{
}