1058 lines
28 KiB
C
1058 lines
28 KiB
C
/* $Id: t_bdTest.c $ */
|
|
|
|
/***** BEGIN LICENSE BLOCK *****
|
|
*
|
|
* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
|
*
|
|
* Copyright (c) 2001-16 David Ireland, D.I. Management Services Pty Limited
|
|
* <http://www.di-mgt.com.au/bigdigits.html>. All rights reserved.
|
|
*
|
|
***** END LICENSE BLOCK *****/
|
|
/*
|
|
* Last updated:
|
|
* $Date: 2016-03-31 09:51:00 $
|
|
* $Revision: 2.6.1 $
|
|
* $Author: dai $
|
|
*/
|
|
|
|
/* Various tests of "bd" functions, not exhaustive */
|
|
|
|
#if _MSC_VER >= 1100
|
|
/* Detect memory leaks in MSVC++ */
|
|
#define _CRTDBG_MAP_ALLOC
|
|
#include <stdlib.h>
|
|
#include <crtdbg.h>
|
|
#else
|
|
#include <stdlib.h>
|
|
#endif
|
|
|
|
#ifdef NDEBUG
|
|
#undef NDEBUG
|
|
#endif
|
|
#include <assert.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <time.h>
|
|
#include "bigd.h"
|
|
#include "bigdRand.h"
|
|
|
|
static void pr_bytesmsg(const char *msg, unsigned char *bytes, size_t nbytes)
|
|
/* Display a message followed by the hex values of a byte array */
|
|
{
|
|
size_t i;
|
|
printf("%s", msg);
|
|
for (i = 0; i < nbytes; i++)
|
|
printf("%02x", bytes[i]);
|
|
printf("\n");
|
|
}
|
|
|
|
int my_rand(unsigned char *bytes, size_t nbytes, const unsigned char *seed, size_t seedlen)
|
|
/* Our own (very insecure) random generator call-back function using good old rand()
|
|
This demonstrates the required format for BD_RANDFUNC
|
|
-- replace this in practice with your own cryptographically-secure function.
|
|
*/
|
|
{
|
|
unsigned int myseed;
|
|
size_t i;
|
|
int offset;
|
|
|
|
/* Use time - then blend in seed, if any */
|
|
myseed = (unsigned)time(NULL);
|
|
if (seed)
|
|
{
|
|
for (offset = 0, i = 0; i < seedlen; i++, offset = (offset + 1) % sizeof(unsigned))
|
|
myseed ^= ((unsigned int)seed[i] << (offset * 8));
|
|
}
|
|
|
|
srand(myseed);
|
|
while (nbytes--)
|
|
{
|
|
*bytes++ = rand() & 0xFF;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
int fermat_test(BIGD n)
|
|
{
|
|
/* Carries out a quick Fermat primality test on n > 4.
|
|
Returns 1 if n is prime and 0 if composite or -1 if n < 5.
|
|
This is not foolproof but we use it as a
|
|
check on our main bdIsPrime function.
|
|
It will return a false positive for Fermat Liars, which
|
|
are very rare.
|
|
*/
|
|
BIGD a, e, r;
|
|
int isprime = 1;
|
|
|
|
/* For any integer a, 1<=a<=n-1, if a^(n-1) mod n != 1
|
|
then n is composite. */
|
|
|
|
if (bdShortCmp(n, 5) < 0) return -1;
|
|
|
|
a = bdNew();
|
|
e = bdNew();
|
|
r = bdNew();
|
|
/* e = n -1 */
|
|
bdSetEqual(e, n);
|
|
bdDecrement(e);
|
|
|
|
/* Set a = 2 and compute a^(n-1) mod n */
|
|
bdSetShort(a, 2);
|
|
bdModExp(r, a, e, n);
|
|
if (bdShortCmp(r, 1) != 0)
|
|
isprime = 0;
|
|
|
|
/* a = 3 */
|
|
bdSetShort(a, 3);
|
|
bdModExp(r, a, e, n);
|
|
if (bdShortCmp(r, 1) != 0)
|
|
isprime = 0;
|
|
|
|
/* a = 5 */
|
|
bdSetShort(a, 5);
|
|
bdModExp(r, a, e, n);
|
|
if (bdShortCmp(r, 1) != 0)
|
|
isprime = 0;
|
|
|
|
bdFree(&a);
|
|
bdFree(&e);
|
|
bdFree(&r);
|
|
|
|
return isprime;
|
|
}
|
|
|
|
/** Compute w = u - v using cutoff subtraction so `w >= 0` always.
|
|
* @return 1 if subtraction underflowed or 0 for normal result
|
|
*/
|
|
int cutoff_subtraction(BIGD w, BIGD u, BIGD v)
|
|
{
|
|
int carry = 0;
|
|
if (bdCompare(u, v) < 0) {
|
|
bdSetZero(w);
|
|
carry = 1;
|
|
}
|
|
else {
|
|
bdSubtract(w, u, v);
|
|
}
|
|
return carry;
|
|
}
|
|
|
|
int main(void)
|
|
{
|
|
BIGD u, v, w, q, r, p, b, a;
|
|
BIGD n, e, m, c, z, mz, cz, t;
|
|
BIGD x, y;
|
|
bdigit_t overflow, d;
|
|
int cmp, res;
|
|
unsigned char ff[64], bytes[16];
|
|
int i, mc, jac;
|
|
size_t nbytes, nbits;
|
|
char s[128];
|
|
|
|
/* MSVC memory leak checking stuff */
|
|
#if _MSC_VER >= 1100
|
|
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
|
_CrtSetReportMode( _CRT_WARN, _CRTDBG_MODE_FILE );
|
|
_CrtSetReportFile( _CRT_WARN, _CRTDBG_FILE_STDOUT );
|
|
_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_FILE );
|
|
_CrtSetReportFile( _CRT_ERROR, _CRTDBG_FILE_STDOUT );
|
|
#endif
|
|
|
|
printf("Tests for BIGD functions\n");
|
|
|
|
/* Initialize - new way in [v2.6]*/
|
|
bdNewVars(&u, &v, &w, &p, &q, &r, &x, &y);
|
|
//u = bdNew();
|
|
//v = bdNew();
|
|
//w = bdNew();
|
|
//p = bdNew();
|
|
//q = bdNew();
|
|
//r = bdNew();
|
|
//x = bdNew();
|
|
//y = bdNew();
|
|
|
|
printf("\nSIMPLE ARITHMETIC OPERATIONS...\n");
|
|
bdPrintDecimal("At start w=", w, "\n");
|
|
assert(bdIsZero(w));
|
|
|
|
/* Addition */
|
|
/* 1 + 1 = 2 */
|
|
bdSetShort(u, 1);
|
|
bdSetShort(v, 1);
|
|
bdAdd(w, u, v);
|
|
bdPrintDecimal("1+1=", w, "\n");
|
|
assert(bdShortCmp(w, 2) == 0);
|
|
|
|
/* Add with digit overflow */
|
|
bdSetShort(u, 0xffffffff);
|
|
bdSetShort(v, 0xffffffff);
|
|
bdAdd(w, u, v);
|
|
bdPrintHex("ffffffff+ffffffff=", w, "\n");
|
|
/* ffffffff+ffffffff=00000001 fffffffe */
|
|
assert(bdSizeof(w) == 2);
|
|
|
|
/* Bigger random digits */
|
|
bdSetRandTest(u, 10);
|
|
bdSetRandTest(v, 10);
|
|
bdAdd(w, u, v);
|
|
bdPrintHex("u=\n", u, "\n");
|
|
bdPrintHex("v=\n", v, "\n");
|
|
bdPrintHex("w=u+v=\n", w, "\n");
|
|
|
|
/* Subtract */
|
|
bdSubtract(r, w, v);
|
|
bdPrintHex("w-v=\n", r, "\n");
|
|
assert(bdCompare(r, u) == 0);
|
|
|
|
/* Multiplication */
|
|
/* 2 * 3 = 6 */
|
|
bdSetShort(u, 2);
|
|
bdSetShort(v, 3);
|
|
bdMultiply(w, u, v);
|
|
bdPrintDecimal("2 * 3=", w, "\n");
|
|
assert(bdShortCmp(w, 6) == 0);
|
|
|
|
bdSetShort(u, 0xffffffff);
|
|
bdSetShort(v, 0xffffffff);
|
|
bdMultiply(w, u, v);
|
|
bdPrintHex("ffffffff*ffffffff=", w, "\n");
|
|
/* ffffffff*ffffffff=fffffffe 00000001 */
|
|
assert(bdGetBit(w, 0) == 1);
|
|
|
|
/* Use ShortMult */
|
|
bdShortMult(p, u, 0xffffffff);
|
|
bdPrintHex("(Short)ffffffff*ffffffff=", p, "\n");
|
|
assert(bdCompare(p, w) == 0);
|
|
|
|
/* Use larger random u, v */
|
|
bdSetRandTest(u, 10);
|
|
bdSetRandTest(v, 20);
|
|
bdPrintHex("u=\n", u, "\n");
|
|
bdPrintHex("v=\n", v, "\n");
|
|
|
|
/* Use ShortMult by one: w = v * 1 */
|
|
bdShortMult(w, v, 1);
|
|
bdPrintHex("(Short)v*1=\n", w, "\n");
|
|
assert(bdCompare(w, v) == 0);
|
|
|
|
/* Use ShortMult by two */
|
|
bdShortMult(w, u, 2);
|
|
bdPrintHex("(Short)u*2=\n", w, "\n");
|
|
assert(bdIsEven(w));
|
|
|
|
/* Big multiplication */
|
|
bdMultiply(w, u, v);
|
|
bdPrintHex("w=u*v=\n", w, "\n");
|
|
|
|
/* Divide expecting q = w/v == u and r = w%v == 0 */
|
|
bdDivide(q, r, w, v);
|
|
bdPrintHex("w/v=\n", q, "\n");
|
|
bdPrintHex("w%v=", r, "\n");
|
|
assert(bdIsEqual(q, u));
|
|
assert(bdShortCmp(r, 0) == 0);
|
|
|
|
/* Modulo */
|
|
bdIncrement(w);
|
|
bdModulo(r, w, v);
|
|
bdPrintHex("w+1 mod v=", r, "\n");
|
|
assert(bdShortCmp(r, 1) == 0);
|
|
|
|
bdDecrement(w);
|
|
bdModulo(r, w, u);
|
|
bdPrintHex("w+1-1 mod u=", r, "\n");
|
|
assert(bdShortCmp(r, 0) == 0);
|
|
|
|
/* Use a short divisor q=w/2 */
|
|
bdShortDiv(q, r, w, 2);
|
|
bdPrintHex("(ShortDiv)w/2=\n", q, "\n");
|
|
bdPrintHex("(ShortDiv)w%2=", r, "\n");
|
|
|
|
printf("w is %s\n", bdIsOdd(w) ? "ODD" : "EVEN");
|
|
bdShortMod(r, w, 2);
|
|
bdPrintHex("w mod 2=", r, "\n");
|
|
bdIncrement(w);
|
|
printf("w+1 is %s\n", bdIsOdd(w) ? "ODD" : "EVEN");
|
|
bdShortMod(r, w, 2);
|
|
bdPrintHex("++w mod 2=", r, "\n");
|
|
bdDecrement(w);
|
|
|
|
/* Check with short mult u = q*2 */
|
|
bdShortMult(u, q, 2);
|
|
bdPrintHex("(ShortMult) (w/2) * 2=\n", u, "\n");
|
|
|
|
printf("\nSQUARE AND SQUARE ROOT...\n");
|
|
/* Square a random number w = u^2 */
|
|
bdSetRandTest(u, 10);
|
|
bdPrintHex("random u=\n", u, "\n");
|
|
bdSquare(w, u);
|
|
bdPrintHex("(Square) u^2=", w, "\n");
|
|
/* check against product p = u * u */
|
|
bdMultiply(p, u, u);
|
|
bdPrintHex("u*u=", p, "\n");
|
|
assert(bdIsEqual(p, w));
|
|
/* Compute integer square root [new in v2.1] */
|
|
bdSqrt(p, w);
|
|
bdPrintHex("sqrt(w)=", p, "\n");
|
|
assert(bdIsEqual(p, u));
|
|
|
|
printf("\nMODULAR ARITHMETIC...\n");
|
|
/* Check that (u mod n + v mod n) mod n == (u+v) mod n */
|
|
bdSetRandTest(u, 10);
|
|
bdSetRandTest(v, 10);
|
|
bdSetRandTest(w, 10);
|
|
bdPrintHex("(Modulo)\nNew random u=", u, "\n");
|
|
bdPrintHex("v=", v, "\n");
|
|
bdPrintHex("w=", w, "\n");
|
|
/* r = u mod w */
|
|
bdModulo(r, u, w);
|
|
/* q = v mod w */
|
|
bdModulo(q, v, w);
|
|
/* q = u mod n + v mod n */
|
|
bdAdd(q, q, r);
|
|
/* r = (u mod w + v mod w) mod w */
|
|
bdModulo(r, q, w);
|
|
bdPrintHex("(u mod w + v mod w) mod w=\n", r, "\n");
|
|
/* q = (u+v) mod w */
|
|
bdSetEqual(p, u);
|
|
bdAdd(p, p, v);
|
|
bdModulo(q, p, w);
|
|
bdPrintHex("(u+v) mod w=\n", q, "\n");
|
|
assert(bdIsEqual(r, q));
|
|
|
|
/* ModMult and ModSquare */
|
|
bdModMult(p, u, v, w);
|
|
bdPrintHex("u * v mod w=\n", p, "\n");
|
|
bdModMult(p, u, u, w);
|
|
bdPrintHex("u * u mod w=\n", p, "\n");
|
|
bdModSquare(q, u, w);
|
|
bdPrintHex("u^2 mod w=\n", q, "\n");
|
|
assert(bdIsEqual(p, q));
|
|
|
|
|
|
/* Clear and start again */
|
|
bdSetZero(u);
|
|
bdSetZero(v);
|
|
bdSetZero(w);
|
|
|
|
printf("\nARITHMETIC BOUNDARY CONDITIONS...\n");
|
|
/* This causes Divide algorithm to `Add Back' with 32-bit digits
|
|
See Knuth 4.3.1 Algorithm D Step D6 */
|
|
printf("Check `Add Back' in Divide algorithm\n");
|
|
bdConvFromHex(u, "7fffffff 80000001 00000000 00000000");
|
|
bdConvFromHex(v, "00000000 80000000 80000002 00000005");
|
|
bdDivide(q, r, u, v);
|
|
bdPrintHex("u=", u, "\n");
|
|
bdPrintHex("v=", v, "\n");
|
|
bdPrintHex("q=u/v=", q, "\n");
|
|
bdPrintHex("r=u mod v=", r, "\n");
|
|
/* check that qv + r = u */
|
|
bdMultiply(w, q, v);
|
|
bdAdd(w, w, r);
|
|
bdPrintHex("qv+r=", w, "\n");
|
|
assert(bdIsEqual(w, u));
|
|
/* And check that r = u mod v >= (1-2/b)v
|
|
See Knuth 4.3.1 Exercise 21 */
|
|
bdConvFromHex(p, "1 00000000");
|
|
bdSetEqual(w, p);
|
|
bdShortSub(w, w, 2);
|
|
bdMultiply(u, w, v);
|
|
bdDivide(q, w, u, p);
|
|
bdPrintHex("(1-2/b)=", q, "\n");
|
|
cmp = bdCompare(r, q);
|
|
printf("u mod v %s (1-2/b)v\n", (cmp >= 0 ? ">=" : "<"));
|
|
|
|
|
|
printf("\nCope, sort of, with `negative` numbers...\n");
|
|
bdSetZero(u);
|
|
overflow = bdShortSub(w, u, 2);
|
|
bdPrintHex("w=0-2=", w, "\n");
|
|
printf("overflow=%" PRIuBIGD "\n", overflow);
|
|
overflow = bdIncrement(w);
|
|
bdPrintHex("w+1=", w, "\n");
|
|
printf("overflow=%" PRIuBIGD "\n", overflow);
|
|
overflow = bdIncrement(w);
|
|
bdPrintHex("(Note error!) w+1=", w, "\n");
|
|
printf("overflow=%" PRIuBIGD "\n", overflow);
|
|
|
|
printf("\nUse cut-off subtraction...\n");
|
|
bdSetShort(u, 3);
|
|
bdSetShort(v, 7);
|
|
cutoff_subtraction(w, u, v);
|
|
bdPrintDecimal("3-7=", w, "\n");
|
|
// But OK if no underflow
|
|
cutoff_subtraction(w, v, u);
|
|
bdPrintDecimal("7-3=", w, "\n");
|
|
|
|
printf("\nCatch problems working close to zero...\n");
|
|
bdSetZero(u);
|
|
overflow = bdShortAdd(u, u, 1);
|
|
bdPrintHex("u=0+1=", u, "\n");
|
|
printf("overflow=%" PRIuBIGD " (expected 0)\n", overflow);
|
|
|
|
printf("Compute w = 0 + 0...\n");
|
|
bdSetZero(u);
|
|
bdSetZero(v);
|
|
bdAdd(w, u, v);
|
|
printf("bdPrint(w)=");
|
|
bdPrint(w, 0x1);
|
|
bdPrintDecimal("w=0+0=", w, "\n");
|
|
bdPrintHex("w=0+0=0x", w, "\n");
|
|
bdPrintBits("w=0+0='", w, "'b\n");
|
|
assert(bdIsZero(w));
|
|
|
|
bdAdd(u, w, v);
|
|
bdPrintHex("w+0=", u, "\n");
|
|
bdAdd(w, w, v);
|
|
bdPrintHex("w+=0=", w, "\n");
|
|
|
|
|
|
/* Set u = v = ffff...ffff */
|
|
for (i = 0; i < sizeof(ff); i++)
|
|
ff[i] = 0xff;
|
|
bdConvFromOctets(u, ff, sizeof(ff));
|
|
bdConvFromOctets(v, ff, sizeof(ff));
|
|
bdPrintHex("u=", u,"\n");
|
|
bdPrintHex("v=", v,"\n");
|
|
|
|
/* Compute u * v */
|
|
bdMultiply(w, u, v);
|
|
bdPrintHex("w = u * v =\n", w,"\n");
|
|
/* Set v = w / u */
|
|
bdDivide(v, r, w, u);
|
|
bdPrintHex("v = w / u =\n", v,"\n");
|
|
bdPrintHex("rem=", r,"\n");
|
|
assert(bdIsEqual(u, v));
|
|
assert(bdShortCmp(r, 0) == 0);
|
|
|
|
bdIncrement(u);
|
|
bdDecrement(v);
|
|
bdMultiply(w, u, v);
|
|
bdPrintHex("w = ++u * --v =\n", w,"\n");
|
|
bdDivide(w, r, u, v);
|
|
bdPrintHex("q = u / v =", w,"\n");
|
|
bdPrintHex("rem=", r,"\n");
|
|
assert(bdShortCmp(w, 1) == 0);
|
|
assert(bdShortCmp(r, 2) == 0);
|
|
|
|
|
|
/* Clear and start again */
|
|
bdSetZero(u);
|
|
bdSetZero(v);
|
|
bdSetZero(w);
|
|
|
|
bdSetShort(u, 0); /* Fixed [v2.3]: This used to cause an error */
|
|
bdPrintDecimal("bdSetShort(u, 0)=> u=", u, "\n");
|
|
bdSetShort(v, 3);
|
|
bdModulo(w, u, v);
|
|
bdPrintDecimal("0 mod 3=", w, "\n");
|
|
|
|
/* Set a new random value for v */
|
|
bdSetRandTest(v, 10);
|
|
bdPrintHex("Random v=\n", v,"\n");
|
|
bdShortAdd(u, v, 1);
|
|
bdPrintHex("u = v + 1 =\n", u,"\n");
|
|
cmp = bdCompare(u, v);
|
|
printf("bdCompare(u-v) = %d\n", cmp);
|
|
assert(cmp > 0);
|
|
cmp = bdCompare(v, u);
|
|
printf("bdCompare(v-u) = %d\n", cmp);
|
|
assert(cmp < 0);
|
|
cmp = bdCompare(u, u);
|
|
printf("bdCompare(u-u) = %d\n", cmp);
|
|
assert(cmp == 0);
|
|
|
|
/* Compare with short */
|
|
bdSetShort(w, 0xfffffffe);
|
|
bdPrintHex("w=", w,"\n");
|
|
cmp = bdShortCmp(w, 1);
|
|
assert(cmp > 0);
|
|
printf("bdShortCmp(w-1) = %d\n", cmp);
|
|
cmp = bdShortCmp(w, 0xffffffff);
|
|
assert(cmp < 0);
|
|
printf("bdShortCmp(w-0xffffffff) = %d\n", cmp);
|
|
cmp = bdShortCmp(w, 0xfffffffd);
|
|
printf("bdShortCmp(w-0xfffffffd) = %d\n", cmp);
|
|
assert(cmp > 0);
|
|
/* Convert w back to a short and compare */
|
|
d = bdToShort(w); /* NB This will truncate if w is too big */
|
|
printf("d=bdToShort(w)=%" PRIxBIGD "\n", d);
|
|
cmp = bdShortIsEqual(w, d);
|
|
printf("bdShortIsEqual(w, d)=%d\n", cmp);
|
|
assert(cmp == 1);
|
|
|
|
printf("\nBIT SHIFT OPERATIONS...\n");
|
|
/* Try shifting bits */
|
|
bdPrintHex("w = ", w,"\n");
|
|
bdFree(&u);
|
|
u = bdNew();
|
|
bdShiftLeft(u, w, 2);
|
|
bdPrintHex("w << 2 = ", u,"\n");
|
|
assert(bdGetBit(u, 33) == 1);
|
|
bdShiftRight(v, u, 3);
|
|
bdPrintHex("(w << 2) >> 3 = ", v,"\n");
|
|
assert(bdGetBit(v, 31) == 0);
|
|
|
|
/* Bigger shift */
|
|
bdShiftLeft(u, w, 128);
|
|
bdPrintHex("w << 128 = ", u,"\n");
|
|
assert(bdGetBit(u, 159) == 1);
|
|
bdShiftRight(v, u, 129);
|
|
bdPrintHex("(w << 128) >> 129 = ", v,"\n");
|
|
assert(bdGetBit(v, 31) == 0);
|
|
|
|
/* Use a new variable */
|
|
b = bdNew();
|
|
bdSetZero(b); /* overkill */
|
|
bdSetBit(b, 510, 1);
|
|
bdSetBit(b, 477, 1);
|
|
bdSetBit(b, 31, 1);
|
|
bdSetBit(b, 0, 1);
|
|
bdPrintHex("b=\n", b,"\n");
|
|
|
|
bdSetBit(b, 512, 1);
|
|
bdSetBit(b, 31, 0);
|
|
bdPrintHex("b'=\n", b,"\n");
|
|
printf("Bit 512 is %d\n", bdGetBit(b, 512));
|
|
assert(bdGetBit(b, 512) == 1);
|
|
printf("Bit 511 is %d\n", bdGetBit(b, 511));
|
|
assert(bdGetBit(b, 511) == 0);
|
|
assert(bdGetBit(b, 477) == 1);
|
|
/* NB one-based bit lengths so expecting 513 */
|
|
printf("Bit Length = %u\n", bdBitLength(b));
|
|
assert(bdBitLength(b) == 513);
|
|
bdPrintHex("b'=\n", b,"\n");
|
|
/* Destroy b */
|
|
bdFree(&b);
|
|
|
|
printf("\nRANDOM NUMBER GENERATION...\n");
|
|
/* Create a random number using `my_rand' callback function */
|
|
bdRandomSeeded(r, 508, (const unsigned char*)"", 0, my_rand);
|
|
bdPrintHex("random=\n", r,"\n");
|
|
/* NB bit length may be less than 508 */
|
|
printf("%u bits\n", bdBitLength(r));
|
|
assert(bdBitLength(r) <= 508);
|
|
|
|
/* Create a random number using the internal RNG */
|
|
bdRandomBits(r, 509);
|
|
bdPrintHex("random=\n", r,"\n");
|
|
printf("%u bits\n", bdBitLength(r));
|
|
assert(bdBitLength(r) <= 509);
|
|
|
|
printf("\nPRIME NUMBERS...\n");
|
|
/* Generate two random primes */
|
|
printf("Generating two primes...\n");
|
|
bdGeneratePrime(p, 128, 5, (const unsigned char*)"1", 1, my_rand);
|
|
bdPrintHex("prime p=\n", p,"\n");
|
|
bdGeneratePrime(q, 128, 5, (const unsigned char*)"abcdef", 6, my_rand);
|
|
bdPrintHex("prime q=\n", q,"\n");
|
|
|
|
/* Check primality with more tests (64 vs 5) */
|
|
/* NB vv small chance this could fail */
|
|
printf("Checking prime: p ");
|
|
res = bdIsPrime(p, 64);
|
|
printf("%s\n", (res ? "is OK" : "is NOT prime!!"));
|
|
/* And again using Fermat test */
|
|
res = fermat_test(p);
|
|
if (res == 0) printf("WARNING: p failed Fermat test.\n");
|
|
|
|
/* w = product pq */
|
|
bdMultiply(w, p, q);
|
|
bdPrintHex("pq=\n", w,"\n");
|
|
|
|
/* Product pq should not be prime */
|
|
res = bdIsPrime(w, 5);
|
|
printf("Composite pq %s\n", (res ? "IS prime" : "is NOT prime"));
|
|
assert(res == 0);
|
|
|
|
/* Check GCD: gcd(pq, p) == p */
|
|
bdGcd(r, w, p);
|
|
bdPrintHex("gcd(pq, p) =\n", r,"\n");
|
|
assert(bdIsEqual(r, p));
|
|
|
|
/* --Modular inversion-- */
|
|
printf("\nMODULAR INVERSION...\n");
|
|
/* set v to be a small random multiplier */
|
|
bdSetRandTest(v, 1);
|
|
bdIncrement(v); /* Make sure not zero */
|
|
bdPrintHex("multiplier, v=", v,"\n");
|
|
/* set u = vp - 1 */
|
|
bdMultiply(u, v, p);
|
|
bdDecrement(u);
|
|
bdPrintHex("p=\n", p,"\n");
|
|
bdPrintHex("u = vp - 1 =\n", u,"\n");
|
|
|
|
/* compute w = u^-1 mod p */
|
|
res = bdModInv(w, u, p);
|
|
bdPrintHex("w = u^-1 mod p=\n", w,"\n");
|
|
assert(res == 0);
|
|
|
|
/* check that wu mod p == 1 */
|
|
bdModMult(r, w, u, p);
|
|
bdPrintHex("wu mod p = ", r,"\n");
|
|
assert(bdShortCmp(r, 1) == 0);
|
|
|
|
/* Try mod inversion that should fail */
|
|
/* Set u = pq so that gcd(u, p) != 1 */
|
|
bdMultiply(u, p, q);
|
|
res = bdModInv(w, u, p);
|
|
printf("w = (pq)^-1 mod p returns (expected) error %d\n", res);
|
|
assert(res != 0);
|
|
bdPrintHex("output, w=", w,"\n");
|
|
|
|
/* Do some bit string operations */
|
|
printf("\nBIT STRING OPERATIONS...\n");
|
|
|
|
/* Use XOR to swop two variables without a temp variable, i.e.
|
|
a = a XOR b; b = a XOR b; a = a XOR b; */
|
|
printf("Swop u and w:\n");
|
|
/* Generate 2 random numbers (u,w) each 144 bits long */
|
|
bdRandomBits(u, 144);
|
|
bdRandomBits(w, 144);
|
|
bdPrintHex("u= ", u,"\n");
|
|
bdPrintHex("w= ", w,"\n");
|
|
/* remember these for later (p=u, q=w) */
|
|
bdSetEqual(p, u);
|
|
bdSetEqual(q, w);
|
|
/* Swop using XOR */
|
|
bdXorBits(u, u, w);
|
|
bdXorBits(w, u, w);
|
|
bdXorBits(u, u, w);
|
|
bdPrintHex("u'=", u,"\n");
|
|
bdPrintHex("w'=", w,"\n");
|
|
/* check they have swopped accurately */
|
|
assert(bdIsEqual(u, q));
|
|
assert(bdIsEqual(w, p));
|
|
|
|
/* Try some simple AND and OR ops */
|
|
printf("AND and OR ops:\n");
|
|
/* Set every even bit in u and every odd bit in v */
|
|
bdSetZero(u);
|
|
bdSetZero(v);
|
|
for (i = 0; i < 144 / 2; i++)
|
|
{
|
|
bdSetBit(u, (i * 2), 1);
|
|
bdSetBit(v, (i * 2) + 1, 1);
|
|
}
|
|
bdPrintHex("u= ", u,"\n");
|
|
bdPrintHex("v= ", v,"\n");
|
|
bdAndBits(w, u, v);
|
|
bdPrintHex("u AND v=", w,"\n");
|
|
/* expected answer = zero */
|
|
assert(bdIsZero(w));
|
|
bdOrBits(w, u, v);
|
|
bdPrintHex("u OR v= ", w,"\n");
|
|
/* expected answer p = 2^144 - 1 */
|
|
bdSetZero(p);
|
|
bdSetBit(p, 144, 1);
|
|
bdDecrement(p);
|
|
bdPrintHex("2^144-1=", p,"\n");
|
|
assert(bdIsEqual(p, w));
|
|
|
|
/* Invert all bits */
|
|
bdSetZero(p);
|
|
bdSetZero(q);
|
|
bdSetShort(p, 0xfffe);
|
|
bdShiftLeft(p, p, 32);
|
|
bdShortAdd(p, p, 0xfffe);
|
|
bdPrintHex("p= ", p,"\n");
|
|
bdNotBits(q, p);
|
|
bdPrintHex("NOT p=", q,"\n");
|
|
/* check p AND (NOT p) == 0 */
|
|
bdAndBits(w, p, q);
|
|
bdPrintHex("p AND (NOT p)=", w,"\n");
|
|
assert(bdIsZero(w));
|
|
|
|
/* Compose a 400-bit string by concatenating random 160-bit sections
|
|
and then truncating the result */
|
|
printf("\nBit string concatenation and truncation:\n");
|
|
/*
|
|
ALGORITHM: (based on a similar one in RFC 2631/ANSI X.42)
|
|
Set m' = m/160 where / represents integer division with rounding upwards
|
|
Set U = 0
|
|
For i = 0 to m' - 1
|
|
Set R = FUNC_160 and V = FUNC_160 where FUNC_160 generates a unique 160-bit value
|
|
U = U + (R XOR V) * 2^(160 * i)
|
|
Form q from U by computing U mod (2^m) and setting the most
|
|
significant bit (the 2^(m-1) bit) and the least significant bit to 1.
|
|
In terms of boolean operations, q = U OR 2^(m-1) OR 1.
|
|
Note that 2^(m-1) < q < 2^m
|
|
*/
|
|
/* In this example, m=400 and m'=3, and we just generate 160-bit random values */
|
|
mc = 3;
|
|
bdSetZero(u); /* Set U = 0 */
|
|
for (i = 0; i < mc; i++)
|
|
{
|
|
bdRandomBits(r, 160); /* R = FUNC_160 */
|
|
bdRandomBits(v, 160); /* V = FUNC_160 */
|
|
bdXorBits(p, r, v); /* p = (R XOR V) */
|
|
/* w = p * 2^160i, i.e. shift p left by 160i bits */
|
|
bdShiftLeft(w, p, (160 * i));
|
|
bdOrBits(u, u, w); /* q = q + w */
|
|
printf("w(%d)=", i);
|
|
bdPrintHex("", w,"\n");
|
|
}
|
|
bdPrintHex("u = w(0)+w(1)+w(2) =\n", u,"\n");
|
|
bdModPowerOf2(u, 400); /* U = U mod (2^m) */
|
|
bdPrintHex("u = u mod (2^m) = // `ModPowerOf2' \n", u,"\n");
|
|
/* q = U OR 2^(m-1) OR 1 */
|
|
bdSetEqual(q, u); /* q = U */
|
|
bdSetBit(q, 400-1, 1); /* q = q OR 2^(m-1) */
|
|
bdSetBit(q, 0, 1); /* q = q OR 1 */
|
|
bdPrintHex("q = u OR 2^(m-1) OR 1 =\n", q,"\n");
|
|
/* Check that 2^(m-1) < q < 2^m */
|
|
printf("BitLength(q)=%d\n", bdBitLength(q));
|
|
bdSetZero(p);
|
|
bdSetBit(p, 400-1, 1); /* p = 2^(m-1) */
|
|
assert(bdCompare(p, q) < 1); /* p < q */
|
|
bdSetZero(r);
|
|
bdSetBit(r, 400, 1); /* r = 2^m */
|
|
assert(bdCompare(q, r) < 1); /* q < r */
|
|
printf("OK, checked that 2^(m-1) < q < 2^m\n");
|
|
|
|
|
|
/* Create a new set for Modular exponentiation test */
|
|
printf("\nMODULAR EXPONENTIATION...\n");
|
|
n = bdNew();
|
|
e = bdNew();
|
|
m = bdNew();
|
|
c = bdNew();
|
|
z = bdNew();
|
|
mz = bdNew();
|
|
cz = bdNew();
|
|
t = bdNew();
|
|
|
|
/* n is a prime modulus */
|
|
printf("Generating a prime...\n");
|
|
bdGeneratePrime(n, 513, 5, NULL, 0, my_rand);
|
|
bdPrintHex("prime n=\n", n,"\n");
|
|
printf("bdBitLength(n)=%u bdSizeof(n)=%u\n", bdBitLength(n), bdSizeof(n));
|
|
/* Check primality using Fermat test (NB could fail!) */
|
|
res = fermat_test(n);
|
|
if (res == 0) printf("WARNING: n failed Fermat test (this can happen!).\n");
|
|
|
|
/* exponent e and base m are some random numbers < n */
|
|
bdSetRandTest(e, bdSizeof(n) - 1);
|
|
bdPrintHex("e=", e,"\n");
|
|
bdSetRandTest(m, bdSizeof(n) - 1);
|
|
bdPrintHex("random m=\n", m,"\n");
|
|
|
|
/* Compute c = m^e mod n */
|
|
bdModExp(c, m, e, n);
|
|
bdPrintHex("c = m^e mod n =\n", c,"\n");
|
|
|
|
/* Now use a random z and check that
|
|
c.z^e == (m.z)^e (mod n) */
|
|
bdSetRandTest(z, bdSizeof(n));
|
|
bdPrintHex("random z=\n", z,"\n");
|
|
|
|
/* Compute cz = c.z^e mod n (Note use of temp t) */
|
|
bdModExp(t, z, e, n);
|
|
bdModMult(cz, c, t, n);
|
|
bdPrintHex("c.z^e mod n=\n", cz,"\n");
|
|
/* Compute mz = (m.z)^e mod n */
|
|
bdModMult(t, m, z, n);
|
|
bdModExp(mz, t, e, n);
|
|
bdPrintHex("(m.z)^e mod n==\n", mz,"\n");
|
|
if (!bdIsEqual(mz, cz))
|
|
printf("ERROR: (c.z^e == (m.z)^e (mod n) DOES NOT MATCH m'\n");
|
|
else
|
|
printf("c.z^e == (m.z)^e (mod n) checks OK\n");
|
|
assert(bdIsEqual(mz, cz));
|
|
|
|
/* Repeat using constant-time exponentiation */
|
|
|
|
printf("Using constant-time exponentiation...\n");
|
|
/* Compute cz = c.z^e mod n (Note use of temp t) */
|
|
bdModExp_ct(t, z, e, n);
|
|
bdModMult(cz, c, t, n);
|
|
bdPrintHex("c.z^e mod n=\n", cz,"\n");
|
|
/* Compute mz = (m.z)^e mod n */
|
|
bdModMult(t, m, z, n);
|
|
bdModExp_ct(mz, t, e, n);
|
|
bdPrintHex("(m.z)^e mod n==\n", mz,"\n");
|
|
if (!bdIsEqual(mz, cz))
|
|
printf("ERROR: (c.z^e == (m.z)^e (mod n) DOES NOT MATCH m'\n");
|
|
else
|
|
printf("c.z^e == (m.z)^e (mod n) checks OK\n");
|
|
assert(bdIsEqual(mz, cz));
|
|
|
|
|
|
printf("\nCONVERSIONS WITH HEX AND DECIMAL...\n");
|
|
/* Do some conversions with hex and decimal strings */
|
|
bdSetZero(u);
|
|
bdConvFromHex(u, "DeadBeefCafeBabeBeddedDefacedDeafBeadFacade");
|
|
bdPrintHex("From Hex: ", u,"\n");
|
|
bdConvToHex(u, s, sizeof(s));
|
|
printf("To Hex: %s\n", s);
|
|
bdConvFromDecimal(u, "1234567890123456789012345678901234567890");
|
|
bdPrintHex("From Decimal: ", u,"\n");
|
|
bdConvToDecimal(u, s, sizeof(s));
|
|
printf("To Decimal: %s\n", s);
|
|
cmp = strcmp(s, "1234567890123456789012345678901234567890");
|
|
assert(cmp == 0);
|
|
|
|
/* 987654321 x 81 = 80000000001 */
|
|
bdConvFromDecimal(u, "987654321");
|
|
bdShortMult(v, u, 81);
|
|
bdConvToDecimal(v, s, sizeof(s));
|
|
printf("987654321 x 81 = %s\n", s);
|
|
cmp = strcmp(s, "80000000001");
|
|
assert(cmp == 0);
|
|
|
|
/* 123456789 x 9 + 10 = 1111111111 */
|
|
bdConvFromDecimal(u, "123456789");
|
|
bdShortMult(v, u, 9);
|
|
bdShortAdd(w, v, 10);
|
|
bdConvToDecimal(w, s, sizeof(s));
|
|
printf("123456789 x 9 + 10 = %s\n", s);
|
|
cmp = strcmp(s, "1111111111");
|
|
assert(cmp == 0);
|
|
|
|
/* Convert an empty decimal string to a BIGD */
|
|
bdSetShort(u, 0xfdfdfdfd);
|
|
bdConvFromDecimal(u, "");
|
|
bdPrintHex("bdConvFromDecimal(u, '')=", u,"\n");
|
|
assert(bdIsZero(u));
|
|
/* ditto an empty hex string */
|
|
bdSetShort(u, 0xfdfdfdfd);
|
|
bdConvFromHex(u, "");
|
|
bdPrintHex("bdConvFromHex(u, '')=", u,"\n");
|
|
assert(bdIsZero(u));
|
|
/* Convert zero BIGD value to a decimal string */
|
|
bdSetZero(u);
|
|
bdConvToDecimal(u, s, sizeof(s));
|
|
printf("Decimal zero = '%s'\n", s);
|
|
cmp = strcmp(s, "0");
|
|
assert(cmp == 0);
|
|
/* ditto to a hex string */
|
|
bdConvToHex(u, s, sizeof(s));
|
|
printf("Hex zero = '%s'\n", s);
|
|
cmp = strcmp(s, "0");
|
|
assert(cmp == 0);
|
|
/* Convert a zero BIGD to an array of octets */
|
|
memset(bytes, 0xdf, sizeof(bytes));
|
|
bdSetZero(u);
|
|
nbytes = bdConvToOctets(u, bytes, sizeof(bytes));
|
|
printf("bdConvToOctets returns %d: ", nbytes);
|
|
/* show that all bytes are zero */
|
|
pr_bytesmsg("", bytes, sizeof(bytes));
|
|
assert(0 == bytes[sizeof(bytes)-1] && 0 == bytes[0]);
|
|
/* Convert an zero-length array of octets to a BIGD */
|
|
bdSetShort(u, 0xfdfdfdfd);
|
|
bdConvFromOctets(u, bytes, 0);
|
|
bdPrintHex("bdConvFromOctets(nbytes=0)=", u,"\n");
|
|
assert(bdIsZero(u));
|
|
|
|
bdFree(&n);
|
|
printf("\nJACOBI AND LEGENDRE SYMBOLS...\n");
|
|
/* Try computing some Jacobi and Legendre symbol values */
|
|
a = bdNew();
|
|
n = bdNew();
|
|
bdSetShort(a, 158);
|
|
bdSetShort(n, 235);
|
|
jac = bdJacobi(a, n);
|
|
printf("Jacobi(158, 235)=%d\n", jac);
|
|
assert(-1 == jac);
|
|
bdSetShort(a, 2183);
|
|
bdSetShort(n, 9907);
|
|
jac = bdJacobi(a, n);
|
|
printf("Jacobi(2183, 9907)=%d\n", jac);
|
|
assert(1 == jac);
|
|
bdSetShort(a, 1001);
|
|
jac = bdJacobi(a, n);
|
|
printf("Jacobi(1001, 9907)=%d\n", jac);
|
|
assert(-1 == jac);
|
|
bdShortMult(a, n, 10000);
|
|
jac = bdJacobi(a, n);
|
|
printf("Jacobi(10000 * 9907, 9907)=%d\n", jac);
|
|
assert(0 == jac);
|
|
|
|
printf("\nSQUARE AND SQUARE ROOT...\n");
|
|
/* Square a random number w = u^2 */
|
|
bdSetRandTest(u, 10);
|
|
bdPrintHex("random u=\n", u, "\n");
|
|
bdSquare(w, u);
|
|
bdPrintHex("(Square) u^2=", w, "\n");
|
|
/* check against product p = u * u */
|
|
bdMultiply(p, u, u);
|
|
bdPrintHex("u*u=", p, "\n");
|
|
assert(bdIsEqual(p, w));
|
|
/* and check against power function */
|
|
bdPower(p, u, 2);
|
|
bdPrintHex("u power 2=", p, "\n");
|
|
assert(bdIsEqual(p, w));
|
|
/* Compute integer square root [new in v2.1] */
|
|
bdSqrt(p, w);
|
|
bdPrintHex("sqrt(u^2)=", p, "\n");
|
|
assert(bdIsEqual(p, u));
|
|
/* Now test sqrt(u^2 - 1) */
|
|
bdDecrement(w);
|
|
bdPrintHex("u^2-1=", w, "\n");
|
|
bdSqrt(r, w);
|
|
bdPrintHex("sqrt(u^2-1)=", r, "\n");
|
|
/* Check difference is 1 */
|
|
bdSubtract(q, p, r);
|
|
bdPrintHex("difference=", q, " (expected 1)\n");
|
|
assert(bdShortCmp(q, 1) == 0);
|
|
|
|
printf("\nCUBE AND CUBE ROOT...\n");
|
|
/* Cube a random number w = u^2 */
|
|
bdPrintHex("u=", u, "\n");
|
|
bdSquare(v, u);
|
|
bdMultiply(w, v, u);
|
|
bdPrintHex("(Cube) u^3=", w, "\n");
|
|
/* Check that power function works */
|
|
bdPower(v, u, 0);
|
|
bdPrintHex("u^0=", v, "\n");
|
|
bdPower(v, u, 1);
|
|
bdPrintHex("u^1=", v, "\n");
|
|
bdPower(v, u, 3);
|
|
bdPrintHex("(Power) u^3=", v, "\n");
|
|
assert(bdIsEqual(v, w));
|
|
/* Compute integer cube root (new in [v2.3]) */
|
|
bdCubeRoot(p, w);
|
|
bdPrintHex("cuberoot(u^3)=", p, "\n");
|
|
assert(bdIsEqual(p, u));
|
|
/* Now test cuberoot(u^2 - 1) */
|
|
bdDecrement(w);
|
|
bdPrintHex("u^3-1=", w, "\n");
|
|
bdCubeRoot(r, w);
|
|
bdPrintHex("cuberoot(u^3-1)=", r, "\n");
|
|
/* Check difference is 1 */
|
|
bdSubtract(q, p, r);
|
|
bdPrintHex("difference=", q, " (expected 1)\n");
|
|
assert(bdShortCmp(q, 1) == 0);
|
|
|
|
printf("\nQUICK-AND-DIRTY RANDOM NUMBERS (bitlen <= nbits)...\n");
|
|
for (i = 0; i < 5; i++)
|
|
{
|
|
int nbits = 128 + i;
|
|
bdQuickRandBits(a, nbits);
|
|
printf("q-rand(%d)=", nbits);
|
|
bdPrintHex("", a, "");
|
|
printf("\t%d bits\n", bdBitLength(a));
|
|
}
|
|
|
|
printf("\nPRINT BITS...\n");
|
|
bdSetShort(u, 0xdeadbeef);
|
|
bdPrintHex("u=0x", u, " => ");
|
|
bdPrintBits("'", u, "'b\n");
|
|
printf("(correct)= %s\n", "11011110101011011011111011101111");
|
|
bdSetShort(u, 0);
|
|
bdPrintHex("u=0x", u, " => ");
|
|
bdPrintBits("'", u, "'b\n");
|
|
bdSetShort(u, 1);
|
|
bdPrintHex("u=0x", u, " => ");
|
|
bdPrintBits("'", u, "'b\n");
|
|
|
|
printf("\nMODULAR SQUARE ROOT...\n");
|
|
printf("Select a 192-bit prime number...\n");
|
|
bdConvFromHex(p, "fffffffffffffffffffffffffffffffeffffffffffffffff");
|
|
bdPrintHex("p=0x", p, "\n");
|
|
bdPrintDecimal("p=", p, "\n");
|
|
res = bdIsPrime(p, 50);
|
|
printf("bdIsPrime(p)=%d\n", res);
|
|
assert(r != 0);
|
|
nbits = bdBitLength(p);
|
|
printf("p is %d bits\n", nbits);
|
|
// Pick a number just smaller than p
|
|
bdQuickRandBits(u, nbits - 1);
|
|
bdPrintDecimal("u= ", u, "\n");
|
|
// Square it
|
|
bdModSquare(w, u, p);
|
|
bdPrintDecimal("w=u^2(mod p)= ", w, "\n");
|
|
/* Check we have a quadratic residue */
|
|
jac = bdJacobi(w, p);
|
|
printf("Legendre symbol (w|p)=%d (expected 1)\n", jac);
|
|
assert(jac == 1);
|
|
/* Compute one modular square root */
|
|
bdModSqrt(x, w, p);
|
|
bdPrintDecimal("x=sqrt(w)(mod p)=", x, "\n");
|
|
/* and the other */
|
|
bdSubtract(y, p, x);
|
|
bdPrintDecimal("other root y=p-x=", y, "\n");
|
|
assert(bdIsEqual(x, u) || bdIsEqual(y, u));
|
|
if (bdIsEqual(x, u)) {
|
|
printf("u == x => OK\n");
|
|
}
|
|
else {
|
|
printf("u == p-x => OK\n");
|
|
}
|
|
|
|
printf("\nFind a number that is not a quadratic residue mod p...\n");
|
|
do {
|
|
bdQuickRandBits(v, nbits - 1);
|
|
} while (bdJacobi(v, p) != -1);
|
|
bdPrintDecimal("v=", v, "\n");
|
|
printf("Legendre symbol (v|p)=%d (expected -1)\n", bdJacobi(v, p));
|
|
res = bdModSqrt(x, v, p);
|
|
printf("bdModSqrt(v) returns %d (-1 => square root does not exist)\n", res);
|
|
assert(res != 0);
|
|
|
|
printf("\nADD AND SUBTRACT MODULO M ...\n");
|
|
/* Add two random numbers w = u + v mod p */
|
|
bdQuickRandBits(u, nbits - 1);
|
|
bdQuickRandBits(v, nbits - 1);
|
|
bdPrintDecimal("u= ", u, "\n");
|
|
bdPrintDecimal("v= ", v, "\n");
|
|
bdModAdd(w, u, v, p);
|
|
bdPrintDecimal("w=u+v(mod p)=", w, "\n");
|
|
|
|
/* y = w - v */
|
|
bdModSub(y, w, v, p);
|
|
bdPrintDecimal("y=w-v(mod p)=", y, "\n");
|
|
/* Check y == u */
|
|
printf("y == u => %s\n", (bdIsEqual(y, u) ? "OK" : "ERROR"));
|
|
assert(bdIsEqual(y, u));
|
|
|
|
printf("\nDivide an integer by 2 modulo p using bdModHalve()...\n");
|
|
bdSetEqual(w, u);
|
|
bdPrintDecimal("w= ", u, "\n");
|
|
bdModHalve(w, w, p);
|
|
bdPrintDecimal("w=w/2(mod p)=", w, "\n");
|
|
// Check result
|
|
bdModAdd(v, w, w, p);
|
|
bdPrintDecimal("v=w+w(mod p)=", v, "\n");
|
|
printf("v == u => %s\n", (bdIsEqual(v, u) ? "OK" : "ERROR"));
|
|
assert(bdIsEqual(v, u));
|
|
|
|
|
|
/* Finally, show the current version number */
|
|
printf("\nVERSION=%d\n", bdVersion());
|
|
printf("Compiled on [%s]\n", bdCompileTime());
|
|
|
|
|
|
/* Clear up */
|
|
|
|
bdFree(&a);
|
|
bdFree(&n);
|
|
bdFree(&e);
|
|
bdFree(&m);
|
|
bdFree(&c);
|
|
bdFree(&z);
|
|
bdFree(&mz);
|
|
bdFree(&cz);
|
|
bdFree(&t);
|
|
|
|
|
|
/* Old method... */
|
|
//bdFree(&u);
|
|
//bdFree(&v);
|
|
//bdFree(&w);
|
|
//bdFree(&q);
|
|
//bdFree(&r);
|
|
//bdFree(&p);
|
|
//bdFree(&x);
|
|
//bdFree(&y);
|
|
|
|
/* New way in [v2.6] */
|
|
bdFreeVars(&u, &v, &w, &p, &q, &r, &x, &y);
|
|
printf("OK, successfully completed tests.\n");
|
|
|
|
return 0;
|
|
}
|
|
|