/* $Id: t_mpTest.c $ */ /* Some tests of the BigDigits "mp" functions. Not exhaustive. */ /***** 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 * . All rights reserved. * ***** END LICENSE BLOCK *****/ /* * Last updated: * $Date: 2016-03-31 09:51:00 $ * $Revision: 2.6.1 $ * $Author: dai $ */ #ifdef NDEBUG #undef NDEBUG #endif #include #include #include "bigdigits.h" #include "bigdigitsRand.h" #define TEST_LEN 32 static int debug = 1; DIGIT_T u[TEST_LEN]; DIGIT_T v[TEST_LEN]; DIGIT_T w[TEST_LEN]; DIGIT_T q[TEST_LEN]; DIGIT_T r[TEST_LEN]; DIGIT_T p1[TEST_LEN]; DIGIT_T p2[TEST_LEN]; DIGIT_T p3[TEST_LEN]; DIGIT_T g[TEST_LEN]; DIGIT_T a[TEST_LEN]; DIGIT_T n[TEST_LEN]; void ClearAll(void) { mpSetZero(u, TEST_LEN); mpSetZero(v, TEST_LEN); mpSetZero(w, TEST_LEN); mpSetZero(q, TEST_LEN); mpSetZero(r, TEST_LEN); mpSetZero(g, TEST_LEN); mpSetZero(p1, TEST_LEN); mpSetZero(p2, TEST_LEN); mpSetZero(p3, TEST_LEN); mpSetZero(a, TEST_LEN); mpSetZero(n, TEST_LEN); } static int MakeMultiplePrime(DIGIT_T p[], size_t ndigits) { /* Returns a random prime number of ndigits */ /* WARNING: This is not cryptographically secure because the random number generator isn't */ size_t i; for (i = 0; i < ndigits; i++) p[i] = spBetterRand(); /* Make sure the highest and low bits are set */ p[ndigits - 1] |= HIBITMASK; p[0] |= 0x1; //printf("p="); mpPrintNL(p, ndigits); /* Check if prime */ while (!mpIsPrime(p, ndigits, 10)) { /* Keep adding 2 until find a prime */ mpShortAdd(p, p, 2, ndigits); //printf("p="); mpPrintNL(p, ndigits); printf("."); /* Check for overflow */ if (!(p[ndigits - 1] & HIBITMASK)) return -1; /* Failed to find a prime */ } return 0; } size_t MakeMultipleRandom(DIGIT_T a[], size_t ndigits) { /* Make a random number of up to ndigits digits */ size_t i, n, bits; DIGIT_T mask; n = (size_t)spSimpleRand(1, ndigits); for (i = 0; i < n; i++) a[i] = spBetterRand(); for (i = n; i < ndigits; i++) a[i] = 0; /* Zero out a random number of bits in leading digit about half the time */ bits = (size_t)spSimpleRand(0, 2*BITS_PER_DIGIT); if (bits != 0 && bits < BITS_PER_DIGIT) { mask = HIBITMASK; for (i = 1; i < bits; i++) { mask |= (mask >> 1); } mask = ~mask; a[n-1] &= mask; } return n; } void ShowAdd(DIGIT_T w[], DIGIT_T u[], DIGIT_T v[], DIGIT_T carry, size_t ndigits) { mpPrintHex("mpAdd: ", u, ndigits, " + "); mpPrintHex("", v, ndigits, " = "); mpPrintHex("", w, ndigits, ", "); printf("carry = %" PRIxBIGD "\n", carry); } void ShowMult(DIGIT_T w[], DIGIT_T u[], DIGIT_T v[], size_t ndigits) { mpPrintHex("mpMultiply: ", u, ndigits, " x "); mpPrintHex("", v, ndigits, " = "); mpPrintHex("", w, ndigits*2, "\n"); } void ShowDiv(DIGIT_T q[], DIGIT_T r[], DIGIT_T u[], DIGIT_T v[], size_t ndigits) { mpPrintHex("mpDivide: ", u, ndigits, " / "); mpPrintHex("", v, ndigits, " = "); mpPrintHex("", q, ndigits, " "); mpPrintHex("rem ", r, ndigits, "\n"); } int main(void) { DIGIT_T carry, m; int jac; size_t len; size_t NDIGITS; /* Force linker to include copyright notice in executable object image */ copyright_notice(); ClearAll(); printf("Testing BIGDIGITS 'mp' functions.\n"); /* Start easy: 1 + 1 = 2 */ mpSetDigit(u, 1, TEST_LEN); /* u = 1 */ carry = mpAdd(w, u, u, TEST_LEN); /* w = u + u */ ShowAdd(w, u, u, carry, TEST_LEN); /* Check that w == 2 */ assert(mpShortCmp(w, 2, TEST_LEN) == 0); /* ---- Add and subtract ---- */ /* Add two random numbers w = u + v */ MakeMultipleRandom(u, TEST_LEN-1); MakeMultipleRandom(v, TEST_LEN-1); carry = mpAdd(w, u, v, TEST_LEN); /* r = w - v */ carry = mpSubtract(r, w, v, TEST_LEN); /* Check r == u */ assert(mpEqual(r, u, TEST_LEN)); printf("Add and subtract worked OK\n"); ClearAll(); /* ---- Multiply and divide ---- */ /* Multiply two random numbers w = u * v */ MakeMultipleRandom(u, TEST_LEN / 2); MakeMultipleRandom(v, TEST_LEN / 2); mpMultiply(w, u, v, TEST_LEN / 2); if (debug) ShowMult(w, u, v, TEST_LEN / 2); /* q = w / v, r = w % v */ mpDivide(q, r, w, TEST_LEN, v, TEST_LEN / 2); /* Check q == u and r == 0 */ if (debug) mpPrintHex("q=", q, TEST_LEN / 2, "\n"); assert(mpEqual(q, u, TEST_LEN / 2)); assert(mpIsZero(r, TEST_LEN / 2)); ClearAll(); mpSetDigit(a, 0, TEST_LEN); mpSetZero(n, TEST_LEN); assert(mpEqual(a, n, TEST_LEN)); ClearAll(); /* Pick two random numbers u, v */ MakeMultipleRandom(u, TEST_LEN/2); MakeMultipleRandom(v, TEST_LEN/2); /* Divide one by the other: q = u / v, r = u % v */ mpDivide(q, r, u, TEST_LEN/2, v, TEST_LEN/2); if (debug) ShowDiv(q, r, u, v, TEST_LEN/2); /* Check w = q * v + r == u */ mpMultiply(g, q, v, TEST_LEN/2); mpAdd(w, g, r, TEST_LEN/2); assert(mpEqual(w, u, TEST_LEN/2)); printf("Multiply and divide worked OK\n"); /* ---- Greatest Common Divisor ---- */ /* Pick 3x random primes p1, p2, p3 */ printf("Creating 3 prime numbers (be patient):\n"); MakeMultiplePrime(p1, TEST_LEN / 2); printf("(1)\n"); MakeMultiplePrime(p2, TEST_LEN / 2); printf("(2)\n"); MakeMultiplePrime(p3, TEST_LEN / 2); printf("(3)\n"); /* Calculate two products from these primes */ /* u = p1 * p2 */ mpMultiply(u, p1, p2, TEST_LEN / 2); /* v = p1 * p3 */ mpMultiply(v, p1, p3, TEST_LEN / 2); /* Now calculate g = gcd(u, v) */ mpGcd(g, u, v, TEST_LEN); /* And check that g == p1 */ assert(mpEqual(g, p1, TEST_LEN)); printf("Greatest Common Divisor worked OK\n"); /* ---- Modular Inverse ---- */ /* Use previous prime as modulus, v */ mpSetEqual(v, p1, TEST_LEN); /* Pick a small multiplier, m */ m = spSimpleRand(1, MAX_DIGIT); /* Set u = (vm - 1) */ mpShortMult(u, v, m, TEST_LEN); mpShortSub(u, u, 1, TEST_LEN); mpModInv(w, u, v, TEST_LEN); /* Check that g = (w * u) mod v = 1 */ mpModMult(g, w, u, v, TEST_LEN); assert((mpShortCmp(g, 1, TEST_LEN) == 0)); printf("Modular inverse worked OK\n"); /* Compute some Jacobi and Legendre symbol values */ mpSetDigit(a, 158, TEST_LEN); mpSetDigit(n, 235, TEST_LEN); jac = mpJacobi(a, n, TEST_LEN); //printf("Jacobi(158, 235)=%d\n", jac); assert(-1 == jac); mpSetDigit(a, 2183, TEST_LEN); mpSetDigit(n, 9907, TEST_LEN); jac = mpJacobi(a, n, TEST_LEN); //printf("Jacobi(2183, 9907)=%d\n", jac); assert(1 == jac); mpSetDigit(a, 1001, TEST_LEN); jac = mpJacobi(a, n, TEST_LEN); //printf("Jacobi(1001, 9907)=%d\n", jac); assert(-1 == jac); mpShortMult(a, n, 10000, TEST_LEN); jac = mpJacobi(a, n, TEST_LEN); //printf("Jacobi(10000 * 9907, 9907)=%d\n", jac); assert(0 == jac); printf("Jacobi symbol tests worked OK\n"); /* ---- Square, square root and cube root ---- */ printf("\nSquare roots, etc...\n"); /* Pick a random number u */ MakeMultipleRandom(u, TEST_LEN/2); mpPrintHex("u=", u, TEST_LEN/2, "\n"); /* Compute square */ mpSquare(v, u, TEST_LEN/2); mpPrintHex("u^2=", v, TEST_LEN, "\n"); /* Compute square root */ mpSqrt(r, v, TEST_LEN); mpPrintHex("sqrt(u^2)=", r, TEST_LEN, "\n"); /* Now compute square root of v - 1 */ mpShortSub(v, v, 1, TEST_LEN); mpSqrt(w, v, TEST_LEN); mpPrintHex("sqrt(u^2-1)=", w, TEST_LEN, "\n"); /* This should be one less than before */ mpSubtract(g, r, w, TEST_LEN); mpPrintHex("difference=", g, TEST_LEN, " (expecting 1)\n"); assert(mpShortCmp(g, 1, TEST_LEN) == 0); /* Compute cube */ ClearAll(); /* Pick another random number u */ len = TEST_LEN/4; MakeMultipleRandom(u, len); mpPrintHex("u=", u, len, "\n"); /* Compute cube (NB we use LEN/4 to avoid overflow on 2nd multiplication) */ mpSquare(w, u, len); len = 2 * len; mpMultiply(v, w, u, len); mpPrintHex("u^3=", v, TEST_LEN, "\n"); /* Compute cube root */ mpCubeRoot(r, v, TEST_LEN); mpPrintHex("cuberoot(u^3)=", r, TEST_LEN, "\n"); assert(mpCompare(r, u, TEST_LEN) == 0); /* Now compute cube root of v - 1 */ mpShortSub(v, v, 1, TEST_LEN); mpCubeRoot(w, v, TEST_LEN); mpPrintHex("cuberoot(u^3-1)=", w, TEST_LEN, "\n"); /* This should be one less than before */ mpSubtract(g, r, w, TEST_LEN); mpPrintHex("difference=", g, TEST_LEN, " (expecting 1)\n"); assert(mpShortCmp(g, 1, TEST_LEN) == 0); printf("Testing signed arithmetic...\n"); NDIGITS = 4; mpSetDigit(u, 2, NDIGITS); mpSetDigit(v, 5, NDIGITS); mpSubtract(w, u, v, NDIGITS); mpPrintDecimalSigned("signed w=", w, NDIGITS, "\n"); mpPrintHex("unsigned w=0x", w, NDIGITS, "\n"); /* Display version number */ printf("\nVersion=%d\n", mpVersion()); /* For further checks do RSA calculation - see t_mpRSA.c */ printf("OK, successfully completed tests.\n"); return 0; }