1use crate::{
4 Bounded, Choice, ConstOne, CtAssign, CtEq, CtOption, CtSelect, Int, Integer, Limb, Mul,
5 NonZero, One, Uint, UintRef,
6};
7use core::{cmp::Ordering, fmt, ops::Deref, ptr};
8use ctutils::{CtAssignSlice, CtEqSlice};
9
10#[cfg(feature = "alloc")]
11use crate::{BoxedUint, Resize};
12
13#[cfg(feature = "rand_core")]
14use crate::{Random, rand_core::TryRng};
15
16#[cfg(all(feature = "alloc", feature = "rand_core"))]
17use crate::RandomBits;
18
19#[cfg(feature = "serde")]
20use crate::Zero;
21#[cfg(feature = "serde")]
22use serdect::serde::{
23 Deserialize, Deserializer, Serialize, Serializer,
24 de::{Error, Unexpected},
25};
26
27pub type OddUint<const LIMBS: usize> = Odd<Uint<LIMBS>>;
29
30pub type OddUintRef = Odd<UintRef>;
32
33pub type OddInt<const LIMBS: usize> = Odd<Int<LIMBS>>;
35
36#[cfg(feature = "alloc")]
38pub type OddBoxedUint = Odd<BoxedUint>;
39
40#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
44#[repr(transparent)]
45pub struct Odd<T: ?Sized>(T);
46
47impl<T> Odd<T> {
48 #[inline]
50 pub fn new(mut n: T) -> CtOption<Self>
51 where
52 T: Integer,
53 {
54 let is_odd = n.is_odd();
55
56 n.ct_assign(&T::one_like(&n), !is_odd);
60 CtOption::new(Self(n), is_odd)
61 }
62
63 #[inline]
72 #[must_use]
73 pub(crate) const fn new_unchecked(n: T) -> Odd<T> {
74 Self(n)
75 }
76
77 #[inline]
79 pub fn get(self) -> T {
80 self.0
81 }
82
83 #[inline]
88 pub const fn get_copy(self) -> T
89 where
90 T: Copy,
91 {
92 self.0
93 }
94
95 pub fn into_nz(self) -> NonZero<T> {
98 NonZero::new_unchecked(self.0)
99 }
100}
101
102impl<T: ?Sized> Odd<T> {
103 #[inline]
105 pub const fn as_ref(&self) -> &T {
106 &self.0
107 }
108
109 #[inline]
112 pub const fn as_nz_ref(&self) -> &NonZero<T> {
113 NonZero::new_ref_unchecked(&self.0)
115 }
116
117 #[inline]
126 #[must_use]
127 #[allow(unsafe_code)]
128 pub(crate) const fn new_ref_unchecked(refval: &T) -> &Odd<T> {
129 unsafe { &*(ptr::from_ref(refval) as *const Odd<T>) }
131 }
132}
133
134impl<T> Odd<T>
135where
136 T: Bounded + ?Sized,
137{
138 pub const BITS: u32 = T::BITS;
140
141 pub const BYTES: usize = T::BYTES;
143}
144
145impl<const LIMBS: usize> OddUint<LIMBS> {
146 #[must_use]
152 #[track_caller]
153 pub const fn from_be_hex(hex: &str) -> Self {
154 let uint = Uint::<LIMBS>::from_be_hex(hex);
155 assert!(uint.is_odd().to_bool_vartime(), "number must be odd");
156 Odd(uint)
157 }
158
159 #[must_use]
165 #[track_caller]
166 pub const fn from_le_hex(hex: &str) -> Self {
167 let uint = Uint::<LIMBS>::from_le_hex(hex);
168 assert!(uint.is_odd().to_bool_vartime(), "number must be odd");
169 Odd(uint)
170 }
171
172 #[inline]
174 #[must_use]
175 pub const fn as_uint_ref(&self) -> &OddUintRef {
176 Odd::new_ref_unchecked(self.0.as_uint_ref())
177 }
178
179 #[must_use]
183 pub const fn resize<const T: usize>(&self) -> Odd<Uint<T>> {
184 Odd(self.0.resize())
185 }
186}
187
188impl<const LIMBS: usize> AsRef<OddUintRef> for OddUint<LIMBS> {
189 fn as_ref(&self) -> &OddUintRef {
190 self.as_uint_ref()
191 }
192}
193
194impl<const LIMBS: usize> Odd<Int<LIMBS>> {
195 #[must_use]
197 pub const fn abs_sign(&self) -> (Odd<Uint<LIMBS>>, Choice) {
198 let (abs, sgn) = Int::abs_sign(self.as_ref());
200 (Odd(abs), sgn)
201 }
202
203 #[must_use]
205 pub const fn abs(&self) -> Odd<Uint<LIMBS>> {
206 self.abs_sign().0
207 }
208}
209
210impl<T: ?Sized> AsRef<T> for Odd<T> {
211 fn as_ref(&self) -> &T {
212 &self.0
213 }
214}
215
216impl<T> AsRef<[Limb]> for Odd<T>
217where
218 T: AsRef<[Limb]>,
219{
220 fn as_ref(&self) -> &[Limb] {
221 self.0.as_ref()
222 }
223}
224
225impl<T: ?Sized> AsRef<NonZero<T>> for Odd<T> {
226 fn as_ref(&self) -> &NonZero<T> {
227 self.as_nz_ref()
228 }
229}
230
231impl<T> CtAssign for Odd<T>
232where
233 T: CtAssign,
234{
235 #[inline]
236 fn ct_assign(&mut self, other: &Self, choice: Choice) {
237 self.0.ct_assign(&other.0, choice);
238 }
239}
240impl<T> CtAssignSlice for Odd<T> where T: CtAssignSlice {}
241
242impl<T> CtEq for Odd<T>
243where
244 T: CtEq + ?Sized,
245{
246 #[inline]
247 fn ct_eq(&self, other: &Self) -> Choice {
248 CtEq::ct_eq(&self.0, &other.0)
249 }
250}
251impl<T> CtEqSlice for Odd<T> where T: CtEq {}
252
253impl<T> CtSelect for Odd<T>
254where
255 T: CtSelect,
256{
257 #[inline]
258 fn ct_select(&self, other: &Self, choice: Choice) -> Self {
259 Self(self.0.ct_select(&other.0, choice))
260 }
261}
262
263impl<T> Default for Odd<T>
264where
265 T: One,
266{
267 #[inline]
268 fn default() -> Self {
269 Odd(T::one())
270 }
271}
272
273impl<T: ?Sized> Deref for Odd<T> {
274 type Target = T;
275
276 fn deref(&self) -> &T {
277 &self.0
278 }
279}
280
281impl<T> ConstOne for Odd<T>
282where
283 T: ConstOne + One,
284{
285 const ONE: Self = Self(T::ONE);
286}
287
288impl<T> One for Odd<T>
289where
290 T: One,
291{
292 #[inline]
293 fn one() -> Self {
294 Self(T::one())
295 }
296}
297
298impl<T> num_traits::One for Odd<T>
299where
300 T: One + Mul<T, Output = T>,
301{
302 #[inline]
303 fn one() -> Self {
304 Self(T::one())
305 }
306
307 fn is_one(&self) -> bool {
308 self.0.is_one().into()
309 }
310}
311
312impl<T> Mul<Self> for Odd<T>
314where
315 T: Mul<T, Output = T>,
316{
317 type Output = Self;
318
319 fn mul(self, rhs: Self) -> Self {
320 Self(self.0 * rhs.0)
321 }
322}
323
324impl<const LIMBS: usize> PartialEq<Odd<Uint<LIMBS>>> for Uint<LIMBS> {
325 fn eq(&self, other: &Odd<Uint<LIMBS>>) -> bool {
326 self.eq(&other.0)
327 }
328}
329
330impl<const LIMBS: usize> PartialOrd<Odd<Uint<LIMBS>>> for Uint<LIMBS> {
331 fn partial_cmp(&self, other: &Odd<Uint<LIMBS>>) -> Option<Ordering> {
332 Some(self.cmp(&other.0))
333 }
334}
335
336impl OddUintRef {
337 #[must_use]
341 pub const fn to_uint_resize<const T: usize>(&self) -> Odd<Uint<T>> {
342 Odd(self.0.to_uint_resize())
343 }
344}
345
346#[cfg(feature = "alloc")]
347impl OddBoxedUint {
348 #[inline]
350 #[must_use]
351 pub const fn as_uint_ref(&self) -> &OddUintRef {
352 Odd::new_ref_unchecked(self.0.as_uint_ref())
353 }
354
355 #[cfg(feature = "rand_core")]
357 pub fn random<R: TryRng + ?Sized>(rng: &mut R, bit_length: u32) -> Self {
358 let mut ret = BoxedUint::random_bits(rng, bit_length);
359 ret.limbs[0] |= Limb::ONE;
360 Odd(ret)
361 }
362}
363
364#[cfg(feature = "alloc")]
365impl AsRef<OddUintRef> for OddBoxedUint {
366 fn as_ref(&self) -> &OddUintRef {
367 self.as_uint_ref()
368 }
369}
370
371#[cfg(feature = "alloc")]
372impl PartialEq<OddBoxedUint> for BoxedUint {
373 fn eq(&self, other: &OddBoxedUint) -> bool {
374 self.eq(&other.0)
375 }
376}
377
378#[cfg(feature = "alloc")]
379impl PartialOrd<OddBoxedUint> for BoxedUint {
380 fn partial_cmp(&self, other: &OddBoxedUint) -> Option<Ordering> {
381 Some(self.cmp(&other.0))
382 }
383}
384
385#[cfg(feature = "alloc")]
386impl Resize for OddBoxedUint {
387 type Output = Self;
388
389 fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output {
390 Odd(self.0.resize_unchecked(at_least_bits_precision))
391 }
392
393 fn try_resize(self, at_least_bits_precision: u32) -> Option<Self::Output> {
394 self.0.try_resize(at_least_bits_precision).map(Odd)
395 }
396}
397
398#[cfg(feature = "alloc")]
399impl Resize for &OddBoxedUint {
400 type Output = OddBoxedUint;
401
402 fn resize_unchecked(self, at_least_bits_precision: u32) -> Self::Output {
403 Odd((&self.0).resize_unchecked(at_least_bits_precision))
404 }
405
406 fn try_resize(self, at_least_bits_precision: u32) -> Option<Self::Output> {
407 (&self.0).try_resize(at_least_bits_precision).map(Odd)
408 }
409}
410
411#[cfg(feature = "rand_core")]
412impl<const LIMBS: usize> Random for Odd<Uint<LIMBS>> {
413 fn try_random_from_rng<R: TryRng + ?Sized>(rng: &mut R) -> Result<Self, R::Error> {
415 let mut ret = Uint::try_random_from_rng(rng)?;
416 ret.limbs[0] |= Limb::ONE;
417 Ok(Odd(ret))
418 }
419}
420
421impl<T> fmt::Display for Odd<T>
422where
423 T: fmt::Display + ?Sized,
424{
425 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
426 fmt::Display::fmt(&self.0, f)
427 }
428}
429
430impl<T> fmt::Binary for Odd<T>
431where
432 T: fmt::Binary + ?Sized,
433{
434 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
435 fmt::Binary::fmt(&self.0, f)
436 }
437}
438
439impl<T> fmt::Octal for Odd<T>
440where
441 T: fmt::Octal + ?Sized,
442{
443 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
444 fmt::Octal::fmt(&self.0, f)
445 }
446}
447
448impl<T> fmt::LowerHex for Odd<T>
449where
450 T: fmt::LowerHex + ?Sized,
451{
452 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453 fmt::LowerHex::fmt(&self.0, f)
454 }
455}
456
457impl<T> fmt::UpperHex for Odd<T>
458where
459 T: fmt::UpperHex + ?Sized,
460{
461 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
462 fmt::UpperHex::fmt(&self.0, f)
463 }
464}
465
466#[cfg(feature = "serde")]
467impl<'de, T: Deserialize<'de> + Integer + Zero> Deserialize<'de> for Odd<T> {
468 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
469 where
470 D: Deserializer<'de>,
471 {
472 let value: T = T::deserialize(deserializer)?;
473 Option::<Self>::from(Self::new(value)).ok_or(D::Error::invalid_value(
474 Unexpected::Other("even"),
475 &"a non-zero odd value",
476 ))
477 }
478}
479
480#[cfg(feature = "serde")]
481impl<T: Serialize + Zero> Serialize for Odd<T> {
482 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
483 where
484 S: Serializer,
485 {
486 self.0.serialize(serializer)
487 }
488}
489
490#[cfg(feature = "subtle")]
491impl<T> subtle::ConditionallySelectable for Odd<T>
492where
493 T: Copy,
494 Self: CtSelect,
495{
496 fn conditional_select(a: &Self, b: &Self, choice: subtle::Choice) -> Self {
497 a.ct_select(b, choice.into())
498 }
499}
500
501#[cfg(feature = "subtle")]
502impl<T> subtle::ConstantTimeEq for Odd<T>
503where
504 T: ?Sized,
505 Self: CtEq,
506{
507 fn ct_eq(&self, other: &Self) -> subtle::Choice {
508 CtEq::ct_eq(self, other).into()
509 }
510}
511
512#[cfg(feature = "zeroize")]
513impl<T: zeroize::Zeroize + One> zeroize::Zeroize for Odd<T> {
514 fn zeroize(&mut self) {
515 self.0.zeroize();
516 self.0 = T::one_like(&self.0);
517 }
518}
519
520#[cfg(test)]
521mod tests {
522 use super::Odd;
523 use crate::{ConstOne, U128, Uint};
524
525 #[cfg(feature = "alloc")]
526 use crate::BoxedUint;
527
528 #[cfg(feature = "zeroize")]
529 use zeroize::Zeroize;
530
531 #[test]
532 fn default() {
533 assert!(Odd::<U128>::default().is_odd().to_bool());
534 }
535
536 #[test]
537 fn from_be_hex_when_odd() {
538 assert_eq!(
539 Odd::<U128>::from_be_hex("00000000000000000000000000000001"),
540 Odd::<U128>::ONE
541 );
542 }
543
544 #[test]
545 #[should_panic]
546 fn from_be_hex_when_even() {
547 let _ = Odd::<U128>::from_be_hex("00000000000000000000000000000002");
548 }
549
550 #[test]
551 fn from_le_hex_when_odd() {
552 assert_eq!(
553 Odd::<U128>::from_le_hex("01000000000000000000000000000000"),
554 Odd::<U128>::ONE
555 );
556 }
557
558 #[test]
559 #[should_panic]
560 fn from_le_hex_when_even() {
561 let _ = Odd::<U128>::from_le_hex("20000000000000000000000000000000");
562 }
563
564 #[test]
565 fn not_odd_numbers() {
566 let zero = Odd::new(Uint::<4>::ZERO);
567 assert!(bool::from(zero.is_none()));
568 let two = Odd::new(Uint::<4>::from(2u8));
569 assert!(bool::from(two.is_none()));
570 }
571
572 #[cfg(feature = "alloc")]
573 #[test]
574 fn not_odd_numbers_boxed() {
575 let zero = Odd::new(BoxedUint::zero());
576 assert!(bool::from(zero.is_none()));
577 let two = Odd::new(BoxedUint::from(2u8));
578 assert!(bool::from(two.is_none()));
579 }
580 #[cfg(feature = "zeroize")]
581 #[test]
582 fn zeroize_preserves_invariant() {
583 let mut value = Odd::new(U128::from(0x1235u64)).unwrap();
584
585 value.zeroize();
586
587 assert_eq!(*value.as_ref(), U128::ONE);
588 }
589
590 #[cfg(all(feature = "alloc", feature = "zeroize"))]
591 #[test]
592 fn boxed_zeroize_preserves_invariant_and_precision() {
593 let mut value = Odd::new(BoxedUint::from_be_slice(&[0x12, 0x35], 128).unwrap()).unwrap();
594
595 value.zeroize();
596
597 assert_eq!(value.as_ref(), &BoxedUint::one_with_precision(128));
598 assert_eq!(value.bits_precision(), 128);
599 }
600}