/** * Multiplies two binary field elements using shift-and-add 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_basic_imp(dig_t *c, const dig_t *a, const dig_t *b, int size) { int i; dv_t s; dv_null(s); TRY { /* We need a temporary variable so that c can be a or b. */ dv_new(s); dv_zero(s, 2 * FB_DIGS); dv_copy(s, b, size); dv_zero(c, 2 * size); if (a[0] & 1) { dv_copy(c, b, size); } for (i = 1; i <= (FB_DIGIT * size) - 1; i++) { fb_lsh1_low(s, s); fb_rdc(s, s); if (fb_get_bit(a, i)) { fb_add(c, c, s); } } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { dv_free(s); } }
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); } }
void fb_sqr_table(fb_t c, const fb_t a) { dv_t t; dv_null(t); TRY { /* We need a temporary variable so that c can be a or b. */ dv_new(t); fb_sqrl_low(t, a); fb_rdc(c, t); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { dv_free(t); } }
void fb_mul_lodah(fb_t c, const fb_t a, const fb_t b) { dv_t t; dv_null(t); TRY { dv_new(t); fb_muln_low(t, a, b); fb_rdc(c, t); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { dv_free(t); } }
void fb_mul_basic(fb_t c, const fb_t a, const fb_t b) { int i; dv_t s; fb_t t; dv_null(s); fb_null(t); TRY { /* We need a temporary variable so that c can be a or b. */ fb_new(t); dv_new(s); fb_zero(t); dv_zero(s + FB_DIGS, FB_DIGS); fb_copy(s, b); if (a[0] & 1) { fb_copy(t, b); } for (i = 1; i < FB_BITS; i++) { /* We are already shifting a temporary value, so this is more efficient * than calling fb_lsh(). */ s[FB_DIGS] = fb_lsh1_low(s, s); fb_rdc(s, s); if (fb_get_bit(a, i)) { fb_add(t, t, s); } } if (fb_bits(t) > FB_BITS) { fb_poly_add(c, t); } else { fb_copy(c, t); } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { fb_free(t); fb_free(s); } }
void fb_mul_karat(fb_t c, const fb_t a, const fb_t b) { dv_t t; dv_null(t); TRY { /* We need a temporary variable so that c can be a or b. */ dv_new(t); dv_zero(t, 2 * FB_DIGS); fb_mul_karat_imp(t, a, b, FB_DIGS, FB_KARAT); fb_rdc(c, t); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { dv_free(t); } }
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); } }