diff options
author | tb <> | 2022-07-25 20:48:57 +0000 |
---|---|---|
committer | tb <> | 2022-07-25 20:48:57 +0000 |
commit | 044a3e182a9c5e520024e4fb88d4d5d134af5bf0 (patch) | |
tree | 7e50d6ce59b316501132cf86504c150035b1ab49 /src | |
parent | 20aea8136defb6b04d2ebae31195a55bf10ae314 (diff) | |
download | openbsd-044a3e182a9c5e520024e4fb88d4d5d134af5bf0.tar.gz openbsd-044a3e182a9c5e520024e4fb88d4d5d134af5bf0.tar.bz2 openbsd-044a3e182a9c5e520024e4fb88d4d5d134af5bf0.zip |
Add a regression test for bn_isqrt.c
This validates the tables used in bn_is_perfect_square() and checks that
for randomly generated numbers the isqrt() is what it is expected to be.
Diffstat (limited to 'src')
-rw-r--r-- | src/regress/lib/libcrypto/bn/general/Makefile | 11 | ||||
-rw-r--r-- | src/regress/lib/libcrypto/bn/general/bn_isqrt.c | 292 |
2 files changed, 302 insertions, 1 deletions
diff --git a/src/regress/lib/libcrypto/bn/general/Makefile b/src/regress/lib/libcrypto/bn/general/Makefile index 913a3db19b..ab642e0769 100644 --- a/src/regress/lib/libcrypto/bn/general/Makefile +++ b/src/regress/lib/libcrypto/bn/general/Makefile | |||
@@ -1,8 +1,9 @@ | |||
1 | # $OpenBSD: Makefile,v 1.13 2022/06/23 18:09:19 tb Exp $ | 1 | # $OpenBSD: Makefile,v 1.14 2022/07/25 20:48:57 tb Exp $ |
2 | 2 | ||
3 | .include "../../Makefile.inc" | 3 | .include "../../Makefile.inc" |
4 | 4 | ||
5 | PROGS += bntest | 5 | PROGS += bntest |
6 | PROGS += bn_isqrt | ||
6 | PROGS += bn_mod_exp2_mont | 7 | PROGS += bn_mod_exp2_mont |
7 | PROGS += bn_mod_sqrt | 8 | PROGS += bn_mod_sqrt |
8 | PROGS += bn_primes | 9 | PROGS += bn_primes |
@@ -42,4 +43,12 @@ REGRESS_TARGETS += run-bn_to_string | |||
42 | run-bn_to_string: bn_to_string | 43 | run-bn_to_string: bn_to_string |
43 | ./bn_to_string | 44 | ./bn_to_string |
44 | 45 | ||
46 | LDADD_bn_isqrt = ${CRYPTO_INT} | ||
47 | REGRESS_TARGETS += run-bn_isqrt | ||
48 | run-bn_isqrt: bn_isqrt | ||
49 | ./bn_isqrt | ||
50 | |||
51 | print-tables: bn_isqrt | ||
52 | @./bn_isqrt -C | ||
53 | |||
45 | .include <bsd.regress.mk> | 54 | .include <bsd.regress.mk> |
diff --git a/src/regress/lib/libcrypto/bn/general/bn_isqrt.c b/src/regress/lib/libcrypto/bn/general/bn_isqrt.c new file mode 100644 index 0000000000..24e15a8aee --- /dev/null +++ b/src/regress/lib/libcrypto/bn/general/bn_isqrt.c | |||
@@ -0,0 +1,292 @@ | |||
1 | /* $OpenBSD: bn_isqrt.c,v 1.1 2022/07/25 20:48:57 tb Exp $ */ | ||
2 | /* | ||
3 | * Copyright (c) 2022 Theo Buehler <tb@openbsd.org> | ||
4 | * | ||
5 | * Permission to use, copy, modify, and distribute this software for any | ||
6 | * purpose with or without fee is hereby granted, provided that the above | ||
7 | * copyright notice and this permission notice appear in all copies. | ||
8 | * | ||
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | ||
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | ||
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | ||
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | ||
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | ||
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | ||
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | ||
16 | */ | ||
17 | |||
18 | #include <err.h> | ||
19 | #include <string.h> | ||
20 | #include <unistd.h> | ||
21 | |||
22 | #include <openssl/bn.h> | ||
23 | |||
24 | #include "bn_lcl.h" | ||
25 | |||
26 | #define N_TESTS 400 | ||
27 | |||
28 | /* Sample squares between 2^128 and 2^4096. */ | ||
29 | #define LOWER_BITS 128 | ||
30 | #define UPPER_BITS 4096 | ||
31 | |||
32 | extern const uint8_t is_square_mod_11[]; | ||
33 | extern const uint8_t is_square_mod_63[]; | ||
34 | extern const uint8_t is_square_mod_64[]; | ||
35 | extern const uint8_t is_square_mod_65[]; | ||
36 | |||
37 | static void | ||
38 | hexdump(const unsigned char *buf, size_t len) | ||
39 | { | ||
40 | size_t i; | ||
41 | |||
42 | for (i = 1; i <= len; i++) | ||
43 | fprintf(stderr, " 0x%02hhx,%s", buf[i - 1], i % 8 ? "" : "\n"); | ||
44 | |||
45 | if (len % 8) | ||
46 | fprintf(stderr, "\n"); | ||
47 | } | ||
48 | |||
49 | static const uint8_t * | ||
50 | get_table(int modulus) | ||
51 | { | ||
52 | switch (modulus) { | ||
53 | case 11: | ||
54 | return is_square_mod_11; | ||
55 | case 63: | ||
56 | return is_square_mod_63; | ||
57 | case 64: | ||
58 | return is_square_mod_64; | ||
59 | case 65: | ||
60 | return is_square_mod_65; | ||
61 | default: | ||
62 | return NULL; | ||
63 | } | ||
64 | } | ||
65 | |||
66 | static int | ||
67 | check_tables(int print) | ||
68 | { | ||
69 | int fill[] = {11, 63, 64, 65}; | ||
70 | const uint8_t *table; | ||
71 | uint8_t q[65]; | ||
72 | size_t i; | ||
73 | int j; | ||
74 | int failed = 0; | ||
75 | |||
76 | for (i = 0; i < sizeof(fill) / sizeof(fill[0]); i++) { | ||
77 | memset(q, 0, sizeof(q)); | ||
78 | |||
79 | for (j = 0; j <= fill[i]; j++) | ||
80 | q[(j * j) % fill[i]] = 1; | ||
81 | |||
82 | if ((table = get_table(fill[i])) == NULL) { | ||
83 | fprintf(stderr, "failed to get table %d\n", fill[i]); | ||
84 | failed |= 1; | ||
85 | continue; | ||
86 | } | ||
87 | |||
88 | if (memcmp(table, q, fill[i]) != 0) { | ||
89 | fprintf(stderr, "table %d does not match:\n", fill[i]); | ||
90 | fprintf(stderr, "want:\n"); | ||
91 | hexdump(table, fill[i]); | ||
92 | fprintf(stderr, "got:\n"); | ||
93 | hexdump(q, fill[i]); | ||
94 | failed |= 1; | ||
95 | continue; | ||
96 | } | ||
97 | |||
98 | if (!print) | ||
99 | continue; | ||
100 | |||
101 | printf("const uint8_t is_square_mod_%d[] = {\n\t", | ||
102 | fill[i]); | ||
103 | for (j = 0; j < fill[i]; j++) { | ||
104 | const char *end = " "; | ||
105 | |||
106 | if (j % 16 == 15) | ||
107 | end = "\n\t"; | ||
108 | if (j + 1 == fill[i]) | ||
109 | end = ""; | ||
110 | |||
111 | printf("%d,%s", q[j], end); | ||
112 | } | ||
113 | printf("\n};\nCTASSERT(sizeof(is_square_mod_%d) == %d);\n\n", | ||
114 | fill[i], fill[i]); | ||
115 | } | ||
116 | |||
117 | return failed; | ||
118 | } | ||
119 | |||
120 | /* | ||
121 | * Choose a random number n between 2^10 and 2^16384 and check n == isqrt(n^2). | ||
122 | * Random numbers n^2 <= test < (n + 1)^2 are checked to have isqrt(test) == n. | ||
123 | */ | ||
124 | static int | ||
125 | isqrt_test(void) | ||
126 | { | ||
127 | BN_CTX *ctx; | ||
128 | BIGNUM *n, *n_sqr, *lower, *upper, *testcase, *isqrt; | ||
129 | int cmp, is_perfect_square; | ||
130 | int i; | ||
131 | int failed = 0; | ||
132 | |||
133 | if ((ctx = BN_CTX_new()) == NULL) | ||
134 | errx(1, "BN_CTX_new"); | ||
135 | |||
136 | BN_CTX_start(ctx); | ||
137 | |||
138 | if ((lower = BN_CTX_get(ctx)) == NULL) | ||
139 | errx(1, "lower = BN_CTX_get(ctx)"); | ||
140 | if ((upper = BN_CTX_get(ctx)) == NULL) | ||
141 | errx(1, "upper = BN_CTX_get(ctx)"); | ||
142 | if ((n = BN_CTX_get(ctx)) == NULL) | ||
143 | errx(1, "n = BN_CTX_get(ctx)"); | ||
144 | if ((n_sqr = BN_CTX_get(ctx)) == NULL) | ||
145 | errx(1, "n = BN_CTX_get(ctx)"); | ||
146 | if ((isqrt = BN_CTX_get(ctx)) == NULL) | ||
147 | errx(1, "result = BN_CTX_get(ctx)"); | ||
148 | if ((testcase = BN_CTX_get(ctx)) == NULL) | ||
149 | errx(1, "testcase = BN_CTX_get(ctx)"); | ||
150 | |||
151 | /* lower = 2^LOWER_BITS, upper = 2^UPPER_BITS. */ | ||
152 | if (!BN_set_bit(lower, LOWER_BITS)) | ||
153 | errx(1, "BN_set_bit(lower, %d)", LOWER_BITS); | ||
154 | if (!BN_set_bit(upper, UPPER_BITS)) | ||
155 | errx(1, "BN_set_bit(upper, %d)", UPPER_BITS); | ||
156 | |||
157 | if (!bn_rand_interval(n, lower, upper)) | ||
158 | errx(1, "bn_rand_interval n"); | ||
159 | |||
160 | /* n_sqr = n^2 */ | ||
161 | if (!BN_sqr(n_sqr, n, ctx)) | ||
162 | errx(1, "BN_sqr"); | ||
163 | |||
164 | if (!bn_isqrt(isqrt, &is_perfect_square, n_sqr, ctx)) | ||
165 | errx(1, "bn_isqrt n_sqr"); | ||
166 | |||
167 | if ((cmp = BN_cmp(n, isqrt)) != 0 || !is_perfect_square) { | ||
168 | fprintf(stderr, "n = "); | ||
169 | BN_print_fp(stderr, n); | ||
170 | fprintf(stderr, "n^2 is_perfect_square: %d, cmp: %d\n", | ||
171 | is_perfect_square, cmp); | ||
172 | failed = 1; | ||
173 | } | ||
174 | |||
175 | /* upper = 2 * n + 1 */ | ||
176 | if (!BN_lshift1(upper, n)) | ||
177 | errx(1, "BN_lshift1(upper, n)"); | ||
178 | if (!BN_add_word(upper, 1)) | ||
179 | errx(1, "BN_sub_word(upper, 1)"); | ||
180 | |||
181 | /* upper = (n + 1)^2 = n^2 + upper */ | ||
182 | if (!BN_add(upper, n_sqr, upper)) | ||
183 | errx(1, "BN_add"); | ||
184 | |||
185 | /* | ||
186 | * Check that isqrt((n + 1)^2) - 1 == n. | ||
187 | */ | ||
188 | |||
189 | if (!bn_isqrt(isqrt, &is_perfect_square, upper, ctx)) | ||
190 | errx(1, "bn_isqrt(upper)"); | ||
191 | |||
192 | if (!BN_sub_word(isqrt, 1)) | ||
193 | errx(1, "BN_add_word(isqrt, 1)"); | ||
194 | |||
195 | if ((cmp = BN_cmp(n, isqrt)) != 0 || !is_perfect_square) { | ||
196 | fprintf(stderr, "n = "); | ||
197 | BN_print_fp(stderr, n); | ||
198 | fprintf(stderr, "\n(n + 1)^2 is_perfect_square: %d, cmp: %d\n", | ||
199 | is_perfect_square, cmp); | ||
200 | failed = 1; | ||
201 | } | ||
202 | |||
203 | /* | ||
204 | * Test N_TESTS random numbers n^2 <= testcase < (n + 1)^2 and check | ||
205 | * that their isqrt is n. | ||
206 | */ | ||
207 | |||
208 | for (i = 1; i < N_TESTS; i++) { | ||
209 | if (!bn_rand_interval(testcase, n_sqr, upper)) | ||
210 | errx(1, "bn_rand_interval testcase"); | ||
211 | |||
212 | if (!bn_isqrt(isqrt, &is_perfect_square, testcase, ctx)) | ||
213 | errx(1, "bn_isqrt testcase"); | ||
214 | |||
215 | if ((cmp = BN_cmp(n, isqrt)) != 0 || is_perfect_square) { | ||
216 | fprintf(stderr, "n = "); | ||
217 | BN_print_fp(stderr, n); | ||
218 | fprintf(stderr, "\ntestcase = "); | ||
219 | BN_print_fp(stderr, testcase); | ||
220 | fprintf(stderr, | ||
221 | "\ntestcase is_perfect_square: %d, cmp: %d\n", | ||
222 | is_perfect_square, cmp); | ||
223 | failed = 1; | ||
224 | } | ||
225 | } | ||
226 | |||
227 | /* | ||
228 | * Finally check that isqrt(n^2 - 1) + 1 = n. | ||
229 | */ | ||
230 | |||
231 | if (!BN_sub(testcase, n_sqr, BN_value_one())) | ||
232 | errx(1, "BN_sub(testcase, n_sqr, 1)"); | ||
233 | |||
234 | if (!bn_isqrt(isqrt, &is_perfect_square, testcase, ctx)) | ||
235 | errx(1, "bn_isqrt(n_sqr - 1)"); | ||
236 | |||
237 | if (!BN_add_word(isqrt, 1)) | ||
238 | errx(1, "BN_add_word(isqrt, 1)"); | ||
239 | |||
240 | if ((cmp = BN_cmp(n, isqrt)) != 0 || is_perfect_square) { | ||
241 | fprintf(stderr, "n = "); | ||
242 | BN_print_fp(stderr, n); | ||
243 | fprintf(stderr, "\nn_sqr - 1 is_perfect_square: %d, cmp: %d\n", | ||
244 | is_perfect_square, cmp); | ||
245 | failed = 1; | ||
246 | } | ||
247 | |||
248 | |||
249 | BN_CTX_end(ctx); | ||
250 | BN_CTX_free(ctx); | ||
251 | |||
252 | return failed; | ||
253 | } | ||
254 | |||
255 | static void | ||
256 | usage(void) | ||
257 | { | ||
258 | fprintf(stderr, "usage: bn_isqrt [-C]\n"); | ||
259 | exit(1); | ||
260 | } | ||
261 | |||
262 | int | ||
263 | main(int argc, char *argv[]) | ||
264 | { | ||
265 | size_t i; | ||
266 | int ch; | ||
267 | int failed = 0, print = 0; | ||
268 | |||
269 | while ((ch = getopt(argc, argv, "C")) != -1) { | ||
270 | switch (ch) { | ||
271 | case 'C': | ||
272 | print = 1; | ||
273 | break; | ||
274 | default: | ||
275 | usage(); | ||
276 | break; | ||
277 | } | ||
278 | } | ||
279 | |||
280 | if (print) | ||
281 | return check_tables(1); | ||
282 | |||
283 | for (i = 0; i < N_TESTS; i++) | ||
284 | failed |= isqrt_test(); | ||
285 | |||
286 | failed |= check_tables(0); | ||
287 | |||
288 | if (!failed) | ||
289 | printf("SUCCESS\n"); | ||
290 | |||
291 | return failed; | ||
292 | } | ||