Coverage Report

Created: 2022-11-30 06:20

/src/openssl/crypto/bn/bn_div.c
Line
Count
Source (jump to first uncovered line)
1
/* crypto/bn/bn_div.c */
2
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3
 * All rights reserved.
4
 *
5
 * This package is an SSL implementation written
6
 * by Eric Young (eay@cryptsoft.com).
7
 * The implementation was written so as to conform with Netscapes SSL.
8
 *
9
 * This library is free for commercial and non-commercial use as long as
10
 * the following conditions are aheared to.  The following conditions
11
 * apply to all code found in this distribution, be it the RC4, RSA,
12
 * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
13
 * included with this distribution is covered by the same copyright terms
14
 * except that the holder is Tim Hudson (tjh@cryptsoft.com).
15
 *
16
 * Copyright remains Eric Young's, and as such any Copyright notices in
17
 * the code are not to be removed.
18
 * If this package is used in a product, Eric Young should be given attribution
19
 * as the author of the parts of the library used.
20
 * This can be in the form of a textual message at program startup or
21
 * in documentation (online or textual) provided with the package.
22
 *
23
 * Redistribution and use in source and binary forms, with or without
24
 * modification, are permitted provided that the following conditions
25
 * are met:
26
 * 1. Redistributions of source code must retain the copyright
27
 *    notice, this list of conditions and the following disclaimer.
28
 * 2. Redistributions in binary form must reproduce the above copyright
29
 *    notice, this list of conditions and the following disclaimer in the
30
 *    documentation and/or other materials provided with the distribution.
31
 * 3. All advertising materials mentioning features or use of this software
32
 *    must display the following acknowledgement:
33
 *    "This product includes cryptographic software written by
34
 *     Eric Young (eay@cryptsoft.com)"
35
 *    The word 'cryptographic' can be left out if the rouines from the library
36
 *    being used are not cryptographic related :-).
37
 * 4. If you include any Windows specific code (or a derivative thereof) from
38
 *    the apps directory (application code) you must include an acknowledgement:
39
 *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
40
 *
41
 * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
42
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
43
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
44
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
45
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
46
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
47
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
48
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
49
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
50
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51
 * SUCH DAMAGE.
52
 *
53
 * The licence and distribution terms for any publically available version or
54
 * derivative of this code cannot be changed.  i.e. this code cannot simply be
55
 * copied and put under another distribution licence
56
 * [including the GNU Public Licence.]
57
 */
58
59
#include <stdio.h>
60
#include <openssl/bn.h>
61
#include "cryptlib.h"
62
#include "bn_lcl.h"
63
64
/* The old slow way */
65
#if 0
66
int BN_div(BIGNUM *dv, BIGNUM *rem, const BIGNUM *m, const BIGNUM *d,
67
           BN_CTX *ctx)
68
{
69
    int i, nm, nd;
70
    int ret = 0;
71
    BIGNUM *D;
72
73
    bn_check_top(m);
74
    bn_check_top(d);
75
    if (BN_is_zero(d)) {
76
        BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO);
77
        return (0);
78
    }
79
80
    if (BN_ucmp(m, d) < 0) {
81
        if (rem != NULL) {
82
            if (BN_copy(rem, m) == NULL)
83
                return (0);
84
        }
85
        if (dv != NULL)
86
            BN_zero(dv);
87
        return (1);
88
    }
89
90
    BN_CTX_start(ctx);
91
    D = BN_CTX_get(ctx);
92
    if (dv == NULL)
93
        dv = BN_CTX_get(ctx);
94
    if (rem == NULL)
95
        rem = BN_CTX_get(ctx);
96
    if (D == NULL || dv == NULL || rem == NULL)
97
        goto end;
98
99
    nd = BN_num_bits(d);
100
    nm = BN_num_bits(m);
101
    if (BN_copy(D, d) == NULL)
102
        goto end;
103
    if (BN_copy(rem, m) == NULL)
104
        goto end;
105
106
    /*
107
     * The next 2 are needed so we can do a dv->d[0]|=1 later since
108
     * BN_lshift1 will only work once there is a value :-)
109
     */
110
    BN_zero(dv);
111
    if (bn_wexpand(dv, 1) == NULL)
112
        goto end;
113
    dv->top = 1;
114
115
    if (!BN_lshift(D, D, nm - nd))
116
        goto end;
117
    for (i = nm - nd; i >= 0; i--) {
118
        if (!BN_lshift1(dv, dv))
119
            goto end;
120
        if (BN_ucmp(rem, D) >= 0) {
121
            dv->d[0] |= 1;
122
            if (!BN_usub(rem, rem, D))
123
                goto end;
124
        }
125
/* CAN IMPROVE (and have now :=) */
126
        if (!BN_rshift1(D, D))
127
            goto end;
128
    }
129
    rem->neg = BN_is_zero(rem) ? 0 : m->neg;
130
    dv->neg = m->neg ^ d->neg;
131
    ret = 1;
132
 end:
133
    BN_CTX_end(ctx);
134
    return (ret);
135
}
136
137
#else
138
139
# if !defined(OPENSSL_NO_ASM) && !defined(OPENSSL_NO_INLINE_ASM) \
140
    && !defined(PEDANTIC) && !defined(BN_DIV3W)
141
#  if defined(__GNUC__) && __GNUC__>=2
142
#   if defined(__i386) || defined (__i386__)
143
   /*-
144
    * There were two reasons for implementing this template:
145
    * - GNU C generates a call to a function (__udivdi3 to be exact)
146
    *   in reply to ((((BN_ULLONG)n0)<<BN_BITS2)|n1)/d0 (I fail to
147
    *   understand why...);
148
    * - divl doesn't only calculate quotient, but also leaves
149
    *   remainder in %edx which we can definitely use here:-)
150
    *
151
    *                                   <appro@fy.chalmers.se>
152
    */
153
#    undef bn_div_words
154
#    define bn_div_words(n0,n1,d0)                \
155
        ({  asm volatile (                      \
156
                "divl   %4"                     \
157
                : "=a"(q), "=d"(rem)            \
158
                : "a"(n1), "d"(n0), "r"(d0)     \
159
                : "cc");                        \
160
            q;                                  \
161
        })
162
#    define REMAINDER_IS_ALREADY_CALCULATED
163
#   elif defined(__x86_64) && defined(SIXTY_FOUR_BIT_LONG)
164
   /*
165
    * Same story here, but it's 128-bit by 64-bit division. Wow!
166
    *                                   <appro@fy.chalmers.se>
167
    */
168
#    undef bn_div_words
169
#    define bn_div_words(n0,n1,d0)                \
170
        ({  asm volatile (                      \
171
                "divq   %4"                     \
172
                : "=a"(q), "=d"(rem)            \
173
                : "a"(n1), "d"(n0), "r"(d0)     \
174
                : "cc");                        \
175
            q;                                  \
176
        })
177
#    define REMAINDER_IS_ALREADY_CALCULATED
178
#   endif                       /* __<cpu> */
179
#  endif                        /* __GNUC__ */
180
# endif                         /* OPENSSL_NO_ASM */
181
182
/*-
183
 * BN_div computes  dv := num / divisor,  rounding towards
184
 * zero, and sets up rm  such that  dv*divisor + rm = num  holds.
185
 * Thus:
186
 *     dv->neg == num->neg ^ divisor->neg  (unless the result is zero)
187
 *     rm->neg == num->neg                 (unless the remainder is zero)
188
 * If 'dv' or 'rm' is NULL, the respective value is not returned.
189
 */
190
int BN_div(BIGNUM *dv, BIGNUM *rm, const BIGNUM *num, const BIGNUM *divisor,
191
           BN_CTX *ctx)
192
0
{
193
0
    int norm_shift, i, loop;
194
0
    BIGNUM *tmp, wnum, *snum, *sdiv, *res;
195
0
    BN_ULONG *resp, *wnump;
196
0
    BN_ULONG d0, d1;
197
0
    int num_n, div_n;
198
0
    int no_branch = 0;
199
200
    /*
201
     * Invalid zero-padding would have particularly bad consequences so don't
202
     * just rely on bn_check_top() here (bn_check_top() works only for
203
     * BN_DEBUG builds)
204
     */
205
0
    if ((num->top > 0 && num->d[num->top - 1] == 0) ||
206
0
        (divisor->top > 0 && divisor->d[divisor->top - 1] == 0)) {
207
0
        BNerr(BN_F_BN_DIV, BN_R_NOT_INITIALIZED);
208
0
        return 0;
209
0
    }
210
211
0
    bn_check_top(num);
212
0
    bn_check_top(divisor);
213
214
0
    if ((BN_get_flags(num, BN_FLG_CONSTTIME) != 0)
215
0
        || (BN_get_flags(divisor, BN_FLG_CONSTTIME) != 0)) {
216
0
        no_branch = 1;
217
0
    }
218
219
0
    bn_check_top(dv);
220
0
    bn_check_top(rm);
221
    /*- bn_check_top(num); *//*
222
     * 'num' has been checked already
223
     */
224
    /*- bn_check_top(divisor); *//*
225
     * 'divisor' has been checked already
226
     */
227
228
0
    if (BN_is_zero(divisor)) {
229
0
        BNerr(BN_F_BN_DIV, BN_R_DIV_BY_ZERO);
230
0
        return (0);
231
0
    }
232
233
0
    if (!no_branch && BN_ucmp(num, divisor) < 0) {
234
0
        if (rm != NULL) {
235
0
            if (BN_copy(rm, num) == NULL)
236
0
                return (0);
237
0
        }
238
0
        if (dv != NULL)
239
0
            BN_zero(dv);
240
0
        return (1);
241
0
    }
242
243
0
    BN_CTX_start(ctx);
244
0
    tmp = BN_CTX_get(ctx);
245
0
    snum = BN_CTX_get(ctx);
246
0
    sdiv = BN_CTX_get(ctx);
247
0
    if (dv == NULL)
248
0
        res = BN_CTX_get(ctx);
249
0
    else
250
0
        res = dv;
251
0
    if (sdiv == NULL || res == NULL || tmp == NULL || snum == NULL)
252
0
        goto err;
253
254
    /* First we normalise the numbers */
255
0
    norm_shift = BN_BITS2 - ((BN_num_bits(divisor)) % BN_BITS2);
256
0
    if (!(BN_lshift(sdiv, divisor, norm_shift)))
257
0
        goto err;
258
0
    sdiv->neg = 0;
259
0
    norm_shift += BN_BITS2;
260
0
    if (!(BN_lshift(snum, num, norm_shift)))
261
0
        goto err;
262
0
    snum->neg = 0;
263
264
0
    if (no_branch) {
265
        /*
266
         * Since we don't know whether snum is larger than sdiv, we pad snum
267
         * with enough zeroes without changing its value.
268
         */
269
0
        if (snum->top <= sdiv->top + 1) {
270
0
            if (bn_wexpand(snum, sdiv->top + 2) == NULL)
271
0
                goto err;
272
0
            for (i = snum->top; i < sdiv->top + 2; i++)
273
0
                snum->d[i] = 0;
274
0
            snum->top = sdiv->top + 2;
275
0
        } else {
276
0
            if (bn_wexpand(snum, snum->top + 1) == NULL)
277
0
                goto err;
278
0
            snum->d[snum->top] = 0;
279
0
            snum->top++;
280
0
        }
281
0
    }
282
283
0
    div_n = sdiv->top;
284
0
    num_n = snum->top;
285
0
    loop = num_n - div_n;
286
    /*
287
     * Lets setup a 'window' into snum This is the part that corresponds to
288
     * the current 'area' being divided
289
     */
290
0
    wnum.neg = 0;
291
0
    wnum.d = &(snum->d[loop]);
292
0
    wnum.top = div_n;
293
    /*
294
     * only needed when BN_ucmp messes up the values between top and max
295
     */
296
0
    wnum.dmax = snum->dmax - loop; /* so we don't step out of bounds */
297
298
    /* Get the top 2 words of sdiv */
299
    /* div_n=sdiv->top; */
300
0
    d0 = sdiv->d[div_n - 1];
301
0
    d1 = (div_n == 1) ? 0 : sdiv->d[div_n - 2];
302
303
    /* pointer to the 'top' of snum */
304
0
    wnump = &(snum->d[num_n - 1]);
305
306
    /* Setup to 'res' */
307
0
    res->neg = (num->neg ^ divisor->neg);
308
0
    if (!bn_wexpand(res, (loop + 1)))
309
0
        goto err;
310
0
    res->top = loop - no_branch;
311
0
    resp = &(res->d[loop - 1]);
312
313
    /* space for temp */
314
0
    if (!bn_wexpand(tmp, (div_n + 1)))
315
0
        goto err;
316
317
0
    if (!no_branch) {
318
0
        if (BN_ucmp(&wnum, sdiv) >= 0) {
319
            /*
320
             * If BN_DEBUG_RAND is defined BN_ucmp changes (via bn_pollute)
321
             * the const bignum arguments => clean the values between top and
322
             * max again
323
             */
324
0
            bn_clear_top2max(&wnum);
325
0
            bn_sub_words(wnum.d, wnum.d, sdiv->d, div_n);
326
0
            *resp = 1;
327
0
        } else
328
0
            res->top--;
329
0
    }
330
331
    /*
332
     * if res->top == 0 then clear the neg value otherwise decrease the resp
333
     * pointer
334
     */
335
0
    if (res->top == 0)
336
0
        res->neg = 0;
337
0
    else
338
0
        resp--;
339
340
0
    for (i = 0; i < loop - 1; i++, wnump--, resp--) {
341
0
        BN_ULONG q, l0;
342
        /*
343
         * the first part of the loop uses the top two words of snum and sdiv
344
         * to calculate a BN_ULONG q such that | wnum - sdiv * q | < sdiv
345
         */
346
# if defined(BN_DIV3W) && !defined(OPENSSL_NO_ASM)
347
        BN_ULONG bn_div_3_words(BN_ULONG *, BN_ULONG, BN_ULONG);
348
        q = bn_div_3_words(wnump, d1, d0);
349
# else
350
0
        BN_ULONG n0, n1, rem = 0;
351
352
0
        n0 = wnump[0];
353
0
        n1 = wnump[-1];
354
0
        if (n0 == d0)
355
0
            q = BN_MASK2;
356
0
        else {                  /* n0 < d0 */
357
358
#  ifdef BN_LLONG
359
            BN_ULLONG t2;
360
361
#   if defined(BN_LLONG) && defined(BN_DIV2W) && !defined(bn_div_words)
362
            q = (BN_ULONG)(((((BN_ULLONG) n0) << BN_BITS2) | n1) / d0);
363
#   else
364
            q = bn_div_words(n0, n1, d0);
365
#    ifdef BN_DEBUG_LEVITTE
366
            fprintf(stderr, "DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\
367
X) -> 0x%08X\n", n0, n1, d0, q);
368
#    endif
369
#   endif
370
371
#   ifndef REMAINDER_IS_ALREADY_CALCULATED
372
            /*
373
             * rem doesn't have to be BN_ULLONG. The least we
374
             * know it's less that d0, isn't it?
375
             */
376
            rem = (n1 - q * d0) & BN_MASK2;
377
#   endif
378
            t2 = (BN_ULLONG) d1 *q;
379
380
            for (;;) {
381
                if (t2 <= ((((BN_ULLONG) rem) << BN_BITS2) | wnump[-2]))
382
                    break;
383
                q--;
384
                rem += d0;
385
                if (rem < d0)
386
                    break;      /* don't let rem overflow */
387
                t2 -= d1;
388
            }
389
#  else                         /* !BN_LLONG */
390
0
            BN_ULONG t2l, t2h;
391
392
0
            q = bn_div_words(n0, n1, d0);
393
#   ifdef BN_DEBUG_LEVITTE
394
            fprintf(stderr, "DEBUG: bn_div_words(0x%08X,0x%08X,0x%08\
395
X) -> 0x%08X\n", n0, n1, d0, q);
396
#   endif
397
0
#   ifndef REMAINDER_IS_ALREADY_CALCULATED
398
0
            rem = (n1 - q * d0) & BN_MASK2;
399
0
#   endif
400
401
#   if defined(BN_UMULT_LOHI)
402
            BN_UMULT_LOHI(t2l, t2h, d1, q);
403
#   elif defined(BN_UMULT_HIGH)
404
            t2l = d1 * q;
405
            t2h = BN_UMULT_HIGH(d1, q);
406
#   else
407
0
            {
408
0
                BN_ULONG ql, qh;
409
0
                t2l = LBITS(d1);
410
0
                t2h = HBITS(d1);
411
0
                ql = LBITS(q);
412
0
                qh = HBITS(q);
413
0
                mul64(t2l, t2h, ql, qh); /* t2=(BN_ULLONG)d1*q; */
414
0
            }
415
0
#   endif
416
417
0
            for (;;) {
418
0
                if ((t2h < rem) || ((t2h == rem) && (t2l <= wnump[-2])))
419
0
                    break;
420
0
                q--;
421
0
                rem += d0;
422
0
                if (rem < d0)
423
0
                    break;      /* don't let rem overflow */
424
0
                if (t2l < d1)
425
0
                    t2h--;
426
0
                t2l -= d1;
427
0
            }
428
0
#  endif                        /* !BN_LLONG */
429
0
        }
430
0
# endif                         /* !BN_DIV3W */
431
432
0
        l0 = bn_mul_words(tmp->d, sdiv->d, div_n, q);
433
0
        tmp->d[div_n] = l0;
434
0
        wnum.d--;
435
        /*
436
         * ingore top values of the bignums just sub the two BN_ULONG arrays
437
         * with bn_sub_words
438
         */
439
0
        if (bn_sub_words(wnum.d, wnum.d, tmp->d, div_n + 1)) {
440
            /*
441
             * Note: As we have considered only the leading two BN_ULONGs in
442
             * the calculation of q, sdiv * q might be greater than wnum (but
443
             * then (q-1) * sdiv is less or equal than wnum)
444
             */
445
0
            q--;
446
0
            if (bn_add_words(wnum.d, wnum.d, sdiv->d, div_n))
447
                /*
448
                 * we can't have an overflow here (assuming that q != 0, but
449
                 * if q == 0 then tmp is zero anyway)
450
                 */
451
0
                (*wnump)++;
452
0
        }
453
        /* store part of the result */
454
0
        *resp = q;
455
0
    }
456
0
    bn_correct_top(snum);
457
0
    if (rm != NULL) {
458
        /*
459
         * Keep a copy of the neg flag in num because if rm==num BN_rshift()
460
         * will overwrite it.
461
         */
462
0
        int neg = num->neg;
463
0
        BN_rshift(rm, snum, norm_shift);
464
0
        if (!BN_is_zero(rm))
465
0
            rm->neg = neg;
466
0
        bn_check_top(rm);
467
0
    }
468
0
    if (no_branch)
469
0
        bn_correct_top(res);
470
0
    BN_CTX_end(ctx);
471
0
    return (1);
472
0
 err:
473
0
    bn_check_top(rm);
474
0
    BN_CTX_end(ctx);
475
0
    return (0);
476
0
}
477
#endif