void bn_rsh(bn_t c, bn_t a, int bits) { int digits = 0; if (bits <= 0) { bn_copy(c, a); return; } SPLIT(bits, digits, bits, BN_DIG_LOG); if (digits > 0) { bn_rshd_low(c->dp, a->dp, a->used, digits); } c->used = a->used - digits; c->sign = a->sign; if (c->used > 0 && bits > 0) { if (digits == 0 && c != a) { bn_rshb_low(c->dp, a->dp + digits, a->used - digits, bits); } else { bn_rshb_low(c->dp, c->dp, c->used, bits); } } bn_trim(c); }
void fp_rdcs_low(dig_t *c, dig_t *a, dig_t *m) { align dig_t q[2 * FP_DIGS], _q[2 * FP_DIGS]; align dig_t _r[2 * FP_DIGS], r[2 * FP_DIGS], t[2 * FP_DIGS]; int *sform, len; int first, i, j, b0, d0, b1, d1; dig_t carry; sform = fp_prime_get_sps(&len); SPLIT(b0, d0, FP_BITS, FP_DIG_LOG); first = (d0) + (b0 == 0 ? 0 : 1); /* q = floor(a/b^k) */ dv_zero(q, 2 * FP_DIGS); bn_rshd_low(q, a, 2 * FP_DIGS, d0); if (b0 > 0) { bn_rshb_low(q, q, 2 * FP_DIGS, b0); } /* r = a - qb^k. */ dv_copy(r, a, first); if (b0 > 0) { r[first - 1] &= MASK(b0); } carry = 0; while (!fp_is_zero(q)) { dv_zero(_q, 2 * FP_DIGS); for (i = len - 1; i > 0; i--) { j = (sform[i] < 0 ? -sform[i] : sform[i]); SPLIT(b1, d1, j, FP_DIG_LOG); dv_zero(t, 2 * FP_DIGS); bn_lshd_low(t, q, FP_DIGS, d1); if (b1 > 0) { bn_lshb_low(t, t, 2 * FP_DIGS, b1); } if (sform[i] > 0) { bn_subn_low(_q, _q, t, 2 * FP_DIGS); } else { bn_addn_low(_q, _q, t, 2 * FP_DIGS); } } if (sform[0] > 0) { bn_subn_low(_q, _q, q, 2 * FP_DIGS); } else { bn_addn_low(_q, _q, q, 2 * FP_DIGS); } bn_rshd_low(q, _q, 2 * FP_DIGS, d0); if (b0 > 0) { bn_rshb_low(q, q, 2 * FP_DIGS, b0); } dv_copy(_r, _q, first); if (b0 > 0) { _r[first - 1] &= MASK(b0); } fp_add(r, r, _r); } while (fp_cmpn_low(r, m) != CMP_LT) { fp_subn_low(r, r, m); } fp_copy(c, r); }
void bn_divn_low(dig_t *c, dig_t *d, dig_t *a, int sa, dig_t *b, int sb) { int norm, i, n, t, sd; dig_t carry, t1[3], t2[3]; /* Normalize x and y so that the leading digit of y is bigger than * 2^(BN_DIGIT-1). */ norm = util_bits_dig(b[sb - 1]) % BN_DIGIT; if (norm < (int)(BN_DIGIT - 1)) { norm = (BN_DIGIT - 1) - norm; carry = bn_lshb_low(a, a, sa, norm); if (carry) { a[sa++] = carry; } carry = bn_lshb_low(b, b, sb, norm); if (carry) { b[sb++] = carry; } } else { norm = 0; } n = sa - 1; t = sb - 1; /* Shift y so that the most significant digit of y is aligned with the * most significant digit of x. */ bn_lshd_low(b, b, sb, (n - t)); /* Find the most significant digit of the quotient. */ while (bn_cmpn_low(a, b, sa) != CMP_LT) { c[n - t]++; bn_subn_low(a, a, b, sa); } /* Shift y back. */ bn_rshd_low(b, b, sb + (n - t), (n - t)); /* Find the remaining digits. */ for (i = n; i >= (t + 1); i--) { if (i > sa) { continue; } if (a[i] == b[t]) { c[i - t - 1] = ((((dbl_t)1) << BN_DIGIT) - 1); } else { dbl_t tmp; tmp = ((dbl_t)a[i]) << ((dbl_t)BN_DIGIT); tmp |= (dbl_t)(a[i - 1]); tmp /= (dbl_t)(b[t]); c[i - t - 1] = (dig_t)tmp; } c[i - t - 1]++; do { c[i - t - 1]--; t1[0] = (t - 1 < 0) ? 0 : b[t - 1]; t1[1] = b[t]; carry = bn_mul1_low(t1, t1, c[i - t - 1], 2); t1[2] = carry; t2[0] = (i - 2 < 0) ? 0 : a[i - 2]; t2[1] = (i - 1 < 0) ? 0 : a[i - 1]; t2[2] = a[i]; } while (bn_cmpn_low(t1, t2, 3) == CMP_GT); carry = bn_mul1_low(d, b, c[i - t - 1], sb); sd = sb; if (carry) { d[sd++] = carry; } carry = bn_subn_low(a + (i - t - 1), a + (i - t - 1), d, sd); sd += (i - t - 1); if (sa - sd > 0) { carry = bn_sub1_low(a + sd, a + sd, carry, sa - sd); } if (carry) { sd = sb + (i - t - 1); carry = bn_addn_low(a + (i - t - 1), a + (i - t - 1), b, sb); carry = bn_add1_low(a + sd, a + sd, carry, sa - sd); c[i - t - 1]--; } } /* Remainder should be not be longer than the divisor. */ bn_rshb_low(d, a, sb, norm); }