dashu_int/monty/
convert.rs1use crate::{
4 arch::word::{DoubleWord, Word},
5 buffer::Buffer,
6 ibig::IBig,
7 memory::MemoryAllocation,
8 primitive::shrink_dword,
9 repr::{Repr, TypedReprRef},
10 ubig::UBig,
11 Sign,
12};
13use dashu_base::UnsignedAbs;
14use num_modular::Reducer;
15
16use super::mul::{mul_memory_requirement, mul_normalized_large, residue_normalized_large};
17use super::repr::{
18 to_exact_words, Montgomery, MontgomeryInner, MontgomeryLargeVal, MontgomeryRepr,
19 MontgomeryReprData,
20};
21
22impl Montgomery<'_> {
23 #[inline]
34 pub fn residue(&self) -> UBig {
35 match self.repr() {
36 MontgomeryInner::Single(raw, ring) => UBig::from_word(ring.0.residue(*raw)),
37 MontgomeryInner::Double(raw, ring) => UBig::from_dword(ring.0.residue(*raw)),
38 MontgomeryInner::Large(raw, ring) => {
39 let memory_requirement = mul_memory_requirement(ring);
40 let mut allocation = MemoryAllocation::new(memory_requirement);
41 let mut memory = allocation.memory();
42 let res = residue_normalized_large(ring, &raw.0, &mut memory);
43 UBig(Repr::from_buffer(Buffer::from(res)))
44 }
45 }
46 }
47
48 pub fn modulus(&self) -> UBig {
50 match self.repr() {
51 MontgomeryInner::Single(_, ring) => UBig::from_word(ring.0.modulus()),
52 MontgomeryInner::Double(_, ring) => UBig::from_dword(ring.0.modulus()),
53 MontgomeryInner::Large(_, ring) => {
54 UBig(Repr::from_buffer(Buffer::from(&ring.modulus[..])))
55 }
56 }
57 }
58}
59
60pub trait IntoMontgomeryRing<'a, Ring> {
62 type RingElement: 'a;
64 fn into_monty(self, ring: &'a Ring) -> Self::RingElement;
66}
67
68impl<'a> IntoMontgomeryRing<'a, MontgomeryRepr> for UBig {
69 type RingElement = Montgomery<'a>;
70
71 #[inline]
72 fn into_monty(self, ring: &'a MontgomeryRepr) -> Montgomery<'a> {
73 match ring.data() {
74 MontgomeryReprData::Single(r) => {
75 let modulus = r.0.modulus();
76 let residue = &self % &UBig::from_word(modulus);
77 Montgomery::from_single(r.0.transform(ubig_to_word(&residue)), r)
78 }
79 MontgomeryReprData::Double(r) => {
80 let modulus = r.0.modulus();
81 let residue = &self % &UBig::from_dword(modulus);
82 Montgomery::from_double(r.0.transform(ubig_to_dword(&residue)), r)
83 }
84 MontgomeryReprData::Large(r) => {
85 let s = r.modulus.len();
86 let modulus = UBig(Repr::from_buffer(Buffer::from(&r.modulus[..])));
87 let residue = &self % &modulus;
88 let residue_words = to_exact_words(&residue, s);
89 let memory_requirement = mul_memory_requirement(r);
90 let mut allocation = MemoryAllocation::new(memory_requirement);
91 let mut memory = allocation.memory();
92 let monty = mul_normalized_large(r, &residue_words, &r.r2_mod_m, &mut memory);
93 Montgomery::from_large(
94 MontgomeryLargeVal(Buffer::from(monty).into_boxed_slice()),
95 r,
96 )
97 }
98 }
99 }
100}
101
102impl<'a> IntoMontgomeryRing<'a, MontgomeryRepr> for IBig {
103 type RingElement = Montgomery<'a>;
104
105 #[inline]
106 fn into_monty(self, ring: &'a MontgomeryRepr) -> Montgomery<'a> {
107 let sign = self.sign();
108 let modulo = self.unsigned_abs().into_monty(ring);
109 match sign {
110 Sign::Positive => modulo,
111 Sign::Negative => -modulo,
112 }
113 }
114}
115
116macro_rules! impl_into_monty_for_unsigned {
118 ($t:ty) => {
119 impl<'a> IntoMontgomeryRing<'a, MontgomeryRepr> for $t {
120 type RingElement = Montgomery<'a>;
121 #[inline]
122 fn into_monty(self, ring: &'a MontgomeryRepr) -> Montgomery<'a> {
123 UBig::from(self).into_monty(ring)
124 }
125 }
126 };
127}
128
129macro_rules! impl_into_monty_for_signed {
131 ($t:ty) => {
132 impl<'a> IntoMontgomeryRing<'a, MontgomeryRepr> for $t {
133 type RingElement = Montgomery<'a>;
134 #[inline]
135 fn into_monty(self, ring: &'a MontgomeryRepr) -> Montgomery<'a> {
136 IBig::from(self).into_monty(ring)
137 }
138 }
139 };
140}
141
142impl_into_monty_for_unsigned!(bool);
143impl_into_monty_for_unsigned!(u8);
144impl_into_monty_for_unsigned!(u16);
145impl_into_monty_for_unsigned!(u32);
146impl_into_monty_for_unsigned!(u64);
147impl_into_monty_for_unsigned!(u128);
148impl_into_monty_for_unsigned!(usize);
149impl_into_monty_for_signed!(i8);
150impl_into_monty_for_signed!(i16);
151impl_into_monty_for_signed!(i32);
152impl_into_monty_for_signed!(i64);
153impl_into_monty_for_signed!(i128);
154impl_into_monty_for_signed!(isize);
155
156impl MontgomeryRepr {
157 pub fn reduce<'a, T: IntoMontgomeryRing<'a, MontgomeryRepr, RingElement = Montgomery<'a>>>(
169 &'a self,
170 x: T,
171 ) -> Montgomery<'a> {
172 x.into_monty(self)
173 }
174}
175
176fn ubig_to_word(u: &UBig) -> Word {
178 match u.repr() {
179 TypedReprRef::RefSmall(d) => shrink_dword(d).expect("value fits in a word"),
180 TypedReprRef::RefLarge(_) => unreachable!("value is less than a single-word modulus"),
181 }
182}
183
184fn ubig_to_dword(u: &UBig) -> DoubleWord {
186 match u.repr() {
187 TypedReprRef::RefSmall(d) => d,
188 TypedReprRef::RefLarge(_) => unreachable!("value is less than a double-word modulus"),
189 }
190}