Faster BN_mod_sqrt algorithm for p == 5 (8).

This commit is contained in:
Bodo Möller 2000-12-06 12:25:33 +00:00
parent 1a4d6400ae
commit bac685417a
2 changed files with 80 additions and 6 deletions

View file

@ -32,7 +32,7 @@
[Richard Levitte]
*) New function BN_mod_sqrt for computing square roots modulo a prime
(Tonelli-Shanks algorithm).
(Tonelli-Shanks algorithm unless p == 3 (mod 4) or p == 5 (mod 8)).
[Lenka Fibikova <fibikova@exp-math.uni-essen.de>, Bodo Moeller]
*) Store verify_result within SSL_SESSION also for client side to

View file

@ -93,6 +93,20 @@ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
return(NULL);
}
if (BN_is_zero(a) || BN_is_one(a))
{
if (ret == NULL)
ret = BN_new();
if (ret == NULL)
goto end;
if (!BN_set_word(ret, BN_is_one(a)))
{
BN_free(ret);
return NULL;
}
return ret;
}
#if 0 /* if BN_mod_sqrt is used with correct input, this just wastes time */
r = BN_kronecker(a, p, ctx);
if (r < -1) return NULL;
@ -119,7 +133,9 @@ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
e = 1;
while (!BN_is_bit_set(p, e))
e++;
if (!BN_rshift(q, p, e)) goto end;
if (e > 2)
/* we don't need this q if e = 1 or 2 */
if (!BN_rshift(q, p, e)) goto end;
q->neg = 0;
if (e == 1)
@ -129,16 +145,74 @@ BIGNUM *BN_mod_sqrt(BIGNUM *in, const BIGNUM *a, const BIGNUM *p, BN_CTX *ctx)
* directly by modular exponentiation.
* We have
* 2 * (p+1)/4 == 1 (mod (p-1)/2),
* so we can use exponent (p+1)/4, i.e. (q+1)/2.
* so we can use exponent (p+1)/4, i.e. (p-3)/4 + 1.
*/
if (!BN_add_word(q,1)) goto end;
if (!BN_rshift1(q,q)) goto end;
if (!BN_rshift(q, p, 2)) goto end;
if (!BN_add_word(q, 1)) goto end;
if (!BN_mod_exp(ret, a, q, p, ctx)) goto end;
err = 0;
goto end;
}
/* e > 1, so we really have to use the Tonelli/Shanks algorithm.
if (e == 2)
{
/* p == 5 (mod 8)
*
* In this case 2 is always a non-square since
* Legendre(2,p) = (-1)^((p^2-1)/8) for any odd prime.
* So if a really is a square, then 2*a is a non-square.
* Thus for
* b := (2*a)^((p-5)/8),
* i := (2*a)*b^2
* we have
* i^2 = (2*a)^((1 + (p-5)/4)*2)
* = (2*a)^((p-1)/2)
* = -1;
* so if we set
* x := a*b*(i-1),
* then
* x^2 = a^2 * b^2 * (i^2 - 2*i + 1)
* = a^2 * b^2 * (-2*i)
* = a*(-i)*(2*a*b^2)
* = a*(-i)*i
* = a.
*
* (This is due to A.O.L. Atkin,
* <URL: http://listserv.nodak.edu/scripts/wa.exe?A2=ind9211&L=nmbrthry&O=T&P=562>,
* November 1992.)
*/
/* make sure that a is reduced modulo p */
if (a->neg || BN_ucmp(a, p) >= 0)
{
if (!BN_nnmod(x, a, p, ctx)) goto end;
a = x; /* use x as temporary variable */
}
/* t := 2*a */
if (!BN_mod_lshift1_quick(t, a, p)) goto end;
/* b := (2*a)^((p-5)/8) */
if (!BN_rshift(q, p, 3)) goto end;
if (!BN_mod_exp(b, t, q, p, ctx)) goto end;
/* y := b^2 */
if (!BN_mod_sqr(y, b, p, ctx)) goto end;
/* t := (2*a)*b^2 - 1*/
if (!BN_mod_mul(t, t, y, p, ctx)) goto end;
if (!BN_sub_word(t, 1)) goto end; /* cannot become negative */
/* x = a*b*t */
if (!BN_mod_mul(x, a, b, p, ctx)) goto end;
if (!BN_mod_mul(x, x, t, p, ctx)) goto end;
if (!BN_copy(ret, x)) goto end;
err = 0;
goto end;
}
/* e > 2, so we really have to use the Tonelli/Shanks algorithm.
* First, find some y that is not a square. */
i = 2;
do