1use crate::{helper_macros, ibig::IBig, ubig::UBig};
4use core::ops::{Mul, MulAssign};
5
6helper_macros::forward_ubig_binop_to_repr!(impl Mul, mul);
7helper_macros::impl_binop_assign_by_taking!(impl MulAssign<UBig> for UBig, mul_assign, mul);
8
9macro_rules! impl_ibig_mul {
10 ($sign0:ident, $mag0:ident, $sign1:ident, $mag1:ident) => {
11 IBig($mag0.mul($mag1).with_sign($sign0 * $sign1))
12 };
13}
14helper_macros::forward_ibig_binop_to_repr!(impl Mul, mul, Output = IBig, impl_ibig_mul);
15helper_macros::impl_binop_assign_by_taking!(impl MulAssign<IBig> for IBig, mul_assign, mul);
16
17macro_rules! impl_ubig_ibig_mul {
18 ($mag0:ident, $sign1:ident, $mag1:ident) => {
19 IBig($mag0.mul($mag1).with_sign($sign1))
20 };
21}
22helper_macros::forward_ubig_ibig_binop_to_repr!(impl Mul, mul, Output = IBig, impl_ubig_ibig_mul);
23
24macro_rules! impl_ibig_ubig_mul {
25 ($sign0:ident, $mag0:ident, $mag1:ident) => {
26 IBig($mag0.mul($mag1).with_sign($sign0))
27 };
28}
29helper_macros::forward_ibig_ubig_binop_to_repr!(impl Mul, mul, Output = IBig, impl_ibig_ubig_mul);
30helper_macros::impl_binop_assign_by_taking!(impl MulAssign<UBig> for IBig, mul_assign, mul);
31
32macro_rules! impl_div_primitive_with_ubig {
35 ($($t:ty)*) => {$(
36 helper_macros::impl_commutative_binop_with_primitive!(impl Mul<$t> for UBig, mul);
37 helper_macros::impl_binop_assign_with_primitive!(impl MulAssign<$t> for UBig, mul_assign);
38 )*};
39}
40impl_div_primitive_with_ubig!(u8 u16 u32 u64 u128 usize);
41
42macro_rules! impl_div_primitive_with_ibig {
43 ($($t:ty)*) => {$(
44 helper_macros::impl_commutative_binop_with_primitive!(impl Mul<$t> for IBig, mul);
45 helper_macros::impl_binop_assign_with_primitive!(impl MulAssign<$t> for IBig, mul_assign);
46 )*};
47}
48impl_div_primitive_with_ibig!(u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize);
49
50impl UBig {
51 #[inline]
60 pub fn sqr(&self) -> UBig {
61 UBig(self.repr().sqr())
62 }
63
64 #[inline]
73 pub fn cubic(&self) -> UBig {
74 self * self.sqr()
75 }
76}
77
78impl IBig {
79 #[inline]
88 pub fn sqr(&self) -> UBig {
89 UBig(self.as_sign_repr().1.sqr())
90 }
91
92 #[inline]
101 pub fn cubic(&self) -> IBig {
102 self * self.sqr()
103 }
104}
105
106pub(crate) mod repr {
107 use super::*;
108 use crate::{
109 arch::word::{DoubleWord, Word},
110 buffer::Buffer,
111 cmp::cmp_in_place,
112 math,
113 memory::MemoryAllocation,
114 mul,
115 primitive::{extend_word, shrink_dword, split_dword},
116 repr::{
117 Repr,
118 TypedRepr::{self, *},
119 TypedReprRef::{self, *},
120 },
121 shift, sqr,
122 };
123
124 impl Mul<TypedRepr> for TypedRepr {
125 type Output = Repr;
126
127 #[inline]
128 fn mul(self, rhs: TypedRepr) -> Repr {
129 match (self, rhs) {
130 (Small(dword0), Small(dword1)) => mul_dword(dword0, dword1),
131 (Small(dword0), Large(buffer1)) => mul_large_dword(buffer1, dword0),
132 (Large(buffer0), Small(dword1)) => mul_large_dword(buffer0, dword1),
133 (Large(buffer0), Large(buffer1)) => mul_large(&buffer0, &buffer1),
134 }
135 }
136 }
137
138 impl<'l> Mul<TypedRepr> for TypedReprRef<'l> {
139 type Output = Repr;
140
141 #[inline]
142 fn mul(self, rhs: TypedRepr) -> Repr {
143 match (self, rhs) {
144 (RefSmall(dword0), Small(dword1)) => mul_dword(dword0, dword1),
145 (RefSmall(dword0), Large(buffer1)) => mul_large_dword(buffer1, dword0),
146 (RefLarge(buffer0), Small(dword1)) => mul_large_dword(buffer0.into(), dword1),
147 (RefLarge(buffer0), Large(buffer1)) => mul_large(buffer0, &buffer1),
148 }
149 }
150 }
151
152 impl<'r> Mul<TypedReprRef<'r>> for TypedRepr {
153 type Output = Repr;
154
155 #[inline]
156 fn mul(self, rhs: TypedReprRef) -> Self::Output {
157 rhs.mul(self)
159 }
160 }
161
162 impl<'l, 'r> Mul<TypedReprRef<'r>> for TypedReprRef<'l> {
163 type Output = Repr;
164
165 #[inline]
166 fn mul(self, rhs: TypedReprRef) -> Repr {
167 match (self, rhs) {
168 (RefSmall(dword0), RefSmall(dword1)) => mul_dword(dword0, dword1),
169 (RefSmall(dword0), RefLarge(buffer1)) => mul_large_dword(buffer1.into(), dword0),
170 (RefLarge(buffer0), RefSmall(dword1)) => mul_large_dword(buffer0.into(), dword1),
171 (RefLarge(buffer0), RefLarge(buffer1)) => mul_large(buffer0, buffer1),
172 }
173 }
174 }
175
176 #[inline]
178 fn mul_dword(a: DoubleWord, b: DoubleWord) -> Repr {
179 if a <= Word::MAX as DoubleWord && b <= Word::MAX as DoubleWord {
180 Repr::from_dword(a * b)
181 } else {
182 mul_dword_spilled(a, b)
183 }
184 }
185
186 fn mul_dword_spilled(lhs: DoubleWord, rhs: DoubleWord) -> Repr {
187 let (lo, hi) = math::mul_add_carry_dword(lhs, rhs, 0);
188 let mut buffer = Buffer::allocate(4);
189 let (n0, n1) = split_dword(lo);
190 buffer.push(n0);
191 buffer.push(n1);
192 let (n2, n3) = split_dword(hi);
193 buffer.push(n2);
194 buffer.push(n3);
195 Repr::from_buffer(buffer)
196 }
197
198 pub(crate) fn mul_large_dword(mut buffer: Buffer, rhs: DoubleWord) -> Repr {
200 match rhs {
201 0 => Repr::zero(),
202 1 => Repr::from_buffer(buffer),
203 dw => {
204 if let Some(word) = shrink_dword(dw) {
205 let carry = if dw.is_power_of_two() {
206 shift::shl_in_place(&mut buffer, dw.trailing_zeros())
207 } else {
208 mul::mul_word_in_place(&mut buffer, word)
209 };
210 buffer.push_resizing(carry);
211 Repr::from_buffer(buffer)
212 } else {
213 let carry = mul::mul_dword_in_place(&mut buffer, dw);
214 if carry != 0 {
215 let (lo, hi) = split_dword(carry);
216 buffer.ensure_capacity(buffer.len() + 2);
217 buffer.push(lo);
218 buffer.push(hi);
219 }
220 Repr::from_buffer(buffer)
221 }
222 }
223 }
224 }
225
226 pub(crate) fn mul_large(lhs: &[Word], rhs: &[Word]) -> Repr {
228 debug_assert!(lhs.len() >= 2 && rhs.len() >= 2);
229
230 if cmp_in_place(lhs, rhs).is_eq() {
232 return square_large(lhs);
233 }
234
235 let res_len = lhs.len() + rhs.len();
236 let mut buffer = Buffer::allocate(res_len);
237 buffer.push_zeros(res_len);
238
239 let mut allocation =
240 MemoryAllocation::new(mul::memory_requirement_exact(res_len, lhs.len().min(rhs.len())));
241 mul::multiply(&mut buffer, lhs, rhs, &mut allocation.memory());
242 Repr::from_buffer(buffer)
243 }
244
245 impl TypedReprRef<'_> {
246 pub fn sqr(&self) -> Repr {
247 match self {
248 TypedReprRef::RefSmall(dword) => {
249 if let Some(word) = shrink_dword(*dword) {
250 Repr::from_dword(extend_word(word) * extend_word(word))
251 } else {
252 square_dword_spilled(*dword)
253 }
254 }
255 TypedReprRef::RefLarge(words) => square_large(words),
256 }
257 }
258 }
259
260 fn square_dword_spilled(dw: DoubleWord) -> Repr {
261 let (lo, hi) = math::mul_add_carry_dword(dw, dw, 0);
262 let mut buffer = Buffer::allocate(4);
263 let (n0, n1) = split_dword(lo);
264 buffer.push(n0);
265 buffer.push(n1);
266 let (n2, n3) = split_dword(hi);
267 buffer.push(n2);
268 buffer.push(n3);
269 Repr::from_buffer(buffer)
270 }
271
272 pub(crate) fn square_large(words: &[Word]) -> Repr {
273 debug_assert!(words.len() >= 2);
274
275 let mut buffer = Buffer::allocate(words.len() * 2);
276 buffer.push_zeros(words.len() * 2);
277
278 let mut allocation = MemoryAllocation::new(sqr::memory_requirement_exact(words.len()));
279 sqr::sqr(&mut buffer, words, &mut allocation.memory());
280 Repr::from_buffer(buffer)
281 }
282}