void bn_add(bn_t c, bn_t a, bn_t b) { int sa, sb; sa = a->sign; sb = b->sign; if (sa == sb) { /* If the signs are equal, copy the sign and add. */ c->sign = sa; if (bn_cmp_abs(a, b) == CMP_LT) { bn_add_imp(c, b, a); } else { bn_add_imp(c, a, b); } } else { /* If the signs are different, subtract. */ if (bn_cmp_abs(a, b) == CMP_LT) { c->sign = sb; bn_sub_imp(c, b, a); } else { c->sign = sa; bn_sub_imp(c, a, b); } } }
void bn_sub(bn_t c, bn_t a, bn_t b) { int sa, sb; sa = a->sign; sb = b->sign; if (sa != sb) { /* If the signs are different, copy the sign of the first number and * add. */ c->sign = sa; if (bn_cmp_abs(a, b) == CMP_LT) { bn_add_imp(c, b, a); } else { bn_add_imp(c, a, b); } } else { /* If the signs are equal, adjust the sign and subtract. */ if (bn_cmp_abs(a, b) != CMP_LT) { c->sign = sa; bn_sub_imp(c, a, b); } else { c->sign = (sa == BN_POS) ? BN_NEG : BN_POS; bn_sub_imp(c, b, a); } } }
int bn_cmp(bn_t a, bn_t b) { if (a->sign == BN_POS && b->sign == BN_NEG) { return CMP_GT; } if (a->sign == BN_NEG && b->sign == BN_POS) { return CMP_LT; } if (a->sign == BN_NEG) { return bn_cmp_abs(b, a); } return bn_cmp_abs(a, b); }
void bn_lcm(bn_t c, const bn_t a, const bn_t b) { bn_t u, v; bn_null(u); bn_null(v); TRY { bn_new(u); bn_new(v); bn_gcd(u, a, b); if (bn_cmp_abs(a, b) == CMP_LT) { bn_div(v, a, u); bn_mul(c, b, v); } else { bn_div(v, b, u); bn_mul(c, a, v); } c->sign = BN_POS; } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(u); bn_free(v); } }
/** * Divides two multiple precision integers, computing the quotient and the * remainder. * * @param[out] c - the quotient. * @param[out] d - the remainder. * @param[in] a - the dividend. * @param[in] b - the the divisor. */ static void bn_div_imp(bn_t c, bn_t d, const bn_t a, const bn_t b) { bn_t q, x, y, r; int sign; bn_null(q); bn_null(x); bn_null(y); bn_null(r); /* If a < b, we're done. */ if (bn_cmp_abs(a, b) == CMP_LT) { if (bn_sign(a) == BN_POS) { if (c != NULL) { bn_zero(c); } if (d != NULL) { bn_copy(d, a); } } else { if (c != NULL) { bn_set_dig(c, 1); if (bn_sign(b) == BN_POS) { bn_neg(c, c); } } if (d != NULL) { if (bn_sign(b) == BN_POS) { bn_add(d, a, b); } else { bn_sub(d, a, b); } } } return; } TRY { bn_new(x); bn_new(y); bn_new_size(q, a->used + 1); bn_new(r); bn_zero(q); bn_zero(r); bn_abs(x, a); bn_abs(y, b); /* Find the sign. */ sign = (a->sign == b->sign ? BN_POS : BN_NEG); bn_divn_low(q->dp, r->dp, x->dp, a->used, y->dp, b->used); /* We have the quotient in q and the remainder in r. */ if (c != NULL) { q->used = a->used - b->used + 1; q->sign = sign; bn_trim(q); if (bn_sign(a) == BN_NEG) { bn_sub_dig(c, q, 1); } else { bn_copy(c, q); } } if (d != NULL) { r->used = b->used; r->sign = a->sign; bn_trim(r); if (bn_sign(a) == BN_NEG) { bn_add(d, r, b); } else { bn_copy(d, r); } } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(r); bn_free(q); bn_free(x); bn_free(y); } }
void bn_rand_mod(bn_t a, bn_t b) { do { bn_rand(a, bn_sign(b), bn_bits(b)); } while (bn_is_zero(a) || bn_cmp_abs(a, b) != CMP_LT); }