This commit is contained in:
purplerain 2023-05-13 14:25:18 +00:00
parent f609457dcf
commit 62073e0295
Signed by: purplerain
GPG key ID: F42C07F07E2E35B7
318 changed files with 8112 additions and 4346 deletions

View file

@ -1,4 +1,4 @@
/* $OpenBSD: bn_bpsw.c,v 1.8 2022/11/26 16:08:51 tb Exp $ */
/* $OpenBSD: bn_bpsw.c,v 1.10 2023/05/10 21:05:24 tb Exp $ */
/*
* Copyright (c) 2022 Martin Grenouilloux <martin.grenouilloux@lse.epita.fr>
* Copyright (c) 2022 Theo Buehler <tb@openbsd.org>
@ -156,7 +156,7 @@ bn_lucas(BIGNUM *U, BIGNUM *V, const BIGNUM *k, const BIGNUM *D,
*/
static int
bn_strong_lucas_test(int *is_prime, const BIGNUM *n, const BIGNUM *D,
bn_strong_lucas_test(int *is_pseudoprime, const BIGNUM *n, const BIGNUM *D,
BN_CTX *ctx)
{
BIGNUM *k, *U, *V;
@ -194,7 +194,7 @@ bn_strong_lucas_test(int *is_prime, const BIGNUM *n, const BIGNUM *D,
goto err;
if (BN_is_zero(U) || BN_is_zero(V)) {
*is_prime = 1;
*is_pseudoprime = 1;
goto done;
}
@ -208,7 +208,7 @@ bn_strong_lucas_test(int *is_prime, const BIGNUM *n, const BIGNUM *D,
goto err;
if (BN_is_zero(V)) {
*is_prime = 1;
*is_pseudoprime = 1;
goto done;
}
}
@ -217,7 +217,7 @@ bn_strong_lucas_test(int *is_prime, const BIGNUM *n, const BIGNUM *D,
* If we got here, n is definitely composite.
*/
*is_prime = 0;
*is_pseudoprime = 0;
done:
ret = 1;
@ -235,7 +235,7 @@ bn_strong_lucas_test(int *is_prime, const BIGNUM *n, const BIGNUM *D,
*/
static int
bn_strong_lucas_selfridge(int *is_prime, const BIGNUM *n, BN_CTX *ctx)
bn_strong_lucas_selfridge(int *is_pseudoprime, const BIGNUM *n, BN_CTX *ctx)
{
BIGNUM *D, *two;
int is_perfect_square, jacobi_symbol, sign;
@ -247,7 +247,7 @@ bn_strong_lucas_selfridge(int *is_prime, const BIGNUM *n, BN_CTX *ctx)
if (!bn_is_perfect_square(&is_perfect_square, n, ctx))
goto err;
if (is_perfect_square) {
*is_prime = 0;
*is_pseudoprime = 0;
goto done;
}
@ -278,7 +278,7 @@ bn_strong_lucas_selfridge(int *is_prime, const BIGNUM *n, BN_CTX *ctx)
/* n and D have prime factors in common. */
if (jacobi_symbol == 0) {
*is_prime = 0;
*is_pseudoprime = 0;
goto done;
}
@ -288,7 +288,7 @@ bn_strong_lucas_selfridge(int *is_prime, const BIGNUM *n, BN_CTX *ctx)
BN_set_negative(D, sign == -1);
}
if (!bn_strong_lucas_test(is_prime, n, D, ctx))
if (!bn_strong_lucas_test(is_pseudoprime, n, D, ctx))
goto err;
done:
@ -301,32 +301,113 @@ bn_strong_lucas_selfridge(int *is_prime, const BIGNUM *n, BN_CTX *ctx)
}
/*
* Miller-Rabin primality test for base 2.
* Fermat criterion in Miller-Rabin test.
*
* Check whether 1 < base < n - 1 witnesses that n is composite. For prime n:
*
* * Fermat's little theorem: base^(n-1) = 1 (mod n).
* * The only square roots of 1 (mod n) are 1 and -1.
*
* Calculate base^((n-1)/2) by writing n - 1 = k * 2^s with odd k. Iteratively
* compute power = (base^k)^(2^(s-1)) by successive squaring of base^k.
*
* If power ever reaches -1, base^(n-1) is equal to 1 and n is a pseudoprime
* for base. If power reaches 1 before -1 during successive squaring, we have
* an unexpected square root of 1 and n is composite. Otherwise base^(n-1) != 1,
* and n is composite.
*/
static int
bn_miller_rabin_base_2(int *is_prime, const BIGNUM *n, BN_CTX *ctx)
bn_fermat(int *is_pseudoprime, const BIGNUM *n, const BIGNUM *n_minus_one,
const BIGNUM *k, int s, const BIGNUM *base, BN_CTX *ctx, BN_MONT_CTX *mctx)
{
BIGNUM *n_minus_one, *k, *x;
int i, s;
BIGNUM *power;
int ret = 0;
int i;
BN_CTX_start(ctx);
if ((power = BN_CTX_get(ctx)) == NULL)
goto err;
/* Sanity check: ensure that 1 < base < n - 1. */
if (BN_cmp(base, BN_value_one()) <= 0 || BN_cmp(base, n_minus_one) >= 0)
goto err;
if (!BN_mod_exp_mont_ct(power, base, k, n, ctx, mctx))
goto err;
if (BN_is_one(power) || BN_cmp(power, n_minus_one) == 0) {
*is_pseudoprime = 1;
goto done;
}
/* Loop invariant: power is neither 1 nor -1 (mod n). */
for (i = 1; i < s; i++) {
if (!BN_mod_sqr(power, power, n, ctx))
goto err;
/* n is a pseudoprime for base. */
if (BN_cmp(power, n_minus_one) == 0) {
*is_pseudoprime = 1;
goto done;
}
/* n is composite: there's a square root of unity != 1 or -1. */
if (BN_is_one(power)) {
*is_pseudoprime = 0;
goto done;
}
}
/*
* If we get here, n is definitely composite: base^(n-1) != 1.
*/
*is_pseudoprime = 0;
done:
ret = 1;
err:
BN_CTX_end(ctx);
return ret;
}
/*
* Miller-Rabin primality test for base 2 and for |rounds| of random bases.
* On success: is_pseudoprime == 0 implies that n is composite.
*/
static int
bn_miller_rabin(int *is_pseudoprime, const BIGNUM *n, BN_CTX *ctx,
size_t rounds)
{
BN_MONT_CTX *mctx = NULL;
BIGNUM *base, *k, *n_minus_one, *three;
size_t i;
int s;
int ret = 0;
BN_CTX_start(ctx);
if ((n_minus_one = BN_CTX_get(ctx)) == NULL)
if ((base = BN_CTX_get(ctx)) == NULL)
goto err;
if ((k = BN_CTX_get(ctx)) == NULL)
goto err;
if ((x = BN_CTX_get(ctx)) == NULL)
if ((n_minus_one = BN_CTX_get(ctx)) == NULL)
goto err;
if ((three = BN_CTX_get(ctx)) == NULL)
goto err;
if (BN_is_word(n, 2) || BN_is_word(n, 3)) {
*is_prime = 1;
*is_pseudoprime = 1;
goto done;
}
if (BN_cmp(n, BN_value_one()) <= 0 || !BN_is_odd(n)) {
*is_prime = 0;
*is_pseudoprime = 0;
goto done;
}
@ -344,43 +425,57 @@ bn_miller_rabin_base_2(int *is_prime, const BIGNUM *n, BN_CTX *ctx)
goto err;
/*
* If 2^k is 1 or -1 (mod n) then n is a 2-pseudoprime.
* Montgomery setup for n.
*/
if (!BN_set_word(x, 2))
goto err;
if (!BN_mod_exp_ct(x, x, k, n, ctx))
if ((mctx = BN_MONT_CTX_new()) == NULL)
goto err;
if (BN_is_one(x) || BN_cmp(x, n_minus_one) == 0) {
*is_prime = 1;
if (!BN_MONT_CTX_set(mctx, n, ctx))
goto err;
/*
* Perform a Miller-Rabin test for base 2 as required by BPSW.
*/
if (!BN_set_word(base, 2))
goto err;
if (!bn_fermat(is_pseudoprime, n, n_minus_one, k, s, base, ctx, mctx))
goto err;
if (!*is_pseudoprime)
goto done;
}
/*
* If 2^{2^i k} == -1 (mod n) for some 1 <= i < s, then n is a
* 2-pseudoprime.
* Perform Miller-Rabin tests with random 3 <= base < n - 1 to reduce
* risk of false positives in BPSW.
*/
for (i = 1; i < s; i++) {
if (!BN_mod_sqr(x, x, n, ctx))
if (!BN_set_word(three, 3))
goto err;
for (i = 0; i < rounds; i++) {
if (!bn_rand_interval(base, three, n_minus_one))
goto err;
if (BN_cmp(x, n_minus_one) == 0) {
*is_prime = 1;
if (!bn_fermat(is_pseudoprime, n, n_minus_one, k, s, base, ctx,
mctx))
goto err;
if (!*is_pseudoprime)
goto done;
}
}
/*
* If we got here, n is definitely composite.
* If we got here, we have a Miller-Rabin pseudoprime.
*/
*is_prime = 0;
*is_pseudoprime = 1;
done:
ret = 1;
err:
BN_MONT_CTX_free(mctx);
BN_CTX_end(ctx);
return ret;
@ -392,7 +487,8 @@ bn_miller_rabin_base_2(int *is_prime, const BIGNUM *n, BN_CTX *ctx)
*/
int
bn_is_prime_bpsw(int *is_prime, const BIGNUM *n, BN_CTX *in_ctx)
bn_is_prime_bpsw(int *is_pseudoprime, const BIGNUM *n, BN_CTX *in_ctx,
size_t rounds)
{
BN_CTX *ctx = NULL;
BN_ULONG mod;
@ -400,12 +496,12 @@ bn_is_prime_bpsw(int *is_prime, const BIGNUM *n, BN_CTX *in_ctx)
int ret = 0;
if (BN_is_word(n, 2)) {
*is_prime = 1;
*is_pseudoprime = 1;
goto done;
}
if (BN_cmp(n, BN_value_one()) <= 0 || !BN_is_odd(n)) {
*is_prime = 0;
*is_pseudoprime = 0;
goto done;
}
@ -414,7 +510,7 @@ bn_is_prime_bpsw(int *is_prime, const BIGNUM *n, BN_CTX *in_ctx)
if ((mod = BN_mod_word(n, primes[i])) == (BN_ULONG)-1)
goto err;
if (mod == 0) {
*is_prime = BN_is_word(n, primes[i]);
*is_pseudoprime = BN_is_word(n, primes[i]);
goto done;
}
}
@ -424,14 +520,12 @@ bn_is_prime_bpsw(int *is_prime, const BIGNUM *n, BN_CTX *in_ctx)
if (ctx == NULL)
goto err;
if (!bn_miller_rabin_base_2(is_prime, n, ctx))
if (!bn_miller_rabin(is_pseudoprime, n, ctx, rounds))
goto err;
if (!*is_prime)
if (!*is_pseudoprime)
goto done;
/* XXX - Miller-Rabin for random bases? See FIPS 186-4, Table C.1. */
if (!bn_strong_lucas_selfridge(is_prime, n, ctx))
if (!bn_strong_lucas_selfridge(is_pseudoprime, n, ctx))
goto err;
done:

View file

@ -1,4 +1,4 @@
/* $OpenBSD: bn_convert.c,v 1.6 2023/04/19 11:14:04 jsing Exp $ */
/* $OpenBSD: bn_convert.c,v 1.8 2023/05/09 05:15:55 jsing Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@ -68,6 +68,7 @@
#include <openssl/err.h>
#include "bn_local.h"
#include "bytestring.h"
static const char hex_digits[] = "0123456789ABCDEF";
@ -270,85 +271,82 @@ BN_asc2bn(BIGNUM **bn, const char *a)
return 1;
}
/* Must 'free' the returned data */
char *
BN_bn2dec(const BIGNUM *a)
BN_bn2dec(const BIGNUM *bn)
{
int i = 0, num, bn_data_num, ok = 0;
char *buf = NULL;
char *p;
BIGNUM *t = NULL;
BN_ULONG *bn_data = NULL, *lp;
int started = 0;
BIGNUM *tmp = NULL;
uint8_t *data = NULL;
size_t data_len = 0;
uint8_t *s = NULL;
size_t s_len;
BN_ULONG v, w;
uint8_t c;
CBB cbb;
CBS cbs;
int i;
if (BN_is_zero(a)) {
buf = malloc(BN_is_negative(a) + 2);
if (buf == NULL) {
BNerror(ERR_R_MALLOC_FAILURE);
goto err;
}
p = buf;
if (BN_is_negative(a))
*p++ = '-';
*p++ = '0';
*p++ = '\0';
return (buf);
}
if (!CBB_init(&cbb, 0))
goto err;
/* get an upper bound for the length of the decimal integer
* num <= (BN_num_bits(a) + 1) * log(2)
* <= 3 * BN_num_bits(a) * 0.1001 + log(2) + 1 (rounding error)
* <= BN_num_bits(a)/10 + BN_num_bits/1000 + 1 + 1
if ((tmp = BN_dup(bn)) == NULL)
goto err;
/*
* Divide the BIGNUM by a large multiple of 10, then break the remainder
* into decimal digits. This produces a reversed string of digits,
* potentially with leading zeroes.
*/
i = BN_num_bits(a) * 3;
num = (i / 10 + i / 1000 + 1) + 1;
bn_data_num = num / BN_DEC_NUM + 1;
bn_data = reallocarray(NULL, bn_data_num, sizeof(BN_ULONG));
buf = malloc(num + 3);
if ((buf == NULL) || (bn_data == NULL)) {
BNerror(ERR_R_MALLOC_FAILURE);
goto err;
while (!BN_is_zero(tmp)) {
if ((w = BN_div_word(tmp, BN_DEC_CONV)) == -1)
goto err;
for (i = 0; i < BN_DEC_NUM; i++) {
v = w % 10;
if (!CBB_add_u8(&cbb, '0' + v))
goto err;
w /= 10;
}
}
if ((t = BN_dup(a)) == NULL)
if (!CBB_finish(&cbb, &data, &data_len))
goto err;
#define BUF_REMAIN (num+3 - (size_t)(p - buf))
p = buf;
lp = bn_data;
if (BN_is_negative(t))
*p++ = '-';
if (data_len > SIZE_MAX - 3)
goto err;
if (!CBB_init(&cbb, data_len + 3))
goto err;
while (!BN_is_zero(t)) {
if (lp - bn_data >= bn_data_num)
if (BN_is_negative(bn)) {
if (!CBB_add_u8(&cbb, '-'))
goto err;
*lp = BN_div_word(t, BN_DEC_CONV);
if (*lp == (BN_ULONG)-1)
}
/* Reverse digits and trim leading zeroes. */
CBS_init(&cbs, data, data_len);
while (CBS_len(&cbs) > 0) {
if (!CBS_get_last_u8(&cbs, &c))
goto err;
lp++;
}
lp--;
/* We now have a series of blocks, BN_DEC_NUM chars
* in length, where the last one needs truncation.
* The blocks need to be reversed in order. */
snprintf(p, BUF_REMAIN, BN_DEC_FMT1, *lp);
while (*p)
p++;
while (lp != bn_data) {
lp--;
snprintf(p, BUF_REMAIN, BN_DEC_FMT2, *lp);
while (*p)
p++;
}
ok = 1;
err:
free(bn_data);
BN_free(t);
if (!ok && buf) {
free(buf);
buf = NULL;
if (!started && c == '0')
continue;
if (!CBB_add_u8(&cbb, c))
goto err;
started = 1;
}
return (buf);
if (!started) {
if (!CBB_add_u8(&cbb, '0'))
goto err;
}
if (!CBB_add_u8(&cbb, '\0'))
goto err;
if (!CBB_finish(&cbb, &s, &s_len))
goto err;
err:
BN_free(tmp);
CBB_cleanup(&cbb);
freezero(data, data_len);
return s;
}
int
@ -420,39 +418,49 @@ err:
return (0);
}
/* Must 'free' the returned data */
char *
BN_bn2hex(const BIGNUM *a)
BN_bn2hex(const BIGNUM *bn)
{
int i, j, v, z = 0;
char *buf;
char *p;
int started = 0;
uint8_t *s = NULL;
size_t s_len;
BN_ULONG v, w;
int i, j;
CBB cbb;
buf = malloc(BN_is_negative(a) + a->top * BN_BYTES * 2 + 2);
if (buf == NULL) {
BNerror(ERR_R_MALLOC_FAILURE);
if (!CBB_init(&cbb, 0))
goto err;
if (BN_is_negative(bn)) {
if (!CBB_add_u8(&cbb, '-'))
goto err;
}
p = buf;
if (BN_is_negative(a))
*p++ = '-';
if (BN_is_zero(a))
*p++ = '0';
for (i = a->top - 1; i >=0; i--) {
if (BN_is_zero(bn)) {
if (!CBB_add_u8(&cbb, '0'))
goto err;
}
for (i = bn->top - 1; i >= 0; i--) {
w = bn->d[i];
for (j = BN_BITS2 - 8; j >= 0; j -= 8) {
/* strip leading zeros */
v = ((int)(a->d[i] >> (long)j)) & 0xff;
if (z || (v != 0)) {
*p++ = hex_digits[v >> 4];
*p++ = hex_digits[v & 0x0f];
z = 1;
}
v = (w >> j) & 0xff;
if (!started && v == 0)
continue;
if (!CBB_add_u8(&cbb, hex_digits[v >> 4]))
goto err;
if (!CBB_add_u8(&cbb, hex_digits[v & 0xf]))
goto err;
started = 1;
}
}
*p = '\0';
if (!CBB_add_u8(&cbb, '\0'))
goto err;
if (!CBB_finish(&cbb, &s, &s_len))
goto err;
err:
return (buf);
err:
CBB_cleanup(&cbb);
return s;
}
int

View file

@ -1,4 +1,4 @@
/* $OpenBSD: bn_exp.c,v 1.45 2023/03/30 14:21:10 tb Exp $ */
/* $OpenBSD: bn_exp.c,v 1.46 2023/05/09 05:38:11 tb Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@ -194,7 +194,7 @@ BN_mod_exp_simple(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
bits = BN_num_bits(p);
if (bits == 0) {
/* x**0 mod 1 is still zero. */
if (BN_is_one(m)) {
if (BN_abs_is_word(m, 1)) {
ret = 1;
BN_zero(r);
} else
@ -402,7 +402,7 @@ BN_mod_exp_mont_consttime(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p,
bits = BN_num_bits(p);
if (bits == 0) {
/* x**0 mod 1 is still zero. */
if (BN_is_one(m)) {
if (BN_abs_is_word(m, 1)) {
ret = 1;
BN_zero(rr);
} else
@ -658,7 +658,7 @@ BN_mod_exp_mont_internal(BIGNUM *rr, const BIGNUM *a, const BIGNUM *p, const BIG
bits = BN_num_bits(p);
if (bits == 0) {
/* x**0 mod 1 is still zero. */
if (BN_is_one(m)) {
if (BN_abs_is_word(m, 1)) {
ret = 1;
BN_zero(rr);
} else
@ -843,7 +843,7 @@ BN_mod_exp_mont_word(BIGNUM *rr, BN_ULONG a, const BIGNUM *p, const BIGNUM *m,
bits = BN_num_bits(p);
if (bits == 0) {
/* x**0 mod 1 is still zero. */
if (BN_is_one(m)) {
if (BN_abs_is_word(m, 1)) {
ret = 1;
BN_zero(rr);
} else
@ -968,7 +968,7 @@ BN_mod_exp_recp(BIGNUM *r, const BIGNUM *a, const BIGNUM *p, const BIGNUM *m,
bits = BN_num_bits(p);
if (bits == 0) {
/* x**0 mod 1 is still zero. */
if (BN_is_one(m)) {
if (BN_abs_is_word(m, 1)) {
ret = 1;
BN_zero(r);
} else

View file

@ -1,4 +1,4 @@
/* $OpenBSD: bn_local.h,v 1.21 2023/04/25 17:59:41 tb Exp $ */
/* $OpenBSD: bn_local.h,v 1.22 2023/05/10 12:21:55 tb Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@ -324,7 +324,7 @@ int bn_copy(BIGNUM *dst, const BIGNUM *src);
int bn_isqrt(BIGNUM *out_sqrt, int *out_perfect, const BIGNUM *n, BN_CTX *ctx);
int bn_is_perfect_square(int *out_perfect, const BIGNUM *n, BN_CTX *ctx);
int bn_is_prime_bpsw(int *is_prime, const BIGNUM *n, BN_CTX *in_ctx);
int bn_is_prime_bpsw(int *is_prime, const BIGNUM *n, BN_CTX *ctx, size_t rounds);
__END_HIDDEN_DECLS
#endif /* !HEADER_BN_LOCAL_H */

View file

@ -1,4 +1,4 @@
/* $OpenBSD: bn_prime.c,v 1.31 2023/04/25 19:57:59 tb Exp $ */
/* $OpenBSD: bn_prime.c,v 1.32 2023/05/10 12:21:55 tb Exp $ */
/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
* All rights reserved.
*
@ -195,12 +195,12 @@ BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add,
goto err;
if (!safe) {
if (!bn_is_prime_bpsw(&is_prime, ret, ctx))
if (!bn_is_prime_bpsw(&is_prime, ret, ctx, 1))
goto err;
if (!is_prime)
goto loop;
} else {
if (!bn_is_prime_bpsw(&is_prime, ret, ctx))
if (!bn_is_prime_bpsw(&is_prime, ret, ctx, 1))
goto err;
if (!is_prime)
goto loop;
@ -213,7 +213,7 @@ BN_generate_prime_ex(BIGNUM *ret, int bits, int safe, const BIGNUM *add,
if (!BN_rshift1(p, ret))
goto err;
if (!bn_is_prime_bpsw(&is_prime, p, ctx))
if (!bn_is_prime_bpsw(&is_prime, p, ctx, 1))
goto err;
if (!is_prime)
goto loop;
@ -243,8 +243,14 @@ BN_is_prime_fasttest_ex(const BIGNUM *a, int checks, BN_CTX *ctx_passed,
{
int is_prime;
if (checks < 0)
return -1;
if (checks == BN_prime_checks)
checks = BN_prime_checks_for_size(BN_num_bits(a));
/* XXX - tickle BN_GENCB in bn_is_prime_bpsw(). */
if (!bn_is_prime_bpsw(&is_prime, a, ctx_passed))
if (!bn_is_prime_bpsw(&is_prime, a, ctx_passed, checks))
return -1;
return is_prime;