Skip to main content

crypto_bigint/
word.rs

1//! `Word` represents the core integer type we use as the core of `Limb`, and is typically the same
2//! size as a pointer on a particular CPU.
3
4use ctutils::Choice;
5
6cpubits::cpubits! {
7    16 => { compile_error!("this crate builds on 32-bit and 64-bit platforms only") }
8    32 => {
9        /// Inner integer type that the [`Limb`] newtype wraps.
10        pub type Word = u32;
11
12        /// Unsigned wide integer type: double the width of [`Word`].
13        pub type WideWord = u64;
14
15        /// Returns the truthy value if `x <= y` and the falsy value otherwise.
16        #[inline]
17        pub(crate) const fn choice_from_le(x: Word, y: Word) -> Choice {
18            Choice::from_u32_le(x, y)
19        }
20
21        /// Returns the truthy value if `x < y`, and the falsy value otherwise.
22        #[inline]
23        pub(crate) const fn choice_from_lt(x: Word, y: Word) -> Choice {
24            Choice::from_u32_lt(x, y)
25        }
26
27        /// Returns the truthy value if `x <= y` and the falsy value otherwise.
28        #[inline]
29        pub(crate) const fn choice_from_wide_le(x: WideWord, y: WideWord) -> Choice {
30            Choice::from_u64_le(x, y)
31        }
32    }
33    64 => {
34        /// Unsigned integer type that the [`Limb`][`crate::Limb`] newtype wraps.
35        pub type Word = u64;
36
37        /// Wide integer type: double the width of [`Word`].
38        pub type WideWord = u128;
39
40        /// Returns the truthy value if `x <= y` and the falsy value otherwise.
41        #[inline]
42        pub(crate) const fn choice_from_le(x: Word, y: Word) -> Choice {
43            Choice::from_u64_le(x, y)
44        }
45
46        /// Returns the truthy value if `x < y`, and the falsy value otherwise.
47        #[inline]
48        pub(crate) const fn choice_from_lt(x: Word, y: Word) -> Choice {
49            Choice::from_u64_lt(x, y)
50        }
51
52        /// Returns the truthy value if `x <= y` and the falsy value otherwise.
53        #[inline]
54        pub(crate) const fn choice_from_wide_le(x: WideWord, y: WideWord) -> Choice {
55            Choice::from_u128_le(x, y)
56        }
57    }
58}
59
60/// Returns the truthy value if `x == y`, and the falsy value otherwise.
61#[inline]
62pub(crate) const fn choice_from_eq(x: Word, y: Word) -> Choice {
63    choice_from_nz(x ^ y).not()
64}
65
66/// Returns the truthy value if `x > y`, and the falsy value otherwise.
67#[inline]
68pub(crate) const fn choice_from_gt(x: Word, y: Word) -> Choice {
69    choice_from_lt(y, x)
70}
71
72/// Returns the truthy value if `value == 1`, and the falsy value if `value == 0`.
73#[inline]
74pub(crate) const fn choice_from_lsb(value: Word) -> Choice {
75    Choice::from_u8_lsb((value & 1) as u8)
76}
77
78/// Returns the truthy value if `value == Word::MAX`, and the falsy value if `value == 0`.
79#[inline]
80pub(crate) const fn choice_from_mask(value: Word) -> Choice {
81    choice_from_eq(value, Word::MAX)
82}
83
84/// Returns the truthy value if the most significant bit of `value` is `1`,
85/// and the falsy value if it equals `0`.
86#[inline]
87pub(crate) const fn choice_from_msb(value: Word) -> Choice {
88    choice_from_lsb(value >> (Word::BITS - 1))
89}
90
91/// Returns the truthy value if `value != 0`, and the falsy value otherwise.
92#[inline]
93pub(crate) const fn choice_from_nz(value: Word) -> Choice {
94    choice_from_lsb((value | value.wrapping_neg()) >> (Word::BITS - 1))
95}
96
97/// Return `b` if `self` is truthy, otherwise return `a`.
98#[inline]
99pub(crate) const fn select(a: Word, b: Word, choice: Choice) -> Word {
100    a ^ (choice_to_mask(choice) & (a ^ b))
101}
102
103/// Return `b` if `self` is truthy, otherwise return `a`.
104#[inline]
105pub(crate) const fn select_wide(a: WideWord, b: WideWord, choice: Choice) -> WideWord {
106    a ^ (choice_to_wide_mask(choice) & (a ^ b))
107}
108
109/// Create a `Word`-sized bitmask.
110///
111/// # Returns
112/// - `0` for `Choice::FALSE`
113/// - `Word::MAX` for `Choice::TRUE`
114#[inline]
115pub(crate) const fn choice_to_mask(choice: Choice) -> Word {
116    (choice.to_u8_vartime() as Word).wrapping_neg()
117}
118
119/// Create a `WideWord`-sized bitmask.
120///
121/// # Returns
122/// - `0` for `Choice::FALSE`
123/// - `Word::MAX` for `Choice::TRUE`
124#[inline]
125pub(crate) const fn choice_to_wide_mask(choice: Choice) -> WideWord {
126    (choice.to_u8_vartime() as WideWord).wrapping_neg()
127}
128
129#[cfg(test)]
130mod tests {
131    use super::{Choice, WideWord, Word};
132
133    #[test]
134    fn choice_from_lt() {
135        assert!(super::choice_from_lt(4, 5).to_bool());
136        assert!(!super::choice_from_lt(5, 5).to_bool());
137        assert!(!super::choice_from_lt(6, 5).to_bool());
138    }
139
140    #[test]
141    fn choice_from_gt() {
142        assert!(!super::choice_from_gt(4, 5).to_bool());
143        assert!(!super::choice_from_gt(5, 5).to_bool());
144        assert!(super::choice_from_gt(6, 5).to_bool());
145    }
146
147    #[test]
148    fn choice_from_wide_le() {
149        assert!(super::choice_from_wide_le(4, 5).to_bool());
150        assert!(super::choice_from_wide_le(5, 5).to_bool());
151        assert!(!super::choice_from_wide_le(6, 5).to_bool());
152    }
153
154    #[test]
155    fn select() {
156        let a: Word = 1;
157        let b: Word = 2;
158        assert_eq!(super::select(a, b, Choice::FALSE), a);
159        assert_eq!(super::select(a, b, Choice::TRUE), b);
160    }
161
162    #[test]
163    fn select_wide() {
164        let a: WideWord = (1 << Word::BITS) + 1;
165        let b: WideWord = (3 << Word::BITS) + 4;
166        assert_eq!(super::select_wide(a, b, Choice::FALSE), a);
167        assert_eq!(super::select_wide(a, b, Choice::TRUE), b);
168    }
169}