static int mod_exp(BIGNUM *r0, const BIGNUM *I, RSA *rsa, BN_CTX *ctx) { assert(ctx != NULL); assert(rsa->n != NULL); assert(rsa->e != NULL); assert(rsa->d != NULL); assert(rsa->p != NULL); assert(rsa->q != NULL); assert(rsa->dmp1 != NULL); assert(rsa->dmq1 != NULL); assert(rsa->iqmp != NULL); BIGNUM *r1, *m1; int ret = 0; BN_CTX_start(ctx); r1 = BN_CTX_get(ctx); m1 = BN_CTX_get(ctx); if (r1 == NULL || m1 == NULL) { goto err; } if (!freeze_private_key(rsa, ctx)) { goto err; } // Implementing RSA with CRT in constant-time is sensitive to which prime is // larger. Canonicalize fields so that |p| is the larger prime. const BIGNUM *dmp1 = rsa->dmp1_fixed, *dmq1 = rsa->dmq1_fixed; const BN_MONT_CTX *mont_p = rsa->mont_p, *mont_q = rsa->mont_q; if (BN_cmp(rsa->p, rsa->q) < 0) { mont_p = rsa->mont_q; mont_q = rsa->mont_p; dmp1 = rsa->dmq1_fixed; dmq1 = rsa->dmp1_fixed; } // Use the minimal-width versions of |n|, |p|, and |q|. Either works, but if // someone gives us non-minimal values, these will be slightly more efficient // on the non-Montgomery operations. const BIGNUM *n = &rsa->mont_n->N; const BIGNUM *p = &mont_p->N; const BIGNUM *q = &mont_q->N; // This is a pre-condition for |mod_montgomery|. It was already checked by the // caller. assert(BN_ucmp(I, n) < 0); if (// |m1| is the result modulo |q|. !mod_montgomery(r1, I, q, mont_q, p, ctx) || !BN_mod_exp_mont_consttime(m1, r1, dmq1, q, ctx, mont_q) || // |r0| is the result modulo |p|. !mod_montgomery(r1, I, p, mont_p, q, ctx) || !BN_mod_exp_mont_consttime(r0, r1, dmp1, p, ctx, mont_p) || // Compute r0 = r0 - m1 mod p. |p| is the larger prime, so |m1| is already // fully reduced mod |p|. !bn_mod_sub_consttime(r0, r0, m1, p, ctx) || // r0 = r0 * iqmp mod p. We use Montgomery multiplication to compute this // in constant time. |inv_small_mod_large_mont| is in Montgomery form and // r0 is not, so the result is taken out of Montgomery form. !BN_mod_mul_montgomery(r0, r0, rsa->inv_small_mod_large_mont, mont_p, ctx) || // r0 = r0 * q + m1 gives the final result. Reducing modulo q gives m1, so // it is correct mod p. Reducing modulo p gives (r0-m1)*iqmp*q + m1 = r0, // so it is correct mod q. Finally, the result is bounded by [m1, n + m1), // and the result is at least |m1|, so this must be the unique answer in // [0, n). !bn_mul_consttime(r0, r0, q, ctx) || !bn_uadd_consttime(r0, r0, m1) || // The result should be bounded by |n|, but fixed-width operations may // bound the width slightly higher, so fix it. !bn_resize_words(r0, n->width)) { goto err; } ret = 1; err: BN_CTX_end(ctx); return ret; }
int ec_GFp_simple_dbl(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, BN_CTX *ctx) { int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *n0, *n1, *n2, *n3; int ret = 0; if (EC_POINT_is_at_infinity(group, a)) { BN_zero(&r->Z); return 1; } field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = &group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { return 0; } } BN_CTX_start(ctx); n0 = BN_CTX_get(ctx); n1 = BN_CTX_get(ctx); n2 = BN_CTX_get(ctx); n3 = BN_CTX_get(ctx); if (n3 == NULL) { goto err; } // Note that in this function we must not read components of 'a' // once we have written the corresponding components of 'r'. // ('r' might the same as 'a'.) // n1 if (BN_cmp(&a->Z, &group->one) == 0) { if (!field_sqr(group, n0, &a->X, ctx) || !bn_mod_lshift1_consttime(n1, n0, p, ctx) || !bn_mod_add_consttime(n0, n0, n1, p, ctx) || !bn_mod_add_consttime(n1, n0, &group->a, p, ctx)) { goto err; } // n1 = 3 * X_a^2 + a_curve } else if (group->a_is_minus3) { if (!field_sqr(group, n1, &a->Z, ctx) || !bn_mod_add_consttime(n0, &a->X, n1, p, ctx) || !bn_mod_sub_consttime(n2, &a->X, n1, p, ctx) || !field_mul(group, n1, n0, n2, ctx) || !bn_mod_lshift1_consttime(n0, n1, p, ctx) || !bn_mod_add_consttime(n1, n0, n1, p, ctx)) { goto err; } // n1 = 3 * (X_a + Z_a^2) * (X_a - Z_a^2) // = 3 * X_a^2 - 3 * Z_a^4 } else { if (!field_sqr(group, n0, &a->X, ctx) || !bn_mod_lshift1_consttime(n1, n0, p, ctx) || !bn_mod_add_consttime(n0, n0, n1, p, ctx) || !field_sqr(group, n1, &a->Z, ctx) || !field_sqr(group, n1, n1, ctx) || !field_mul(group, n1, n1, &group->a, ctx) || !bn_mod_add_consttime(n1, n1, n0, p, ctx)) { goto err; } // n1 = 3 * X_a^2 + a_curve * Z_a^4 } // Z_r if (BN_cmp(&a->Z, &group->one) == 0) { if (!BN_copy(n0, &a->Y)) { goto err; } } else if (!field_mul(group, n0, &a->Y, &a->Z, ctx)) { goto err; } if (!bn_mod_lshift1_consttime(&r->Z, n0, p, ctx)) { goto err; } // Z_r = 2 * Y_a * Z_a // n2 if (!field_sqr(group, n3, &a->Y, ctx) || !field_mul(group, n2, &a->X, n3, ctx) || !bn_mod_lshift_consttime(n2, n2, 2, p, ctx)) { goto err; } // n2 = 4 * X_a * Y_a^2 // X_r if (!bn_mod_lshift1_consttime(n0, n2, p, ctx) || !field_sqr(group, &r->X, n1, ctx) || !bn_mod_sub_consttime(&r->X, &r->X, n0, p, ctx)) { goto err; } // X_r = n1^2 - 2 * n2 // n3 if (!field_sqr(group, n0, n3, ctx) || !bn_mod_lshift_consttime(n3, n0, 3, p, ctx)) { goto err; } // n3 = 8 * Y_a^4 // Y_r if (!bn_mod_sub_consttime(n0, n2, &r->X, p, ctx) || !field_mul(group, n0, n1, n0, ctx) || !bn_mod_sub_consttime(&r->Y, n0, n3, p, ctx)) { goto err; } // Y_r = n1 * (n2 - X_r) - n3 ret = 1; err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_is_on_curve(const EC_GROUP *group, const EC_POINT *point, BN_CTX *ctx) { int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *rh, *tmp, *Z4, *Z6; int ret = 0; if (EC_POINT_is_at_infinity(group, point)) { return 1; } field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = &group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { return 0; } } BN_CTX_start(ctx); rh = BN_CTX_get(ctx); tmp = BN_CTX_get(ctx); Z4 = BN_CTX_get(ctx); Z6 = BN_CTX_get(ctx); if (Z6 == NULL) { goto err; } // We have a curve defined by a Weierstrass equation // y^2 = x^3 + a*x + b. // The point to consider is given in Jacobian projective coordinates // where (X, Y, Z) represents (x, y) = (X/Z^2, Y/Z^3). // Substituting this and multiplying by Z^6 transforms the above equation // into // Y^2 = X^3 + a*X*Z^4 + b*Z^6. // To test this, we add up the right-hand side in 'rh'. // rh := X^2 if (!field_sqr(group, rh, &point->X, ctx)) { goto err; } if (BN_cmp(&point->Z, &group->one) != 0) { if (!field_sqr(group, tmp, &point->Z, ctx) || !field_sqr(group, Z4, tmp, ctx) || !field_mul(group, Z6, Z4, tmp, ctx)) { goto err; } // rh := (rh + a*Z^4)*X if (group->a_is_minus3) { if (!bn_mod_lshift1_consttime(tmp, Z4, p, ctx) || !bn_mod_add_consttime(tmp, tmp, Z4, p, ctx) || !bn_mod_sub_consttime(rh, rh, tmp, p, ctx) || !field_mul(group, rh, rh, &point->X, ctx)) { goto err; } } else { if (!field_mul(group, tmp, Z4, &group->a, ctx) || !bn_mod_add_consttime(rh, rh, tmp, p, ctx) || !field_mul(group, rh, rh, &point->X, ctx)) { goto err; } } // rh := rh + b*Z^6 if (!field_mul(group, tmp, &group->b, Z6, ctx) || !bn_mod_add_consttime(rh, rh, tmp, p, ctx)) { goto err; } } else { // rh := (rh + a)*X if (!bn_mod_add_consttime(rh, rh, &group->a, p, ctx) || !field_mul(group, rh, rh, &point->X, ctx)) { goto err; } // rh := rh + b if (!bn_mod_add_consttime(rh, rh, &group->b, p, ctx)) { goto err; } } // 'lh' := Y^2 if (!field_sqr(group, tmp, &point->Y, ctx)) { goto err; } ret = (0 == BN_ucmp(tmp, rh)); err: BN_CTX_end(ctx); BN_CTX_free(new_ctx); return ret; }
int ec_GFp_simple_add(const EC_GROUP *group, EC_POINT *r, const EC_POINT *a, const EC_POINT *b, BN_CTX *ctx) { int (*field_mul)(const EC_GROUP *, BIGNUM *, const BIGNUM *, const BIGNUM *, BN_CTX *); int (*field_sqr)(const EC_GROUP *, BIGNUM *, const BIGNUM *, BN_CTX *); const BIGNUM *p; BN_CTX *new_ctx = NULL; BIGNUM *n0, *n1, *n2, *n3, *n4, *n5, *n6; int ret = 0; if (a == b) { return EC_POINT_dbl(group, r, a, ctx); } if (EC_POINT_is_at_infinity(group, a)) { return EC_POINT_copy(r, b); } if (EC_POINT_is_at_infinity(group, b)) { return EC_POINT_copy(r, a); } field_mul = group->meth->field_mul; field_sqr = group->meth->field_sqr; p = &group->field; if (ctx == NULL) { ctx = new_ctx = BN_CTX_new(); if (ctx == NULL) { return 0; } } BN_CTX_start(ctx); n0 = BN_CTX_get(ctx); n1 = BN_CTX_get(ctx); n2 = BN_CTX_get(ctx); n3 = BN_CTX_get(ctx); n4 = BN_CTX_get(ctx); n5 = BN_CTX_get(ctx); n6 = BN_CTX_get(ctx); if (n6 == NULL) { goto end; } // Note that in this function we must not read components of 'a' or 'b' // once we have written the corresponding components of 'r'. // ('r' might be one of 'a' or 'b'.) // n1, n2 int b_Z_is_one = BN_cmp(&b->Z, &group->one) == 0; if (b_Z_is_one) { if (!BN_copy(n1, &a->X) || !BN_copy(n2, &a->Y)) { goto end; } // n1 = X_a // n2 = Y_a } else { if (!field_sqr(group, n0, &b->Z, ctx) || !field_mul(group, n1, &a->X, n0, ctx)) { goto end; } // n1 = X_a * Z_b^2 if (!field_mul(group, n0, n0, &b->Z, ctx) || !field_mul(group, n2, &a->Y, n0, ctx)) { goto end; } // n2 = Y_a * Z_b^3 } // n3, n4 int a_Z_is_one = BN_cmp(&a->Z, &group->one) == 0; if (a_Z_is_one) { if (!BN_copy(n3, &b->X) || !BN_copy(n4, &b->Y)) { goto end; } // n3 = X_b // n4 = Y_b } else { if (!field_sqr(group, n0, &a->Z, ctx) || !field_mul(group, n3, &b->X, n0, ctx)) { goto end; } // n3 = X_b * Z_a^2 if (!field_mul(group, n0, n0, &a->Z, ctx) || !field_mul(group, n4, &b->Y, n0, ctx)) { goto end; } // n4 = Y_b * Z_a^3 } // n5, n6 if (!bn_mod_sub_consttime(n5, n1, n3, p, ctx) || !bn_mod_sub_consttime(n6, n2, n4, p, ctx)) { goto end; } // n5 = n1 - n3 // n6 = n2 - n4 if (BN_is_zero(n5)) { if (BN_is_zero(n6)) { // a is the same point as b BN_CTX_end(ctx); ret = EC_POINT_dbl(group, r, a, ctx); ctx = NULL; goto end; } else { // a is the inverse of b BN_zero(&r->Z); ret = 1; goto end; } } // 'n7', 'n8' if (!bn_mod_add_consttime(n1, n1, n3, p, ctx) || !bn_mod_add_consttime(n2, n2, n4, p, ctx)) { goto end; } // 'n7' = n1 + n3 // 'n8' = n2 + n4 // Z_r if (a_Z_is_one && b_Z_is_one) { if (!BN_copy(&r->Z, n5)) { goto end; } } else { if (a_Z_is_one) { if (!BN_copy(n0, &b->Z)) { goto end; } } else if (b_Z_is_one) { if (!BN_copy(n0, &a->Z)) { goto end; } } else if (!field_mul(group, n0, &a->Z, &b->Z, ctx)) { goto end; } if (!field_mul(group, &r->Z, n0, n5, ctx)) { goto end; } } // Z_r = Z_a * Z_b * n5 // X_r if (!field_sqr(group, n0, n6, ctx) || !field_sqr(group, n4, n5, ctx) || !field_mul(group, n3, n1, n4, ctx) || !bn_mod_sub_consttime(&r->X, n0, n3, p, ctx)) { goto end; } // X_r = n6^2 - n5^2 * 'n7' // 'n9' if (!bn_mod_lshift1_consttime(n0, &r->X, p, ctx) || !bn_mod_sub_consttime(n0, n3, n0, p, ctx)) { goto end; } // n9 = n5^2 * 'n7' - 2 * X_r // Y_r if (!field_mul(group, n0, n0, n6, ctx) || !field_mul(group, n5, n4, n5, ctx)) { goto end; // now n5 is n5^3 } if (!field_mul(group, n1, n2, n5, ctx) || !bn_mod_sub_consttime(n0, n0, n1, p, ctx)) { goto end; } if (BN_is_odd(n0) && !BN_add(n0, n0, p)) { goto end; } // now 0 <= n0 < 2*p, and n0 is even if (!BN_rshift1(&r->Y, n0)) { goto end; } // Y_r = (n6 * 'n9' - 'n8' * 'n5^3') / 2 ret = 1; end: if (ctx) { // otherwise we already called BN_CTX_end BN_CTX_end(ctx); } BN_CTX_free(new_ctx); return ret; }