示例#1
0
void bn_lsh(bn_t c, bn_t a, int bits) {
	int digits;
	dig_t carry;

	bn_copy(c, a);
	if (bits <= 0) {
		return;
	}

	SPLIT(bits, digits, bits, BN_DIG_LOG);

	if (bits > 0) {
		if (bn_bits(c) + bits > c->used * (int)BN_DIGIT) {
			bn_grow(c, c->used + digits + 1);
		}
	} else {
		bn_grow(c, c->used + digits);
	}

	if (digits > 0) {
		bn_lshd_low(c->dp, a->dp, a->used, digits);
	}
	c->used = a->used + digits;
	c->sign = a->sign;

	if (bits > 0) {
		if (c != a) {
			carry = bn_lshb_low(c->dp + digits, a->dp, a->used, bits);
		} else {
			carry = bn_lshb_low(c->dp + digits, c->dp + digits, c->used, bits);
		}
		if (carry != 0) {
			c->dp[c->used] = carry;
			(c->used)++;
		}
	}
	bn_trim(c);
}
示例#2
0
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);
}