void fp_prime_back(bn_t c, const fp_t a) { dv_t t; int i; dv_null(t); TRY { dv_new(t); bn_grow(c, FP_DIGS); for (i = 0; i < FP_DIGS; i++) { c->dp[i] = a[i]; } #if FP_RDC == MONTY dv_zero(t, 2 * FP_DIGS + 1); dv_copy(t, a, FP_DIGS); fp_rdc(c->dp, t); #endif c->used = FP_DIGS; c->sign = BN_POS; bn_trim(c); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { dv_free(t); } }
void bn_sqr_comba(bn_t c, const bn_t a) { int digits; bn_t t; bn_null(t); digits = 2 * a->used; TRY { /* We need a temporary variable so that c can be a or b. */ bn_new_size(t, digits); t->used = digits; bn_sqrn_low(t->dp, a->dp, a->used); t->sign = BN_POS; bn_trim(t); bn_copy(c, t); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(t); } }
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 bn_sqr_basic(bn_t c, const bn_t a) { int i, digits; bn_t t; bn_null(t); digits = 2 * a->used; TRY { bn_new_size(t, digits); bn_zero(t); t->used = digits; for (i = 0; i < a->used; i++) { bn_sqra_low(t->dp + (2 * i), a->dp + i, a->used - i); } t->sign = BN_POS; bn_trim(t); bn_copy(c, t); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(t); } }
void bn_read_bin(bn_t a, const uint8_t *bin, int len) { int i, j; dig_t d = (BN_DIGIT / 8); int digs = (len % d == 0 ? len / d : len / d + 1); bn_grow(a, digs); bn_zero(a); a->used = digs; for (i = 0; i < digs - 1; i++) { d = 0; for (j = (BN_DIGIT / 8) - 1; j >= 0; j--) { d = d << 8; d |= bin[len - 1 - (i * (BN_DIGIT / 8) + j)]; } a->dp[i] = d; } d = 0; for (j = (BN_DIGIT / 8) - 1; j >= 0; j--) { if ((int)(i * (BN_DIGIT / 8) + j) < len) { d = d << 8; d |= bin[len - 1 - (i * (BN_DIGIT / 8) + j)]; } } a->dp[i] = d; a->sign = BN_POS; bn_trim(a); }
void bn_sub_dig(bn_t c, bn_t a, dig_t b) { dig_t carry; bn_grow(c, a->used); /* If a < 0, compute c = -(|a| + b). */ if (a->sign == BN_NEG) { carry = bn_add1_low(c->dp, a->dp, b, a->used); if (carry) { bn_grow(c, a->used + 1); c->dp[a->used] = carry; } c->used = a->used + carry; c->sign = BN_NEG; } else { /* If a > 0 && |a| >= b, compute c = (|a| - b). */ if (a->used > 1 || a->dp[0] >= b) { carry = bn_sub1_low(c->dp, a->dp, b, a->used); c->used = a->used; c->sign = BN_POS; } else { /* If a > 0 && a < b. */ if (a->used == 1) { c->dp[0] = b - a->dp[0]; } else { c->dp[0] = b; } c->used = 1; c->sign = BN_NEG; } } bn_trim(c); }
void bn_hlv(bn_t c, bn_t a) { bn_grow(c, a->used); c->used = a->used; bn_rsh1_low(c->dp, a->dp, c->used); c->sign = a->sign; bn_trim(c); }
void bn_set_bit(bn_t a, int bit, int value) { int d; SPLIT(bit, d, bit, BN_DIG_LOG); if (value == 1) { a->dp[d] |= ((dig_t)1 << bit); if ((d + 1) > a->used) { a->used = d + 1; } } else { a->dp[d] &= ~((dig_t)1 << bit); bn_trim(a); } }
void bn_div_rem_dig(bn_t c, dig_t *d, const bn_t a, dig_t b) { bn_t q; dig_t r; bn_null(q); if (b == 0) { THROW(ERR_NO_VALID); } if (b == 1 || bn_is_zero(a) == 1) { if (d != NULL) { *d = 0; } if (c != NULL) { bn_copy(c, a); } return; } TRY { bn_new(q); int size = a->used; const dig_t *ap = a->dp; bn_div1_low(q->dp, &r, ap, size, b); if (c != NULL) { q->used = a->used; q->sign = a->sign; bn_trim(q); bn_copy(c, q); } if (d != NULL) { *d = r; } } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(q); } }
void bn_rand(bn_t a, int sign, int bits) { int digits; SPLIT(bits, digits, bits, BN_DIG_LOG); digits += (bits > 0 ? 1 : 0); bn_grow(a, digits); rand_bytes((uint8_t *)a->dp, digits * sizeof(dig_t)); a->used = digits; a->sign = sign; if (bits > 0) { dig_t mask = ((dig_t)1 << (dig_t)bits) - 1; a->dp[a->used - 1] &= mask; } bn_trim(a); }
/** * Subtracts two multiple precision integers, where a >= b. * * @param[out] c - the destination. * @param[in] a - the first multiple precision integer to subtract. * @param[in] b - the second multiple precision integer to subtract. */ static void bn_sub_imp(bn_t c, bn_t a, bn_t b) { int max, min; dig_t carry; max = a->used; min = b->used; /* Grow the destination to accomodate the result. */ bn_grow(c, max); if (a->used == b->used) { carry = bn_subn_low(c->dp, a->dp, b->dp, min); } else { carry = bn_subn_low(c->dp, a->dp, b->dp, min); carry = bn_sub1_low(c->dp + min, a->dp + min, carry, max - min); } c->used = max; bn_trim(c); }
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); }
/** * Adds two multiple precision integers, where a >= b. * * @param[out] c - the result. * @param[in] a - the first multiple precision integer to add. * @param[in] b - the second multiple precision integer to add. */ static void bn_add_imp(bn_t c, bn_t a, bn_t b) { int max, min; dig_t carry; max = a->used; min = b->used; /* Grow the result. */ bn_grow(c, max); if (a->used == b->used) { carry = bn_addn_low(c->dp, a->dp, b->dp, max); } else { carry = bn_addn_low(c->dp, a->dp, b->dp, min); carry = bn_add1_low(c->dp + min, a->dp + min, carry, max - min); } if (carry) { bn_grow(c, max + 1); c->dp[max] = carry; } c->used = max + carry; bn_trim(c); }
/** * Computes the square of a multiple precision integer using recursive Karatsuba * squaring. * * @param[out] c - the result. * @param[in] a - the multiple precision integer to square. * @param[in] level - the number of Karatsuba steps to apply. */ static void bn_sqr_karat_imp(bn_t c, const bn_t a, int level) { int h; bn_t a0, a1, a0a0, a1a1, t; const dig_t *tmpa; dig_t *t0; bn_null(a0); bn_null(a1); bn_null(a0a0); bn_null(a1a1); bn_null(t); /* Compute half the digits of a or b. */ h = a->used >> 1; TRY { /* Allocate the temp variables. */ bn_new(a0); bn_new(a1); bn_new(a0a0); bn_new(a1a1); bn_new(t); a0->used = h; a1->used = a->used - h; tmpa = a->dp; /* a = a1 || a0 */ t0 = a0->dp; for (int i = 0; i < h; i++, t0++, tmpa++) *t0 = *tmpa; t0 = a1->dp; for (int i = 0; i < a1->used; i++, t0++, tmpa++) *t0 = *tmpa; bn_trim(a0); if (level <= 1) { /* a0a0 = a0 * a0 and a1a1 = a1 * a1 */ #if BN_SQR == BASIC bn_sqr_basic(a0a0, a0); bn_sqr_basic(a1a1, a1); #elif BN_SQR == COMBA bn_sqr_comba(a0a0, a0); bn_sqr_comba(a1a1, a1); #elif BN_SQR == MULTP bn_mul_comba(a0a0, a0, a0); bn_mul_comba(a1a1, a1, a1); #endif } else { bn_sqr_karat_imp(a0a0, a0, level - 1); bn_sqr_karat_imp(a1a1, a1, level - 1); } /* t = (a1 + a0) */ bn_add(t, a1, a0); if (level <= 1) { /* t = (a1 + a0)*(a1 + a0) */ #if BN_SQR == BASIC bn_sqr_basic(t, t); #elif BN_SQR == COMBA bn_sqr_comba(t, t); #elif BN_SQR == MULTP bn_mul_comba(t, t, t); #endif } else { bn_sqr_karat_imp(t, t, level - 1); } /* t2 = (a0*a0 + a1*a1) */ bn_add(a0, a0a0, a1a1); /* t = (a1 + a0)*(b1 + b0) - (a0*a0 + a1*a1) */ bn_sub(t, t, a0); /* t = (a1 + a0)*(a1 + a0) - (a0*a0 + a1*a1) << h digits */ bn_lsh(t, t, h * BN_DIGIT); /* t2 = a1 * b1 << 2*h digits */ bn_lsh(a1a1, a1a1, 2 * h * BN_DIGIT); /* t = t + a0*a0 */ bn_add(t, t, a0a0); /* c = t + a1*a1 */ bn_add(t, t, a1a1); t->sign = BN_POS; bn_copy(c, t); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(a0); bn_free(a1); bn_free(a0a0); bn_free(a1a1); bn_free(t); } }
/** * Assigns the prime field modulus. * * @param[in] p - the new prime field modulus. */ static void fp_prime_set(const bn_t p) { dv_t s, q; bn_t t; ctx_t *ctx = core_get(); if (p->used != FP_DIGS) { THROW(ERR_NO_VALID); } dv_null(s); bn_null(t); dv_null(q); TRY { dv_new(s); bn_new(t); dv_new(q); bn_copy(&(ctx->prime), p); bn_mod_dig(&(ctx->mod8), &(ctx->prime), 8); switch (ctx->mod8) { case 3: case 7: ctx->qnr = -1; /* The current code for extensions of Fp^3 relies on qnr being * also a cubic non-residue. */ ctx->cnr = 0; break; case 1: case 5: ctx->qnr = ctx->cnr = -2; break; default: ctx->qnr = ctx->cnr = 0; THROW(ERR_NO_VALID); break; } #ifdef FP_QNRES if (ctx->mod8 != 3) { THROW(ERR_NO_VALID); } #endif #if FP_RDC == MONTY || !defined(STRIP) bn_mod_pre_monty(t, &(ctx->prime)); ctx->u = t->dp[0]; dv_zero(s, 2 * FP_DIGS); s[2 * FP_DIGS] = 1; dv_zero(q, 2 * FP_DIGS + 1); dv_copy(q, ctx->prime.dp, FP_DIGS); bn_divn_low(t->dp, ctx->conv.dp, s, 2 * FP_DIGS + 1, q, FP_DIGS); ctx->conv.used = FP_DIGS; bn_trim(&(ctx->conv)); bn_set_dig(&(ctx->one), 1); bn_lsh(&(ctx->one), &(ctx->one), ctx->prime.used * BN_DIGIT); bn_mod(&(ctx->one), &(ctx->one), &(ctx->prime)); #endif fp_prime_calc(); } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { bn_free(t); dv_free(s); dv_free(q); } }
void bn_mxp_slide(bn_t c, const bn_t a, const bn_t b, const bn_t m) { bn_t tab[TABLE_SIZE], t, u, r; int i, j, l, w = 1; uint8_t win[BN_BITS]; bn_null(t); bn_null(u); bn_null(r); /* Initialize table. */ for (i = 0; i < TABLE_SIZE; i++) { bn_null(tab[i]); } TRY { /* Find window size. */ i = bn_bits(b); if (i <= 21) { w = 2; } else if (i <= 32) { w = 3; } else if (i <= 128) { w = 4; } else if (i <= 256) { w = 5; } else { w = 6; } for (i = 1; i < (1 << w); i += 2) { bn_new(tab[i]); } bn_new(t); bn_new(u); bn_new(r); bn_mod_pre(u, m); #if BN_MOD == MONTY bn_set_dig(r, 1); bn_mod_monty_conv(r, r, m); bn_mod_monty_conv(t, a, m); #else /* BN_MOD == BARRT || BN_MOD == RADIX */ bn_set_dig(r, 1); bn_copy(t, a); #endif bn_copy(tab[1], t); bn_sqr(t, tab[1]); bn_mod(t, t, m, u); /* Create table. */ for (i = 1; i < 1 << (w - 1); i++) { bn_mul(tab[2 * i + 1], tab[2 * i - 1], t); bn_mod(tab[2 * i + 1], tab[2 * i + 1], m, u); } l = BN_BITS + 1; bn_rec_slw(win, &l, b, w); for (i = 0; i < l; i++) { if (win[i] == 0) { bn_sqr(r, r); bn_mod(r, r, m, u); } else { for (j = 0; j < util_bits_dig(win[i]); j++) { bn_sqr(r, r); bn_mod(r, r, m, u); } bn_mul(r, r, tab[win[i]]); bn_mod(r, r, m, u); } } bn_trim(r); #if BN_MOD == MONTY bn_mod_monty_back(c, r, m); #else bn_copy(c, r); #endif } CATCH_ANY { THROW(ERR_CAUGHT); } FINALLY { for (i = 1; i < (1 << w); i++) { bn_free(tab[i]); } bn_free(u); bn_free(t); bn_free(r); } }
/** * 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); } }