crypto_bigint/int/
mul_uint.rs1use core::ops::Mul;
2
3use subtle::CtOption;
4
5use crate::{CheckedMul, ConcatMixed, ConstChoice, Int, Uint, Zero};
6
7impl<const LIMBS: usize> Int<LIMBS> {
8 pub const fn split_mul_uint<const RHS_LIMBS: usize>(
15 &self,
16 rhs: &Uint<RHS_LIMBS>,
17 ) -> (Uint<{ LIMBS }>, Uint<{ RHS_LIMBS }>, ConstChoice) {
18 let (lhs_abs, lhs_sgn) = self.abs_sign();
20
21 let (lo, hi) = lhs_abs.split_mul(rhs);
23
24 (lo, hi, lhs_sgn)
26 }
27
28 pub const fn split_mul_uint_right<const RHS_LIMBS: usize>(
35 &self,
36 rhs: &Uint<RHS_LIMBS>,
37 ) -> (Uint<{ RHS_LIMBS }>, Uint<{ LIMBS }>, ConstChoice) {
38 let (lhs_abs, lhs_sgn) = self.abs_sign();
39 let (lo, hi) = rhs.split_mul(&lhs_abs);
40 (lo, hi, lhs_sgn)
41 }
42
43 pub const fn widening_mul_uint<const RHS_LIMBS: usize, const WIDE_LIMBS: usize>(
45 &self,
46 rhs: &Uint<RHS_LIMBS>,
47 ) -> Int<WIDE_LIMBS>
48 where
49 Uint<LIMBS>: ConcatMixed<Uint<RHS_LIMBS>, MixedOutput = Uint<WIDE_LIMBS>>,
50 {
51 let (lhs_abs, lhs_sign) = self.abs_sign();
52 let product_abs = lhs_abs.widening_mul(rhs);
53
54 product_abs.wrapping_neg_if(lhs_sign).as_int()
56 }
57
58 pub fn checked_mul_uint_right<const RHS_LIMBS: usize>(
61 &self,
62 rhs: &Uint<RHS_LIMBS>,
63 ) -> CtOption<Int<RHS_LIMBS>> {
64 let (lo, hi, is_negative) = self.split_mul_uint_right(rhs);
65 let val = Int::<RHS_LIMBS>::new_from_abs_sign(lo, is_negative);
66 CtOption::from(val).and_then(|int| CtOption::new(int, hi.is_zero()))
67 }
68}
69
70impl<const LIMBS: usize, const RHS_LIMBS: usize> CheckedMul<Uint<RHS_LIMBS>> for Int<LIMBS> {
71 #[inline]
72 fn checked_mul(&self, rhs: &Uint<RHS_LIMBS>) -> CtOption<Self> {
73 let (lo, hi, is_negative) = self.split_mul_uint(rhs);
74 let val = Self::new_from_abs_sign(lo, is_negative);
75 CtOption::from(val).and_then(|int| CtOption::new(int, hi.is_zero()))
76 }
77}
78
79impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Uint<RHS_LIMBS>> for Int<LIMBS> {
80 type Output = Int<LIMBS>;
81
82 fn mul(self, rhs: Uint<RHS_LIMBS>) -> Self {
83 self.mul(&rhs)
84 }
85}
86
87impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Uint<RHS_LIMBS>> for Int<LIMBS> {
88 type Output = Int<LIMBS>;
89
90 fn mul(self, rhs: &Uint<RHS_LIMBS>) -> Self {
91 (&self).mul(rhs)
92 }
93}
94
95impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<Uint<RHS_LIMBS>> for &Int<LIMBS> {
96 type Output = Int<LIMBS>;
97
98 fn mul(self, rhs: Uint<RHS_LIMBS>) -> Self::Output {
99 self.mul(&rhs)
100 }
101}
102
103impl<const LIMBS: usize, const RHS_LIMBS: usize> Mul<&Uint<RHS_LIMBS>> for &Int<LIMBS> {
104 type Output = Int<LIMBS>;
105
106 fn mul(self, rhs: &Uint<RHS_LIMBS>) -> Self::Output {
107 self.checked_mul(rhs)
108 .expect("attempted to multiply with overflow")
109 }
110}
111
112#[cfg(test)]
113mod tests {
114 use crate::{CheckedMul, I128, I256, U128, U256};
115
116 #[test]
117 fn test_checked_mul_uint() {
118 let result = I128::MIN.checked_mul(&U128::ZERO);
121 assert_eq!(result.unwrap(), I128::ZERO);
122
123 let result = I128::MIN.checked_mul(&U128::ONE);
124 assert_eq!(result.unwrap(), I128::MIN);
125
126 let result = I128::MIN.checked_mul(&U128::MAX);
127 assert!(bool::from(result.is_none()));
128
129 let result = I128::MINUS_ONE.checked_mul(&U128::ZERO);
132 assert_eq!(result.unwrap(), I128::ZERO);
133
134 let result = I128::MINUS_ONE.checked_mul(&U128::ONE);
135 assert_eq!(result.unwrap(), I128::MINUS_ONE);
136
137 let result = I128::MINUS_ONE.checked_mul(&U128::MAX);
138 assert!(bool::from(result.is_none()));
139
140 let result = I128::ZERO.checked_mul(&U128::ZERO);
143 assert_eq!(result.unwrap(), I128::ZERO);
144
145 let result = I128::ZERO.checked_mul(&U128::ONE);
146 assert_eq!(result.unwrap(), I128::ZERO);
147
148 let result = I128::ZERO.checked_mul(&U128::MAX);
149 assert_eq!(result.unwrap(), I128::ZERO);
150
151 let result = I128::ONE.checked_mul(&U128::ZERO);
154 assert_eq!(result.unwrap(), I128::ZERO);
155
156 let result = I128::ONE.checked_mul(&U128::ONE);
157 assert_eq!(result.unwrap(), I128::ONE);
158
159 let result = I128::ONE.checked_mul(&U128::MAX);
160 assert!(bool::from(result.is_none()));
161
162 let result = I128::MAX.checked_mul(&U128::ZERO);
165 assert_eq!(result.unwrap(), I128::ZERO);
166
167 let result = I128::MAX.checked_mul(&U128::ONE);
168 assert_eq!(result.unwrap(), I128::MAX);
169
170 let result = I128::MAX.checked_mul(&U128::MAX);
171 assert!(bool::from(result.is_none()));
172 }
173
174 #[test]
175 fn test_checked_mul_uint_right() {
176 let result = I256::MIN.checked_mul_uint_right(&U128::ZERO);
178 assert!(bool::from(result.is_some()));
179 assert_eq!(result.unwrap(), I128::ZERO);
180
181 let result = I128::MIN.checked_mul_uint_right(&U256::ZERO);
182 assert!(bool::from(result.is_some()));
183 assert_eq!(result.unwrap(), I256::ZERO);
184
185 let result = I256::MIN.checked_mul_uint_right(&U128::ONE);
187 assert!(bool::from(result.is_none()));
188
189 let result = I128::MIN.checked_mul_uint_right(&U256::ONE);
190 assert!(bool::from(result.is_some()));
191 assert_eq!(result.unwrap(), I128::MIN.resize());
192
193 let result = I256::ONE.checked_mul_uint_right(&I128::MAX.as_uint());
195 assert!(bool::from(result.is_some()));
196 assert_eq!(result.unwrap(), I128::MAX.resize());
197
198 let result = I128::ONE.checked_mul_uint_right(&I256::MAX.as_uint());
199 assert!(bool::from(result.is_some()));
200 assert_eq!(result.unwrap(), I256::MAX);
201
202 let result = I256::ONE.checked_mul_uint_right(&U128::MAX);
204 assert!(bool::from(result.is_none()));
205
206 let result = I128::MIN.checked_mul_uint_right(&U256::MAX);
207 assert!(bool::from(result.is_none()));
208 }
209
210 #[test]
211 fn test_widening_mul_uint() {
212 assert_eq!(I128::MIN.widening_mul_uint(&U128::ZERO), I256::ZERO);
213 assert_eq!(
214 I128::MIN.widening_mul_uint(&U128::ONE),
215 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF80000000000000000000000000000000")
216 );
217 assert_eq!(
218 I128::MIN.widening_mul_uint(&U128::MAX),
219 I256::from_be_hex("8000000000000000000000000000000080000000000000000000000000000000")
220 );
221
222 assert_eq!(I128::MINUS_ONE.widening_mul_uint(&U128::ZERO), I256::ZERO);
223 assert_eq!(
224 I128::MINUS_ONE.widening_mul_uint(&U128::ONE),
225 I256::MINUS_ONE
226 );
227 assert_eq!(
228 I128::MINUS_ONE.widening_mul_uint(&U128::MAX),
229 I256::from_be_hex("FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00000000000000000000000000000001")
230 );
231
232 assert_eq!(I128::ZERO.widening_mul_uint(&U128::ZERO), I256::ZERO);
233 assert_eq!(I128::ZERO.widening_mul_uint(&U128::ONE), I256::ZERO);
234 assert_eq!(I128::ZERO.widening_mul_uint(&U128::MAX), I256::ZERO);
235
236 assert_eq!(I128::ONE.widening_mul_uint(&U128::ZERO), I256::ZERO);
237 assert_eq!(I128::ONE.widening_mul_uint(&U128::ONE), I256::ONE);
238 assert_eq!(
239 I128::ONE.widening_mul_uint(&U128::MAX),
240 I256::from_be_hex("00000000000000000000000000000000FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
241 );
242
243 assert_eq!(I128::MAX.widening_mul_uint(&U128::ZERO), I256::ZERO);
244 assert_eq!(
245 I128::MAX.widening_mul_uint(&U128::ONE),
246 I256::from_be_hex("000000000000000000000000000000007FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF")
247 );
248 assert_eq!(
249 I128::MAX.widening_mul_uint(&U128::MAX),
250 I256::from_be_hex("7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFE80000000000000000000000000000001")
251 );
252 }
253}