/src/boringssl/crypto/fipsmodule/bn/mul.cc.inc
Line | Count | Source |
1 | | // Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved. |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/bn.h> |
16 | | |
17 | | #include <assert.h> |
18 | | #include <stdlib.h> |
19 | | #include <string.h> |
20 | | |
21 | | #include <openssl/err.h> |
22 | | #include <openssl/mem.h> |
23 | | |
24 | | #include "../../internal.h" |
25 | | #include "internal.h" |
26 | | |
27 | | |
28 | | using namespace bssl; |
29 | | |
30 | | static void bn_mul_normal(BN_ULONG *r, const BN_ULONG *a, size_t na, |
31 | 549k | const BN_ULONG *b, size_t nb) { |
32 | 549k | if (na < nb) { |
33 | 7.59k | size_t itmp = na; |
34 | 7.59k | na = nb; |
35 | 7.59k | nb = itmp; |
36 | 7.59k | const BN_ULONG *ltmp = a; |
37 | 7.59k | a = b; |
38 | 7.59k | b = ltmp; |
39 | 7.59k | } |
40 | 549k | BN_ULONG *rr = &(r[na]); |
41 | 549k | if (nb == 0) { |
42 | 0 | OPENSSL_memset(r, 0, na * sizeof(BN_ULONG)); |
43 | 0 | return; |
44 | 0 | } |
45 | 549k | rr[0] = bn_mul_words(r, a, na, b[0]); |
46 | | |
47 | 931k | for (;;) { |
48 | 931k | if (--nb == 0) { |
49 | 222k | return; |
50 | 222k | } |
51 | 708k | rr[1] = bn_mul_add_words(&(r[1]), a, na, b[1]); |
52 | 708k | if (--nb == 0) { |
53 | 38.9k | return; |
54 | 38.9k | } |
55 | 669k | rr[2] = bn_mul_add_words(&(r[2]), a, na, b[2]); |
56 | 669k | if (--nb == 0) { |
57 | 14.1k | return; |
58 | 14.1k | } |
59 | 655k | rr[3] = bn_mul_add_words(&(r[3]), a, na, b[3]); |
60 | 655k | if (--nb == 0) { |
61 | 273k | return; |
62 | 273k | } |
63 | 382k | rr[4] = bn_mul_add_words(&(r[4]), a, na, b[4]); |
64 | 382k | rr += 4; |
65 | 382k | r += 4; |
66 | 382k | b += 4; |
67 | 382k | } |
68 | 549k | } |
69 | | |
70 | | // bn_sub_part_words sets |r| to |a| - |b|. It returns the borrow bit, which is |
71 | | // one if the operation underflowed and zero otherwise. `cl` is the common |
72 | | // length, that is, the shorter of len(a) or len(b). `dl` is the delta length, |
73 | | // that is, len(a) - len(b). |r|'s length matches the larger of |a| and |b|, or |
74 | | // cl + abs(dl). |
75 | | // |
76 | | // TODO(davidben): Make this take `size_t`. The `cl` + `dl` calling convention |
77 | | // is confusing. |
78 | | static BN_ULONG bn_sub_part_words(BN_ULONG *r, const BN_ULONG *a, |
79 | 0 | const BN_ULONG *b, int cl, int dl) { |
80 | 0 | assert(cl >= 0); |
81 | 0 | BN_ULONG borrow = bn_sub_words(r, a, b, cl); |
82 | 0 | if (dl == 0) { |
83 | 0 | return borrow; |
84 | 0 | } |
85 | | |
86 | 0 | r += cl; |
87 | 0 | a += cl; |
88 | 0 | b += cl; |
89 | |
|
90 | 0 | if (dl < 0) { |
91 | | // `a` is shorter than `b`. Complete the subtraction as if the excess words |
92 | | // in `a` were zeros. |
93 | 0 | dl = -dl; |
94 | 0 | for (int i = 0; i < dl; i++) { |
95 | 0 | r[i] = CRYPTO_subc_w(0, b[i], borrow, &borrow); |
96 | 0 | } |
97 | 0 | } else { |
98 | | // `b` is shorter than `a`. Complete the subtraction as if the excess words |
99 | | // in `b` were zeros. |
100 | 0 | for (int i = 0; i < dl; i++) { |
101 | 0 | r[i] = CRYPTO_subc_w(a[i], 0, borrow, &borrow); |
102 | 0 | } |
103 | 0 | } |
104 | |
|
105 | 0 | return borrow; |
106 | 0 | } |
107 | | |
108 | | // bn_abs_sub_part_words computes |r| = |a| - |b|, storing the absolute value |
109 | | // and returning a mask of all ones if the result was negative and all zeros if |
110 | | // the result was positive. `cl` and `dl` follow the `bn_sub_part_words` calling |
111 | | // convention. |
112 | | // |
113 | | // TODO(davidben): Make this take `size_t`. The `cl` + `dl` calling convention |
114 | | // is confusing. |
115 | | // |
116 | | // TODO(davidben): This function used to be used as part of a general Karatsuba |
117 | | // multiplication implementation, which had to account for differently-sized |
118 | | // inputs. Now it is only used as part of RSA key generation, which does not |
119 | | // need all this. |
120 | | static BN_ULONG bn_abs_sub_part_words(BN_ULONG *r, const BN_ULONG *a, |
121 | | const BN_ULONG *b, int cl, int dl, |
122 | 0 | BN_ULONG *tmp) { |
123 | 0 | BN_ULONG borrow = bn_sub_part_words(tmp, a, b, cl, dl); |
124 | 0 | bn_sub_part_words(r, b, a, cl, -dl); |
125 | 0 | int r_len = cl + (dl < 0 ? -dl : dl); |
126 | 0 | borrow = 0 - borrow; |
127 | 0 | bn_select_words(r, borrow, r /* tmp < 0 */, tmp /* tmp >= 0 */, r_len); |
128 | 0 | return borrow; |
129 | 0 | } |
130 | | |
131 | | int bssl::bn_abs_sub_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, |
132 | 0 | BN_CTX *ctx) { |
133 | 0 | int cl = a->width < b->width ? a->width : b->width; |
134 | 0 | int dl = a->width - b->width; |
135 | 0 | int r_len = a->width < b->width ? b->width : a->width; |
136 | 0 | BN_CTXScope scope(ctx); |
137 | 0 | BIGNUM *tmp = BN_CTX_get(ctx); |
138 | 0 | if (tmp == nullptr || !bn_wexpand(r, r_len) || !bn_wexpand(tmp, r_len)) { |
139 | 0 | return 0; |
140 | 0 | } |
141 | 0 | bn_abs_sub_part_words(r->d, a->d, b->d, cl, dl, tmp->d); |
142 | 0 | r->width = r_len; |
143 | 0 | r->neg = 0; |
144 | 0 | return 1; |
145 | 0 | } |
146 | | |
147 | | // bn_mul_impl implements `BN_mul` and `bn_mul_consttime`. Note this function |
148 | | // breaks `BIGNUM` invariants and may return a negative zero. This is handled by |
149 | | // the callers. |
150 | | static int bn_mul_impl(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, |
151 | 678k | BN_CTX *ctx) { |
152 | 678k | int al = a->width; |
153 | 678k | int bl = b->width; |
154 | 678k | if (al == 0 || bl == 0) { |
155 | 101k | BN_zero(r); |
156 | 101k | return 1; |
157 | 101k | } |
158 | | |
159 | 576k | int i, top; |
160 | 576k | BIGNUM *rr; |
161 | 576k | BN_CTXScope scope(ctx); |
162 | 576k | if (r == a || r == b) { |
163 | 273k | rr = BN_CTX_get(ctx); |
164 | 273k | if (rr == nullptr) { |
165 | 0 | return 0; |
166 | 0 | } |
167 | 303k | } else { |
168 | 303k | rr = r; |
169 | 303k | } |
170 | 576k | rr->neg = a->neg ^ b->neg; |
171 | | |
172 | 576k | i = al - bl; |
173 | 576k | if (i == 0) { |
174 | 561k | if (al == 8) { |
175 | 27.6k | if (!bn_wexpand(rr, 16)) { |
176 | 0 | return 0; |
177 | 0 | } |
178 | 27.6k | rr->width = 16; |
179 | 27.6k | bn_mul_comba8(rr->d, a->d, b->d); |
180 | 27.6k | goto end; |
181 | 27.6k | } |
182 | 561k | } |
183 | | |
184 | 549k | top = al + bl; |
185 | 549k | if (!bn_wexpand(rr, top)) { |
186 | 0 | return 0; |
187 | 0 | } |
188 | 549k | rr->width = top; |
189 | 549k | bn_mul_normal(rr->d, a->d, al, b->d, bl); |
190 | | |
191 | 576k | end: |
192 | 576k | if (r != rr && !BN_copy(r, rr)) { |
193 | 0 | return 0; |
194 | 0 | } |
195 | 576k | return 1; |
196 | 576k | } |
197 | | |
198 | 590k | int BN_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) { |
199 | 590k | if (!bn_mul_impl(r, a, b, ctx)) { |
200 | 0 | return 0; |
201 | 0 | } |
202 | | |
203 | | // This additionally fixes any negative zeros created by `bn_mul_impl`. |
204 | 590k | bn_set_minimal_width(r); |
205 | 590k | return 1; |
206 | 590k | } |
207 | | |
208 | | int bssl::bn_mul_consttime(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, |
209 | 87.5k | BN_CTX *ctx) { |
210 | | // Prevent negative zeros. |
211 | 87.5k | if (a->neg || b->neg) { |
212 | 0 | OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER); |
213 | 0 | return 0; |
214 | 0 | } |
215 | | |
216 | 87.5k | return bn_mul_impl(r, a, b, ctx); |
217 | 87.5k | } |
218 | | |
219 | | void bssl::bn_mul_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, |
220 | 0 | size_t num_a, const BN_ULONG *b, size_t num_b) { |
221 | 0 | if (num_r != num_a + num_b) { |
222 | 0 | abort(); |
223 | 0 | } |
224 | | // TODO(davidben): Should this call `bn_mul_comba4` too? `BN_mul` does not |
225 | | // hit that code. |
226 | 0 | if (num_a == 8 && num_b == 8) { |
227 | 0 | bn_mul_comba8(r, a, b); |
228 | 0 | } else { |
229 | 0 | bn_mul_normal(r, a, num_a, b, num_b); |
230 | 0 | } |
231 | 0 | } |
232 | | |
233 | 319k | static void bn_sqr_normal(BN_ULONG *r, const BN_ULONG *a, size_t n) { |
234 | 319k | if (n == 0) { |
235 | 0 | return; |
236 | 0 | } |
237 | | |
238 | 319k | size_t max = n * 2; |
239 | 319k | const BN_ULONG *ap = a; |
240 | 319k | BN_ULONG *rp = r; |
241 | 319k | rp[0] = rp[max - 1] = 0; |
242 | 319k | rp++; |
243 | | |
244 | | // Compute the contribution of a[i] * a[j] for all i < j. |
245 | 319k | if (n > 1) { |
246 | 2.39k | ap++; |
247 | 2.39k | rp[n - 1] = bn_mul_words(rp, ap, n - 1, ap[-1]); |
248 | 2.39k | rp += 2; |
249 | 2.39k | } |
250 | 319k | if (n > 2) { |
251 | 12.5k | for (size_t i = n - 2; i > 0; i--) { |
252 | 10.9k | ap++; |
253 | 10.9k | rp[i] = bn_mul_add_words(rp, ap, i, ap[-1]); |
254 | 10.9k | rp += 2; |
255 | 10.9k | } |
256 | 1.64k | } |
257 | | |
258 | | // The final result fits in `max` words, so none of the following operations |
259 | | // will overflow. |
260 | | |
261 | | // Double `r`, giving the contribution of a[i] * a[j] for all i != j. |
262 | 319k | bn_add_words(r, r, r, max); |
263 | | |
264 | | // Add in the contribution of a[i] * a[i] for all i. |
265 | 319k | bn_sqr_add_words(r, a, n); |
266 | 319k | } |
267 | | |
268 | 17.3k | int BN_mul_word(BIGNUM *bn, BN_ULONG w) { |
269 | 17.3k | if (!bn->width) { |
270 | 10.1k | return 1; |
271 | 10.1k | } |
272 | | |
273 | 7.20k | if (w == 0) { |
274 | 0 | BN_zero(bn); |
275 | 0 | return 1; |
276 | 0 | } |
277 | | |
278 | 7.20k | BN_ULONG ll = bn_mul_words(bn->d, bn->d, bn->width, w); |
279 | 7.20k | if (ll) { |
280 | 6.26k | if (!bn_wexpand(bn, bn->width + 1)) { |
281 | 0 | return 0; |
282 | 0 | } |
283 | 6.26k | bn->d[bn->width++] = ll; |
284 | 6.26k | } |
285 | | |
286 | 7.20k | return 1; |
287 | 7.20k | } |
288 | | |
289 | 5.80M | int bssl::bn_sqr_consttime(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) { |
290 | 5.80M | int al = a->width; |
291 | 5.80M | if (al <= 0) { |
292 | 23.3k | r->width = 0; |
293 | 23.3k | r->neg = 0; |
294 | 23.3k | return 1; |
295 | 23.3k | } |
296 | | |
297 | 5.78M | BN_CTXScope scope(ctx); |
298 | 5.78M | BIGNUM *rr = (a != r) ? r : BN_CTX_get(ctx); |
299 | 5.78M | if (!rr) { |
300 | 0 | return 0; |
301 | 0 | } |
302 | | |
303 | 5.78M | int max = 2 * al; // Non-zero (from above) |
304 | 5.78M | if (!bn_wexpand(rr, max)) { |
305 | 0 | return 0; |
306 | 0 | } |
307 | | |
308 | 5.78M | if (al == 4) { |
309 | 5.46M | bn_sqr_comba4(rr->d, a->d); |
310 | 5.46M | } else if (al == 8) { |
311 | 324 | bn_sqr_comba8(rr->d, a->d); |
312 | 319k | } else { |
313 | 319k | bn_sqr_normal(rr->d, a->d, al); |
314 | 319k | } |
315 | | |
316 | 5.78M | rr->neg = 0; |
317 | 5.78M | rr->width = max; |
318 | | |
319 | 5.78M | if (rr != r && !BN_copy(r, rr)) { |
320 | 0 | return 0; |
321 | 0 | } |
322 | 5.78M | return 1; |
323 | 5.78M | } |
324 | | |
325 | 5.51M | int BN_sqr(BIGNUM *r, const BIGNUM *a, BN_CTX *ctx) { |
326 | 5.51M | if (!bn_sqr_consttime(r, a, ctx)) { |
327 | 0 | return 0; |
328 | 0 | } |
329 | | |
330 | 5.51M | bn_set_minimal_width(r); |
331 | 5.51M | return 1; |
332 | 5.51M | } |
333 | | |
334 | | void bssl::bn_sqr_small(BN_ULONG *r, size_t num_r, const BN_ULONG *a, |
335 | 0 | size_t num_a) { |
336 | 0 | assert(r != a); |
337 | 0 | if (num_r != 2 * num_a) { |
338 | 0 | abort(); |
339 | 0 | } |
340 | 0 | if (num_a == 4) { |
341 | 0 | bn_sqr_comba4(r, a); |
342 | 0 | } else if (num_a == 8) { |
343 | 0 | bn_sqr_comba8(r, a); |
344 | 0 | } else { |
345 | 0 | bn_sqr_normal(r, a, num_a); |
346 | 0 | } |
347 | 0 | } |