blob: 7f261f1c08d69bfaa48d463b1d09f6191be23ad3 [file] [log] [blame]
Adam Langleyd9e397b2015-01-22 14:27:53 -08001/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
2 * All rights reserved.
3 *
4 * This package is an SSL implementation written
5 * by Eric Young (eay@cryptsoft.com).
6 * The implementation was written so as to conform with Netscapes SSL.
7 *
8 * This library is free for commercial and non-commercial use as long as
9 * the following conditions are aheared to. The following conditions
10 * apply to all code found in this distribution, be it the RC4, RSA,
11 * lhash, DES, etc., code; not just the SSL code. The SSL documentation
12 * included with this distribution is covered by the same copyright terms
13 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
14 *
15 * Copyright remains Eric Young's, and as such any Copyright notices in
16 * the code are not to be removed.
17 * If this package is used in a product, Eric Young should be given attribution
18 * as the author of the parts of the library used.
19 * This can be in the form of a textual message at program startup or
20 * in documentation (online or textual) provided with the package.
21 *
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions
24 * are met:
25 * 1. Redistributions of source code must retain the copyright
26 * notice, this list of conditions and the following disclaimer.
27 * 2. Redistributions in binary form must reproduce the above copyright
28 * notice, this list of conditions and the following disclaimer in the
29 * documentation and/or other materials provided with the distribution.
30 * 3. All advertising materials mentioning features or use of this software
31 * must display the following acknowledgement:
32 * "This product includes cryptographic software written by
33 * Eric Young (eay@cryptsoft.com)"
34 * The word 'cryptographic' can be left out if the rouines from the library
35 * being used are not cryptographic related :-).
36 * 4. If you include any Windows specific code (or a derivative thereof) from
37 * the apps directory (application code) you must include an acknowledgement:
38 * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
39 *
40 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
41 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
42 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
43 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
44 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
45 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
46 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
47 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
48 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
49 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
50 * SUCH DAMAGE.
51 *
52 * The licence and distribution terms for any publically available version or
53 * derivative of this code cannot be changed. i.e. this code cannot simply be
54 * copied and put under another distribution licence
55 * [including the GNU Public Licence.] */
56
57#include <openssl/bn.h>
58
David Benjamin4969cc92016-04-22 15:02:23 -040059#include <assert.h>
Adam Langleyd9e397b2015-01-22 14:27:53 -080060#include <limits.h>
Robert Sloan5d625782017-02-13 09:55:39 -080061
Adam Langleyd9e397b2015-01-22 14:27:53 -080062#include <openssl/err.h>
63
64#include "internal.h"
65
66
David Benjamin4969cc92016-04-22 15:02:23 -040067#if !defined(BN_ULLONG)
Robert Sloan8f860b12017-08-28 07:37:06 -070068// bn_div_words divides a double-width |h|,|l| by |d| and returns the result,
69// which must fit in a |BN_ULONG|.
David Benjamin4969cc92016-04-22 15:02:23 -040070static BN_ULONG bn_div_words(BN_ULONG h, BN_ULONG l, BN_ULONG d) {
71 BN_ULONG dh, dl, q, ret = 0, th, tl, t;
72 int i, count = 2;
Adam Langleyd9e397b2015-01-22 14:27:53 -080073
David Benjamin4969cc92016-04-22 15:02:23 -040074 if (d == 0) {
75 return BN_MASK2;
76 }
77
78 i = BN_num_bits_word(d);
79 assert((i == BN_BITS2) || (h <= (BN_ULONG)1 << i));
80
81 i = BN_BITS2 - i;
82 if (h >= d) {
83 h -= d;
84 }
85
86 if (i) {
87 d <<= i;
88 h = (h << i) | (l >> (BN_BITS2 - i));
89 l <<= i;
90 }
91 dh = (d & BN_MASK2h) >> BN_BITS4;
92 dl = (d & BN_MASK2l);
93 for (;;) {
94 if ((h >> BN_BITS4) == dh) {
95 q = BN_MASK2l;
96 } else {
97 q = h / dh;
98 }
99
100 th = q * dh;
101 tl = dl * q;
102 for (;;) {
103 t = h - th;
104 if ((t & BN_MASK2h) ||
105 ((tl) <= ((t << BN_BITS4) | ((l & BN_MASK2h) >> BN_BITS4)))) {
106 break;
107 }
108 q--;
109 th -= dh;
110 tl -= dl;
111 }
112 t = (tl >> BN_BITS4);
113 tl = (tl << BN_BITS4) & BN_MASK2h;
114 th += t;
115
116 if (l < tl) {
117 th++;
118 }
119 l -= tl;
120 if (h < th) {
121 h += d;
122 q--;
123 }
124 h -= th;
125
126 if (--count == 0) {
127 break;
128 }
129
130 ret = q << BN_BITS4;
Robert Sloan29c1d2c2017-10-30 14:10:28 -0700131 h = (h << BN_BITS4) | (l >> BN_BITS4);
David Benjamin4969cc92016-04-22 15:02:23 -0400132 l = (l & BN_MASK2l) << BN_BITS4;
133 }
134
135 ret |= q;
136 return ret;
137}
Robert Sloan8f860b12017-08-28 07:37:06 -0700138#endif // !defined(BN_ULLONG)
David Benjamin4969cc92016-04-22 15:02:23 -0400139
140static inline void bn_div_rem_words(BN_ULONG *quotient_out, BN_ULONG *rem_out,
141 BN_ULONG n0, BN_ULONG n1, BN_ULONG d0) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700142 // GCC and Clang generate function calls to |__udivdi3| and |__umoddi3| when
143 // the |BN_ULLONG|-based C code is used.
144 //
145 // GCC bugs:
146 // * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=14224
147 // * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=43721
148 // * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=54183
149 // * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=58897
150 // * https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65668
151 //
152 // Clang bugs:
153 // * https://llvm.org/bugs/show_bug.cgi?id=6397
154 // * https://llvm.org/bugs/show_bug.cgi?id=12418
155 //
156 // These issues aren't specific to x86 and x86_64, so it might be worthwhile
157 // to add more assembly language implementations.
Robert Sloan55818102017-12-18 11:26:17 -0800158#if !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86) && \
159 (defined(__GNUC__) || defined(__clang__))
160 __asm__ volatile("divl %4"
161 : "=a"(*quotient_out), "=d"(*rem_out)
162 : "a"(n1), "d"(n0), "rm"(d0)
163 : "cc");
164#elif !defined(OPENSSL_NO_ASM) && defined(OPENSSL_X86_64) && \
165 (defined(__GNUC__) || defined(__clang__))
166 __asm__ volatile("divq %4"
167 : "=a"(*quotient_out), "=d"(*rem_out)
168 : "a"(n1), "d"(n0), "rm"(d0)
169 : "cc");
David Benjamin4969cc92016-04-22 15:02:23 -0400170#else
171#if defined(BN_ULLONG)
172 BN_ULLONG n = (((BN_ULLONG)n0) << BN_BITS2) | n1;
173 *quotient_out = (BN_ULONG)(n / d0);
174#else
175 *quotient_out = bn_div_words(n0, n1, d0);
176#endif
177 *rem_out = n1 - (*quotient_out * d0);
178#endif
179}
Adam Langleyd9e397b2015-01-22 14:27:53 -0800180
Robert Sloand5c22152017-11-13 09:22:12 -0800181// BN_div computes "quotient := numerator / divisor", rounding towards zero,
182// and sets up |rem| such that "quotient * divisor + rem = numerator" holds.
183//
Robert Sloan8f860b12017-08-28 07:37:06 -0700184// Thus:
Robert Sloand5c22152017-11-13 09:22:12 -0800185//
186// quotient->neg == numerator->neg ^ divisor->neg
187// (unless the result is zero)
188// rem->neg == numerator->neg
189// (unless the remainder is zero)
190//
191// If |quotient| or |rem| is NULL, the respective value is not returned.
Robert Sloan8f860b12017-08-28 07:37:06 -0700192//
193// This was specifically designed to contain fewer branches that may leak
194// sensitive information; see "New Branch Prediction Vulnerabilities in OpenSSL
195// and Necessary Software Countermeasures" by Onur Acıçmez, Shay Gueron, and
196// Jean-Pierre Seifert.
Robert Sloand5c22152017-11-13 09:22:12 -0800197int BN_div(BIGNUM *quotient, BIGNUM *rem, const BIGNUM *numerator,
198 const BIGNUM *divisor, BN_CTX *ctx) {
199 int norm_shift, loop;
200 BIGNUM wnum;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800201 BN_ULONG *resp, *wnump;
202 BN_ULONG d0, d1;
203 int num_n, div_n;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800204
Robert Sloan8f860b12017-08-28 07:37:06 -0700205 // Invalid zero-padding would have particularly bad consequences
206 // so don't just rely on bn_check_top() here
Robert Sloand5c22152017-11-13 09:22:12 -0800207 if ((numerator->top > 0 && numerator->d[numerator->top - 1] == 0) ||
Adam Langleyd9e397b2015-01-22 14:27:53 -0800208 (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) {
Kenny Rootb8494592015-09-25 02:29:14 +0000209 OPENSSL_PUT_ERROR(BN, BN_R_NOT_INITIALIZED);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800210 return 0;
211 }
212
Adam Langleyd9e397b2015-01-22 14:27:53 -0800213 if (BN_is_zero(divisor)) {
Kenny Rootb8494592015-09-25 02:29:14 +0000214 OPENSSL_PUT_ERROR(BN, BN_R_DIV_BY_ZERO);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800215 return 0;
216 }
217
Adam Langleyd9e397b2015-01-22 14:27:53 -0800218 BN_CTX_start(ctx);
Robert Sloand5c22152017-11-13 09:22:12 -0800219 BIGNUM *tmp = BN_CTX_get(ctx);
220 BIGNUM *snum = BN_CTX_get(ctx);
221 BIGNUM *sdiv = BN_CTX_get(ctx);
222 BIGNUM *res = NULL;
223 if (quotient == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800224 res = BN_CTX_get(ctx);
225 } else {
Robert Sloand5c22152017-11-13 09:22:12 -0800226 res = quotient;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800227 }
Robert Sloand5c22152017-11-13 09:22:12 -0800228 if (sdiv == NULL || res == NULL) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800229 goto err;
230 }
231
Robert Sloan8f860b12017-08-28 07:37:06 -0700232 // First we normalise the numbers
Robert Sloand5c22152017-11-13 09:22:12 -0800233 norm_shift = BN_BITS2 - (BN_num_bits(divisor) % BN_BITS2);
234 if (!BN_lshift(sdiv, divisor, norm_shift)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800235 goto err;
236 }
237 sdiv->neg = 0;
238 norm_shift += BN_BITS2;
Robert Sloand5c22152017-11-13 09:22:12 -0800239 if (!BN_lshift(snum, numerator, norm_shift)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800240 goto err;
241 }
242 snum->neg = 0;
243
Robert Sloan8f860b12017-08-28 07:37:06 -0700244 // Since we don't want to have special-case logic for the case where snum is
245 // larger than sdiv, we pad snum with enough zeroes without changing its
246 // value.
Robert Sloan69939df2017-01-09 10:53:07 -0800247 if (snum->top <= sdiv->top + 1) {
Robert Sloan9254e682017-04-24 09:42:06 -0700248 if (!bn_wexpand(snum, sdiv->top + 2)) {
Robert Sloan69939df2017-01-09 10:53:07 -0800249 goto err;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800250 }
Robert Sloand5c22152017-11-13 09:22:12 -0800251 for (int i = snum->top; i < sdiv->top + 2; i++) {
Robert Sloan69939df2017-01-09 10:53:07 -0800252 snum->d[i] = 0;
253 }
254 snum->top = sdiv->top + 2;
255 } else {
Robert Sloan9254e682017-04-24 09:42:06 -0700256 if (!bn_wexpand(snum, snum->top + 1)) {
Robert Sloan69939df2017-01-09 10:53:07 -0800257 goto err;
258 }
259 snum->d[snum->top] = 0;
260 snum->top++;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800261 }
262
263 div_n = sdiv->top;
264 num_n = snum->top;
265 loop = num_n - div_n;
Robert Sloan8f860b12017-08-28 07:37:06 -0700266 // Lets setup a 'window' into snum
267 // This is the part that corresponds to the current
268 // 'area' being divided
Adam Langleyd9e397b2015-01-22 14:27:53 -0800269 wnum.neg = 0;
270 wnum.d = &(snum->d[loop]);
271 wnum.top = div_n;
Robert Sloan8f860b12017-08-28 07:37:06 -0700272 // only needed when BN_ucmp messes up the values between top and max
273 wnum.dmax = snum->dmax - loop; // so we don't step out of bounds
Adam Langleyd9e397b2015-01-22 14:27:53 -0800274
Robert Sloan8f860b12017-08-28 07:37:06 -0700275 // Get the top 2 words of sdiv
276 // div_n=sdiv->top;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800277 d0 = sdiv->d[div_n - 1];
278 d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2];
279
Robert Sloan8f860b12017-08-28 07:37:06 -0700280 // pointer to the 'top' of snum
Adam Langleyd9e397b2015-01-22 14:27:53 -0800281 wnump = &(snum->d[num_n - 1]);
282
Robert Sloan8f860b12017-08-28 07:37:06 -0700283 // Setup to 'res'
Robert Sloand5c22152017-11-13 09:22:12 -0800284 res->neg = (numerator->neg ^ divisor->neg);
285 if (!bn_wexpand(res, loop + 1)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800286 goto err;
287 }
Robert Sloan69939df2017-01-09 10:53:07 -0800288 res->top = loop - 1;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800289 resp = &(res->d[loop - 1]);
290
Robert Sloan8f860b12017-08-28 07:37:06 -0700291 // space for temp
Robert Sloand5c22152017-11-13 09:22:12 -0800292 if (!bn_wexpand(tmp, div_n + 1)) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800293 goto err;
294 }
295
Robert Sloan8f860b12017-08-28 07:37:06 -0700296 // if res->top == 0 then clear the neg value otherwise decrease
297 // the resp pointer
Adam Langleyd9e397b2015-01-22 14:27:53 -0800298 if (res->top == 0) {
299 res->neg = 0;
300 } else {
301 resp--;
302 }
303
Robert Sloand5c22152017-11-13 09:22:12 -0800304 for (int i = 0; i < loop - 1; i++, wnump--, resp--) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800305 BN_ULONG q, l0;
Robert Sloan8f860b12017-08-28 07:37:06 -0700306 // the first part of the loop uses the top two words of snum and sdiv to
307 // calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv
Robert Sloand5c22152017-11-13 09:22:12 -0800308 BN_ULONG n0, n1, rm = 0;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800309
310 n0 = wnump[0];
311 n1 = wnump[-1];
312 if (n0 == d0) {
313 q = BN_MASK2;
314 } else {
Robert Sloan8f860b12017-08-28 07:37:06 -0700315 // n0 < d0
Robert Sloand5c22152017-11-13 09:22:12 -0800316 bn_div_rem_words(&q, &rm, n0, n1, d0);
David Benjamin4969cc92016-04-22 15:02:23 -0400317
Adam Langley4139edb2016-01-13 15:00:54 -0800318#ifdef BN_ULLONG
David Benjamin4969cc92016-04-22 15:02:23 -0400319 BN_ULLONG t2 = (BN_ULLONG)d1 * q;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800320 for (;;) {
Robert Sloand5c22152017-11-13 09:22:12 -0800321 if (t2 <= ((((BN_ULLONG)rm) << BN_BITS2) | wnump[-2])) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800322 break;
Adam Langleye9ada862015-05-11 17:20:37 -0700323 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800324 q--;
Robert Sloand5c22152017-11-13 09:22:12 -0800325 rm += d0;
326 if (rm < d0) {
327 break; // don't let rm overflow
Adam Langleye9ada862015-05-11 17:20:37 -0700328 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800329 t2 -= d1;
330 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700331#else // !BN_ULLONG
Adam Langleyd9e397b2015-01-22 14:27:53 -0800332 BN_ULONG t2l, t2h;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800333 BN_UMULT_LOHI(t2l, t2h, d1, q);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800334 for (;;) {
Robert Sloand5c22152017-11-13 09:22:12 -0800335 if (t2h < rm ||
336 (t2h == rm && t2l <= wnump[-2])) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800337 break;
Adam Langleye9ada862015-05-11 17:20:37 -0700338 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800339 q--;
Robert Sloand5c22152017-11-13 09:22:12 -0800340 rm += d0;
341 if (rm < d0) {
342 break; // don't let rm overflow
Adam Langleye9ada862015-05-11 17:20:37 -0700343 }
344 if (t2l < d1) {
Adam Langleyd9e397b2015-01-22 14:27:53 -0800345 t2h--;
Adam Langleye9ada862015-05-11 17:20:37 -0700346 }
Adam Langleyd9e397b2015-01-22 14:27:53 -0800347 t2l -= d1;
348 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700349#endif // !BN_ULLONG
Adam Langleyd9e397b2015-01-22 14:27:53 -0800350 }
351
352 l0 = bn_mul_words(tmp->d, sdiv->d, div_n, q);
353 tmp->d[div_n] = l0;
354 wnum.d--;
Robert Sloan8f860b12017-08-28 07:37:06 -0700355 // ingore top values of the bignums just sub the two
356 // BN_ULONG arrays with bn_sub_words
Adam Langleyd9e397b2015-01-22 14:27:53 -0800357 if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700358 // Note: As we have considered only the leading
359 // two BN_ULONGs in the calculation of q, sdiv * q
360 // might be greater than wnum (but then (q-1) * sdiv
361 // is less or equal than wnum)
Adam Langleyd9e397b2015-01-22 14:27:53 -0800362 q--;
363 if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n)) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700364 // we can't have an overflow here (assuming
365 // that q != 0, but if q == 0 then tmp is
366 // zero anyway)
Adam Langleyd9e397b2015-01-22 14:27:53 -0800367 (*wnump)++;
368 }
369 }
Robert Sloan8f860b12017-08-28 07:37:06 -0700370 // store part of the result
Adam Langleyd9e397b2015-01-22 14:27:53 -0800371 *resp = q;
372 }
Robert Sloand5c22152017-11-13 09:22:12 -0800373
Adam Langleyd9e397b2015-01-22 14:27:53 -0800374 bn_correct_top(snum);
Robert Sloand5c22152017-11-13 09:22:12 -0800375
376 if (rem != NULL) {
377 // Keep a copy of the neg flag in numerator because if |rem| == |numerator|
378 // |BN_rshift| will overwrite it.
379 int neg = numerator->neg;
380 if (!BN_rshift(rem, snum, norm_shift)) {
Adam Langleye9ada862015-05-11 17:20:37 -0700381 goto err;
382 }
Robert Sloand5c22152017-11-13 09:22:12 -0800383 if (!BN_is_zero(rem)) {
384 rem->neg = neg;
Adam Langleyd9e397b2015-01-22 14:27:53 -0800385 }
386 }
Robert Sloand5c22152017-11-13 09:22:12 -0800387
Robert Sloan69939df2017-01-09 10:53:07 -0800388 bn_correct_top(res);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800389 BN_CTX_end(ctx);
390 return 1;
391
392err:
393 BN_CTX_end(ctx);
394 return 0;
395}
396
397int BN_nnmod(BIGNUM *r, const BIGNUM *m, const BIGNUM *d, BN_CTX *ctx) {
398 if (!(BN_mod(r, m, d, ctx))) {
399 return 0;
400 }
401 if (!r->neg) {
402 return 1;
403 }
404
Robert Sloan8f860b12017-08-28 07:37:06 -0700405 // now -|d| < r < 0, so we have to set r := r + |d|.
Adam Langleyd9e397b2015-01-22 14:27:53 -0800406 return (d->neg ? BN_sub : BN_add)(r, r, d);
407}
408
409int BN_mod_add(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
410 BN_CTX *ctx) {
411 if (!BN_add(r, a, b)) {
412 return 0;
413 }
414 return BN_nnmod(r, r, m, ctx);
415}
416
417int BN_mod_add_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
418 const BIGNUM *m) {
419 if (!BN_uadd(r, a, b)) {
420 return 0;
421 }
422 if (BN_ucmp(r, m) >= 0) {
423 return BN_usub(r, r, m);
424 }
425 return 1;
426}
427
428int BN_mod_sub(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
429 BN_CTX *ctx) {
430 if (!BN_sub(r, a, b)) {
431 return 0;
432 }
433 return BN_nnmod(r, r, m, ctx);
434}
435
Robert Sloan8f860b12017-08-28 07:37:06 -0700436// BN_mod_sub variant that may be used if both a and b are non-negative
437// and less than m
Adam Langleyd9e397b2015-01-22 14:27:53 -0800438int BN_mod_sub_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *b,
439 const BIGNUM *m) {
440 if (!BN_sub(r, a, b)) {
441 return 0;
442 }
443 if (r->neg) {
444 return BN_add(r, r, m);
445 }
446 return 1;
447}
448
449int BN_mod_mul(BIGNUM *r, const BIGNUM *a, const BIGNUM *b, const BIGNUM *m,
450 BN_CTX *ctx) {
451 BIGNUM *t;
452 int ret = 0;
453
454 BN_CTX_start(ctx);
455 t = BN_CTX_get(ctx);
456 if (t == NULL) {
457 goto err;
458 }
459
460 if (a == b) {
461 if (!BN_sqr(t, a, ctx)) {
462 goto err;
463 }
464 } else {
465 if (!BN_mul(t, a, b, ctx)) {
466 goto err;
467 }
468 }
469
470 if (!BN_nnmod(r, t, m, ctx)) {
471 goto err;
472 }
473
474 ret = 1;
475
476err:
477 BN_CTX_end(ctx);
478 return ret;
479}
480
481int BN_mod_sqr(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) {
482 if (!BN_sqr(r, a, ctx)) {
483 return 0;
484 }
485
Robert Sloan8f860b12017-08-28 07:37:06 -0700486 // r->neg == 0, thus we don't need BN_nnmod
Adam Langleyd9e397b2015-01-22 14:27:53 -0800487 return BN_mod(r, r, m, ctx);
488}
489
490int BN_mod_lshift(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m,
491 BN_CTX *ctx) {
492 BIGNUM *abs_m = NULL;
493 int ret;
494
495 if (!BN_nnmod(r, a, m, ctx)) {
496 return 0;
497 }
498
499 if (m->neg) {
500 abs_m = BN_dup(m);
501 if (abs_m == NULL) {
502 return 0;
503 }
504 abs_m->neg = 0;
505 }
506
507 ret = BN_mod_lshift_quick(r, r, n, (abs_m ? abs_m : m));
508
Adam Langleye9ada862015-05-11 17:20:37 -0700509 BN_free(abs_m);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800510 return ret;
511}
512
513int BN_mod_lshift_quick(BIGNUM *r, const BIGNUM *a, int n, const BIGNUM *m) {
514 if (r != a) {
515 if (BN_copy(r, a) == NULL) {
516 return 0;
517 }
518 }
519
520 while (n > 0) {
521 int max_shift;
522
Robert Sloan8f860b12017-08-28 07:37:06 -0700523 // 0 < r < m
Adam Langleyd9e397b2015-01-22 14:27:53 -0800524 max_shift = BN_num_bits(m) - BN_num_bits(r);
Robert Sloan8f860b12017-08-28 07:37:06 -0700525 // max_shift >= 0
Adam Langleyd9e397b2015-01-22 14:27:53 -0800526
527 if (max_shift < 0) {
Kenny Rootb8494592015-09-25 02:29:14 +0000528 OPENSSL_PUT_ERROR(BN, BN_R_INPUT_NOT_REDUCED);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800529 return 0;
530 }
531
532 if (max_shift > n) {
533 max_shift = n;
534 }
535
536 if (max_shift) {
537 if (!BN_lshift(r, r, max_shift)) {
538 return 0;
539 }
540 n -= max_shift;
541 } else {
542 if (!BN_lshift1(r, r)) {
543 return 0;
544 }
545 --n;
546 }
547
Robert Sloan8f860b12017-08-28 07:37:06 -0700548 // BN_num_bits(r) <= BN_num_bits(m)
Adam Langleyd9e397b2015-01-22 14:27:53 -0800549 if (BN_cmp(r, m) >= 0) {
550 if (!BN_sub(r, r, m)) {
551 return 0;
552 }
553 }
554 }
555
556 return 1;
557}
558
559int BN_mod_lshift1(BIGNUM *r, const BIGNUM *a, const BIGNUM *m, BN_CTX *ctx) {
560 if (!BN_lshift1(r, a)) {
561 return 0;
562 }
563
564 return BN_nnmod(r, r, m, ctx);
565}
566
567int BN_mod_lshift1_quick(BIGNUM *r, const BIGNUM *a, const BIGNUM *m) {
568 if (!BN_lshift1(r, a)) {
569 return 0;
570 }
571 if (BN_cmp(r, m) >= 0) {
572 return BN_sub(r, r, m);
573 }
574
575 return 1;
576}
577
578BN_ULONG BN_div_word(BIGNUM *a, BN_ULONG w) {
579 BN_ULONG ret = 0;
580 int i, j;
581
Adam Langleyd9e397b2015-01-22 14:27:53 -0800582 if (!w) {
Robert Sloan8f860b12017-08-28 07:37:06 -0700583 // actually this an error (division by zero)
Adam Langleyd9e397b2015-01-22 14:27:53 -0800584 return (BN_ULONG) - 1;
585 }
586
587 if (a->top == 0) {
588 return 0;
589 }
590
Robert Sloan8f860b12017-08-28 07:37:06 -0700591 // normalize input for |bn_div_rem_words|.
Adam Langleyd9e397b2015-01-22 14:27:53 -0800592 j = BN_BITS2 - BN_num_bits_word(w);
593 w <<= j;
594 if (!BN_lshift(a, a, j)) {
595 return (BN_ULONG) - 1;
596 }
597
598 for (i = a->top - 1; i >= 0; i--) {
David Benjamin4969cc92016-04-22 15:02:23 -0400599 BN_ULONG l = a->d[i];
600 BN_ULONG d;
601 BN_ULONG unused_rem;
602 bn_div_rem_words(&d, &unused_rem, ret, l, w);
Robert Sloan29c1d2c2017-10-30 14:10:28 -0700603 ret = l - (d * w);
Adam Langleyd9e397b2015-01-22 14:27:53 -0800604 a->d[i] = d;
605 }
606
607 if ((a->top > 0) && (a->d[a->top - 1] == 0)) {
608 a->top--;
609 }
610
Steven Valdez909b19f2016-11-21 15:35:44 -0500611 if (a->top == 0) {
612 a->neg = 0;
613 }
614
Adam Langleyd9e397b2015-01-22 14:27:53 -0800615 ret >>= j;
616 return ret;
617}
618
619BN_ULONG BN_mod_word(const BIGNUM *a, BN_ULONG w) {
Robert Sloan55818102017-12-18 11:26:17 -0800620#ifndef BN_CAN_DIVIDE_ULLONG
Adam Langleyd9e397b2015-01-22 14:27:53 -0800621 BN_ULONG ret = 0;
622#else
623 BN_ULLONG ret = 0;
624#endif
625 int i;
626
627 if (w == 0) {
628 return (BN_ULONG) -1;
629 }
630
Robert Sloan55818102017-12-18 11:26:17 -0800631#ifndef BN_CAN_DIVIDE_ULLONG
632 // If |w| is too long and we don't have |BN_ULLONG| division then we need to
633 // fall back to using |BN_div_word|.
David Benjamin6e899c72016-06-09 18:02:18 -0400634 if (w > ((BN_ULONG)1 << BN_BITS4)) {
635 BIGNUM *tmp = BN_dup(a);
636 if (tmp == NULL) {
637 return (BN_ULONG)-1;
638 }
639 ret = BN_div_word(tmp, w);
640 BN_free(tmp);
641 return ret;
642 }
643#endif
644
Adam Langleyd9e397b2015-01-22 14:27:53 -0800645 for (i = a->top - 1; i >= 0; i--) {
Robert Sloan55818102017-12-18 11:26:17 -0800646#ifndef BN_CAN_DIVIDE_ULLONG
Adam Langleyd9e397b2015-01-22 14:27:53 -0800647 ret = ((ret << BN_BITS4) | ((a->d[i] >> BN_BITS4) & BN_MASK2l)) % w;
648 ret = ((ret << BN_BITS4) | (a->d[i] & BN_MASK2l)) % w;
649#else
650 ret = (BN_ULLONG)(((ret << (BN_ULLONG)BN_BITS2) | a->d[i]) % (BN_ULLONG)w);
651#endif
652 }
653 return (BN_ULONG)ret;
654}
Robert Sloan5d625782017-02-13 09:55:39 -0800655
656int BN_mod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) {
657 if (e == 0 || a->top == 0) {
658 BN_zero(r);
659 return 1;
660 }
661
662 size_t num_words = 1 + ((e - 1) / BN_BITS2);
663
Robert Sloan8f860b12017-08-28 07:37:06 -0700664 // If |a| definitely has less than |e| bits, just BN_copy.
Robert Sloan5d625782017-02-13 09:55:39 -0800665 if ((size_t) a->top < num_words) {
666 return BN_copy(r, a) != NULL;
667 }
668
Robert Sloan8f860b12017-08-28 07:37:06 -0700669 // Otherwise, first make sure we have enough space in |r|.
670 // Note that this will fail if num_words > INT_MAX.
Robert Sloan9254e682017-04-24 09:42:06 -0700671 if (!bn_wexpand(r, num_words)) {
Robert Sloan5d625782017-02-13 09:55:39 -0800672 return 0;
673 }
674
Robert Sloan8f860b12017-08-28 07:37:06 -0700675 // Copy the content of |a| into |r|.
Robert Sloan5d625782017-02-13 09:55:39 -0800676 OPENSSL_memcpy(r->d, a->d, num_words * sizeof(BN_ULONG));
677
Robert Sloan8f860b12017-08-28 07:37:06 -0700678 // If |e| isn't word-aligned, we have to mask off some of our bits.
Robert Sloan5d625782017-02-13 09:55:39 -0800679 size_t top_word_exponent = e % (sizeof(BN_ULONG) * 8);
680 if (top_word_exponent != 0) {
681 r->d[num_words - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1;
682 }
683
Robert Sloan8f860b12017-08-28 07:37:06 -0700684 // Fill in the remaining fields of |r|.
Robert Sloan5d625782017-02-13 09:55:39 -0800685 r->neg = a->neg;
686 r->top = (int) num_words;
687 bn_correct_top(r);
688 return 1;
689}
690
691int BN_nnmod_pow2(BIGNUM *r, const BIGNUM *a, size_t e) {
692 if (!BN_mod_pow2(r, a, e)) {
693 return 0;
694 }
695
Robert Sloan8f860b12017-08-28 07:37:06 -0700696 // If the returned value was non-negative, we're done.
Robert Sloan5d625782017-02-13 09:55:39 -0800697 if (BN_is_zero(r) || !r->neg) {
698 return 1;
699 }
700
701 size_t num_words = 1 + (e - 1) / BN_BITS2;
702
Robert Sloan8f860b12017-08-28 07:37:06 -0700703 // Expand |r| to the size of our modulus.
Robert Sloan9254e682017-04-24 09:42:06 -0700704 if (!bn_wexpand(r, num_words)) {
Robert Sloan5d625782017-02-13 09:55:39 -0800705 return 0;
706 }
707
Robert Sloan8f860b12017-08-28 07:37:06 -0700708 // Clear the upper words of |r|.
Robert Sloan5d625782017-02-13 09:55:39 -0800709 OPENSSL_memset(&r->d[r->top], 0, (num_words - r->top) * BN_BYTES);
710
Robert Sloan8f860b12017-08-28 07:37:06 -0700711 // Set parameters of |r|.
Robert Sloan5d625782017-02-13 09:55:39 -0800712 r->neg = 0;
713 r->top = (int) num_words;
714
Robert Sloan8f860b12017-08-28 07:37:06 -0700715 // Now, invert every word. The idea here is that we want to compute 2^e-|x|,
716 // which is actually equivalent to the twos-complement representation of |x|
717 // in |e| bits, which is -x = ~x + 1.
Robert Sloan5d625782017-02-13 09:55:39 -0800718 for (int i = 0; i < r->top; i++) {
719 r->d[i] = ~r->d[i];
720 }
721
Robert Sloan8f860b12017-08-28 07:37:06 -0700722 // If our exponent doesn't span the top word, we have to mask the rest.
Robert Sloan5d625782017-02-13 09:55:39 -0800723 size_t top_word_exponent = e % BN_BITS2;
724 if (top_word_exponent != 0) {
725 r->d[r->top - 1] &= (((BN_ULONG) 1) << top_word_exponent) - 1;
726 }
727
Robert Sloan8f860b12017-08-28 07:37:06 -0700728 // Keep the correct_top invariant for BN_add.
Robert Sloan5d625782017-02-13 09:55:39 -0800729 bn_correct_top(r);
730
Robert Sloan8f860b12017-08-28 07:37:06 -0700731 // Finally, add one, for the reason described above.
Robert Sloan5d625782017-02-13 09:55:39 -0800732 return BN_add(r, r, BN_value_one());
733}