use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct SecretScalar<const LIMBS: usize> {
limbs: [u64; LIMBS],
}
impl<const LIMBS: usize> SecretScalar<LIMBS> {
pub const fn new(limbs: [u64; LIMBS]) -> Self {
Self { limbs }
}
pub fn as_limbs(&self) -> &[u64; LIMBS] {
&self.limbs
}
pub fn to_limbs(self) -> [u64; LIMBS] {
self.limbs
}
pub const fn bit_len() -> usize {
64 * LIMBS
}
pub fn bit_be(&self, i: usize) -> Choice {
debug_assert!(i < Self::bit_len());
let limb_from_msb = i / 64;
let bit_in_limb = 63 - (i % 64);
let limb_index = LIMBS - 1 - limb_from_msb;
Choice::from(((self.limbs[limb_index] >> bit_in_limb) & 1) as u8)
}
}
impl<const LIMBS: usize> Default for SecretScalar<LIMBS> {
fn default() -> Self {
Self { limbs: [0u64; LIMBS] }
}
}
impl<const LIMBS: usize> ConditionallySelectable for SecretScalar<LIMBS> {
fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
let mut limbs = [0u64; LIMBS];
for i in 0..LIMBS {
limbs[i] = u64::conditional_select(&a.limbs[i], &b.limbs[i], choice);
}
Self { limbs }
}
fn conditional_assign(&mut self, other: &Self, choice: Choice) {
for i in 0..LIMBS {
self.limbs[i].conditional_assign(&other.limbs[i], choice);
}
}
fn conditional_swap(a: &mut Self, b: &mut Self, choice: Choice) {
for i in 0..LIMBS {
u64::conditional_swap(&mut a.limbs[i], &mut b.limbs[i], choice);
}
}
}
impl<const LIMBS: usize> ConstantTimeEq for SecretScalar<LIMBS> {
fn ct_eq(&self, other: &Self) -> Choice {
let mut acc = Choice::from(1u8);
for i in 0..LIMBS {
acc = acc & self.limbs[i].ct_eq(&other.limbs[i]);
}
acc
}
}