1mod add;
5mod bit_and;
6mod bit_not;
7mod bit_or;
8mod bit_xor;
9mod bits;
10mod cmp;
11mod ct;
12mod div;
13mod encoding;
14mod from;
15mod gcd;
16mod mul;
17mod neg;
18mod shl;
19mod shr;
20mod sqrt;
21mod sub;
22
23#[cfg(feature = "rand_core")]
24mod rand;
25
26use crate::{
27 Bounded, Choice, ConstOne, ConstZero, Constants, CtEq, CtOption, Integer, NonZero, One,
28 UintRef, Unsigned, WideWord, Word, Zero, primitives::u32_bits, traits::sealed::Sealed, word,
29};
30use core::{fmt, ptr, slice};
31
32#[cfg(feature = "serde")]
33use serdect::serde::{Deserialize, Deserializer, Serialize, Serializer};
34
35#[inline(always)]
38#[must_use]
39pub const fn nlimbs(bits: u32) -> usize {
40 match cpubits::CPUBITS {
41 32 => ((bits + 31) >> 5) as usize,
42 64 => ((bits + 63) >> 6) as usize,
43 _ => unreachable!(),
44 }
45}
46
47#[allow(clippy::derived_hash_with_manual_eq)]
54#[derive(Copy, Clone, Default, Hash)]
55#[repr(transparent)]
56pub struct Limb(pub Word);
57
58impl Limb {
59 pub const ZERO: Self = Limb(0);
61
62 pub const ONE: Self = Limb(1);
64
65 pub const MAX: Self = Limb(Word::MAX);
67
68 pub(crate) const HI_BIT: u32 = Limb::BITS - 1;
70
71 cpubits::cpubits! {
72 32 => {
73 pub const BITS: u32 = 32;
75 pub const BYTES: usize = 4;
77 }
78 64 => {
79 pub const BITS: u32 = 64;
81 pub const BYTES: usize = 8;
83 }
84 }
85
86 pub const LOG2_BITS: u32 = u32_bits(Self::BITS - 1);
88
89 #[must_use]
91 pub const fn is_zero(&self) -> Choice {
92 word::choice_from_nz(self.0).not()
93 }
94
95 #[must_use]
99 pub const fn to_nz(self) -> CtOption<NonZero<Self>> {
100 let is_nz = self.is_nonzero();
101
102 let nz_word = word::select(1, self.0, is_nz);
104 CtOption::new(NonZero(Self(nz_word)), is_nz)
105 }
106
107 #[must_use]
109 pub const fn lsb_to_choice(self) -> Choice {
110 word::choice_from_lsb(self.0)
111 }
112
113 #[inline]
116 #[must_use]
117 pub const fn array_as_words<const N: usize>(array: &[Self; N]) -> &[Word; N] {
118 #[allow(unsafe_code)]
120 unsafe {
121 &*array.as_ptr().cast()
122 }
123 }
124
125 #[inline]
128 pub const fn array_as_mut_words<const N: usize>(array: &mut [Self; N]) -> &mut [Word; N] {
129 #[allow(unsafe_code)]
131 unsafe {
132 &mut *array.as_mut_ptr().cast()
133 }
134 }
135
136 #[inline]
139 #[must_use]
140 pub const fn slice_as_words(slice: &[Self]) -> &[Word] {
141 #[allow(unsafe_code)]
143 unsafe {
144 &*(ptr::from_ref(slice) as *const [Word])
145 }
146 }
147
148 #[inline]
151 pub const fn slice_as_mut_words(slice: &mut [Self]) -> &mut [Word] {
152 #[allow(unsafe_code)]
154 unsafe {
155 &mut *(ptr::from_mut(slice) as *mut [Word])
156 }
157 }
158}
159
160impl AsRef<[Limb]> for Limb {
161 #[inline(always)]
162 fn as_ref(&self) -> &[Limb] {
163 slice::from_ref(self)
164 }
165}
166
167impl AsMut<[Limb]> for Limb {
168 #[inline(always)]
169 fn as_mut(&mut self) -> &mut [Limb] {
170 slice::from_mut(self)
171 }
172}
173
174impl AsRef<UintRef> for Limb {
175 #[inline(always)]
176 fn as_ref(&self) -> &UintRef {
177 UintRef::new(slice::from_ref(self))
178 }
179}
180
181impl AsMut<UintRef> for Limb {
182 #[inline(always)]
183 fn as_mut(&mut self) -> &mut UintRef {
184 UintRef::new_mut(slice::from_mut(self))
185 }
186}
187
188impl Bounded for Limb {
189 const BITS: u32 = Self::BITS;
190 const BYTES: usize = Self::BYTES;
191}
192
193impl Constants for Limb {
194 const MAX: Self = Self::MAX;
195}
196
197impl ConstZero for Limb {
198 const ZERO: Self = Self::ZERO;
199}
200
201impl ConstOne for Limb {
202 const ONE: Self = Self::ONE;
203}
204
205impl Zero for Limb {
206 #[inline(always)]
207 fn zero() -> Self {
208 Self::ZERO
209 }
210}
211
212impl One for Limb {
213 #[inline(always)]
214 fn one() -> Self {
215 Self::ONE
216 }
217}
218
219impl num_traits::Zero for Limb {
220 fn zero() -> Self {
221 Self::ZERO
222 }
223
224 fn is_zero(&self) -> bool {
225 self.ct_eq(&Self::ZERO).into()
226 }
227}
228
229impl num_traits::One for Limb {
230 fn one() -> Self {
231 Self::ONE
232 }
233
234 fn is_one(&self) -> bool {
235 self.ct_eq(&Self::ONE).into()
236 }
237}
238
239impl Integer for Limb {
240 #[inline]
241 fn as_limbs(&self) -> &[Limb] {
242 self.as_ref()
243 }
244
245 #[inline]
246 fn as_mut_limbs(&mut self) -> &mut [Limb] {
247 self.as_mut()
248 }
249
250 #[inline]
251 fn nlimbs(&self) -> usize {
252 1
253 }
254
255 fn is_even(&self) -> Choice {
256 (*self).is_odd().not()
257 }
258
259 fn is_odd(&self) -> Choice {
260 (*self).is_odd()
261 }
262}
263
264impl Sealed for Limb {}
265
266impl Unsigned for Limb {
267 #[inline]
268 fn as_uint_ref(&self) -> &UintRef {
269 self.as_ref()
270 }
271
272 #[inline]
273 fn as_mut_uint_ref(&mut self) -> &mut UintRef {
274 self.as_mut()
275 }
276
277 #[inline]
278 fn from_limb_like(limb: Limb, _other: &Self) -> Self {
279 limb
280 }
281}
282
283impl fmt::Debug for Limb {
284 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
285 write!(f, "Limb(0x{self:X})")
286 }
287}
288
289impl fmt::Display for Limb {
290 #[inline]
291 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
292 fmt::UpperHex::fmt(self, f)
293 }
294}
295
296impl fmt::Binary for Limb {
297 #[inline]
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 if f.alternate() {
300 write!(f, "0b")?;
301 }
302
303 write!(f, "{:0width$b}", &self.0, width = Self::BITS as usize)
304 }
305}
306
307impl fmt::Octal for Limb {
308 #[inline]
309 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
310 if f.alternate() {
311 write!(f, "0o")?;
312 }
313 write!(
314 f,
315 "{:0width$o}",
316 &self.0,
317 width = Self::BITS.div_ceil(3) as usize
318 )
319 }
320}
321
322impl fmt::LowerHex for Limb {
323 #[inline]
324 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
325 if f.alternate() {
326 write!(f, "0x")?;
327 }
328 write!(f, "{:0width$x}", &self.0, width = Self::BYTES * 2)
329 }
330}
331
332impl fmt::UpperHex for Limb {
333 #[inline]
334 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
335 if f.alternate() {
336 write!(f, "0x")?;
337 }
338 write!(f, "{:0width$X}", &self.0, width = Self::BYTES * 2)
339 }
340}
341
342#[cfg(feature = "serde")]
343impl<'de> Deserialize<'de> for Limb {
344 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
345 where
346 D: Deserializer<'de>,
347 {
348 Ok(Self(Word::deserialize(deserializer)?))
349 }
350}
351
352#[cfg(feature = "serde")]
353impl Serialize for Limb {
354 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
355 where
356 S: Serializer,
357 {
358 self.0.serialize(serializer)
359 }
360}
361
362#[cfg(feature = "zeroize")]
363impl zeroize::DefaultIsZeroes for Limb {}
364
365#[cfg(test)]
366mod tests {
367 use super::Limb;
368 #[cfg(feature = "alloc")]
369 use alloc::format;
370
371 cpubits::cpubits! {
372 32 => {
373 #[test]
374 fn nlimbs_for_bits_macro() {
375 assert_eq!(super::nlimbs(64), 2);
376 assert_eq!(super::nlimbs(65), 3);
377 assert_eq!(super::nlimbs(128), 4);
378 assert_eq!(super::nlimbs(129), 5);
379 assert_eq!(super::nlimbs(192), 6);
380 assert_eq!(super::nlimbs(193), 7);
381 assert_eq!(super::nlimbs(256), 8);
382 assert_eq!(super::nlimbs(257), 9);
383 }
384 }
385 64 => {
386 #[test]
387 fn nlimbs_for_bits_macro() {
388 assert_eq!(super::nlimbs(64), 1);
389 assert_eq!(super::nlimbs(65), 2);
390 assert_eq!(super::nlimbs(128), 2);
391 assert_eq!(super::nlimbs(129), 3);
392 assert_eq!(super::nlimbs(192), 3);
393 assert_eq!(super::nlimbs(193), 4);
394 assert_eq!(super::nlimbs(256), 4);
395 }
396 }
397 }
398
399 #[cfg(feature = "alloc")]
400 #[test]
401 fn debug() {
402 cpubits::cpubits! {
403 32 => { assert_eq!(format!("{:?}", Limb(42)), "Limb(0x0000002A)"); }
404 64 => { assert_eq!(format!("{:?}", Limb(42)), "Limb(0x000000000000002A)"); }
405 }
406 }
407
408 #[cfg(feature = "alloc")]
409 #[test]
410 fn binary() {
411 cpubits::cpubits! {
412 32 => {
413 assert_eq!(
414 format!("{:b}", Limb(42)),
415 "00000000000000000000000000101010"
416 );
417 assert_eq!(
418 format!("{:#b}", Limb(42)),
419 "0b00000000000000000000000000101010"
420 );
421 }
422 64 => {
423 assert_eq!(
424 format!("{:b}", Limb(42)),
425 "0000000000000000000000000000000000000000000000000000000000101010"
426 );
427 assert_eq!(
428 format!("{:#b}", Limb(42)),
429 "0b0000000000000000000000000000000000000000000000000000000000101010"
430 );
431 }
432 }
433 }
434
435 #[cfg(feature = "alloc")]
436 #[test]
437 fn octal() {
438 cpubits::cpubits! {
439 32 => {
440 assert_eq!(format!("{:o}", Limb(42)), "00000000052");
441 assert_eq!(format!("{:#o}", Limb(42)), "0o00000000052");
442 }
443 64 => {
444 assert_eq!(format!("{:o}", Limb(42)), "0000000000000000000052");
445 assert_eq!(format!("{:#o}", Limb(42)), "0o0000000000000000000052");
446 }
447 }
448 }
449
450 #[cfg(feature = "alloc")]
451 #[test]
452 fn lower_hex() {
453 cpubits::cpubits! {
454 32 => {
455 assert_eq!(format!("{:x}", Limb(42)), "0000002a");
456 assert_eq!(format!("{:#x}", Limb(42)), "0x0000002a");
457 }
458 64 => {
459 assert_eq!(format!("{:x}", Limb(42)), "000000000000002a");
460 assert_eq!(format!("{:#x}", Limb(42)), "0x000000000000002a");
461 }
462 }
463 }
464
465 #[cfg(feature = "alloc")]
466 #[test]
467 fn upper_hex() {
468 cpubits::cpubits! {
469 32 => {
470 assert_eq!(format!("{:X}", Limb(42)), "0000002A");
471 assert_eq!(format!("{:#X}", Limb(42)), "0x0000002A");
472 }
473 64 => {
474 assert_eq!(format!("{:X}", Limb(42)), "000000000000002A");
475 assert_eq!(format!("{:#X}", Limb(42)), "0x000000000000002A");
476 }
477 }
478 }
479
480 #[test]
481 fn test_unsigned() {
482 crate::traits::tests::test_unsigned(Limb::ZERO, Limb::MAX);
483 }
484}