/* * Compute a = a % m. * Input in first alen words of a and first mlen words of m. * Output in first alen words of a * (of which first alen-mlen words will be zero). * The MSW of m MUST have its high bit set. * Quotient is accumulated in the `quotient' array, which is a Bignum * rather than the internal bigendian format. Quotient parts are shifted * left by `qshift' before adding into quot. */ static void internal_mod(BignumInt *a, int alen, BignumInt *m, int mlen, BignumInt *quot, int qshift) { BignumInt m0, m1; unsigned int h; int i, k; m0 = m[0]; if (mlen > 1) m1 = m[1]; else m1 = 0; for (i = 0; i <= alen - mlen; i++) { BignumDblInt t; unsigned int q, r, c, ai1; if (i == 0) { h = 0; } else { h = a[i - 1]; a[i - 1] = 0; } if (i == alen - 1) ai1 = 0; else ai1 = a[i + 1]; /* Find q = h:a[i] / m0 */ if (h >= m0) { /* * Special case. * * To illustrate it, suppose a BignumInt is 8 bits, and * we are dividing (say) A1:23:45:67 by A1:B2:C3. Then * our initial division will be 0xA123 / 0xA1, which * will give a quotient of 0x100 and a divide overflow. * However, the invariants in this division algorithm * are not violated, since the full number A1:23:... is * _less_ than the quotient prefix A1:B2:... and so the * following correction loop would have sorted it out. * * In this situation we set q to be the largest * quotient we _can_ stomach (0xFF, of course). */ q = BIGNUM_INT_MASK; } else { DIVMOD_WORD(q, r, h, a[i], m0); /* Refine our estimate of q by looking at h:a[i]:a[i+1] / m0:m1 */ t = MUL_WORD(m1, q); if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) { q--; t -= m1; r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */ if (r >= (BignumDblInt) m0 && t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--; } } /* Subtract q * m from a[i...] */ c = 0; for (k = mlen - 1; k >= 0; k--) { t = MUL_WORD(q, m[k]); t += c; c = t >> BIGNUM_INT_BITS; if ((BignumInt) t > a[i + k]) c++; a[i + k] -= (BignumInt) t; } /* Add back m in case of borrow */ if (c != h) { t = 0; for (k = mlen - 1; k >= 0; k--) { t += m[k]; t += a[i + k]; a[i + k] = (BignumInt) t; t = t >> BIGNUM_INT_BITS; } q--; } if (quot) internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i)); }
/* * Compute a = a % m. * Input in first alen words of a and first mlen words of m. * Output in first alen words of a * (of which first alen-mlen words will be zero). * The MSW of m MUST have its high bit set. * Quotient is accumulated in the `quotient' array, which is a Bignum * rather than the internal bigendian format. Quotient parts are shifted * left by `qshift' before adding into quot. */ static void internal_mod(BignumInt *a, int alen, BignumInt *m, int mlen, BignumInt *quot, int qshift) { BignumInt m0, m1; unsigned int h; int i, k; m0 = m[0]; if (mlen > 1) m1 = m[1]; else m1 = 0; for (i = 0; i <= alen - mlen; i++) { BignumDblInt t; unsigned int q, r, c, ai1; if (i == 0) { h = 0; } else { h = a[i - 1]; a[i - 1] = 0; } if (i == alen - 1) ai1 = 0; else ai1 = a[i + 1]; /* Find q = h:a[i] / m0 */ DIVMOD_WORD(q, r, h, a[i], m0); /* Refine our estimate of q by looking at h:a[i]:a[i+1] / m0:m1 */ t = MUL_WORD(m1, q); if (t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) { q--; t -= m1; r = (r + m0) & BIGNUM_INT_MASK; /* overflow? */ if (r >= (BignumDblInt) m0 && t > ((BignumDblInt) r << BIGNUM_INT_BITS) + ai1) q--; } /* Subtract q * m from a[i...] */ c = 0; for (k = mlen - 1; k >= 0; k--) { t = MUL_WORD(q, m[k]); t += c; c = t >> BIGNUM_INT_BITS; if ((BignumInt) t > a[i + k]) c++; a[i + k] -= (BignumInt) t; } /* Add back m in case of borrow */ if (c != h) { t = 0; for (k = mlen - 1; k >= 0; k--) { t += m[k]; t += a[i + k]; a[i + k] = (BignumInt) t; t = t >> BIGNUM_INT_BITS; } q--; } if (quot) internal_add_shifted(quot, q, qshift + BIGNUM_INT_BITS * (alen - mlen - i)); }