/src/libgcrypt/mpi/mpi-div.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* mpi-div.c - MPI functions |
2 | | * Copyright (C) 1994, 1996, 1998, 2001, 2002, |
3 | | * 2003 Free Software Foundation, Inc. |
4 | | * |
5 | | * This file is part of Libgcrypt. |
6 | | * |
7 | | * Libgcrypt is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU Lesser General Public License as |
9 | | * published by the Free Software Foundation; either version 2.1 of |
10 | | * the License, or (at your option) any later version. |
11 | | * |
12 | | * Libgcrypt 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 Lesser General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU Lesser General Public |
18 | | * License 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 | | */ |
27 | | |
28 | | #include <config.h> |
29 | | #include <stdio.h> |
30 | | #include <stdlib.h> |
31 | | #include "mpi-internal.h" |
32 | | #include "longlong.h" |
33 | | #include "g10lib.h" |
34 | | |
35 | | |
36 | | void |
37 | | _gcry_mpi_fdiv_r( gcry_mpi_t rem, gcry_mpi_t dividend, gcry_mpi_t divisor ) |
38 | 168k | { |
39 | 168k | int divisor_sign = divisor->sign; |
40 | 168k | gcry_mpi_t temp_divisor = NULL; |
41 | | |
42 | | /* We need the original value of the divisor after the remainder has been |
43 | | * preliminary calculated. We have to copy it to temporary space if it's |
44 | | * the same variable as REM. */ |
45 | 168k | if( rem == divisor ) { |
46 | 0 | temp_divisor = mpi_copy( divisor ); |
47 | 0 | divisor = temp_divisor; |
48 | 0 | } |
49 | | |
50 | 168k | _gcry_mpi_tdiv_r( rem, dividend, divisor ); |
51 | | |
52 | 168k | if( ((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs ) |
53 | 0 | mpi_add (rem, rem, divisor); |
54 | | |
55 | 168k | if( temp_divisor ) |
56 | 0 | mpi_free(temp_divisor); |
57 | 168k | } |
58 | | |
59 | | |
60 | | |
61 | | /**************** |
62 | | * Division rounding the quotient towards -infinity. |
63 | | * The remainder gets the same sign as the denominator. |
64 | | * rem is optional |
65 | | */ |
66 | | |
67 | | unsigned long |
68 | | _gcry_mpi_fdiv_r_ui( gcry_mpi_t rem, gcry_mpi_t dividend, |
69 | | unsigned long divisor ) |
70 | 0 | { |
71 | 0 | mpi_limb_t rlimb; |
72 | |
|
73 | 0 | rlimb = _gcry_mpih_mod_1( dividend->d, dividend->nlimbs, divisor ); |
74 | 0 | if( rlimb && dividend->sign ) |
75 | 0 | rlimb = divisor - rlimb; |
76 | |
|
77 | 0 | if( rem ) { |
78 | 0 | rem->d[0] = rlimb; |
79 | 0 | rem->nlimbs = rlimb? 1:0; |
80 | 0 | } |
81 | 0 | return rlimb; |
82 | 0 | } |
83 | | |
84 | | |
85 | | void |
86 | | _gcry_mpi_fdiv_q( gcry_mpi_t quot, gcry_mpi_t dividend, gcry_mpi_t divisor ) |
87 | 0 | { |
88 | 0 | gcry_mpi_t tmp = mpi_alloc( mpi_get_nlimbs(quot) ); |
89 | 0 | _gcry_mpi_fdiv_qr( quot, tmp, dividend, divisor); |
90 | 0 | mpi_free(tmp); |
91 | 0 | } |
92 | | |
93 | | void |
94 | | _gcry_mpi_fdiv_qr( gcry_mpi_t quot, gcry_mpi_t rem, gcry_mpi_t dividend, gcry_mpi_t divisor ) |
95 | 0 | { |
96 | 0 | int divisor_sign = divisor->sign; |
97 | 0 | gcry_mpi_t temp_divisor = NULL; |
98 | |
|
99 | 0 | if( quot == divisor || rem == divisor ) { |
100 | 0 | temp_divisor = mpi_copy( divisor ); |
101 | 0 | divisor = temp_divisor; |
102 | 0 | } |
103 | |
|
104 | 0 | _gcry_mpi_tdiv_qr( quot, rem, dividend, divisor ); |
105 | |
|
106 | 0 | if( (divisor_sign ^ dividend->sign) && rem->nlimbs ) { |
107 | 0 | mpi_sub_ui( quot, quot, 1 ); |
108 | 0 | mpi_add( rem, rem, divisor); |
109 | 0 | } |
110 | |
|
111 | 0 | if( temp_divisor ) |
112 | 0 | mpi_free(temp_divisor); |
113 | 0 | } |
114 | | |
115 | | |
116 | | /* If den == quot, den needs temporary storage. |
117 | | * If den == rem, den needs temporary storage. |
118 | | * If num == quot, num needs temporary storage. |
119 | | * If den has temporary storage, it can be normalized while being copied, |
120 | | * i.e no extra storage should be allocated. |
121 | | */ |
122 | | |
123 | | void |
124 | | _gcry_mpi_tdiv_r( gcry_mpi_t rem, gcry_mpi_t num, gcry_mpi_t den) |
125 | 2.35M | { |
126 | 2.35M | _gcry_mpi_tdiv_qr(NULL, rem, num, den ); |
127 | 2.35M | } |
128 | | |
129 | | void |
130 | | _gcry_mpi_tdiv_qr( gcry_mpi_t quot, gcry_mpi_t rem, gcry_mpi_t num, gcry_mpi_t den) |
131 | 2.35M | { |
132 | 2.35M | mpi_ptr_t np, dp; |
133 | 2.35M | mpi_ptr_t qp, rp; |
134 | 2.35M | mpi_size_t nsize = num->nlimbs; |
135 | 2.35M | mpi_size_t dsize = den->nlimbs; |
136 | 2.35M | mpi_size_t qsize, rsize; |
137 | 2.35M | mpi_size_t sign_remainder = num->sign; |
138 | 2.35M | mpi_size_t sign_quotient = num->sign ^ den->sign; |
139 | 2.35M | unsigned normalization_steps; |
140 | 2.35M | mpi_limb_t q_limb; |
141 | 2.35M | mpi_ptr_t marker[5]; |
142 | 2.35M | unsigned int marker_nlimbs[5]; |
143 | 2.35M | int markidx=0; |
144 | | |
145 | | /* Ensure space is enough for quotient and remainder. |
146 | | * We need space for an extra limb in the remainder, because it's |
147 | | * up-shifted (normalized) below. */ |
148 | 2.35M | rsize = nsize + 1; |
149 | 2.35M | mpi_resize( rem, rsize); |
150 | | |
151 | 2.35M | qsize = rsize - dsize; /* qsize cannot be bigger than this. */ |
152 | 2.35M | if( qsize <= 0 ) { |
153 | 809k | if( num != rem ) { |
154 | 0 | rem->nlimbs = num->nlimbs; |
155 | 0 | rem->sign = num->sign; |
156 | 0 | MPN_COPY(rem->d, num->d, nsize); |
157 | 0 | } |
158 | 809k | if( quot ) { |
159 | | /* This needs to follow the assignment to rem, in case the |
160 | | * numerator and quotient are the same. */ |
161 | 0 | quot->nlimbs = 0; |
162 | 0 | quot->sign = 0; |
163 | 0 | } |
164 | 809k | return; |
165 | 809k | } |
166 | | |
167 | 1.54M | if( quot ) |
168 | 0 | mpi_resize( quot, qsize); |
169 | | |
170 | 1.54M | if (!dsize) |
171 | 0 | _gcry_divide_by_zero(); |
172 | | |
173 | | /* Read pointers here, when reallocation is finished. */ |
174 | 1.54M | np = num->d; |
175 | 1.54M | dp = den->d; |
176 | 1.54M | rp = rem->d; |
177 | | |
178 | | /* Optimize division by a single-limb divisor. */ |
179 | 1.54M | if( dsize == 1 ) { |
180 | 0 | mpi_limb_t rlimb; |
181 | 0 | if( quot ) { |
182 | 0 | qp = quot->d; |
183 | 0 | rlimb = _gcry_mpih_divmod_1( qp, np, nsize, dp[0] ); |
184 | 0 | qsize -= qp[qsize - 1] == 0; |
185 | 0 | quot->nlimbs = qsize; |
186 | 0 | quot->sign = sign_quotient; |
187 | 0 | } |
188 | 0 | else |
189 | 0 | rlimb = _gcry_mpih_mod_1( np, nsize, dp[0] ); |
190 | 0 | rp[0] = rlimb; |
191 | 0 | rsize = rlimb != 0?1:0; |
192 | 0 | rem->nlimbs = rsize; |
193 | 0 | rem->sign = sign_remainder; |
194 | 0 | return; |
195 | 0 | } |
196 | | |
197 | | |
198 | 1.54M | if( quot ) { |
199 | 0 | qp = quot->d; |
200 | | /* Make sure QP and NP point to different objects. Otherwise the |
201 | | * numerator would be gradually overwritten by the quotient limbs. */ |
202 | 0 | if(qp == np) { /* Copy NP object to temporary space. */ |
203 | 0 | marker_nlimbs[markidx] = nsize; |
204 | 0 | np = marker[markidx++] = mpi_alloc_limb_space(nsize, |
205 | 0 | mpi_is_secure(quot)); |
206 | 0 | MPN_COPY(np, qp, nsize); |
207 | 0 | } |
208 | 0 | } |
209 | 1.54M | else /* Put quotient at top of remainder. */ |
210 | 1.54M | qp = rp + dsize; |
211 | | |
212 | 1.54M | count_leading_zeros( normalization_steps, dp[dsize - 1] ); |
213 | | |
214 | | /* Normalize the denominator, i.e. make its most significant bit set by |
215 | | * shifting it NORMALIZATION_STEPS bits to the left. Also shift the |
216 | | * numerator the same number of steps (to keep the quotient the same!). |
217 | | */ |
218 | 1.54M | if( normalization_steps ) { |
219 | 1.03M | mpi_ptr_t tp; |
220 | 1.03M | mpi_limb_t nlimb; |
221 | | |
222 | | /* Shift up the denominator setting the most significant bit of |
223 | | * the most significant word. Use temporary storage not to clobber |
224 | | * the original contents of the denominator. */ |
225 | 1.03M | marker_nlimbs[markidx] = dsize; |
226 | 1.03M | tp = marker[markidx++] = mpi_alloc_limb_space(dsize,mpi_is_secure(den)); |
227 | 1.03M | _gcry_mpih_lshift( tp, dp, dsize, normalization_steps ); |
228 | 1.03M | dp = tp; |
229 | | |
230 | | /* Shift up the numerator, possibly introducing a new most |
231 | | * significant word. Move the shifted numerator in the remainder |
232 | | * meanwhile. */ |
233 | 1.03M | nlimb = _gcry_mpih_lshift(rp, np, nsize, normalization_steps); |
234 | 1.03M | if( nlimb ) { |
235 | 58.4k | rp[nsize] = nlimb; |
236 | 58.4k | rsize = nsize + 1; |
237 | 58.4k | } |
238 | 973k | else |
239 | 973k | rsize = nsize; |
240 | 1.03M | } |
241 | 516k | else { |
242 | | /* The denominator is already normalized, as required. Copy it to |
243 | | * temporary space if it overlaps with the quotient or remainder. */ |
244 | 516k | if( dp == rp || (quot && (dp == qp))) { |
245 | 0 | mpi_ptr_t tp; |
246 | |
|
247 | 0 | marker_nlimbs[markidx] = dsize; |
248 | 0 | tp = marker[markidx++] = mpi_alloc_limb_space(dsize, |
249 | 0 | mpi_is_secure(den)); |
250 | 0 | MPN_COPY( tp, dp, dsize ); |
251 | 0 | dp = tp; |
252 | 0 | } |
253 | | |
254 | | /* Move the numerator to the remainder. */ |
255 | 516k | if( rp != np ) |
256 | 0 | MPN_COPY(rp, np, nsize); |
257 | | |
258 | 516k | rsize = nsize; |
259 | 516k | } |
260 | | |
261 | 1.54M | q_limb = _gcry_mpih_divrem( qp, 0, rp, rsize, dp, dsize ); |
262 | | |
263 | 1.54M | if( quot ) { |
264 | 0 | qsize = rsize - dsize; |
265 | 0 | if(q_limb) { |
266 | 0 | qp[qsize] = q_limb; |
267 | 0 | qsize += 1; |
268 | 0 | } |
269 | |
|
270 | 0 | quot->nlimbs = qsize; |
271 | 0 | quot->sign = sign_quotient; |
272 | 0 | } |
273 | | |
274 | 1.54M | rsize = dsize; |
275 | 1.54M | MPN_NORMALIZE (rp, rsize); |
276 | | |
277 | 1.54M | if( normalization_steps && rsize ) { |
278 | 1.03M | _gcry_mpih_rshift(rp, rp, rsize, normalization_steps); |
279 | 1.03M | rsize -= rp[rsize - 1] == 0?1:0; |
280 | 1.03M | } |
281 | | |
282 | 1.54M | rem->nlimbs = rsize; |
283 | 1.54M | rem->sign = sign_remainder; |
284 | 2.57M | while( markidx ) |
285 | 1.03M | { |
286 | 1.03M | markidx--; |
287 | 1.03M | _gcry_mpi_free_limb_space (marker[markidx], marker_nlimbs[markidx]); |
288 | 1.03M | } |
289 | 1.54M | } |
290 | | |
291 | | void |
292 | | _gcry_mpi_tdiv_q_2exp( gcry_mpi_t w, gcry_mpi_t u, unsigned int count ) |
293 | 0 | { |
294 | 0 | mpi_size_t usize, wsize; |
295 | 0 | mpi_size_t limb_cnt; |
296 | |
|
297 | 0 | usize = u->nlimbs; |
298 | 0 | limb_cnt = count / BITS_PER_MPI_LIMB; |
299 | 0 | wsize = usize - limb_cnt; |
300 | 0 | if( limb_cnt >= usize ) |
301 | 0 | w->nlimbs = 0; |
302 | 0 | else { |
303 | 0 | mpi_ptr_t wp; |
304 | 0 | mpi_ptr_t up; |
305 | |
|
306 | 0 | RESIZE_IF_NEEDED( w, wsize ); |
307 | 0 | wp = w->d; |
308 | 0 | up = u->d; |
309 | |
|
310 | 0 | count %= BITS_PER_MPI_LIMB; |
311 | 0 | if( count ) { |
312 | 0 | _gcry_mpih_rshift( wp, up + limb_cnt, wsize, count ); |
313 | 0 | wsize -= !wp[wsize - 1]; |
314 | 0 | } |
315 | 0 | else { |
316 | 0 | MPN_COPY_INCR( wp, up + limb_cnt, wsize); |
317 | 0 | } |
318 | |
|
319 | 0 | w->nlimbs = wsize; |
320 | 0 | } |
321 | 0 | } |
322 | | |
323 | | /**************** |
324 | | * Check whether dividend is divisible by divisor |
325 | | * (note: divisor must fit into a limb) |
326 | | */ |
327 | | int |
328 | | _gcry_mpi_divisible_ui(gcry_mpi_t dividend, unsigned long divisor ) |
329 | 0 | { |
330 | 0 | return !_gcry_mpih_mod_1( dividend->d, dividend->nlimbs, divisor ); |
331 | 0 | } |
332 | | |
333 | | |
334 | | void |
335 | | _gcry_mpi_div (gcry_mpi_t quot, gcry_mpi_t rem, gcry_mpi_t dividend, |
336 | | gcry_mpi_t divisor, int round) |
337 | 0 | { |
338 | 0 | if (!round) |
339 | 0 | { |
340 | 0 | if (!rem) |
341 | 0 | { |
342 | 0 | gcry_mpi_t tmp = mpi_alloc (mpi_get_nlimbs(quot)); |
343 | 0 | _gcry_mpi_tdiv_qr (quot, tmp, dividend, divisor); |
344 | 0 | mpi_free (tmp); |
345 | 0 | } |
346 | 0 | else |
347 | 0 | _gcry_mpi_tdiv_qr (quot, rem, dividend, divisor); |
348 | 0 | } |
349 | 0 | else if (round < 0) |
350 | 0 | { |
351 | 0 | if (!rem) |
352 | 0 | _gcry_mpi_fdiv_q (quot, dividend, divisor); |
353 | 0 | else if (!quot) |
354 | 0 | _gcry_mpi_fdiv_r (rem, dividend, divisor); |
355 | 0 | else |
356 | 0 | _gcry_mpi_fdiv_qr (quot, rem, dividend, divisor); |
357 | 0 | } |
358 | 0 | else |
359 | 0 | log_bug ("mpi rounding to ceiling not yet implemented\n"); |
360 | 0 | } |