zinc_utils/
mul_by_scalar.rs1use crate::from_ref::FromRef;
2use crypto_primitives::{
3 Wrapper,
4 boolean::Boolean,
5 crypto_bigint_int::Int,
6 crypto_bigint_uint::{U64, U128},
7};
8use num_traits::{CheckedMul, ConstZero};
9
10pub trait MulByScalar<Rhs, Out = Self>: Sized {
16 fn mul_by_scalar<const CHECK: bool>(self, rhs: &Rhs) -> Option<Out>;
20}
21
22macro_rules! impl_mul_by_scalar_for_primitives {
23 ($($t:ty),*) => {
24 $(
25 impl MulByScalar<$t> for $t {
26 #[allow(clippy::arithmetic_side_effects)] fn mul_by_scalar<const CHECK: bool>(self, rhs: &$t) -> Option<$t> {
28 if CHECK {
29 self.checked_mul(*rhs)
30 } else {
31 Some(self * *rhs)
32 }
33 }
34 }
35 )*
36 };
37}
38
39impl_mul_by_scalar_for_primitives!(i8, i16, i32, i64, i128);
40
41impl<const LIMBS: usize, const LIMBS2: usize> MulByScalar<Int<LIMBS2>> for Int<LIMBS> {
42 #[allow(clippy::arithmetic_side_effects)] fn mul_by_scalar<const CHECK: bool>(self, rhs: &Int<LIMBS2>) -> Option<Int<LIMBS>> {
44 if LIMBS < LIMBS2 {
45 return None; }
47 if CHECK {
48 self.checked_mul(&rhs.resize())
49 } else {
50 Some(widening_wrapping_mul(self, rhs))
52 }
53 }
54}
55
56macro_rules! impl_mul_int_by_primitive_scalar {
57 ($(($t:ty, $rhs_limbs:expr)),*) => {
58 $(
59 impl<const LIMBS: usize, const LIMBS2: usize> MulByScalar<$t, Int<LIMBS2>> for Int<LIMBS> {
60 #[allow(clippy::arithmetic_side_effects)] fn mul_by_scalar<const CHECK: bool>(self, rhs: &$t) -> Option<Int<LIMBS2>> {
62 const {
63 assert!(LIMBS <= LIMBS2, "Cannot multiply if the left operand has more limbs than the output");
64 }
65 if CHECK {
66 let rhs: Int<LIMBS2> = Int::from_ref(rhs);
67 rhs.checked_mul(&self.resize())
68 } else {
69 let rhs_short: Int<{ $rhs_limbs }> = Int::from(*rhs);
70 Some(widening_wrapping_mul(self.resize::<LIMBS2>(), &rhs_short))
71 }
72 }
73 }
74 )*
75 };
76}
77
78impl_mul_int_by_primitive_scalar!(
79 (i8, U64::LIMBS),
80 (i16, U64::LIMBS),
81 (i32, U64::LIMBS),
82 (i64, U64::LIMBS),
83 (i128, U128::LIMBS)
84);
85
86impl<T> MulByScalar<Boolean> for T
88where
89 T: Clone + ConstZero + From<Boolean>,
90{
91 fn mul_by_scalar<const CHECK: bool>(self, rhs: &Boolean) -> Option<T> {
92 Some(if *rhs.inner() { self } else { T::ZERO })
93 }
94}
95
96impl MulByScalar<i64, i128> for i32 {
97 #[inline(always)]
98 #[allow(clippy::arithmetic_side_effects)] fn mul_by_scalar<const CHECK: bool>(self, rhs: &i64) -> Option<i128> {
100 Some(i128::from(self) * i128::from(*rhs))
101 }
102}
103
104impl MulByScalar<i64, i128> for i128 {
105 #[inline(always)]
106 #[allow(clippy::arithmetic_side_effects)] fn mul_by_scalar<const CHECK: bool>(self, rhs: &i64) -> Option<i128> {
108 let rhs = i128::from(*rhs);
109 if CHECK {
110 self.checked_mul(rhs)
111 } else {
112 Some(self * rhs)
113 }
114 }
115}
116
117impl MulByScalar<i64, i128> for i64 {
118 #[inline(always)]
119 #[allow(clippy::arithmetic_side_effects)] fn mul_by_scalar<const CHECK: bool>(self, rhs: &i64) -> Option<i128> {
121 Some(i128::from(self) * i128::from(*rhs))
122 }
123}
124
125fn widening_wrapping_mul<const LIMBS: usize, const LIMBS2: usize>(
129 lhs: Int<LIMBS>,
130 rhs: &Int<LIMBS2>,
131) -> Int<LIMBS> {
132 Int::new(lhs.into_inner().wrapping_mul(rhs.inner()))
133}