/* This should be made into an inline function in gmp.h. */ void mpihelp_mul_n( mpi_ptr_t prodp, mpi_ptr_t up, mpi_ptr_t vp, mpi_size_t size) { int secure; if( up == vp ) { if( size < KARATSUBA_THRESHOLD ) mpih_sqr_n_basecase( prodp, up, size ); else { mpi_ptr_t tspace; secure = m_is_secure( up ); tspace = mpi_alloc_limb_space( 2 * size, secure ); mpih_sqr_n( prodp, up, size, tspace ); mpi_free_limb_space( tspace ); } } else { if( size < KARATSUBA_THRESHOLD ) mul_n_basecase( prodp, up, vp, size ); else { mpi_ptr_t tspace; secure = m_is_secure( up ) || m_is_secure( vp ); tspace = mpi_alloc_limb_space( 2 * size, secure ); mul_n (prodp, up, vp, size, tspace); mpi_free_limb_space( tspace ); } } }
void mpihelp_mul_karatsuba_case( mpi_ptr_t prodp, mpi_ptr_t up, mpi_size_t usize, mpi_ptr_t vp, mpi_size_t vsize, struct karatsuba_ctx *ctx ) { mpi_limb_t cy; if( !ctx->tspace || ctx->tspace_size < vsize ) { if( ctx->tspace ) mpi_free_limb_space( ctx->tspace ); ctx->tspace = mpi_alloc_limb_space( 2 * vsize, m_is_secure( up ) || m_is_secure( vp ) ); ctx->tspace_size = vsize; } MPN_MUL_N_RECURSE( prodp, up, vp, vsize, ctx->tspace ); prodp += vsize; up += vsize; usize -= vsize; if( usize >= vsize ) { if( !ctx->tp || ctx->tp_size < vsize ) { if( ctx->tp ) mpi_free_limb_space( ctx->tp ); ctx->tp = mpi_alloc_limb_space( 2 * vsize, m_is_secure( up ) || m_is_secure( vp ) ); ctx->tp_size = vsize; } do { MPN_MUL_N_RECURSE( ctx->tp, up, vp, vsize, ctx->tspace ); cy = mpihelp_add_n( prodp, prodp, ctx->tp, vsize ); mpihelp_add_1( prodp + vsize, ctx->tp + vsize, vsize, cy ); prodp += vsize; up += vsize; usize -= vsize; } while( usize >= vsize ); } if( usize ) { if( usize < KARATSUBA_THRESHOLD ) { mpihelp_mul( ctx->tspace, vp, vsize, up, usize ); } else { if( !ctx->next ) { ctx->next = m_alloc_clear( sizeof *ctx ); } mpihelp_mul_karatsuba_case( ctx->tspace, vp, vsize, up, usize, ctx->next ); } cy = mpihelp_add_n( prodp, prodp, ctx->tspace, vsize); mpihelp_add_1( prodp + vsize, ctx->tspace + vsize, usize, cy ); } }
MPI mpi_set_opaque( MPI a, void *p, unsigned int len ) { if( !a ) { #ifdef M_DEBUG a = mpi_debug_alloc(0,"alloc_opaque"); #else a = mpi_alloc(0); #endif } if( a->flags & 4 ) xfree( a->d ); else { #ifdef M_DEBUG mpi_debug_free_limb_space(a->d, "alloc_opaque"); #else mpi_free_limb_space(a->d); #endif } a->d = p; a->alloced = 0; a->nlimbs = 0; a->nbits = len; a->flags = 4; return a; }
void mpi_set_secure( MPI a ) { mpi_ptr_t ap, bp; if( (a->flags & 1) ) return; a->flags |= 1; ap = a->d; if( !a->nlimbs ) { assert(!ap); return; } #ifdef M_DEBUG bp = mpi_debug_alloc_limb_space( a->nlimbs, 1, "set_secure" ); #else bp = mpi_alloc_limb_space( a->nlimbs, 1 ); #endif MPN_COPY( bp, ap, a->nlimbs ); a->d = bp; #ifdef M_DEBUG mpi_debug_free_limb_space(ap, "set_secure"); #else mpi_free_limb_space(ap); #endif }
void mpi_assign_limb_space( MPI a, mpi_ptr_t ap, unsigned nlimbs ) { mpi_free_limb_space(a->d); a->d = ap; a->alloced = nlimbs; }
void mpihelp_release_karatsuba_ctx( struct karatsuba_ctx *ctx ) { struct karatsuba_ctx *ctx2; if( ctx->tp ) mpi_free_limb_space( ctx->tp ); if( ctx->tspace ) mpi_free_limb_space( ctx->tspace ); for( ctx=ctx->next; ctx; ctx = ctx2 ) { ctx2 = ctx->next; if( ctx->tp ) mpi_free_limb_space( ctx->tp ); if( ctx->tspace ) mpi_free_limb_space( ctx->tspace ); m_free( ctx ); } }
void mpi_free(MPI a) { if (!a) return; if (a->flags & 4) kzfree(a->d); else mpi_free_limb_space(a->d); if (a->flags & ~7) pr_info("invalid flag value in mpi\n"); kfree(a); }
void mpi_free(MPI a) { if (!a) return; if (a->flags & 4) kfree(a->d); else { mpi_free_limb_space(a->d); } if (a->flags & ~7 ) printk("invalid flag value in mpi\n"); kfree(a); }
mpi_free( MPI a ) #endif { if( !a ) return; if( DBG_MEMORY ) log_debug("mpi_free\n" ); if( a->flags & 4 ) xfree( a->d ); else { #ifdef M_DEBUG mpi_debug_free_limb_space(a->d, info); #else mpi_free_limb_space(a->d); #endif } if( a->flags & ~7 ) log_bug("invalid flag value in mpi\n"); xfree(a); }
void mpi_mul( MPI w, MPI u, MPI v) { mpi_size_t usize, vsize, wsize; mpi_ptr_t up, vp, wp; mpi_limb_t cy; int usign, vsign, usecure, vsecure, sign_product; int assign_wp=0; mpi_ptr_t tmp_limb=NULL; if( u->nlimbs < v->nlimbs ) { /* Swap U and V. */ usize = v->nlimbs; usign = v->sign; usecure = mpi_is_secure(v); up = v->d; vsize = u->nlimbs; vsign = u->sign; vsecure = mpi_is_secure(u); vp = u->d; } else { usize = u->nlimbs; usign = u->sign; usecure = mpi_is_secure(u); up = u->d; vsize = v->nlimbs; vsign = v->sign; vsecure = mpi_is_secure(v); vp = v->d; } sign_product = usign ^ vsign; wp = w->d; /* Ensure W has space enough to store the result. */ wsize = usize + vsize; if ( !mpi_is_secure (w) && (mpi_is_secure (u) || mpi_is_secure (v)) ) { /* w is not allocated in secure space but u or v is. To make sure * that no temporray results are stored in w, we temporary use * a newly allocated limb space for w */ wp = mpi_alloc_limb_space( wsize, 1 ); assign_wp = 2; /* mark it as 2 so that we can later copy it back to * mormal memory */ } else if( w->alloced < wsize ) { if( wp == up || wp == vp ) { wp = mpi_alloc_limb_space( wsize, mpi_is_secure(w) ); assign_wp = 1; } else { mpi_resize(w, wsize ); wp = w->d; } } else { /* Make U and V not overlap with W. */ if( wp == up ) { /* W and U are identical. Allocate temporary space for U. */ up = tmp_limb = mpi_alloc_limb_space( usize, usecure ); /* Is V identical too? Keep it identical with U. */ if( wp == vp ) vp = up; /* Copy to the temporary space. */ MPN_COPY( up, wp, usize ); } else if( wp == vp ) { /* W and V are identical. Allocate temporary space for V. */ vp = tmp_limb = mpi_alloc_limb_space( vsize, vsecure ); /* Copy to the temporary space. */ MPN_COPY( vp, wp, vsize ); } } if( !vsize ) wsize = 0; else { cy = mpihelp_mul( wp, up, usize, vp, vsize ); wsize -= cy? 0:1; } if( assign_wp ) { if (assign_wp == 2) { /* copy the temp wp from secure memory back to normal memory */ mpi_ptr_t tmp_wp = mpi_alloc_limb_space (wsize, 0); MPN_COPY (tmp_wp, wp, wsize); mpi_free_limb_space (wp); wp = tmp_wp; } mpi_assign_limb_space( w, wp, wsize ); } w->nlimbs = wsize; w->sign = sign_product; if( tmp_limb ) mpi_free_limb_space( tmp_limb ); }
int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) { mpi_ptr_t mp_marker = NULL, bp_marker = NULL, ep_marker = NULL; mpi_ptr_t xp_marker = NULL; mpi_ptr_t tspace = NULL; mpi_ptr_t rp, ep, mp, bp; mpi_size_t esize, msize, bsize, rsize; int esign, msign, bsign, rsign; mpi_size_t size; int mod_shift_cnt; int negative_result; int assign_rp = 0; mpi_size_t tsize = 0; int rc = -ENOMEM; esize = exp->nlimbs; msize = mod->nlimbs; size = 2 * msize; esign = exp->sign; msign = mod->sign; rp = res->d; ep = exp->d; if (!msize) return -EINVAL; if (!esize) { rp[0] = 1; res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1; res->sign = 0; goto leave; } mp = mp_marker = mpi_alloc_limb_space(msize); if (!mp) goto enomem; count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]); if (mod_shift_cnt) mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt); else MPN_COPY(mp, mod->d, msize); bsize = base->nlimbs; bsign = base->sign; if (bsize > msize) { bp = bp_marker = mpi_alloc_limb_space(bsize + 1); if (!bp) goto enomem; MPN_COPY(bp, base->d, bsize); mpihelp_divrem(bp + msize, 0, bp, bsize, mp, msize); bsize = msize; MPN_NORMALIZE(bp, bsize); } else bp = base->d; if (!bsize) { res->nlimbs = 0; res->sign = 0; goto leave; } if (res->alloced < size) { if (rp == ep || rp == mp || rp == bp) { rp = mpi_alloc_limb_space(size); if (!rp) goto enomem; assign_rp = 1; } else { if (mpi_resize(res, size) < 0) goto enomem; rp = res->d; } } else { if (rp == bp) { BUG_ON(bp_marker); bp = bp_marker = mpi_alloc_limb_space(bsize); if (!bp) goto enomem; MPN_COPY(bp, rp, bsize); } if (rp == ep) { ep = ep_marker = mpi_alloc_limb_space(esize); if (!ep) goto enomem; MPN_COPY(ep, rp, esize); } if (rp == mp) { BUG_ON(mp_marker); mp = mp_marker = mpi_alloc_limb_space(msize); if (!mp) goto enomem; MPN_COPY(mp, rp, msize); } } MPN_COPY(rp, bp, bsize); rsize = bsize; rsign = bsign; { mpi_size_t i; mpi_ptr_t xp; int c; mpi_limb_t e; mpi_limb_t carry_limb; struct karatsuba_ctx karactx; xp = xp_marker = mpi_alloc_limb_space(2 * (msize + 1)); if (!xp) goto enomem; memset(&karactx, 0, sizeof karactx); negative_result = (ep[0] & 1) && base->sign; i = esize - 1; e = ep[i]; count_leading_zeros(c, e); e = (e << c) << 1; c = BITS_PER_MPI_LIMB - 1 - c; for (;;) { while (c) { mpi_ptr_t tp; mpi_size_t xsize; if (rsize < KARATSUBA_THRESHOLD) mpih_sqr_n_basecase(xp, rp, rsize); else { if (!tspace) { tsize = 2 * rsize; tspace = mpi_alloc_limb_space(tsize); if (!tspace) goto enomem; } else if (tsize < (2 * rsize)) { mpi_free_limb_space(tspace); tsize = 2 * rsize; tspace = mpi_alloc_limb_space(tsize); if (!tspace) goto enomem; } mpih_sqr_n(xp, rp, rsize, tspace); } xsize = 2 * rsize; if (xsize > msize) { mpihelp_divrem(xp + msize, 0, xp, xsize, mp, msize); xsize = msize; } tp = rp; rp = xp; xp = tp; rsize = xsize; if ((mpi_limb_signed_t) e < 0) { if (bsize < KARATSUBA_THRESHOLD) { mpi_limb_t tmp; if (mpihelp_mul (xp, rp, rsize, bp, bsize, &tmp) < 0) goto enomem; } else { if (mpihelp_mul_karatsuba_case (xp, rp, rsize, bp, bsize, &karactx) < 0) goto enomem; } xsize = rsize + bsize; if (xsize > msize) { mpihelp_divrem(xp + msize, 0, xp, xsize, mp, msize); xsize = msize; } tp = rp; rp = xp; xp = tp; rsize = xsize; } e <<= 1; c--; } i--; if (i < 0) break; e = ep[i]; c = BITS_PER_MPI_LIMB; } if (mod_shift_cnt) { carry_limb = mpihelp_lshift(res->d, rp, rsize, mod_shift_cnt); rp = res->d; if (carry_limb) { rp[rsize] = carry_limb; rsize++; } } else { MPN_COPY(res->d, rp, rsize); rp = res->d; } if (rsize >= msize) { mpihelp_divrem(rp + msize, 0, rp, rsize, mp, msize); rsize = msize; } if (mod_shift_cnt) mpihelp_rshift(rp, rp, rsize, mod_shift_cnt); MPN_NORMALIZE(rp, rsize); mpihelp_release_karatsuba_ctx(&karactx); } if (negative_result && rsize) { if (mod_shift_cnt) mpihelp_rshift(mp, mp, msize, mod_shift_cnt); mpihelp_sub(rp, mp, msize, rp, rsize); rsize = msize; rsign = msign; MPN_NORMALIZE(rp, rsize); } res->nlimbs = rsize; res->sign = rsign; leave: rc = 0; enomem: if (assign_rp) mpi_assign_limb_space(res, rp, size); if (mp_marker) mpi_free_limb_space(mp_marker); if (bp_marker) mpi_free_limb_space(bp_marker); if (ep_marker) mpi_free_limb_space(ep_marker); if (xp_marker) mpi_free_limb_space(xp_marker); if (tspace) mpi_free_limb_space(tspace); return rc; }
/**************** * RES = BASE ^ EXP mod MOD */ int mpi_powm(MPI res, MPI base, MPI exp, MPI mod) { mpi_ptr_t mp_marker = NULL, bp_marker = NULL, ep_marker = NULL; mpi_ptr_t xp_marker = NULL; mpi_ptr_t tspace = NULL; mpi_ptr_t rp, ep, mp, bp; mpi_size_t esize, msize, bsize, rsize; int esign, msign, bsign, rsign; mpi_size_t size; int mod_shift_cnt; int negative_result; int assign_rp = 0; mpi_size_t tsize = 0; /* to avoid compiler warning */ /* fixme: we should check that the warning is void */ int rc = -ENOMEM; esize = exp->nlimbs; msize = mod->nlimbs; size = 2 * msize; esign = exp->sign; msign = mod->sign; rp = res->d; ep = exp->d; if (!msize) return -EINVAL; if (!esize) { /* Exponent is zero, result is 1 mod MOD, i.e., 1 or 0 * depending on if MOD equals 1. */ rp[0] = 1; res->nlimbs = (msize == 1 && mod->d[0] == 1) ? 0 : 1; res->sign = 0; goto leave; } /* Normalize MOD (i.e. make its most significant bit set) as required by * mpn_divrem. This will make the intermediate values in the calculation * slightly larger, but the correct result is obtained after a final * reduction using the original MOD value. */ mp = mp_marker = mpi_alloc_limb_space(msize); if (!mp) goto enomem; count_leading_zeros(mod_shift_cnt, mod->d[msize - 1]); if (mod_shift_cnt) mpihelp_lshift(mp, mod->d, msize, mod_shift_cnt); else MPN_COPY(mp, mod->d, msize); bsize = base->nlimbs; bsign = base->sign; if (bsize > msize) { /* The base is larger than the module. Reduce it. */ /* Allocate (BSIZE + 1) with space for remainder and quotient. * (The quotient is (bsize - msize + 1) limbs.) */ bp = bp_marker = mpi_alloc_limb_space(bsize + 1); if (!bp) goto enomem; MPN_COPY(bp, base->d, bsize); /* We don't care about the quotient, store it above the remainder, * at BP + MSIZE. */ mpihelp_divrem(bp + msize, 0, bp, bsize, mp, msize); bsize = msize; /* Canonicalize the base, since we are going to multiply with it * quite a few times. */ MPN_NORMALIZE(bp, bsize); } else bp = base->d; if (!bsize) { res->nlimbs = 0; res->sign = 0; goto leave; } if (res->alloced < size) { /* We have to allocate more space for RES. If any of the input * parameters are identical to RES, defer deallocation of the old * space. */ if (rp == ep || rp == mp || rp == bp) { rp = mpi_alloc_limb_space(size); if (!rp) goto enomem; assign_rp = 1; } else { if (mpi_resize(res, size) < 0) goto enomem; rp = res->d; } } else { /* Make BASE, EXP and MOD not overlap with RES. */ if (rp == bp) { /* RES and BASE are identical. Allocate temp. space for BASE. */ BUG_ON(bp_marker); bp = bp_marker = mpi_alloc_limb_space(bsize); if (!bp) goto enomem; MPN_COPY(bp, rp, bsize); } if (rp == ep) { /* RES and EXP are identical. Allocate temp. space for EXP. */ ep = ep_marker = mpi_alloc_limb_space(esize); if (!ep) goto enomem; MPN_COPY(ep, rp, esize); } if (rp == mp) { /* RES and MOD are identical. Allocate temporary space for MOD. */ BUG_ON(mp_marker); mp = mp_marker = mpi_alloc_limb_space(msize); if (!mp) goto enomem; MPN_COPY(mp, rp, msize); } } MPN_COPY(rp, bp, bsize); rsize = bsize; rsign = bsign; { mpi_size_t i; mpi_ptr_t xp; int c; mpi_limb_t e; mpi_limb_t carry_limb; struct karatsuba_ctx karactx; xp = xp_marker = mpi_alloc_limb_space(2 * (msize + 1)); if (!xp) goto enomem; memset(&karactx, 0, sizeof karactx); negative_result = (ep[0] & 1) && base->sign; i = esize - 1; e = ep[i]; count_leading_zeros(c, e); e = (e << c) << 1; /* shift the exp bits to the left, lose msb */ c = BITS_PER_MPI_LIMB - 1 - c; /* Main loop. * * Make the result be pointed to alternately by XP and RP. This * helps us avoid block copying, which would otherwise be necessary * with the overlap restrictions of mpihelp_divmod. With 50% probability * the result after this loop will be in the area originally pointed * by RP (==RES->d), and with 50% probability in the area originally * pointed to by XP. */ for (;;) { while (c) { mpi_ptr_t tp; mpi_size_t xsize; /*if (mpihelp_mul_n(xp, rp, rp, rsize) < 0) goto enomem */ if (rsize < KARATSUBA_THRESHOLD) mpih_sqr_n_basecase(xp, rp, rsize); else { if (!tspace) { tsize = 2 * rsize; tspace = mpi_alloc_limb_space(tsize); if (!tspace) goto enomem; } else if (tsize < (2 * rsize)) { mpi_free_limb_space(tspace); tsize = 2 * rsize; tspace = mpi_alloc_limb_space(tsize); if (!tspace) goto enomem; } mpih_sqr_n(xp, rp, rsize, tspace); } xsize = 2 * rsize; if (xsize > msize) { mpihelp_divrem(xp + msize, 0, xp, xsize, mp, msize); xsize = msize; } tp = rp; rp = xp; xp = tp; rsize = xsize; if ((mpi_limb_signed_t) e < 0) { /*mpihelp_mul( xp, rp, rsize, bp, bsize ); */ if (bsize < KARATSUBA_THRESHOLD) { mpi_limb_t tmp; if (mpihelp_mul (xp, rp, rsize, bp, bsize, &tmp) < 0) goto enomem; } else { if (mpihelp_mul_karatsuba_case (xp, rp, rsize, bp, bsize, &karactx) < 0) goto enomem; } xsize = rsize + bsize; if (xsize > msize) { mpihelp_divrem(xp + msize, 0, xp, xsize, mp, msize); xsize = msize; } tp = rp; rp = xp; xp = tp; rsize = xsize; } e <<= 1; c--; } i--; if (i < 0) break; e = ep[i]; c = BITS_PER_MPI_LIMB; } /* We shifted MOD, the modulo reduction argument, left MOD_SHIFT_CNT * steps. Adjust the result by reducing it with the original MOD. * * Also make sure the result is put in RES->d (where it already * might be, see above). */ if (mod_shift_cnt) { carry_limb = mpihelp_lshift(res->d, rp, rsize, mod_shift_cnt); rp = res->d; if (carry_limb) { rp[rsize] = carry_limb; rsize++; } } else { MPN_COPY(res->d, rp, rsize); rp = res->d; } if (rsize >= msize) { mpihelp_divrem(rp + msize, 0, rp, rsize, mp, msize); rsize = msize; } /* Remove any leading zero words from the result. */ if (mod_shift_cnt) mpihelp_rshift(rp, rp, rsize, mod_shift_cnt); MPN_NORMALIZE(rp, rsize); mpihelp_release_karatsuba_ctx(&karactx); } if (negative_result && rsize) { if (mod_shift_cnt) mpihelp_rshift(mp, mp, msize, mod_shift_cnt); mpihelp_sub(rp, mp, msize, rp, rsize); rsize = msize; rsign = msign; MPN_NORMALIZE(rp, rsize); } res->nlimbs = rsize; res->sign = rsign; leave: rc = 0; enomem: if (assign_rp) mpi_assign_limb_space(res, rp, size); if (mp_marker) mpi_free_limb_space(mp_marker); if (bp_marker) mpi_free_limb_space(bp_marker); if (ep_marker) mpi_free_limb_space(ep_marker); if (xp_marker) mpi_free_limb_space(xp_marker); if (tspace) mpi_free_limb_space(tspace); return rc; }
int mpi_mul(MPI w, MPI u, MPI v) { int rc = -ENOMEM; mpi_size_t usize, vsize, wsize; mpi_ptr_t up, vp, wp; mpi_limb_t cy; int usign, vsign, sign_product; int assign_wp = 0; mpi_ptr_t tmp_limb = NULL; if (u->nlimbs < v->nlimbs) { /* */ usize = v->nlimbs; usign = v->sign; up = v->d; vsize = u->nlimbs; vsign = u->sign; vp = u->d; } else { usize = u->nlimbs; usign = u->sign; up = u->d; vsize = v->nlimbs; vsign = v->sign; vp = v->d; } sign_product = usign ^ vsign; wp = w->d; /* */ wsize = usize + vsize; if (w->alloced < (size_t) wsize) { if (wp == up || wp == vp) { wp = mpi_alloc_limb_space(wsize); if (!wp) goto nomem; assign_wp = 1; } else { if (mpi_resize(w, wsize) < 0) goto nomem; wp = w->d; } } else { /* */ if (wp == up) { /* */ up = tmp_limb = mpi_alloc_limb_space(usize); if (!up) goto nomem; /* */ if (wp == vp) vp = up; /* */ MPN_COPY(up, wp, usize); } else if (wp == vp) { /* */ vp = tmp_limb = mpi_alloc_limb_space(vsize); if (!vp) goto nomem; /* */ MPN_COPY(vp, wp, vsize); } } if (!vsize) wsize = 0; else { if (mpihelp_mul(wp, up, usize, vp, vsize, &cy) < 0) goto nomem; wsize -= cy ? 0 : 1; } if (assign_wp) mpi_assign_limb_space(w, wp, wsize); w->nlimbs = wsize; w->sign = sign_product; rc = 0; nomem: if (tmp_limb) mpi_free_limb_space(tmp_limb); return rc; }
int mpi_tdiv_qr( MPI quot, MPI rem, MPI num, MPI den) { int rc = -ENOMEM; mpi_ptr_t np, dp; mpi_ptr_t qp, rp; mpi_size_t nsize = num->nlimbs; mpi_size_t dsize = den->nlimbs; mpi_size_t qsize, rsize; mpi_size_t sign_remainder = num->sign; mpi_size_t sign_quotient = num->sign ^ den->sign; unsigned normalization_steps; mpi_limb_t q_limb; mpi_ptr_t marker[5]; int markidx=0; memset(marker,0,sizeof(marker)); /* Ensure space is enough for quotient and remainder. * We need space for an extra limb in the remainder, because it's * up-shifted (normalized) below. */ rsize = nsize + 1; if (mpi_resize( rem, rsize) < 0) goto nomem; qsize = rsize - dsize; /* qsize cannot be bigger than this. */ if( qsize <= 0 ) { if( num != rem ) { rem->nlimbs = num->nlimbs; rem->sign = num->sign; MPN_COPY(rem->d, num->d, nsize); } if( quot ) { /* This needs to follow the assignment to rem, in case the * numerator and quotient are the same. */ quot->nlimbs = 0; quot->sign = 0; } return 0; } if( quot ) if (mpi_resize( quot, qsize) < 0) goto nomem; /* Read pointers here, when reallocation is finished. */ np = num->d; dp = den->d; rp = rem->d; /* Optimize division by a single-limb divisor. */ if( dsize == 1 ) { mpi_limb_t rlimb; if( quot ) { qp = quot->d; rlimb = mpihelp_divmod_1( qp, np, nsize, dp[0] ); qsize -= qp[qsize - 1] == 0; quot->nlimbs = qsize; quot->sign = sign_quotient; } else rlimb = mpihelp_mod_1( np, nsize, dp[0] ); rp[0] = rlimb; rsize = rlimb != 0?1:0; rem->nlimbs = rsize; rem->sign = sign_remainder; return 0; } if( quot ) { qp = quot->d; /* Make sure QP and NP point to different objects. Otherwise the * numerator would be gradually overwritten by the quotient limbs. */ if(qp == np) { /* Copy NP object to temporary space. */ np = marker[markidx++] = mpi_alloc_limb_space(nsize); MPN_COPY(np, qp, nsize); } } else /* Put quotient at top of remainder. */ qp = rp + dsize; count_leading_zeros( normalization_steps, dp[dsize - 1] ); /* Normalize the denominator, i.e. make its most significant bit set by * shifting it NORMALIZATION_STEPS bits to the left. Also shift the * numerator the same number of steps (to keep the quotient the same!). */ if( normalization_steps ) { mpi_ptr_t tp; mpi_limb_t nlimb; /* Shift up the denominator setting the most significant bit of * the most significant word. Use temporary storage not to clobber * the original contents of the denominator. */ tp = marker[markidx++] = mpi_alloc_limb_space(dsize); if (!tp) goto nomem; mpihelp_lshift( tp, dp, dsize, normalization_steps ); dp = tp; /* Shift up the numerator, possibly introducing a new most * significant word. Move the shifted numerator in the remainder * meanwhile. */ nlimb = mpihelp_lshift(rp, np, nsize, normalization_steps); if( nlimb ) { rp[nsize] = nlimb; rsize = nsize + 1; } else rsize = nsize; } else { /* The denominator is already normalized, as required. Copy it to * temporary space if it overlaps with the quotient or remainder. */ if( dp == rp || (quot && (dp == qp))) { mpi_ptr_t tp; tp = marker[markidx++] = mpi_alloc_limb_space(dsize); if (!tp) goto nomem; MPN_COPY( tp, dp, dsize ); dp = tp; } /* Move the numerator to the remainder. */ if( rp != np ) MPN_COPY(rp, np, nsize); rsize = nsize; } q_limb = mpihelp_divrem( qp, 0, rp, rsize, dp, dsize ); if( quot ) { qsize = rsize - dsize; if(q_limb) { qp[qsize] = q_limb; qsize += 1; } quot->nlimbs = qsize; quot->sign = sign_quotient; } rsize = dsize; MPN_NORMALIZE (rp, rsize); if( normalization_steps && rsize ) { mpihelp_rshift(rp, rp, rsize, normalization_steps); rsize -= rp[rsize - 1] == 0?1:0; } rem->nlimbs = rsize; rem->sign = sign_remainder; rc = 0; nomem: while( markidx ) mpi_free_limb_space(marker[--markidx]); return rc; }