1use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
8
9#[derive(Debug, Clone, Copy, PartialEq, Eq)]
11pub struct SecretScalar<const LIMBS: usize> {
12 limbs: [u64; LIMBS],
13}
14
15impl<const LIMBS: usize> SecretScalar<LIMBS> {
16 pub const fn new(limbs: [u64; LIMBS]) -> Self {
18 Self { limbs }
19 }
20
21 pub fn as_limbs(&self) -> &[u64; LIMBS] {
23 &self.limbs
24 }
25
26 pub fn to_limbs(self) -> [u64; LIMBS] {
28 self.limbs
29 }
30
31 pub const fn bit_len() -> usize {
33 64 * LIMBS
34 }
35
36 pub fn bit_be(&self, i: usize) -> Choice {
41 debug_assert!(i < Self::bit_len());
42
43 let limb_from_msb = i / 64;
44 let bit_in_limb = 63 - (i % 64);
45 let limb_index = LIMBS - 1 - limb_from_msb;
46 Choice::from(((self.limbs[limb_index] >> bit_in_limb) & 1) as u8)
47 }
48}
49
50impl<const LIMBS: usize> Default for SecretScalar<LIMBS> {
51 fn default() -> Self {
52 Self { limbs: [0u64; LIMBS] }
53 }
54}
55
56impl<const LIMBS: usize> ConditionallySelectable for SecretScalar<LIMBS> {
57 fn conditional_select(a: &Self, b: &Self, choice: Choice) -> Self {
58 let mut limbs = [0u64; LIMBS];
59 for i in 0..LIMBS {
60 limbs[i] = u64::conditional_select(&a.limbs[i], &b.limbs[i], choice);
61 }
62 Self { limbs }
63 }
64
65 fn conditional_assign(&mut self, other: &Self, choice: Choice) {
66 for i in 0..LIMBS {
67 self.limbs[i].conditional_assign(&other.limbs[i], choice);
68 }
69 }
70
71 fn conditional_swap(a: &mut Self, b: &mut Self, choice: Choice) {
72 for i in 0..LIMBS {
73 u64::conditional_swap(&mut a.limbs[i], &mut b.limbs[i], choice);
74 }
75 }
76}
77
78impl<const LIMBS: usize> ConstantTimeEq for SecretScalar<LIMBS> {
79 fn ct_eq(&self, other: &Self) -> Choice {
80 let mut acc = Choice::from(1u8);
81 for i in 0..LIMBS {
82 acc = acc & self.limbs[i].ct_eq(&other.limbs[i]);
83 }
84 acc
85 }
86}