crypto_bigint/int/
sign.rs1use crate::{Choice, ConstZero, CtOption, Int, Uint, Word, word};
2
3impl<const LIMBS: usize> Int<LIMBS> {
4 #[inline(always)]
10 const fn most_significant_word(&self) -> Word {
11 if Self::LIMBS == 0 {
12 Word::ZERO
13 } else {
14 self.0.to_words()[LIMBS - 1]
15 }
16 }
17
18 #[inline]
22 #[must_use]
23 pub const fn new_from_abs_sign(abs: Uint<LIMBS>, is_negative: Choice) -> CtOption<Self> {
24 let abs_int = abs.as_int();
25 let abs_msb = abs_int.is_negative();
26 let signed = abs_int.wrapping_neg_if(is_negative);
27
28 let fits = abs_msb.not().or(is_negative.and(signed.is_negative()));
34 CtOption::new(signed, fits)
35 }
36
37 #[inline]
39 pub(crate) const fn new_from_abs_opt_sign(
40 maybe_abs: CtOption<Uint<LIMBS>>,
41 is_negative: Choice,
42 ) -> CtOption<Self> {
43 Self::new_from_abs_sign(maybe_abs.to_inner_unchecked(), is_negative)
44 .filter_by(maybe_abs.is_some())
45 }
46
47 #[inline(always)]
49 #[must_use]
50 pub const fn is_negative(&self) -> Choice {
51 word::choice_from_msb(self.most_significant_word())
52 }
53
54 #[must_use]
56 pub const fn is_positive(&self) -> Choice {
57 self.is_negative().not().and(self.is_nonzero())
58 }
59
60 #[must_use]
62 pub const fn abs_sign(&self) -> (Uint<LIMBS>, Choice) {
63 let sign = self.is_negative();
64 let abs = self.wrapping_neg_if(sign);
66 (abs.0, sign)
67 }
68
69 #[must_use]
71 pub const fn abs(&self) -> Uint<LIMBS> {
72 self.abs_sign().0
73 }
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use crate::{I128, U128};
80
81 #[test]
82 fn new_from_abs_sign() {
83 assert!(
84 I128::new_from_abs_sign(U128::ZERO, Choice::FALSE)
85 .is_some()
86 .to_bool()
87 );
88 assert!(
89 I128::new_from_abs_sign(U128::ZERO, Choice::TRUE)
90 .is_some()
91 .to_bool()
92 );
93 assert!(
94 I128::new_from_abs_sign(I128::MIN.abs(), Choice::FALSE)
95 .is_none()
96 .to_bool()
97 );
98 assert!(
99 I128::new_from_abs_sign(I128::MIN.abs(), Choice::TRUE)
100 .is_some()
101 .to_bool()
102 );
103 assert!(
104 I128::new_from_abs_sign(I128::MAX.abs(), Choice::FALSE)
105 .is_some()
106 .to_bool()
107 );
108 assert!(
109 I128::new_from_abs_sign(I128::MAX.abs(), Choice::TRUE)
110 .is_some()
111 .to_bool()
112 );
113 assert!(
114 I128::new_from_abs_sign(U128::MAX, Choice::TRUE)
115 .is_none()
116 .to_bool()
117 );
118 }
119
120 #[test]
121 fn is_negative() {
122 assert!(I128::MIN.is_negative().to_bool());
123 assert!(I128::MINUS_ONE.is_negative().to_bool());
124 assert!(!I128::ZERO.is_negative().to_bool());
125 assert!(!I128::ONE.is_negative().to_bool());
126 assert!(!I128::MAX.is_negative().to_bool());
127
128 let random_negative = I128::from_be_hex("91113333555577779999BBBBDDDDFFFF");
129 assert!(random_negative.is_negative().to_bool());
130
131 let random_positive = I128::from_be_hex("71113333555577779999BBBBDDDDFFFF");
132 assert!(!random_positive.is_negative().to_bool());
133 }
134
135 #[test]
136 fn is_positive() {
137 assert!(!I128::MIN.is_positive().to_bool());
138 assert!(!I128::MINUS_ONE.is_positive().to_bool());
139 assert!(!I128::ZERO.is_positive().to_bool());
140 assert!(I128::ONE.is_positive().to_bool());
141 assert!(I128::MAX.is_positive().to_bool());
142
143 let random_negative = I128::from_be_hex("deadbeefcafebabedeadbeefcafebabe");
144 assert!(!random_negative.is_positive().to_bool());
145
146 let random_positive = I128::from_be_hex("0badc0dedeadc0decafebabedeadcafe");
147 assert!(random_positive.is_positive().to_bool());
148 }
149}