162306a36Sopenharmony_ci/* mpi-div.c - MPI functions 262306a36Sopenharmony_ci * Copyright (C) 1994, 1996, 1998, 2001, 2002, 362306a36Sopenharmony_ci * 2003 Free Software Foundation, Inc. 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * This file is part of Libgcrypt. 662306a36Sopenharmony_ci * 762306a36Sopenharmony_ci * Note: This code is heavily based on the GNU MP Library. 862306a36Sopenharmony_ci * Actually it's the same code with only minor changes in the 962306a36Sopenharmony_ci * way the data is stored; this is to support the abstraction 1062306a36Sopenharmony_ci * of an optional secure memory allocation which may be used 1162306a36Sopenharmony_ci * to avoid revealing of sensitive data due to paging etc. 1262306a36Sopenharmony_ci */ 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_ci#include "mpi-internal.h" 1562306a36Sopenharmony_ci#include "longlong.h" 1662306a36Sopenharmony_ci 1762306a36Sopenharmony_civoid mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den); 1862306a36Sopenharmony_civoid mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor); 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_civoid mpi_fdiv_r(MPI rem, MPI dividend, MPI divisor) 2162306a36Sopenharmony_ci{ 2262306a36Sopenharmony_ci int divisor_sign = divisor->sign; 2362306a36Sopenharmony_ci MPI temp_divisor = NULL; 2462306a36Sopenharmony_ci 2562306a36Sopenharmony_ci /* We need the original value of the divisor after the remainder has been 2662306a36Sopenharmony_ci * preliminary calculated. We have to copy it to temporary space if it's 2762306a36Sopenharmony_ci * the same variable as REM. 2862306a36Sopenharmony_ci */ 2962306a36Sopenharmony_ci if (rem == divisor) { 3062306a36Sopenharmony_ci temp_divisor = mpi_copy(divisor); 3162306a36Sopenharmony_ci divisor = temp_divisor; 3262306a36Sopenharmony_ci } 3362306a36Sopenharmony_ci 3462306a36Sopenharmony_ci mpi_tdiv_r(rem, dividend, divisor); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (((divisor_sign?1:0) ^ (dividend->sign?1:0)) && rem->nlimbs) 3762306a36Sopenharmony_ci mpi_add(rem, rem, divisor); 3862306a36Sopenharmony_ci 3962306a36Sopenharmony_ci if (temp_divisor) 4062306a36Sopenharmony_ci mpi_free(temp_divisor); 4162306a36Sopenharmony_ci} 4262306a36Sopenharmony_ci 4362306a36Sopenharmony_civoid mpi_fdiv_q(MPI quot, MPI dividend, MPI divisor) 4462306a36Sopenharmony_ci{ 4562306a36Sopenharmony_ci MPI tmp = mpi_alloc(mpi_get_nlimbs(quot)); 4662306a36Sopenharmony_ci mpi_fdiv_qr(quot, tmp, dividend, divisor); 4762306a36Sopenharmony_ci mpi_free(tmp); 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_civoid mpi_fdiv_qr(MPI quot, MPI rem, MPI dividend, MPI divisor) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci int divisor_sign = divisor->sign; 5362306a36Sopenharmony_ci MPI temp_divisor = NULL; 5462306a36Sopenharmony_ci 5562306a36Sopenharmony_ci if (quot == divisor || rem == divisor) { 5662306a36Sopenharmony_ci temp_divisor = mpi_copy(divisor); 5762306a36Sopenharmony_ci divisor = temp_divisor; 5862306a36Sopenharmony_ci } 5962306a36Sopenharmony_ci 6062306a36Sopenharmony_ci mpi_tdiv_qr(quot, rem, dividend, divisor); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci if ((divisor_sign ^ dividend->sign) && rem->nlimbs) { 6362306a36Sopenharmony_ci mpi_sub_ui(quot, quot, 1); 6462306a36Sopenharmony_ci mpi_add(rem, rem, divisor); 6562306a36Sopenharmony_ci } 6662306a36Sopenharmony_ci 6762306a36Sopenharmony_ci if (temp_divisor) 6862306a36Sopenharmony_ci mpi_free(temp_divisor); 6962306a36Sopenharmony_ci} 7062306a36Sopenharmony_ci 7162306a36Sopenharmony_ci/* If den == quot, den needs temporary storage. 7262306a36Sopenharmony_ci * If den == rem, den needs temporary storage. 7362306a36Sopenharmony_ci * If num == quot, num needs temporary storage. 7462306a36Sopenharmony_ci * If den has temporary storage, it can be normalized while being copied, 7562306a36Sopenharmony_ci * i.e no extra storage should be allocated. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci 7862306a36Sopenharmony_civoid mpi_tdiv_r(MPI rem, MPI num, MPI den) 7962306a36Sopenharmony_ci{ 8062306a36Sopenharmony_ci mpi_tdiv_qr(NULL, rem, num, den); 8162306a36Sopenharmony_ci} 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_civoid mpi_tdiv_qr(MPI quot, MPI rem, MPI num, MPI den) 8462306a36Sopenharmony_ci{ 8562306a36Sopenharmony_ci mpi_ptr_t np, dp; 8662306a36Sopenharmony_ci mpi_ptr_t qp, rp; 8762306a36Sopenharmony_ci mpi_size_t nsize = num->nlimbs; 8862306a36Sopenharmony_ci mpi_size_t dsize = den->nlimbs; 8962306a36Sopenharmony_ci mpi_size_t qsize, rsize; 9062306a36Sopenharmony_ci mpi_size_t sign_remainder = num->sign; 9162306a36Sopenharmony_ci mpi_size_t sign_quotient = num->sign ^ den->sign; 9262306a36Sopenharmony_ci unsigned int normalization_steps; 9362306a36Sopenharmony_ci mpi_limb_t q_limb; 9462306a36Sopenharmony_ci mpi_ptr_t marker[5]; 9562306a36Sopenharmony_ci int markidx = 0; 9662306a36Sopenharmony_ci 9762306a36Sopenharmony_ci /* Ensure space is enough for quotient and remainder. 9862306a36Sopenharmony_ci * We need space for an extra limb in the remainder, because it's 9962306a36Sopenharmony_ci * up-shifted (normalized) below. 10062306a36Sopenharmony_ci */ 10162306a36Sopenharmony_ci rsize = nsize + 1; 10262306a36Sopenharmony_ci mpi_resize(rem, rsize); 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci qsize = rsize - dsize; /* qsize cannot be bigger than this. */ 10562306a36Sopenharmony_ci if (qsize <= 0) { 10662306a36Sopenharmony_ci if (num != rem) { 10762306a36Sopenharmony_ci rem->nlimbs = num->nlimbs; 10862306a36Sopenharmony_ci rem->sign = num->sign; 10962306a36Sopenharmony_ci MPN_COPY(rem->d, num->d, nsize); 11062306a36Sopenharmony_ci } 11162306a36Sopenharmony_ci if (quot) { 11262306a36Sopenharmony_ci /* This needs to follow the assignment to rem, in case the 11362306a36Sopenharmony_ci * numerator and quotient are the same. 11462306a36Sopenharmony_ci */ 11562306a36Sopenharmony_ci quot->nlimbs = 0; 11662306a36Sopenharmony_ci quot->sign = 0; 11762306a36Sopenharmony_ci } 11862306a36Sopenharmony_ci return; 11962306a36Sopenharmony_ci } 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci if (quot) 12262306a36Sopenharmony_ci mpi_resize(quot, qsize); 12362306a36Sopenharmony_ci 12462306a36Sopenharmony_ci /* Read pointers here, when reallocation is finished. */ 12562306a36Sopenharmony_ci np = num->d; 12662306a36Sopenharmony_ci dp = den->d; 12762306a36Sopenharmony_ci rp = rem->d; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci /* Optimize division by a single-limb divisor. */ 13062306a36Sopenharmony_ci if (dsize == 1) { 13162306a36Sopenharmony_ci mpi_limb_t rlimb; 13262306a36Sopenharmony_ci if (quot) { 13362306a36Sopenharmony_ci qp = quot->d; 13462306a36Sopenharmony_ci rlimb = mpihelp_divmod_1(qp, np, nsize, dp[0]); 13562306a36Sopenharmony_ci qsize -= qp[qsize - 1] == 0; 13662306a36Sopenharmony_ci quot->nlimbs = qsize; 13762306a36Sopenharmony_ci quot->sign = sign_quotient; 13862306a36Sopenharmony_ci } else 13962306a36Sopenharmony_ci rlimb = mpihelp_mod_1(np, nsize, dp[0]); 14062306a36Sopenharmony_ci rp[0] = rlimb; 14162306a36Sopenharmony_ci rsize = rlimb != 0?1:0; 14262306a36Sopenharmony_ci rem->nlimbs = rsize; 14362306a36Sopenharmony_ci rem->sign = sign_remainder; 14462306a36Sopenharmony_ci return; 14562306a36Sopenharmony_ci } 14662306a36Sopenharmony_ci 14762306a36Sopenharmony_ci 14862306a36Sopenharmony_ci if (quot) { 14962306a36Sopenharmony_ci qp = quot->d; 15062306a36Sopenharmony_ci /* Make sure QP and NP point to different objects. Otherwise the 15162306a36Sopenharmony_ci * numerator would be gradually overwritten by the quotient limbs. 15262306a36Sopenharmony_ci */ 15362306a36Sopenharmony_ci if (qp == np) { /* Copy NP object to temporary space. */ 15462306a36Sopenharmony_ci np = marker[markidx++] = mpi_alloc_limb_space(nsize); 15562306a36Sopenharmony_ci MPN_COPY(np, qp, nsize); 15662306a36Sopenharmony_ci } 15762306a36Sopenharmony_ci } else /* Put quotient at top of remainder. */ 15862306a36Sopenharmony_ci qp = rp + dsize; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci normalization_steps = count_leading_zeros(dp[dsize - 1]); 16162306a36Sopenharmony_ci 16262306a36Sopenharmony_ci /* Normalize the denominator, i.e. make its most significant bit set by 16362306a36Sopenharmony_ci * shifting it NORMALIZATION_STEPS bits to the left. Also shift the 16462306a36Sopenharmony_ci * numerator the same number of steps (to keep the quotient the same!). 16562306a36Sopenharmony_ci */ 16662306a36Sopenharmony_ci if (normalization_steps) { 16762306a36Sopenharmony_ci mpi_ptr_t tp; 16862306a36Sopenharmony_ci mpi_limb_t nlimb; 16962306a36Sopenharmony_ci 17062306a36Sopenharmony_ci /* Shift up the denominator setting the most significant bit of 17162306a36Sopenharmony_ci * the most significant word. Use temporary storage not to clobber 17262306a36Sopenharmony_ci * the original contents of the denominator. 17362306a36Sopenharmony_ci */ 17462306a36Sopenharmony_ci tp = marker[markidx++] = mpi_alloc_limb_space(dsize); 17562306a36Sopenharmony_ci mpihelp_lshift(tp, dp, dsize, normalization_steps); 17662306a36Sopenharmony_ci dp = tp; 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ci /* Shift up the numerator, possibly introducing a new most 17962306a36Sopenharmony_ci * significant word. Move the shifted numerator in the remainder 18062306a36Sopenharmony_ci * meanwhile. 18162306a36Sopenharmony_ci */ 18262306a36Sopenharmony_ci nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps); 18362306a36Sopenharmony_ci if (nlimb) { 18462306a36Sopenharmony_ci rp[nsize] = nlimb; 18562306a36Sopenharmony_ci rsize = nsize + 1; 18662306a36Sopenharmony_ci } else 18762306a36Sopenharmony_ci rsize = nsize; 18862306a36Sopenharmony_ci } else { 18962306a36Sopenharmony_ci /* The denominator is already normalized, as required. Copy it to 19062306a36Sopenharmony_ci * temporary space if it overlaps with the quotient or remainder. 19162306a36Sopenharmony_ci */ 19262306a36Sopenharmony_ci if (dp == rp || (quot && (dp == qp))) { 19362306a36Sopenharmony_ci mpi_ptr_t tp; 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci tp = marker[markidx++] = mpi_alloc_limb_space(dsize); 19662306a36Sopenharmony_ci MPN_COPY(tp, dp, dsize); 19762306a36Sopenharmony_ci dp = tp; 19862306a36Sopenharmony_ci } 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_ci /* Move the numerator to the remainder. */ 20162306a36Sopenharmony_ci if (rp != np) 20262306a36Sopenharmony_ci MPN_COPY(rp, np, nsize); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci rsize = nsize; 20562306a36Sopenharmony_ci } 20662306a36Sopenharmony_ci 20762306a36Sopenharmony_ci q_limb = mpihelp_divrem(qp, 0, rp, rsize, dp, dsize); 20862306a36Sopenharmony_ci 20962306a36Sopenharmony_ci if (quot) { 21062306a36Sopenharmony_ci qsize = rsize - dsize; 21162306a36Sopenharmony_ci if (q_limb) { 21262306a36Sopenharmony_ci qp[qsize] = q_limb; 21362306a36Sopenharmony_ci qsize += 1; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci quot->nlimbs = qsize; 21762306a36Sopenharmony_ci quot->sign = sign_quotient; 21862306a36Sopenharmony_ci } 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci rsize = dsize; 22162306a36Sopenharmony_ci MPN_NORMALIZE(rp, rsize); 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_ci if (normalization_steps && rsize) { 22462306a36Sopenharmony_ci mpihelp_rshift(rp, rp, rsize, normalization_steps); 22562306a36Sopenharmony_ci rsize -= rp[rsize - 1] == 0?1:0; 22662306a36Sopenharmony_ci } 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci rem->nlimbs = rsize; 22962306a36Sopenharmony_ci rem->sign = sign_remainder; 23062306a36Sopenharmony_ci while (markidx) { 23162306a36Sopenharmony_ci markidx--; 23262306a36Sopenharmony_ci mpi_free_limb_space(marker[markidx]); 23362306a36Sopenharmony_ci } 23462306a36Sopenharmony_ci} 235