/src/botan/src/lib/math/bigint/big_ops3.cpp
Line | Count | Source |
1 | | /* |
2 | | * BigInt Binary Operators |
3 | | * (C) 1999-2007,2018 Jack Lloyd |
4 | | * 2016 Matthias Gierlings |
5 | | * |
6 | | * Botan is released under the Simplified BSD License (see license.txt) |
7 | | */ |
8 | | |
9 | | #include <botan/bigint.h> |
10 | | |
11 | | #include <botan/internal/bit_ops.h> |
12 | | #include <botan/internal/divide.h> |
13 | | #include <botan/internal/mp_core.h> |
14 | | #include <algorithm> |
15 | | |
16 | | namespace Botan { |
17 | | |
18 | | //static |
19 | 16.6k | BigInt BigInt::add2(const BigInt& x, const word y[], size_t y_size, BigInt::Sign y_sign) { |
20 | 16.6k | const size_t x_sw = x.sig_words(); |
21 | | |
22 | 16.6k | BigInt z = BigInt::with_capacity(std::max(x_sw, y_size) + 1); |
23 | | |
24 | 16.6k | if(x.sign() == y_sign) { |
25 | 734 | word carry = bigint_add3(z.mutable_data(), x._data(), x_sw, y, y_size); |
26 | 734 | z.mutable_data()[std::max(x_sw, y_size)] += carry; |
27 | 734 | z.set_sign(x.sign()); |
28 | 15.9k | } else { |
29 | 15.9k | const int32_t relative_size = bigint_cmp(x.data(), x_sw, y, y_size); |
30 | | |
31 | 15.9k | if(relative_size < 0) { |
32 | | // x < y so z = abs(y - x) |
33 | | // NOLINTNEXTLINE(*-suspicious-call-argument) intentionally swapping x and y here |
34 | 234 | bigint_sub3(z.mutable_data(), y, y_size, x.data(), x_sw); |
35 | 234 | z.set_sign(y_sign); |
36 | 15.6k | } else if(relative_size == 0) { |
37 | | // Positive zero (nothing to do in this case) |
38 | 15.6k | } else { |
39 | | /* |
40 | | * We know at this point that x >= y so if y_size is larger than |
41 | | * x_sw, we are guaranteed they are just leading zeros which can |
42 | | * be ignored |
43 | | */ |
44 | 15.6k | y_size = std::min(x_sw, y_size); |
45 | 15.6k | bigint_sub3(z.mutable_data(), x.data(), x_sw, y, y_size); |
46 | 15.6k | z.set_sign(x.sign()); |
47 | 15.6k | } |
48 | 15.9k | } |
49 | | |
50 | 16.6k | return z; |
51 | 16.6k | } |
52 | | |
53 | | /* |
54 | | * Multiplication Operator |
55 | | */ |
56 | 476 | BigInt operator*(const BigInt& x, const BigInt& y) { |
57 | 476 | const size_t x_sw = x.sig_words(); |
58 | 476 | const size_t y_sw = y.sig_words(); |
59 | | |
60 | 476 | BigInt z = BigInt::with_capacity(x.size() + y.size()); |
61 | | |
62 | 476 | if(x_sw == 1 && y_sw > 0) { |
63 | 213 | bigint_linmul3(z.mutable_data(), y._data(), y_sw, x.word_at(0)); |
64 | 263 | } else if(y_sw == 1 && x_sw > 0) { |
65 | 26 | bigint_linmul3(z.mutable_data(), x._data(), x_sw, y.word_at(0)); |
66 | 237 | } else if(x_sw > 0 && y_sw > 0) { |
67 | 203 | secure_vector<word> workspace(z.size()); |
68 | | |
69 | 203 | bigint_mul(z.mutable_data(), |
70 | 203 | z.size(), |
71 | 203 | x._data(), |
72 | 203 | x.size(), |
73 | 203 | x_sw, |
74 | 203 | y._data(), |
75 | 203 | y.size(), |
76 | 203 | y_sw, |
77 | 203 | workspace.data(), |
78 | 203 | workspace.size()); |
79 | 203 | } |
80 | | |
81 | 476 | z.cond_flip_sign(x_sw > 0 && y_sw > 0 && x.sign() != y.sign()); |
82 | | |
83 | 476 | return z; |
84 | 476 | } |
85 | | |
86 | | /* |
87 | | * Multiplication Operator |
88 | | */ |
89 | 51.8k | BigInt operator*(const BigInt& x, word y) { |
90 | 51.8k | const size_t x_sw = x.sig_words(); |
91 | | |
92 | 51.8k | BigInt z = BigInt::with_capacity(x_sw + 1); |
93 | | |
94 | 51.8k | if(x_sw > 0 && y > 0) { |
95 | 51.5k | bigint_linmul3(z.mutable_data(), x._data(), x_sw, y); |
96 | 51.5k | z.set_sign(x.sign()); |
97 | 51.5k | } |
98 | | |
99 | 51.8k | return z; |
100 | 51.8k | } |
101 | | |
102 | | /* |
103 | | * Division Operator |
104 | | */ |
105 | 543 | BigInt operator/(const BigInt& x, const BigInt& y) { |
106 | 543 | if(y.sig_words() == 1) { |
107 | 0 | return x / y.word_at(0); |
108 | 0 | } |
109 | | |
110 | 543 | BigInt q; |
111 | 543 | BigInt r; |
112 | 543 | vartime_divide(x, y, q, r); |
113 | 543 | return q; |
114 | 543 | } |
115 | | |
116 | | /* |
117 | | * Division Operator |
118 | | */ |
119 | 34.7k | BigInt operator/(const BigInt& x, word y) { |
120 | 34.7k | if(y == 0) { |
121 | 0 | throw Invalid_Argument("BigInt::operator/ divide by zero"); |
122 | 0 | } |
123 | | |
124 | 34.7k | BigInt q; |
125 | 34.7k | word r = 0; |
126 | 34.7k | ct_divide_word(x, y, q, r); |
127 | 34.7k | return q; |
128 | 34.7k | } |
129 | | |
130 | | /* |
131 | | * Modulo Operator |
132 | | */ |
133 | 39.3k | BigInt operator%(const BigInt& n, const BigInt& mod) { |
134 | 39.3k | if(mod.is_zero()) { |
135 | 0 | throw Invalid_Argument("BigInt::operator% divide by zero"); |
136 | 0 | } |
137 | 39.3k | if(mod.is_negative()) { |
138 | 0 | throw Invalid_Argument("BigInt::operator% modulus must be > 0"); |
139 | 0 | } |
140 | 39.3k | if(n.is_positive() && mod.is_positive() && n < mod) { |
141 | 5.32k | return n; |
142 | 5.32k | } |
143 | | |
144 | 34.0k | if(mod.sig_words() == 1) { |
145 | 13.3k | return BigInt::from_word(n % mod.word_at(0)); |
146 | 13.3k | } |
147 | | |
148 | 20.6k | BigInt q; |
149 | 20.6k | BigInt r; |
150 | 20.6k | vartime_divide(n, mod, q, r); |
151 | 20.6k | return r; |
152 | 34.0k | } |
153 | | |
154 | | /* |
155 | | * Modulo Operator |
156 | | */ |
157 | 91.4k | word operator%(const BigInt& n, word mod) { |
158 | 91.4k | if(mod == 0) { |
159 | 0 | throw Invalid_Argument("BigInt::operator% divide by zero"); |
160 | 0 | } |
161 | | |
162 | 91.4k | if(mod == 1) { |
163 | 0 | return 0; |
164 | 0 | } |
165 | | |
166 | 91.4k | word remainder = 0; |
167 | | |
168 | 91.4k | if(is_power_of_2(mod)) { |
169 | 78.0k | remainder = (n.word_at(0) & (mod - 1)); |
170 | 78.0k | } else { |
171 | 13.3k | const size_t sw = n.sig_words(); |
172 | 30.1k | for(size_t i = sw; i > 0; --i) { |
173 | 16.7k | remainder = bigint_modop_vartime(remainder, n.word_at(i - 1), mod); |
174 | 16.7k | } |
175 | 13.3k | } |
176 | | |
177 | 91.4k | if(remainder != 0 && n.sign() == BigInt::Negative) { |
178 | 0 | return mod - remainder; |
179 | 0 | } |
180 | 91.4k | return remainder; |
181 | 91.4k | } |
182 | | |
183 | | /* |
184 | | * Left Shift Operator |
185 | | */ |
186 | 21.5k | BigInt operator<<(const BigInt& x, size_t shift) { |
187 | 21.5k | const size_t x_sw = x.sig_words(); |
188 | | |
189 | 21.5k | const size_t new_size = x_sw + (shift + WordInfo<word>::bits - 1) / WordInfo<word>::bits; |
190 | 21.5k | BigInt y = BigInt::with_capacity(new_size); |
191 | 21.5k | bigint_shl2(y.mutable_data(), x._data(), x_sw, shift); |
192 | 21.5k | y.set_sign(x.sign()); |
193 | 21.5k | return y; |
194 | 21.5k | } |
195 | | |
196 | | /* |
197 | | * Right Shift Operator |
198 | | */ |
199 | 803 | BigInt operator>>(const BigInt& x, size_t shift) { |
200 | 803 | const size_t shift_words = shift / WordInfo<word>::bits; |
201 | 803 | const size_t x_sw = x.sig_words(); |
202 | | |
203 | 803 | if(shift_words >= x_sw) { |
204 | 138 | return BigInt::zero(); |
205 | 138 | } |
206 | | |
207 | 665 | BigInt y = BigInt::with_capacity(x_sw - shift_words); |
208 | 665 | bigint_shr2(y.mutable_data(), x._data(), x_sw, shift); |
209 | | |
210 | 665 | if(x.is_negative() && y.is_zero()) { |
211 | 0 | y.set_sign(BigInt::Positive); |
212 | 665 | } else { |
213 | 665 | y.set_sign(x.sign()); |
214 | 665 | } |
215 | | |
216 | 665 | return y; |
217 | 803 | } |
218 | | |
219 | | } // namespace Botan |