~ubuntu-branches/ubuntu/precise/gnupg2/precise-proposed

« back to all changes in this revision

Viewing changes to mpi/mpih-div.c

  • Committer: Bazaar Package Importer
  • Author(s): Matthias Urlichs
  • Date: 2006-01-24 04:31:42 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060124043142-pbg192or6qxv3yk2
Tags: 1.9.20-1
* New Upstream version. Closes:#306890,#344530
  * Closes:#320490: gpg-protect-tool fails to decrypt PKCS-12 files 
* Depend on libopensc2-dev, not -1-. Closes:#348106

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* mpihelp-div.c  -  MPI helper functions
 
2
 *      Copyright (C) 1994, 1996 Free Software Foundation, Inc.
 
3
 *      Copyright (C) 1998, 1999 Free Software Foundation, Inc.
 
4
 *
 
5
 * This file is part of GnuPG.
 
6
 *
 
7
 * GnuPG is free software; you can redistribute it and/or modify
 
8
 * it under the terms of the GNU General Public License as published by
 
9
 * the Free Software Foundation; either version 2 of the License, or
 
10
 * (at your option) any later version.
 
11
 *
 
12
 * GnuPG is distributed in the hope that it will be useful,
 
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
15
 * GNU General Public License for more details.
 
16
 *
 
17
 * You should have received a copy of the GNU General Public License
 
18
 * along with this program; if not, write to the Free Software
 
19
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
 
20
 *
 
21
 * Note: This code is heavily based on the GNU MP Library.
 
22
 *       Actually it's the same code with only minor changes in the
 
23
 *       way the data is stored; this is to support the abstraction
 
24
 *       of an optional secure memory allocation which may be used
 
25
 *       to avoid revealing of sensitive data due to paging etc.
 
26
 *       The GNU MP Library itself is published under the LGPL;
 
27
 *       however I decided to publish this code under the plain GPL.
 
28
 */
 
29
 
 
30
#include <config.h>
 
31
#include <stdio.h>
 
32
#include <stdlib.h>
 
33
#include "mpi-internal.h"
 
34
#include "longlong.h"
 
35
 
 
36
#ifndef UMUL_TIME
 
37
  #define UMUL_TIME 1
 
38
#endif
 
39
#ifndef UDIV_TIME
 
40
  #define UDIV_TIME UMUL_TIME
 
41
#endif
 
42
 
 
43
/* FIXME: We should be using invert_limb (or invert_normalized_limb)
 
44
 * here (not udiv_qrnnd).
 
45
 */
 
46
 
 
47
mpi_limb_t
 
48
mpihelp_mod_1(mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
 
49
                                      mpi_limb_t divisor_limb)
 
50
{
 
51
    mpi_size_t i;
 
52
    mpi_limb_t n1, n0, r;
 
53
    int dummy;
 
54
 
 
55
    /* Botch: Should this be handled at all?  Rely on callers?  */
 
56
    if( !dividend_size )
 
57
        return 0;
 
58
 
 
59
    /* If multiplication is much faster than division, and the
 
60
     * dividend is large, pre-invert the divisor, and use
 
61
     * only multiplications in the inner loop.
 
62
     *
 
63
     * This test should be read:
 
64
     *   Does it ever help to use udiv_qrnnd_preinv?
 
65
     *     && Does what we save compensate for the inversion overhead?
 
66
     */
 
67
    if( UDIV_TIME > (2 * UMUL_TIME + 6)
 
68
        && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME ) {
 
69
        int normalization_steps;
 
70
 
 
71
        count_leading_zeros( normalization_steps, divisor_limb );
 
72
        if( normalization_steps ) {
 
73
            mpi_limb_t divisor_limb_inverted;
 
74
 
 
75
            divisor_limb <<= normalization_steps;
 
76
 
 
77
            /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
 
78
             * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
 
79
             * most significant bit (with weight 2**N) implicit.
 
80
             *
 
81
             * Special case for DIVISOR_LIMB == 100...000.
 
82
             */
 
83
            if( !(divisor_limb << 1) )
 
84
                divisor_limb_inverted = ~(mpi_limb_t)0;
 
85
            else
 
86
                udiv_qrnnd(divisor_limb_inverted, dummy,
 
87
                           -divisor_limb, 0, divisor_limb);
 
88
 
 
89
            n1 = dividend_ptr[dividend_size - 1];
 
90
            r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
 
91
 
 
92
            /* Possible optimization:
 
93
             * if (r == 0
 
94
             * && divisor_limb > ((n1 << normalization_steps)
 
95
             *                 | (dividend_ptr[dividend_size - 2] >> ...)))
 
96
             * ...one division less...
 
97
             */
 
98
            for( i = dividend_size - 2; i >= 0; i--) {
 
99
                n0 = dividend_ptr[i];
 
100
                UDIV_QRNND_PREINV(dummy, r, r,
 
101
                                   ((n1 << normalization_steps)
 
102
                          | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
 
103
                          divisor_limb, divisor_limb_inverted);
 
104
                n1 = n0;
 
105
            }
 
106
            UDIV_QRNND_PREINV(dummy, r, r,
 
107
                              n1 << normalization_steps,
 
108
                              divisor_limb, divisor_limb_inverted);
 
109
            return r >> normalization_steps;
 
110
        }
 
111
        else {
 
112
            mpi_limb_t divisor_limb_inverted;
 
113
 
 
114
            /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
 
115
             * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
 
116
             * most significant bit (with weight 2**N) implicit.
 
117
             *
 
118
             * Special case for DIVISOR_LIMB == 100...000.
 
119
             */
 
120
            if( !(divisor_limb << 1) )
 
121
                divisor_limb_inverted = ~(mpi_limb_t)0;
 
122
            else
 
123
                udiv_qrnnd(divisor_limb_inverted, dummy,
 
124
                            -divisor_limb, 0, divisor_limb);
 
125
 
 
126
            i = dividend_size - 1;
 
127
            r = dividend_ptr[i];
 
128
 
 
129
            if( r >= divisor_limb )
 
130
                r = 0;
 
131
            else
 
132
                i--;
 
133
 
 
134
            for( ; i >= 0; i--) {
 
135
                n0 = dividend_ptr[i];
 
136
                UDIV_QRNND_PREINV(dummy, r, r,
 
137
                                  n0, divisor_limb, divisor_limb_inverted);
 
138
            }
 
139
            return r;
 
140
        }
 
141
    }
 
142
    else {
 
143
        if( UDIV_NEEDS_NORMALIZATION ) {
 
144
            int normalization_steps;
 
145
 
 
146
            count_leading_zeros(normalization_steps, divisor_limb);
 
147
            if( normalization_steps ) {
 
148
                divisor_limb <<= normalization_steps;
 
149
 
 
150
                n1 = dividend_ptr[dividend_size - 1];
 
151
                r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
 
152
 
 
153
                /* Possible optimization:
 
154
                 * if (r == 0
 
155
                 * && divisor_limb > ((n1 << normalization_steps)
 
156
                 *                 | (dividend_ptr[dividend_size - 2] >> ...)))
 
157
                 * ...one division less...
 
158
                 */
 
159
                for(i = dividend_size - 2; i >= 0; i--) {
 
160
                    n0 = dividend_ptr[i];
 
161
                    udiv_qrnnd (dummy, r, r,
 
162
                                ((n1 << normalization_steps)
 
163
                         | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
 
164
                         divisor_limb);
 
165
                    n1 = n0;
 
166
                }
 
167
                udiv_qrnnd (dummy, r, r,
 
168
                            n1 << normalization_steps,
 
169
                            divisor_limb);
 
170
                return r >> normalization_steps;
 
171
            }
 
172
        }
 
173
        /* No normalization needed, either because udiv_qrnnd doesn't require
 
174
         * it, or because DIVISOR_LIMB is already normalized.  */
 
175
        i = dividend_size - 1;
 
176
        r = dividend_ptr[i];
 
177
 
 
178
        if(r >= divisor_limb)
 
179
            r = 0;
 
180
        else
 
181
            i--;
 
182
 
 
183
        for(; i >= 0; i--) {
 
184
            n0 = dividend_ptr[i];
 
185
            udiv_qrnnd (dummy, r, r, n0, divisor_limb);
 
186
        }
 
187
        return r;
 
188
    }
 
189
}
 
190
 
 
191
/* Divide num (NP/NSIZE) by den (DP/DSIZE) and write
 
192
 * the NSIZE-DSIZE least significant quotient limbs at QP
 
193
 * and the DSIZE long remainder at NP.  If QEXTRA_LIMBS is
 
194
 * non-zero, generate that many fraction bits and append them after the
 
195
 * other quotient limbs.
 
196
 * Return the most significant limb of the quotient, this is always 0 or 1.
 
197
 *
 
198
 * Preconditions:
 
199
 * 0. NSIZE >= DSIZE.
 
200
 * 1. The most significant bit of the divisor must be set.
 
201
 * 2. QP must either not overlap with the input operands at all, or
 
202
 *    QP + DSIZE >= NP must hold true.  (This means that it's
 
203
 *    possible to put the quotient in the high part of NUM, right after the
 
204
 *    remainder in NUM.
 
205
 * 3. NSIZE >= DSIZE, even if QEXTRA_LIMBS is non-zero.
 
206
 */
 
207
 
 
208
mpi_limb_t
 
209
mpihelp_divrem( mpi_ptr_t qp, mpi_size_t qextra_limbs,
 
210
                mpi_ptr_t np, mpi_size_t nsize,
 
211
                mpi_ptr_t dp, mpi_size_t dsize)
 
212
{
 
213
    mpi_limb_t most_significant_q_limb = 0;
 
214
 
 
215
    switch(dsize) {
 
216
      case 0:
 
217
        /* We are asked to divide by zero, so go ahead and do it!  (To make
 
218
           the compiler not remove this statement, return the value.)  */
 
219
        return 1 / dsize;
 
220
 
 
221
      case 1:
 
222
        {
 
223
            mpi_size_t i;
 
224
            mpi_limb_t n1;
 
225
            mpi_limb_t d;
 
226
 
 
227
            d = dp[0];
 
228
            n1 = np[nsize - 1];
 
229
 
 
230
            if( n1 >= d ) {
 
231
                n1 -= d;
 
232
                most_significant_q_limb = 1;
 
233
            }
 
234
 
 
235
            qp += qextra_limbs;
 
236
            for( i = nsize - 2; i >= 0; i--)
 
237
                udiv_qrnnd( qp[i], n1, n1, np[i], d );
 
238
            qp -= qextra_limbs;
 
239
 
 
240
            for( i = qextra_limbs - 1; i >= 0; i-- )
 
241
                udiv_qrnnd (qp[i], n1, n1, 0, d);
 
242
 
 
243
            np[0] = n1;
 
244
        }
 
245
        break;
 
246
 
 
247
      case 2:
 
248
        {
 
249
            mpi_size_t i;
 
250
            mpi_limb_t n1, n0, n2;
 
251
            mpi_limb_t d1, d0;
 
252
 
 
253
            np += nsize - 2;
 
254
            d1 = dp[1];
 
255
            d0 = dp[0];
 
256
            n1 = np[1];
 
257
            n0 = np[0];
 
258
 
 
259
            if( n1 >= d1 && (n1 > d1 || n0 >= d0) ) {
 
260
                sub_ddmmss (n1, n0, n1, n0, d1, d0);
 
261
                most_significant_q_limb = 1;
 
262
            }
 
263
 
 
264
            for( i = qextra_limbs + nsize - 2 - 1; i >= 0; i-- ) {
 
265
                mpi_limb_t q;
 
266
                mpi_limb_t r;
 
267
 
 
268
                if( i >= qextra_limbs )
 
269
                    np--;
 
270
                else
 
271
                    np[0] = 0;
 
272
 
 
273
                if( n1 == d1 ) {
 
274
                    /* Q should be either 111..111 or 111..110.  Need special
 
275
                     * treatment of this rare case as normal division would
 
276
                     * give overflow.  */
 
277
                    q = ~(mpi_limb_t)0;
 
278
 
 
279
                    r = n0 + d1;
 
280
                    if( r < d1 ) {   /* Carry in the addition? */
 
281
                        add_ssaaaa( n1, n0, r - d0, np[0], 0, d0 );
 
282
                        qp[i] = q;
 
283
                        continue;
 
284
                    }
 
285
                    n1 = d0 - (d0 != 0?1:0);
 
286
                    n0 = -d0;
 
287
                }
 
288
                else {
 
289
                    udiv_qrnnd (q, r, n1, n0, d1);
 
290
                    umul_ppmm (n1, n0, d0, q);
 
291
                }
 
292
 
 
293
                n2 = np[0];
 
294
              q_test:
 
295
                if( n1 > r || (n1 == r && n0 > n2) ) {
 
296
                    /* The estimated Q was too large.  */
 
297
                    q--;
 
298
                    sub_ddmmss (n1, n0, n1, n0, 0, d0);
 
299
                    r += d1;
 
300
                    if( r >= d1 )    /* If not carry, test Q again.  */
 
301
                        goto q_test;
 
302
                }
 
303
 
 
304
                qp[i] = q;
 
305
                sub_ddmmss (n1, n0, r, n2, n1, n0);
 
306
            }
 
307
            np[1] = n1;
 
308
            np[0] = n0;
 
309
        }
 
310
        break;
 
311
 
 
312
      default:
 
313
        {
 
314
            mpi_size_t i;
 
315
            mpi_limb_t dX, d1, n0;
 
316
 
 
317
            np += nsize - dsize;
 
318
            dX = dp[dsize - 1];
 
319
            d1 = dp[dsize - 2];
 
320
            n0 = np[dsize - 1];
 
321
 
 
322
            if( n0 >= dX ) {
 
323
                if(n0 > dX || mpihelp_cmp(np, dp, dsize - 1) >= 0 ) {
 
324
                    mpihelp_sub_n(np, np, dp, dsize);
 
325
                    n0 = np[dsize - 1];
 
326
                    most_significant_q_limb = 1;
 
327
                }
 
328
            }
 
329
 
 
330
            for( i = qextra_limbs + nsize - dsize - 1; i >= 0; i--) {
 
331
                mpi_limb_t q;
 
332
                mpi_limb_t n1, n2;
 
333
                mpi_limb_t cy_limb;
 
334
 
 
335
                if( i >= qextra_limbs ) {
 
336
                    np--;
 
337
                    n2 = np[dsize];
 
338
                }
 
339
                else {
 
340
                    n2 = np[dsize - 1];
 
341
                    MPN_COPY_DECR (np + 1, np, dsize - 1);
 
342
                    np[0] = 0;
 
343
                }
 
344
 
 
345
                if( n0 == dX ) {
 
346
                    /* This might over-estimate q, but it's probably not worth
 
347
                     * the extra code here to find out.  */
 
348
                    q = ~(mpi_limb_t)0;
 
349
                }
 
350
                else {
 
351
                    mpi_limb_t r;
 
352
 
 
353
                    udiv_qrnnd(q, r, n0, np[dsize - 1], dX);
 
354
                    umul_ppmm(n1, n0, d1, q);
 
355
 
 
356
                    while( n1 > r || (n1 == r && n0 > np[dsize - 2])) {
 
357
                        q--;
 
358
                        r += dX;
 
359
                        if( r < dX ) /* I.e. "carry in previous addition?" */
 
360
                            break;
 
361
                        n1 -= n0 < d1;
 
362
                        n0 -= d1;
 
363
                    }
 
364
                }
 
365
 
 
366
                /* Possible optimization: We already have (q * n0) and (1 * n1)
 
367
                 * after the calculation of q.  Taking advantage of that, we
 
368
                 * could make this loop make two iterations less.  */
 
369
                cy_limb = mpihelp_submul_1(np, dp, dsize, q);
 
370
 
 
371
                if( n2 != cy_limb ) {
 
372
                    mpihelp_add_n(np, np, dp, dsize);
 
373
                    q--;
 
374
                }
 
375
 
 
376
                qp[i] = q;
 
377
                n0 = np[dsize - 1];
 
378
            }
 
379
        }
 
380
    }
 
381
 
 
382
    return most_significant_q_limb;
 
383
}
 
384
 
 
385
 
 
386
/****************
 
387
 * Divide (DIVIDEND_PTR,,DIVIDEND_SIZE) by DIVISOR_LIMB.
 
388
 * Write DIVIDEND_SIZE limbs of quotient at QUOT_PTR.
 
389
 * Return the single-limb remainder.
 
390
 * There are no constraints on the value of the divisor.
 
391
 *
 
392
 * QUOT_PTR and DIVIDEND_PTR might point to the same limb.
 
393
 */
 
394
 
 
395
mpi_limb_t
 
396
mpihelp_divmod_1( mpi_ptr_t quot_ptr,
 
397
                  mpi_ptr_t dividend_ptr, mpi_size_t dividend_size,
 
398
                  mpi_limb_t divisor_limb)
 
399
{
 
400
    mpi_size_t i;
 
401
    mpi_limb_t n1, n0, r;
 
402
    int dummy;
 
403
 
 
404
    if( !dividend_size )
 
405
        return 0;
 
406
 
 
407
    /* If multiplication is much faster than division, and the
 
408
     * dividend is large, pre-invert the divisor, and use
 
409
     * only multiplications in the inner loop.
 
410
     *
 
411
     * This test should be read:
 
412
     * Does it ever help to use udiv_qrnnd_preinv?
 
413
     * && Does what we save compensate for the inversion overhead?
 
414
     */
 
415
    if( UDIV_TIME > (2 * UMUL_TIME + 6)
 
416
        && (UDIV_TIME - (2 * UMUL_TIME + 6)) * dividend_size > UDIV_TIME ) {
 
417
        int normalization_steps;
 
418
 
 
419
        count_leading_zeros( normalization_steps, divisor_limb );
 
420
        if( normalization_steps ) {
 
421
            mpi_limb_t divisor_limb_inverted;
 
422
 
 
423
            divisor_limb <<= normalization_steps;
 
424
 
 
425
            /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
 
426
             * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
 
427
             * most significant bit (with weight 2**N) implicit.
 
428
             */
 
429
            /* Special case for DIVISOR_LIMB == 100...000.  */
 
430
            if( !(divisor_limb << 1) )
 
431
                divisor_limb_inverted = ~(mpi_limb_t)0;
 
432
            else
 
433
                udiv_qrnnd(divisor_limb_inverted, dummy,
 
434
                           -divisor_limb, 0, divisor_limb);
 
435
 
 
436
            n1 = dividend_ptr[dividend_size - 1];
 
437
            r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
 
438
 
 
439
            /* Possible optimization:
 
440
             * if (r == 0
 
441
             * && divisor_limb > ((n1 << normalization_steps)
 
442
             *                 | (dividend_ptr[dividend_size - 2] >> ...)))
 
443
             * ...one division less...
 
444
             */
 
445
            for( i = dividend_size - 2; i >= 0; i--) {
 
446
                n0 = dividend_ptr[i];
 
447
                UDIV_QRNND_PREINV( quot_ptr[i + 1], r, r,
 
448
                                   ((n1 << normalization_steps)
 
449
                         | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
 
450
                              divisor_limb, divisor_limb_inverted);
 
451
                n1 = n0;
 
452
            }
 
453
            UDIV_QRNND_PREINV( quot_ptr[0], r, r,
 
454
                               n1 << normalization_steps,
 
455
                               divisor_limb, divisor_limb_inverted);
 
456
            return r >> normalization_steps;
 
457
        }
 
458
        else {
 
459
            mpi_limb_t divisor_limb_inverted;
 
460
 
 
461
            /* Compute (2**2N - 2**N * DIVISOR_LIMB) / DIVISOR_LIMB.  The
 
462
             * result is a (N+1)-bit approximation to 1/DIVISOR_LIMB, with the
 
463
             * most significant bit (with weight 2**N) implicit.
 
464
             */
 
465
            /* Special case for DIVISOR_LIMB == 100...000.  */
 
466
            if( !(divisor_limb << 1) )
 
467
                divisor_limb_inverted = ~(mpi_limb_t) 0;
 
468
            else
 
469
                udiv_qrnnd(divisor_limb_inverted, dummy,
 
470
                           -divisor_limb, 0, divisor_limb);
 
471
 
 
472
            i = dividend_size - 1;
 
473
            r = dividend_ptr[i];
 
474
 
 
475
            if( r >= divisor_limb )
 
476
                r = 0;
 
477
            else
 
478
                quot_ptr[i--] = 0;
 
479
 
 
480
            for( ; i >= 0; i-- ) {
 
481
                n0 = dividend_ptr[i];
 
482
                UDIV_QRNND_PREINV( quot_ptr[i], r, r,
 
483
                                   n0, divisor_limb, divisor_limb_inverted);
 
484
            }
 
485
            return r;
 
486
        }
 
487
    }
 
488
    else {
 
489
        if(UDIV_NEEDS_NORMALIZATION) {
 
490
            int normalization_steps;
 
491
 
 
492
            count_leading_zeros (normalization_steps, divisor_limb);
 
493
            if( normalization_steps ) {
 
494
                divisor_limb <<= normalization_steps;
 
495
 
 
496
                n1 = dividend_ptr[dividend_size - 1];
 
497
                r = n1 >> (BITS_PER_MPI_LIMB - normalization_steps);
 
498
 
 
499
                /* Possible optimization:
 
500
                 * if (r == 0
 
501
                 * && divisor_limb > ((n1 << normalization_steps)
 
502
                 *                 | (dividend_ptr[dividend_size - 2] >> ...)))
 
503
                 * ...one division less...
 
504
                 */
 
505
                for( i = dividend_size - 2; i >= 0; i--) {
 
506
                    n0 = dividend_ptr[i];
 
507
                    udiv_qrnnd (quot_ptr[i + 1], r, r,
 
508
                             ((n1 << normalization_steps)
 
509
                         | (n0 >> (BITS_PER_MPI_LIMB - normalization_steps))),
 
510
                                divisor_limb);
 
511
                    n1 = n0;
 
512
                }
 
513
                udiv_qrnnd (quot_ptr[0], r, r,
 
514
                            n1 << normalization_steps,
 
515
                            divisor_limb);
 
516
                return r >> normalization_steps;
 
517
            }
 
518
        }
 
519
        /* No normalization needed, either because udiv_qrnnd doesn't require
 
520
         * it, or because DIVISOR_LIMB is already normalized.  */
 
521
        i = dividend_size - 1;
 
522
        r = dividend_ptr[i];
 
523
 
 
524
        if(r >= divisor_limb)
 
525
            r = 0;
 
526
        else
 
527
            quot_ptr[i--] = 0;
 
528
 
 
529
        for(; i >= 0; i--) {
 
530
            n0 = dividend_ptr[i];
 
531
            udiv_qrnnd( quot_ptr[i], r, r, n0, divisor_limb );
 
532
        }
 
533
        return r;
 
534
    }
 
535
}
 
536
 
 
537