Downgrade BN_kronecker to bn_jacobi and unexport.

We only ever compute it for odd (actually, prime) modulus as part of
BN_mod_sqrt.

If we cared, we could probably drop this from most binaries. This is
used to when modular square root needs Tonelli-Shanks.  Modular square
root is only used for compressed coordinates. Of our supported curves
(I'm handwaiving away EC_GROUP_new_curve_GFp here[*]), only P-224 needs
the full Tonelli-Shanks algorithm (p is 1 mod 8). That computes the
Legendre symbol a bunch to find a non-square mod p. But p is known at
compile-time, so we can just hard-code a sample non-square.

Sadly, BN_mod_sqrt has some callers outside of crypto/ec, so there's
also that. Anyway, it's also not that large of a function.

[*] Glancing through SEC 2 and Brainpool, secp224r1 is the only curve
listed in either document whose prime is not either 3 mod 4 or 5 mod 8.
Even 5 mod 8 is rare: only secp224k1. It's unlikely anyone would notice
if we broke annoying primes. Though OpenSSL does support "WTLS" curves
which has an additional 1 mod 8 case.

Change-Id: If36aa78c0d41253ec024f2d90692949515356cd1
Reviewed-on: https://boringssl-review.googlesource.com/15425
Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
David Benjamin 2016-12-08 21:55:39 -05:00 committed by Adam Langley
parent 0d5bf8d86d
commit a684152a2f
5 changed files with 32 additions and 60 deletions

View File

@ -54,7 +54,7 @@ add_library(
exponentiation.c
generic.c
gcd.c
kronecker.c
jacobi.c
montgomery.c
montgomery_inv.c
mul.c

View File

@ -259,6 +259,10 @@ int bn_mod_inverse_prime(BIGNUM *out, const BIGNUM *a, const BIGNUM *p,
int bn_mod_inverse_secret_prime(BIGNUM *out, const BIGNUM *a, const BIGNUM *p,
BN_CTX *ctx, const BN_MONT_CTX *mont_p);
/* bn_jacobi returns the Jacobi symbol of |a| and |b| (which is -1, 0 or 1), or
* -2 on error. */
int bn_jacobi(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
#if defined(__cplusplus)
} /* extern C */

View File

@ -52,17 +52,15 @@
#include <openssl/bn.h>
#include <openssl/err.h>
#include "internal.h"
/* least significant word */
#define BN_lsw(n) (((n)->top == 0) ? (BN_ULONG) 0 : (n)->d[0])
/* Returns -2 for errors because both -1 and 0 are valid results. */
int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
int i;
int ret = -2;
BIGNUM *A, *B, *tmp;
int bn_jacobi(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
/* In 'tab', only odd-indexed entries are relevant:
* For any odd BIGNUM n,
* tab[BN_lsw(n) & 7]
@ -70,9 +68,22 @@ int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
* Note that the sign of n does not matter. */
static const int tab[8] = {0, 1, 0, -1, 0, -1, 0, 1};
/* The Jacobi symbol is only defined for odd modulus. */
if (!BN_is_odd(b)) {
OPENSSL_PUT_ERROR(BN, BN_R_CALLED_WITH_EVEN_MODULUS);
return -2;
}
/* Require b be positive. */
if (BN_is_negative(b)) {
OPENSSL_PUT_ERROR(BN, BN_R_NEGATIVE_NUMBER);
return -2;
}
int ret = -2;
BN_CTX_start(ctx);
A = BN_CTX_get(ctx);
B = BN_CTX_get(ctx);
BIGNUM *A = BN_CTX_get(ctx);
BIGNUM *B = BN_CTX_get(ctx);
if (B == NULL) {
goto end;
}
@ -82,52 +93,11 @@ int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
goto end;
}
/* Kronecker symbol, imlemented according to Henri Cohen,
* "A Course in Computational Algebraic Number Theory"
* (algorithm 1.4.10). */
/* Adapted from logic to compute the Kronecker symbol, originally implemented
* according to Henri Cohen, "A Course in Computational Algebraic Number
* Theory" (algorithm 1.4.10). */
/* Cohen's step 1: */
if (BN_is_zero(B)) {
ret = BN_abs_is_word(A, 1);
goto end;
}
/* Cohen's step 2: */
if (!BN_is_odd(A) && !BN_is_odd(B)) {
ret = 0;
goto end;
}
/* now B is non-zero */
i = 0;
while (!BN_is_bit_set(B, i)) {
i++;
}
if (!BN_rshift(B, B, i)) {
goto end;
}
if (i & 1) {
/* i is odd */
/* (thus B was even, thus A must be odd!) */
/* set 'ret' to $(-1)^{(A^2-1)/8}$ */
ret = tab[BN_lsw(A) & 7];
} else {
/* i is even */
ret = 1;
}
if (B->neg) {
B->neg = 0;
if (A->neg) {
ret = -ret;
}
}
/* now B is positive and odd, so what remains to be done is to compute the
* Jacobi symbol (A/B) and multiply it by 'ret' */
ret = 1;
while (1) {
/* Cohen's step 3: */
@ -139,7 +109,7 @@ int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
}
/* now A is non-zero */
i = 0;
int i = 0;
while (!BN_is_bit_set(A, i)) {
i++;
}
@ -164,7 +134,7 @@ int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx) {
ret = -2;
goto end;
}
tmp = A;
BIGNUM *tmp = A;
A = B;
B = tmp;
tmp->neg = 0;

View File

@ -56,6 +56,8 @@
#include <openssl/err.h>
#include "internal.h"
BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) {
/* Compute a square root of |a| mod |p| using the Tonelli/Shanks algorithm
@ -253,7 +255,7 @@ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx) {
}
}
r = BN_kronecker(y, q, ctx); /* here 'q' is |p| */
r = bn_jacobi(y, q, ctx); /* here 'q' is |p| */
if (r < -1) {
goto end;
}

View File

@ -797,10 +797,6 @@ int BN_mod_inverse_blinded(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
int BN_mod_inverse_odd(BIGNUM *out, int *out_no_inverse, const BIGNUM *a,
const BIGNUM *n, BN_CTX *ctx);
/* BN_kronecker returns the Kronecker symbol of |a| and |b| (which is -1, 0 or
* 1), or -2 on error. */
OPENSSL_EXPORT int BN_kronecker(const BIGNUM *a, const BIGNUM *b, BN_CTX *ctx);
/* Montgomery arithmetic. */