/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 | 15.6k | BigInt BigInt::add2(const BigInt& x, const word y[], size_t y_size, BigInt::Sign y_sign) { |
20 | 15.6k | const size_t x_sw = x.sig_words(); |
21 | | |
22 | 15.6k | BigInt z = BigInt::with_capacity(std::max(x_sw, y_size) + 1); |
23 | | |
24 | 15.6k | if(x.sign() == y_sign) { |
25 | 685 | word carry = bigint_add3(z.mutable_data(), x._data(), x_sw, y, y_size); |
26 | 685 | z.mutable_data()[std::max(x_sw, y_size)] += carry; |
27 | 685 | z.set_sign(x.sign()); |
28 | 14.9k | } else { |
29 | 14.9k | const int32_t relative_size = bigint_cmp(x.data(), x_sw, y, y_size); |
30 | | |
31 | 14.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 | 212 | bigint_sub3(z.mutable_data(), y, y_size, x.data(), x_sw); |
35 | 212 | z.set_sign(y_sign); |
36 | 14.7k | } else if(relative_size == 0) { |
37 | | // Positive zero (nothing to do in this case) |
38 | 14.7k | } 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 | 14.7k | y_size = std::min(x_sw, y_size); |
45 | 14.7k | bigint_sub3(z.mutable_data(), x.data(), x_sw, y, y_size); |
46 | 14.7k | z.set_sign(x.sign()); |
47 | 14.7k | } |
48 | 14.9k | } |
49 | | |
50 | 15.6k | return z; |
51 | 15.6k | } |
52 | | |
53 | | /* |
54 | | * Multiplication Operator |
55 | | */ |
56 | 462 | BigInt operator*(const BigInt& x, const BigInt& y) { |
57 | 462 | const size_t x_sw = x.sig_words(); |
58 | 462 | const size_t y_sw = y.sig_words(); |
59 | | |
60 | 462 | BigInt z = BigInt::with_capacity(x.size() + y.size()); |
61 | | |
62 | 462 | if(x_sw == 1 && y_sw > 0) { |
63 | 191 | bigint_linmul3(z.mutable_data(), y._data(), y_sw, x.word_at(0)); |
64 | 271 | } else if(y_sw == 1 && x_sw > 0) { |
65 | 31 | bigint_linmul3(z.mutable_data(), x._data(), x_sw, y.word_at(0)); |
66 | 240 | } else if(x_sw > 0 && y_sw > 0) { |
67 | 202 | secure_vector<word> workspace(z.size()); |
68 | | |
69 | 202 | bigint_mul(z.mutable_data(), |
70 | 202 | z.size(), |
71 | 202 | x._data(), |
72 | 202 | x.size(), |
73 | 202 | x_sw, |
74 | 202 | y._data(), |
75 | 202 | y.size(), |
76 | 202 | y_sw, |
77 | 202 | workspace.data(), |
78 | 202 | workspace.size()); |
79 | 202 | } |
80 | | |
81 | 462 | z.cond_flip_sign(x_sw > 0 && y_sw > 0 && x.sign() != y.sign()); |
82 | | |
83 | 462 | return z; |
84 | 462 | } |
85 | | |
86 | | /* |
87 | | * Multiplication Operator |
88 | | */ |
89 | 50.3k | BigInt operator*(const BigInt& x, word y) { |
90 | 50.3k | const size_t x_sw = x.sig_words(); |
91 | | |
92 | 50.3k | BigInt z = BigInt::with_capacity(x_sw + 1); |
93 | | |
94 | 50.3k | if(x_sw > 0 && y > 0) { |
95 | 50.0k | bigint_linmul3(z.mutable_data(), x._data(), x_sw, y); |
96 | 50.0k | z.set_sign(x.sign()); |
97 | 50.0k | } |
98 | | |
99 | 50.3k | return z; |
100 | 50.3k | } |
101 | | |
102 | | /* |
103 | | * Division Operator |
104 | | */ |
105 | 506 | BigInt operator/(const BigInt& x, const BigInt& y) { |
106 | 506 | if(y.sig_words() == 1) { |
107 | 0 | return x / y.word_at(0); |
108 | 0 | } |
109 | | |
110 | 506 | BigInt q; |
111 | 506 | BigInt r; |
112 | 506 | vartime_divide(x, y, q, r); |
113 | 506 | return q; |
114 | 506 | } |
115 | | |
116 | | /* |
117 | | * Division Operator |
118 | | */ |
119 | 32.0k | BigInt operator/(const BigInt& x, word y) { |
120 | 32.0k | if(y == 0) { |
121 | 0 | throw Invalid_Argument("BigInt::operator/ divide by zero"); |
122 | 0 | } |
123 | | |
124 | 32.0k | BigInt q; |
125 | 32.0k | word r = 0; |
126 | 32.0k | ct_divide_word(x, y, q, r); |
127 | 32.0k | return q; |
128 | 32.0k | } |
129 | | |
130 | | /* |
131 | | * Modulo Operator |
132 | | */ |
133 | 36.3k | BigInt operator%(const BigInt& n, const BigInt& mod) { |
134 | 36.3k | if(mod.is_zero()) { |
135 | 0 | throw Invalid_Argument("BigInt::operator% divide by zero"); |
136 | 0 | } |
137 | 36.3k | if(mod.is_negative()) { |
138 | 0 | throw Invalid_Argument("BigInt::operator% modulus must be > 0"); |
139 | 0 | } |
140 | 36.3k | if(n.is_positive() && mod.is_positive() && n < mod) { |
141 | 4.82k | return n; |
142 | 4.82k | } |
143 | | |
144 | 31.4k | if(mod.sig_words() == 1) { |
145 | 12.4k | return BigInt::from_word(n % mod.word_at(0)); |
146 | 12.4k | } |
147 | | |
148 | 19.0k | BigInt q; |
149 | 19.0k | BigInt r; |
150 | 19.0k | vartime_divide(n, mod, q, r); |
151 | 19.0k | return r; |
152 | 31.4k | } |
153 | | |
154 | | /* |
155 | | * Modulo Operator |
156 | | */ |
157 | 84.7k | word operator%(const BigInt& n, word mod) { |
158 | 84.7k | if(mod == 0) { |
159 | 0 | throw Invalid_Argument("BigInt::operator% divide by zero"); |
160 | 0 | } |
161 | | |
162 | 84.7k | if(mod == 1) { |
163 | 0 | return 0; |
164 | 0 | } |
165 | | |
166 | 84.7k | word remainder = 0; |
167 | | |
168 | 84.7k | if(is_power_of_2(mod)) { |
169 | 72.2k | remainder = (n.word_at(0) & (mod - 1)); |
170 | 72.2k | } else { |
171 | 12.4k | const size_t sw = n.sig_words(); |
172 | 28.0k | for(size_t i = sw; i > 0; --i) { |
173 | 15.5k | remainder = bigint_modop_vartime(remainder, n.word_at(i - 1), mod); |
174 | 15.5k | } |
175 | 12.4k | } |
176 | | |
177 | 84.7k | if(remainder != 0 && n.sign() == BigInt::Negative) { |
178 | 0 | return mod - remainder; |
179 | 0 | } |
180 | 84.7k | return remainder; |
181 | 84.7k | } |
182 | | |
183 | | /* |
184 | | * Left Shift Operator |
185 | | */ |
186 | 19.8k | BigInt operator<<(const BigInt& x, size_t shift) { |
187 | 19.8k | const size_t x_sw = x.sig_words(); |
188 | | |
189 | 19.8k | const size_t new_size = x_sw + (shift + WordInfo<word>::bits - 1) / WordInfo<word>::bits; |
190 | 19.8k | BigInt y = BigInt::with_capacity(new_size); |
191 | 19.8k | bigint_shl2(y.mutable_data(), x._data(), x_sw, shift); |
192 | 19.8k | y.set_sign(x.sign()); |
193 | 19.8k | return y; |
194 | 19.8k | } |
195 | | |
196 | | /* |
197 | | * Right Shift Operator |
198 | | */ |
199 | 738 | BigInt operator>>(const BigInt& x, size_t shift) { |
200 | 738 | const size_t shift_words = shift / WordInfo<word>::bits; |
201 | 738 | const size_t x_sw = x.sig_words(); |
202 | | |
203 | 738 | if(shift_words >= x_sw) { |
204 | 122 | return BigInt::zero(); |
205 | 122 | } |
206 | | |
207 | 616 | BigInt y = BigInt::with_capacity(x_sw - shift_words); |
208 | 616 | bigint_shr2(y.mutable_data(), x._data(), x_sw, shift); |
209 | | |
210 | 616 | if(x.is_negative() && y.is_zero()) { |
211 | 0 | y.set_sign(BigInt::Positive); |
212 | 616 | } else { |
213 | 616 | y.set_sign(x.sign()); |
214 | 616 | } |
215 | | |
216 | 616 | return y; |
217 | 738 | } |
218 | | |
219 | | } // namespace Botan |