1 /***********************************************************************/
5 /* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
7 /* Copyright 2003 Institut National de Recherche en Informatique et */
8 /* en Automatique. All rights reserved. This file is distributed */
9 /* under the terms of the GNU Library General Public License, with */
10 /* the special exception on linking described in file ../../LICENSE. */
12 /***********************************************************************/
14 /* $Id: test_bng.c 5900 2003-11-07 07:59:10Z xleroy $ */
16 /* Test harness for the BNG primitives. Use BigNum as a reference. */
24 #include "../../../config/m.h"
27 #if defined(__GNUC__) && BNG_ASM_LEVEL > 0
28 #if defined(BNG_ARCH_ia32)
30 #elif defined(BNG_ARCH_amd64)
31 #include "bng_amd64.c"
32 #elif defined(BNG_ARCH_ppc)
34 #elif defined (BNG_ARCH_alpha)
35 #include "bng_alpha.c"
36 #elif defined (BNG_ARCH_sparc)
37 #include "bng_sparc.c"
38 #elif defined (BNG_ARCH_mips)
43 #include "bng_digit.c"
45 /* Random generator for digits. Can either generate "true" PRN numbers
46 or numbers consisting of long sequences of 0 and 1 bits. */
48 static int rand_skewed = 0;
49 static int rand_runlength = 0;
50 static int rand_bit = 0;
51 static bngdigit rand_seed = 0;
53 static bngdigit randdigit(void)
59 for (i = 0, res = 0; i < BNG_BITS_PER_DIGIT; i++) {
60 if (rand_runlength == 0) {
61 rand_runlength = 1 + (rand() % (2 * BNG_BITS_PER_DIGIT));
64 res = (res << 1) | rand_bit;
69 rand_seed = rand_seed * 69069 + 25173;
74 /* Test the operations on digits.
75 This uses double-width integer arithmetic as reference.
76 This is only available on 32-bit platforms that support a 64-bit int type.
79 #if defined(ARCH_UINT64_TYPE) && !defined(ARCH_SIXTYFOUR)
81 typedef ARCH_UINT64_TYPE dbldigit;
83 static int test_digit_ops(int i)
85 bngdigit a1, a2, a3, r1, r2;
94 if ((dbldigit) r1 + ((dbldigit) co << BNG_BITS_PER_DIGIT)
95 != (dbldigit) a1 + (dbldigit) a2) {
96 printf("Round %d, BngAdd2(%lx,%x,%lx, %lx)\n", i, r1, co, a1, a2);
100 BngAdd2Carry(r1,co,a1,a2,ci);
101 if ((dbldigit) r1 + ((dbldigit) co << BNG_BITS_PER_DIGIT)
102 != (dbldigit) a1 + (dbldigit) a2 + (dbldigit) ci) {
103 printf("Round %d, BngAdd2Carry(%lx,%x,%lx, %lx, %x)\n", i, r1, co, a1, a2, ci);
108 BngAdd3(r1,r2,a1,a2,a3);
109 if ((dbldigit) r1 + ((dbldigit) r2 << BNG_BITS_PER_DIGIT)
110 != (dbldigit) a1 + (dbldigit) a2 + (dbldigit) a3) {
111 printf("Round %d, BngAdd3(%lx,%x,%lx, %lx, %lx)\n", i, r1, co, a1, a2, a3);
115 BngSub2(r1,co,a1,a2);
116 if ((dbldigit) r1 - ((dbldigit) co << BNG_BITS_PER_DIGIT)
117 != (dbldigit) a1 - (dbldigit) a2) {
118 printf("Round %d, BngSub2(%lx,%x,%lx, %lx)\n", i, r1, co, a1, a2);
122 BngSub2Carry(r1,co,a1,a2,ci);
123 if ((dbldigit) r1 - ((dbldigit) co << BNG_BITS_PER_DIGIT)
124 != (dbldigit) a1 - (dbldigit) a2 - (dbldigit) ci) {
125 printf("Round %d, BngSub2Carry(%lx,%x,%lx, %lx, %x)\n", i, r1, co, a1, a2, ci);
130 BngSub3(r1,r2,a1,a2,a3);
131 if ((dbldigit) r1 - ((dbldigit) r2 << BNG_BITS_PER_DIGIT)
132 != (dbldigit) a1 - (dbldigit) a2 - (dbldigit) a3) {
133 printf("Round %d, BngSub3(%lx,%x,%lx, %lx, %lx)\n", i, r1, co, a1, a2, a3);
137 BngMult(r1,r2,a1,a2);
138 if ((((dbldigit) r1 << BNG_BITS_PER_DIGIT) | (dbldigit) r2)
139 != (dbldigit) a1 * (dbldigit) a2) {
140 printf("Round %d, BngMult(%lx,%lx,%lx, %lx)\n", i, r1, r2, a1, a2);
144 /* Make sure a3 is normalized */
145 a3 |= 1L << (BNG_BITS_PER_DIGIT - 1);
147 BngDiv(r1,r2,a1,a2,a3);
148 if (r1 != (((dbldigit) a1 << BNG_BITS_PER_DIGIT) | (dbldigit) a2) / a3
150 r2 != (((dbldigit) a1 << BNG_BITS_PER_DIGIT) | (dbldigit) a2) % a3)
152 printf("Round %d, BngDiv(%lx,%lx,%lx, %lx, %lx)\n", i, r1, r2, a1, a2, a3);
157 n = bng_leading_zero_bits(a1);
159 if (n != BNG_BITS_PER_DIGIT) {
160 printf("Round %d, bng_leading_zero(bits(%lx) = %d", i, a1, n);
164 if ((a1 << n) >> n != a1 ||
165 ((a1 << n) & (1L << (BNG_BITS_PER_DIGIT - 1))) == 0) {
166 printf("Round %d, bng_leading_zero(bits(%lx) = %d", i, a1, n);
175 /* Test the bng operations. Use BigNum as a reference. */
177 #define MAX_DIGITS 32
179 void randbng(bng a, bngsize n)
182 for (i = 0; i < n; i++) a[i] = randdigit();
185 char * bng2string(bng a, bngsize n)
187 char * buffer = malloc((BNG_BITS_PER_DIGIT / 4 + 1) * MAX_DIGITS);
188 char temp[BNG_BITS_PER_DIGIT / 4 + 1];
192 for (i = n - 1; i >= 0; i--) {
193 sprintf(temp, "%lx", a[i]);
194 strcat(buffer, temp);
195 if (i > 0) strcat(buffer, "_");
200 int bngsame(bng a, bng b, bngsize n)
203 for (i = 0; i < n; i++)
204 if (a[i] != b[i]) return 0;
208 int test_bng_ops(int i)
211 bngdigit a[MAX_DIGITS], b[MAX_DIGITS], c[MAX_DIGITS], d[MAX_DIGITS];
212 bngdigit f[2 * MAX_DIGITS], g[2 * MAX_DIGITS], h[2 * MAX_DIGITS];
214 bngdigit dg, do_, dp;
217 /* Determine random lengths p and q between 1 and MAX_DIGITS.
219 p = 1 + (rand() % MAX_DIGITS);
220 q = 1 + (rand() % MAX_DIGITS);
221 if (q > p) { bngsize t = p; p = q; q = t; }
223 /* Randomly generate bignums a of size p, b of size q */
229 co = bng_compare(a, p, b, q);
230 cp = BnnCompare(a, p, b, q);
232 printf("Round %d, bng_compare(%s, %ld, %s, %ld) = %d\n",
233 i, bng2string(a, p), p, bng2string(b, q), q, co);
236 co = bng_compare(b, q, a, p);
237 cp = BnnCompare(b, q, a, p);
239 printf("Round %d, bng_compare(%s, %ld, %s, %ld) = %d\n",
240 i, bng2string(b, q), q, bng2string(a, p), p, co);
245 co = bng_add_carry(c, p, ci);
247 cp = BnnAddCarry(d, p, ci);
248 if (co != cp || !bngsame(c, d, p)) {
249 printf("Round %d, bng_add_carry(%s, %ld, %d) -> %s, %d\n",
250 i, bng2string(a, p), p, ci, bng2string(c, p), co);
255 co = bng_add(c, p, b, q, ci);
257 cp = BnnAdd(d, p, b, q, ci);
258 if (co != cp || !bngsame(c, d, p)) {
259 printf("Round %d, bng_add(%s, %ld, %s, %ld, %d) -> %s, %d\n",
260 i, bng2string(a, p), p, bng2string(b, q), q, ci,
261 bng2string(c, p), co);
266 co = bng_sub_carry(c, p, ci);
268 cp = BnnSubtractBorrow(d, p, ci ^ 1) ^ 1;
269 if (co != cp || !bngsame(c, d, p)) {
270 printf("Round %d, bng_sub_carry(%s, %ld, %d) -> %s, %d\n",
271 i, bng2string(a, p), p, ci, bng2string(c, p), co);
276 co = bng_sub(c, p, b, q, ci);
278 cp = BnnSubtract(d, p, b, q, ci ^ 1) ^ 1;
279 if (co != cp || !bngsame(c, d, p)) {
280 printf("Round %d, bng_sub(%s, %ld, %s, %ld, %d) -> %s, %d\n",
281 i, bng2string(a, p), p, bng2string(b, q), q, ci,
282 bng2string(c, p), co);
286 amount = rand() % BNG_BITS_PER_DIGIT;
288 do_ = bng_shift_left(c, p, amount);
290 dp = BnnShiftLeft(d, p, amount);
291 if (do_ != dp || !bngsame(c, d, p)) {
292 printf("Round %d, bng_shift_left(%s, %ld, %d) -> %s, %ld\n",
293 i, bng2string(a, p), p, amount, bng2string(c, p), do_);
297 amount = rand() % BNG_BITS_PER_DIGIT;
299 do_ = bng_shift_right(c, p, amount);
301 dp = BnnShiftRight(d, p, amount);
302 if (do_ != dp || !bngsame(c, d, p)) {
303 printf("Round %d, bng_shift_right(%s, %ld, %d) -> %s, %ld\n",
304 i, bng2string(a, p), p, amount, bng2string(c, p), do_);
311 co = bng_mult_add_digit(c, p, b, q, dg);
313 cp = BnnMultiplyDigit(d, p, b, q, dg);
314 if (co != cp || !bngsame(c, d, p)) {
315 printf("Round %d, bng_mult_add_digit(%s, %ld, %s, %ld, %ld) -> %s, %d\n",
316 i, bng2string(a, p), p, bng2string(b, q), q, dg,
317 bng2string(c, p), co);
324 do_ = bng_mult_add_digit(c, p, b, q, dg);
326 dp = bng_mult_sub_digit(d, p, b, q, dg);
327 if (do_ != dp || !bngsame(a, d, p)) {
328 printf("Round %d, bng_mult_sub_digit(%s, %ld, %s, %ld, %ld) -> %s, %ld\n",
329 i, bng2string(c, p), p, bng2string(b, q), q, dg,
330 bng2string(d, p), dp);
335 bng_assign(g, f, 2*p);
336 co = bng_mult_add(g, 2*p, a, p, b, q);
337 BnnAssign(h, f, 2*p);
338 cp = BnnMultiply(h, 2*p, a, p, b, q);
339 if (co != cp || !bngsame(g, h, 2*p)) {
340 printf("Round %d, bng_mult_add(%s, %ld, %s, %ld, %s, %ld) -> %s, %d\n",
341 i, bng2string(f, 2*p), 2*p,
344 bng2string(g, 2*p), co);
349 bng_assign(g, f, 2*p);
350 co = bng_square_add(g, 2*p, b, q);
351 BnnAssign(h, f, 2*p);
352 cp = BnnAdd(h, 2*p, h, 2*p);
353 cp += BnnMultiply(h, 2*p, b, q, b, q);
354 if (co != cp || !bngsame(g, h, 2*p)) {
355 printf("Round %d, bng_square_add(%s, %ld, %s, %ld) -> %s, %d\n",
356 i, bng2string(f, 2*p), 2*p,
358 bng2string(g, 2*p), co);
363 do_ = bng_div_rem_digit(c, a, p, dg);
364 dp = BnnDivideDigit(d, a, p, dg);
365 if (do_ != dp || !bngsame(c, d, p-1)) {
366 printf("Round %d, bng_div_rem_digit(%s, %s, %ld, %lx) -> %lx\n",
367 i, bng2string(d, p-1), bng2string(a, p), p, dg, do_);
372 if (p > q && a[p - 1] < b[q - 1]) {
374 bng_div_rem(c, p, b, q);
376 BnnDivide(d, p, b, q);
377 if (!bngsame(c, d, p)) {
378 printf("Round %d, bng_div_rem(%s, %ld, %s, %ld) -> %s, %s\n",
379 i, bng2string(a, p), p, bng2string(b, q), q,
380 bng2string(c + q, p - q),
388 int main(int argc, char ** argv)
394 if (argc >= 2) niter = atoi(argv[1]);
395 #if defined(ARCH_UINT64_TYPE) && !defined(ARCH_SIXTYFOUR)
396 printf("Testing single-digit operations\n");
397 for (err = 0, i = 1; i < niter; i++) err += test_digit_ops(i);
398 printf("%d rounds performed, %d errors found\n", niter, err);
400 printf("Testing bignum operations\n");
401 for (err = 0, i = 1; i < niter; i++) err += test_bng_ops(i);
402 printf("%d rounds performed, %d errors found\n", niter, err);
403 printf("Testing bignum operations with skewed PRNG\n");
405 for (err = 0, i = 1; i < niter; i++) err += test_bng_ops(i);
406 printf("%d rounds performed, %d errors found\n", niter, err);