Пример #1
0
void fb_mul_lcomb(fb_t c, const fb_t a, const fb_t b) {
	dv_t t;
	dig_t carry;

	dv_null(t);

	TRY {
		dv_new(t);
		dv_zero(t, 2 * FB_DIGS);

		for (int i = FB_DIGIT - 1; i >= 0; i--) {
			for (int j = 0; j < FB_DIGS; j++) {
				if (a[j] & ((dig_t)1 << i)) {
					/* This cannot use fb_addn_low() because there is no
					 * guarantee that operands will be aligned. */
					fb_addd_low(t + j, t + j, b, FB_DIGS);
				}
			}
			if (i != 0) {
				carry = fb_lsh1_low(t, t);
				fb_lsh1_low(t + FB_DIGS, t + FB_DIGS);
				t[FB_DIGS] |= carry;
			}
		}

		fb_rdc(c, t);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t);
	}
}
Пример #2
0
/**
 * Multiplies two binary field elements using right-to-left comb multiplication.
 *
 * @param c					- the result.
 * @param a					- the first binary field element.
 * @param b					- the second binary field element.
 * @param size				- the number of digits to multiply.
 */
static void fb_mul_rcomb_imp(dig_t *c, const dig_t *a, const dig_t *b, int size) {
	dv_t _b;

	dv_null(_b);

	TRY {
		dv_new(_b);
		dv_zero(c, 2 * size);

		for (int i = 0; i < size; i++)
			_b[i] = b[i];
		_b[size] = 0;

		for (int i = 0; i < FB_DIGIT; i++) {
			for (int j = 0; j < size; j++) {
				if (a[j] & ((dig_t)1 << i)) {
					fb_addd_low(c + j, c + j, _b, size + 1);
				}
			}
			if (i != FB_DIGIT - 1) {
				bn_lsh1_low(_b, _b, size + 1);
			}
		}
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(_b);
	}
}
Пример #3
0
void fb_rdc_basic(fb_t c, dv_t a) {
	int j, k;
	dig_t *tmpa;
	dv_t r;

	dv_null(r);

	TRY {
		dv_new(r);

		tmpa = a + FB_DIGS;

		/* First reduce the high part. */
		for (int i = fb_bits(tmpa) - 1; i >= 0; i--) {
			if (fb_get_bit(tmpa, i)) {
				SPLIT(k, j, i - FB_BITS, FB_DIG_LOG);
				if (k <= 0) {
					fb_addd_low(tmpa + j, tmpa + j, fb_poly_get(), FB_DIGS);
				} else {
					r[FB_DIGS] = fb_lshb_low(r, fb_poly_get(), k);
					fb_addd_low(tmpa + j, tmpa + j, r, FB_DIGS + 1);
				}
			}
		}
		for (int i = fb_bits(a) - 1; i >= FB_BITS; i--) {
			if (fb_get_bit(a, i)) {
				SPLIT(k, j, i - FB_BITS, FB_DIG_LOG);
				if (k == 0) {
					fb_addd_low(a + j, a + j, fb_poly_get(), FB_DIGS);
				} else {
					r[FB_DIGS] = fb_lshb_low(r, fb_poly_get(), k);
					fb_addd_low(a + j, a + j, r, FB_DIGS + 1);
				}
			}
		}

		fb_copy(c, a);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		fb_free(r);
	}
}
Пример #4
0
/**
 * Multiplies two binary field elements using left-to-right comb multiplication.
 *
 * @param c					- the result.
 * @param a					- the first binary field element.
 * @param b					- the second binary field element.
 * @param size				- the number of digits to multiply.
 */
static void fb_mul_lcomb_imp(dig_t *c, const dig_t *a, const dig_t *b, int size) {
	dv_zero(c, 2 * size);

	for (int i = FB_DIGIT - 1; i >= 0; i--) {
		for (int j = 0; j < size; j++) {
			if (a[j] & ((dig_t)1 << i)) {
				fb_addd_low(c + j, c + j, b, size);
			}
		}
		if (i != 0) {
			bn_lsh1_low(c, c, 2 * size);
		}
	}
}
Пример #5
0
void fb_mul_rcomb(fb_t c, const fb_t a, const fb_t b) {
	dv_t t, _b;
	dig_t carry;

	dv_null(t);
	dv_null(_b);

	TRY {
		dv_new(t);
		dv_new(_b);
		dv_zero(t, 2 * FB_DIGS);
		dv_zero(_b, FB_DIGS + 1);

		fb_copy(_b, b);

		for (int i = 0; i < FB_DIGIT; i++) {
			for (int j = 0; j < FB_DIGS; j++) {
				if (a[j] & ((dig_t)1 << i)) {
					fb_addd_low(t + j, t + j, _b, FB_DIGS + 1);
				}
			}
			if (i != FB_DIGIT - 1) {
				carry = fb_lsh1_low(_b, _b);
				_b[FB_DIGS] = (_b[FB_DIGS] << 1) | carry;
			}
		}

		fb_rdc(c, t);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(t);
		dv_free(_b);
	}
}
Пример #6
0
/**
 * Multiplies two binary field elements using recursive Karatsuba
 * multiplication.
 *
 * @param[out] c			- the result.
 * @param[in] a				- the first binary field element.
 * @param[in] b				- the second binary field element.
 * @param[in] size			- the number of digits to multiply.
 * @param[in] level			- the number of Karatsuba steps to apply.
 */
static void fb_mul_karat_imp(dv_t c, const fb_t a, const fb_t b, int size,
		int level) {
	int i, h, h1;
	dv_t a1, b1, ab;
	dig_t *a0b0, *a1b1;

	dv_null(a1);
	dv_null(b1);
	dv_null(ab);

	/* Compute half the digits of a or b. */
	h = size >> 1;
	h1 = size - h;

	TRY {
		/* Allocate the temp variables. */
		dv_new(a1);
		dv_new(b1);
		dv_new(ab);
		a0b0 = ab;
		a1b1 = ab + 2 * h;

		/* a0b0 = a0 * b0 and a1b1 = a1 * b1 */
		if (level <= 1) {
#if FB_MUL == BASIC
			fb_mul_basic_imp(a0b0, a, b, h);
			fb_mul_basic_imp(a1b1, a + h, b + h, h1);
#elif FB_MUL == LCOMB
			fb_mul_lcomb_imp(a0b0, a, b, h);
			fb_mul_lcomb_imp(a1b1, a + h, b + h, h1);
#elif FB_MUL == RCOMB
			fb_mul_rcomb_imp(a0b0, a, b, h);
			fb_mul_rcomb_imp(a1b1, a + h, b + h, h1);
#elif FB_MUL == INTEG || FB_MUL == LODAH
			fb_muld_low(a0b0, a, b, h);
			fb_muld_low(a1b1, a + h, b + h, h1);
#endif
		} else {
			fb_mul_karat_imp(a0b0, a, b, h, level - 1);
			fb_mul_karat_imp(a1b1, a + h, b + h, h1, level - 1);
		}

		for (i = 0; i < 2 * size; i++) {
			c[i] = ab[i];
		}

		/* c = c - (a0*b0 << h digits) */
		fb_addd_low(c + h, c + h, a0b0, 2 * h);

		/* c = c - (a1*b1 << h digits) */
		fb_addd_low(c + h, c + h, a1b1, 2 * h1);

		/* a1 = (a1 + a0) */
		fb_addd_low(a1, a, a + h, h);

		/* b1 = (b1 + b0) */
		fb_addd_low(b1, b, b + h, h);

		if (h1 > h) {
			a1[h1 - 1] = a[h + h1 - 1];
			b1[h1 - 1] = b[h + h1 - 1];
		}

		if (level <= 1) {
			/* a1b1 = (a1 + a0)*(b1 + b0) */
#if FB_MUL == BASIC
			fb_mul_basic_imp(a1b1, a1, b1, h1);
#elif FB_MUL == LCOMB
			fb_mul_lcomb_imp(a1b1, a1, b1, h1);
#elif FB_MUL == RCOMB
			fb_mul_rcomb_imp(a1b1, a1, b1, h1);
#elif FB_MUL == INTEG || FB_MUL == LODAH
			fb_muld_low(a1b1, a1, b1, h1);
#endif
		} else {
			fb_mul_karat_imp(a1b1, a1, b1, h1, level - 1);
		}

		/* c = c + [(a1 + a0)*(b1 + b0) << digits] */
		fb_addd_low(c + h, c + h, a1b1, 2 * h1);
	}
	CATCH_ANY {
		THROW(ERR_CAUGHT);
	}
	FINALLY {
		dv_free(a1);
		dv_free(b1);
		dv_free(ab);
	}
}
Пример #7
0
void fb_invn_low(dig_t *c, const dig_t *a) {
	int j, d, lu, lv, lt, l1, l2, bu, bv;
	align dig_t _u[2 * FB_DIGS], _v[2 * FB_DIGS];
	align dig_t _g1[2 * FB_DIGS], _g2[2 * FB_DIGS];
	dig_t *t = NULL, *u = NULL, *v = NULL, *g1 = NULL, *g2 = NULL, carry;

	dv_zero(_g1, FB_DIGS + 1);
	dv_zero(_g2, FB_DIGS + 1);

	u = _u;
	v = _v;
	g1 = _g1;
	g2 = _g2;

	/* u = a, v = f, g1 = 1, g2 = 0. */
	dv_copy(u, a, FB_DIGS);
	dv_copy(v, fb_poly_get(), FB_DIGS);
	g1[0] = 1;

	lu = lv = FB_DIGS;
	l1 = l2 = 1;

	bu = fb_bits(u);
	bv = FB_BITS + 1;
	j = bu - bv;

	/* While (u != 1). */
	while (1) {
		/* If j < 0 then swap(u, v), swap(g1, g2), j = -j. */
		if (j < 0) {
			t = u;
			u = v;
			v = t;

			lt = lu;
			lu = lv;
			lv = lt;

			t = g1;
			g1 = g2;
			g2 = t;

			lt = l1;
			l1 = l2;
			l2 = lt;

			j = -j;
		}

		SPLIT(j, d, j, FB_DIG_LOG);

		/* u = u + v * z^j. */
		if (j > 0) {
			carry = fb_lsha_low(u + d, v, j, lv);
			u[d + lv] ^= carry;
		} else {
			fb_addd_low(u + d, u + d, v, lv);
		}

		/* g1 = g1 + g2 * z^j. */
		if (j > 0) {
			carry = fb_lsha_low(g1 + d, g2, j, l2);
			l1 = (l2 + d >= l1 ? l2 + d : l1);
			if (carry) {
				g1[d + l2] ^= carry;
				l1 = (l2 + d >= l1 ? l1 + 1 : l1);
			}
		} else {
			fb_addd_low(g1 + d, g1 + d, g2, l2);
			l1 = (l2 + d > l1 ? l2 + d : l1);
		}

		while (u[lu - 1] == 0)
			lu--;
		while (v[lv - 1] == 0)
			lv--;

		if (lu == 1 && u[0] == 1)
			break;

		/* j = deg(u) - deg(v). */
		lt = util_bits_dig(u[lu - 1]) - util_bits_dig(v[lv - 1]);
		j = ((lu - lv) << FB_DIG_LOG) + lt;
	}
	/* Return g1. */
	fb_copy(c, g1);
}