1 /* mpi-div.c - MPI functions
2 * Copyright (C) 1994, 1996, 1998, 2001, 2002,
3 * 2003 Free Software Foundation, Inc.
5 * This file is part of Libgcrypt.
7 * Note: This code is heavily based on the GNU MP Library.
8 * Actually it's the same code with only minor changes in the
9 * way the data is stored; this is to support the abstraction
10 * of an optional secure memory allocation which may be used
11 * to avoid revealing of sensitive data due to paging etc.
14 #include "mpi-internal.h"
17 void mpi_tdiv_qr(MPI quot
, MPI rem
, MPI num
, MPI den
);
18 void mpi_fdiv_qr(MPI quot
, MPI rem
, MPI dividend
, MPI divisor
);
20 void mpi_fdiv_r(MPI rem
, MPI dividend
, MPI divisor
)
22 int divisor_sign
= divisor
->sign
;
23 MPI temp_divisor
= NULL
;
25 /* We need the original value of the divisor after the remainder has been
26 * preliminary calculated. We have to copy it to temporary space if it's
27 * the same variable as REM.
30 temp_divisor
= mpi_copy(divisor
);
31 divisor
= temp_divisor
;
34 mpi_tdiv_r(rem
, dividend
, divisor
);
36 if (((divisor_sign
?1:0) ^ (dividend
->sign
?1:0)) && rem
->nlimbs
)
37 mpi_add(rem
, rem
, divisor
);
40 mpi_free(temp_divisor
);
43 void mpi_fdiv_q(MPI quot
, MPI dividend
, MPI divisor
)
45 MPI tmp
= mpi_alloc(mpi_get_nlimbs(quot
));
46 mpi_fdiv_qr(quot
, tmp
, dividend
, divisor
);
50 void mpi_fdiv_qr(MPI quot
, MPI rem
, MPI dividend
, MPI divisor
)
52 int divisor_sign
= divisor
->sign
;
53 MPI temp_divisor
= NULL
;
55 if (quot
== divisor
|| rem
== divisor
) {
56 temp_divisor
= mpi_copy(divisor
);
57 divisor
= temp_divisor
;
60 mpi_tdiv_qr(quot
, rem
, dividend
, divisor
);
62 if ((divisor_sign
^ dividend
->sign
) && rem
->nlimbs
) {
63 mpi_sub_ui(quot
, quot
, 1);
64 mpi_add(rem
, rem
, divisor
);
68 mpi_free(temp_divisor
);
71 /* If den == quot, den needs temporary storage.
72 * If den == rem, den needs temporary storage.
73 * If num == quot, num needs temporary storage.
74 * If den has temporary storage, it can be normalized while being copied,
75 * i.e no extra storage should be allocated.
78 void mpi_tdiv_r(MPI rem
, MPI num
, MPI den
)
80 mpi_tdiv_qr(NULL
, rem
, num
, den
);
83 void mpi_tdiv_qr(MPI quot
, MPI rem
, MPI num
, MPI den
)
87 mpi_size_t nsize
= num
->nlimbs
;
88 mpi_size_t dsize
= den
->nlimbs
;
89 mpi_size_t qsize
, rsize
;
90 mpi_size_t sign_remainder
= num
->sign
;
91 mpi_size_t sign_quotient
= num
->sign
^ den
->sign
;
92 unsigned int normalization_steps
;
97 /* Ensure space is enough for quotient and remainder.
98 * We need space for an extra limb in the remainder, because it's
99 * up-shifted (normalized) below.
102 mpi_resize(rem
, rsize
);
104 qsize
= rsize
- dsize
; /* qsize cannot be bigger than this. */
107 rem
->nlimbs
= num
->nlimbs
;
108 rem
->sign
= num
->sign
;
109 MPN_COPY(rem
->d
, num
->d
, nsize
);
112 /* This needs to follow the assignment to rem, in case the
113 * numerator and quotient are the same.
122 mpi_resize(quot
, qsize
);
124 /* Read pointers here, when reallocation is finished. */
129 /* Optimize division by a single-limb divisor. */
134 rlimb
= mpihelp_divmod_1(qp
, np
, nsize
, dp
[0]);
135 qsize
-= qp
[qsize
- 1] == 0;
136 quot
->nlimbs
= qsize
;
137 quot
->sign
= sign_quotient
;
139 rlimb
= mpihelp_mod_1(np
, nsize
, dp
[0]);
141 rsize
= rlimb
!= 0?1:0;
143 rem
->sign
= sign_remainder
;
150 /* Make sure QP and NP point to different objects. Otherwise the
151 * numerator would be gradually overwritten by the quotient limbs.
153 if (qp
== np
) { /* Copy NP object to temporary space. */
154 np
= marker
[markidx
++] = mpi_alloc_limb_space(nsize
);
155 MPN_COPY(np
, qp
, nsize
);
157 } else /* Put quotient at top of remainder. */
160 normalization_steps
= count_leading_zeros(dp
[dsize
- 1]);
162 /* Normalize the denominator, i.e. make its most significant bit set by
163 * shifting it NORMALIZATION_STEPS bits to the left. Also shift the
164 * numerator the same number of steps (to keep the quotient the same!).
166 if (normalization_steps
) {
170 /* Shift up the denominator setting the most significant bit of
171 * the most significant word. Use temporary storage not to clobber
172 * the original contents of the denominator.
174 tp
= marker
[markidx
++] = mpi_alloc_limb_space(dsize
);
175 mpihelp_lshift(tp
, dp
, dsize
, normalization_steps
);
178 /* Shift up the numerator, possibly introducing a new most
179 * significant word. Move the shifted numerator in the remainder
182 nlimb
= mpihelp_lshift(rp
, np
, nsize
, normalization_steps
);
189 /* The denominator is already normalized, as required. Copy it to
190 * temporary space if it overlaps with the quotient or remainder.
192 if (dp
== rp
|| (quot
&& (dp
== qp
))) {
195 tp
= marker
[markidx
++] = mpi_alloc_limb_space(dsize
);
196 MPN_COPY(tp
, dp
, dsize
);
200 /* Move the numerator to the remainder. */
202 MPN_COPY(rp
, np
, nsize
);
207 q_limb
= mpihelp_divrem(qp
, 0, rp
, rsize
, dp
, dsize
);
210 qsize
= rsize
- dsize
;
216 quot
->nlimbs
= qsize
;
217 quot
->sign
= sign_quotient
;
221 MPN_NORMALIZE(rp
, rsize
);
223 if (normalization_steps
&& rsize
) {
224 mpihelp_rshift(rp
, rp
, rsize
, normalization_steps
);
225 rsize
-= rp
[rsize
- 1] == 0?1:0;
229 rem
->sign
= sign_remainder
;
232 mpi_free_limb_space(marker
[markidx
]);