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        /// Returns the truthy value if `x < y` and the falsy value otherwise.
34        #[inline]
35        pub(crate) const fn choice_from_wide_lt(x: WideWord, y: WideWord) -> Choice {
36            Choice::from_u64_lt(x, y)
37        }
38    }
39    64 => {
40        /// Unsigned integer type that the [`Limb`][`crate::Limb`] newtype wraps.
41        pub type Word = u64;
42
43        /// Wide integer type: double the width of [`Word`].
44        pub type WideWord = u128;
45
46        /// Returns the truthy value if `x <= y` and the falsy value otherwise.
47        #[inline]
48        pub(crate) const fn choice_from_le(x: Word, y: Word) -> Choice {
49            Choice::from_u64_le(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_lt(x: Word, y: Word) -> Choice {
55            Choice::from_u64_lt(x, y)
56        }
57
58        /// Returns the truthy value if `x <= y` and the falsy value otherwise.
59        #[inline]
60        pub(crate) const fn choice_from_wide_le(x: WideWord, y: WideWord) -> Choice {
61            Choice::from_u128_le(x, y)
62        }
63
64        /// Returns the truthy value if `x < y` and the falsy value otherwise.
65        #[inline]
66        pub(crate) const fn choice_from_wide_lt(x: WideWord, y: WideWord) -> Choice {
67            Choice::from_u128_lt(x, y)
68        }
69    }
70}
71
72/// Returns the truthy value if `x == y`, and the falsy value otherwise.
73#[inline]
74pub(crate) const fn choice_from_eq(x: Word, y: Word) -> Choice {
75    choice_from_nz(x ^ y).not()
76}
77
78/// Returns the truthy value if `x == y`, and the falsy value otherwise.
79#[inline]
80pub(crate) const fn choice_from_wide_eq(x: WideWord, y: WideWord) -> Choice {
81    cpubits::cpubits! {
82        32 => { Choice::from_u64_eq(x, y) }
83        64 => { Choice::from_u128_eq(x, y) }
84    }
85}
86
87/// Returns the truthy value if `x > y`, and the falsy value otherwise.
88#[inline]
89pub(crate) const fn choice_from_gt(x: Word, y: Word) -> Choice {
90    choice_from_lt(y, x)
91}
92
93/// Returns the truthy value if `value == 1`, and the falsy value if `value == 0`.
94#[inline]
95pub(crate) const fn choice_from_lsb(value: Word) -> Choice {
96    Choice::from_u8_lsb((value & 1) as u8)
97}
98
99/// Returns the truthy value if `value == Word::MAX`, and the falsy value if `value == 0`.
100#[inline]
101pub(crate) const fn choice_from_mask(value: Word) -> Choice {
102    choice_from_eq(value, Word::MAX)
103}
104
105/// Returns the truthy value if the most significant bit of `value` is `1`,
106/// and the falsy value if it equals `0`.
107#[inline]
108pub(crate) const fn choice_from_msb(value: Word) -> Choice {
109    choice_from_lsb(value >> (Word::BITS - 1))
110}
111
112/// Returns the truthy value if `value != 0`, and the falsy value otherwise.
113#[inline]
114pub(crate) const fn choice_from_nz(value: Word) -> Choice {
115    cpubits::cpubits! {
116        32 => { Choice::from_u32_nz(value) }
117        64 => { Choice::from_u64_nz(value) }
118    }
119}
120
121/// Return `b` if `self` is truthy, otherwise return `a`.
122#[inline]
123pub(crate) const fn select(a: Word, b: Word, choice: Choice) -> Word {
124    a ^ (choice_to_mask(choice) & (a ^ b))
125}
126
127/// Return `b` if `self` is truthy, otherwise return `a`.
128#[inline]
129pub(crate) const fn select_wide(a: WideWord, b: WideWord, choice: Choice) -> WideWord {
130    a ^ (choice_to_wide_mask(choice) & (a ^ b))
131}
132
133/// Create a `Word`-sized bitmask.
134///
135/// # Returns
136/// - `0` for `Choice::FALSE`
137/// - `Word::MAX` for `Choice::TRUE`
138#[inline]
139pub(crate) const fn choice_to_mask(choice: Choice) -> Word {
140    (choice.to_u8() as Word).wrapping_neg()
141}
142
143/// Create a `WideWord`-sized bitmask.
144///
145/// # Returns
146/// - `0` for `Choice::FALSE`
147/// - `Word::MAX` for `Choice::TRUE`
148#[inline]
149pub(crate) const fn choice_to_wide_mask(choice: Choice) -> WideWord {
150    (choice.to_u8() as WideWord).wrapping_neg()
151}
152
153#[inline(always)]
154pub(crate) const fn join(lo: Word, hi: Word) -> WideWord {
155    ((hi as WideWord) << Word::BITS) | (lo as WideWord)
156}
157
158#[inline(always)]
159#[allow(clippy::cast_possible_truncation)]
160pub(crate) const fn split_wide(wide: WideWord) -> (Word, Word) {
161    (wide as Word, (wide >> Word::BITS) as Word)
162}
163
164#[cfg(test)]
165mod tests {
166    use super::{Choice, WideWord, Word};
167
168    #[test]
169    fn choice_from_lt() {
170        assert!(super::choice_from_lt(4, 5).to_bool());
171        assert!(!super::choice_from_lt(5, 5).to_bool());
172        assert!(!super::choice_from_lt(6, 5).to_bool());
173    }
174
175    #[test]
176    fn choice_from_gt() {
177        assert!(!super::choice_from_gt(4, 5).to_bool());
178        assert!(!super::choice_from_gt(5, 5).to_bool());
179        assert!(super::choice_from_gt(6, 5).to_bool());
180    }
181
182    #[test]
183    fn choice_from_wide_le() {
184        assert!(super::choice_from_wide_le(4, 5).to_bool());
185        assert!(super::choice_from_wide_le(5, 5).to_bool());
186        assert!(!super::choice_from_wide_le(6, 5).to_bool());
187    }
188
189    #[test]
190    fn join_split_wide() {
191        let a: Word = 1;
192        let b: Word = 2;
193        assert_eq!(super::split_wide(super::join(a, b)), (a, b));
194        assert_eq!(super::split_wide(super::join(b, a)), (b, a));
195    }
196
197    #[test]
198    fn select() {
199        let a: Word = 1;
200        let b: Word = 2;
201        assert_eq!(super::select(a, b, Choice::FALSE), a);
202        assert_eq!(super::select(a, b, Choice::TRUE), b);
203    }
204
205    #[test]
206    fn select_wide() {
207        let a: WideWord = (1 << Word::BITS) + 1;
208        let b: WideWord = (3 << Word::BITS) + 4;
209        assert_eq!(super::select_wide(a, b, Choice::FALSE), a);
210        assert_eq!(super::select_wide(a, b, Choice::TRUE), b);
211    }
212}