summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authortb <>2022-07-25 20:48:57 +0000
committertb <>2022-07-25 20:48:57 +0000
commit044a3e182a9c5e520024e4fb88d4d5d134af5bf0 (patch)
tree7e50d6ce59b316501132cf86504c150035b1ab49 /src
parent20aea8136defb6b04d2ebae31195a55bf10ae314 (diff)
downloadopenbsd-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/Makefile11
-rw-r--r--src/regress/lib/libcrypto/bn/general/bn_isqrt.c292
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
5PROGS += bntest 5PROGS += bntest
6PROGS += bn_isqrt
6PROGS += bn_mod_exp2_mont 7PROGS += bn_mod_exp2_mont
7PROGS += bn_mod_sqrt 8PROGS += bn_mod_sqrt
8PROGS += bn_primes 9PROGS += bn_primes
@@ -42,4 +43,12 @@ REGRESS_TARGETS += run-bn_to_string
42run-bn_to_string: bn_to_string 43run-bn_to_string: bn_to_string
43 ./bn_to_string 44 ./bn_to_string
44 45
46LDADD_bn_isqrt = ${CRYPTO_INT}
47REGRESS_TARGETS += run-bn_isqrt
48run-bn_isqrt: bn_isqrt
49 ./bn_isqrt
50
51print-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
32extern const uint8_t is_square_mod_11[];
33extern const uint8_t is_square_mod_63[];
34extern const uint8_t is_square_mod_64[];
35extern const uint8_t is_square_mod_65[];
36
37static void
38hexdump(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
49static const uint8_t *
50get_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
66static int
67check_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 */
124static int
125isqrt_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
255static void
256usage(void)
257{
258 fprintf(stderr, "usage: bn_isqrt [-C]\n");
259 exit(1);
260}
261
262int
263main(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}