/* $Id: t_dibigdBasic.cpp $ */
/*
* Copyright (C) 2026 David Ireland, D.I. Management Services Pty Limited
* <https://di-mgt.com.au/contact/> <https://di-mgt.com.au/bigdigits.html>
* SPDX-License-Identifier: MPL-2.0
*
* Last updated:
* $Date: 2026-05-05 02:02 $
* $Revision: 1.0.1 $
* $Author: dai $
*/
/* Some basic tests using dibigd C++ OOP interface to BigDigits. */
#ifdef NDEBUG
#undef NDEBUG
#endif
#include <iostream>
#include <stdexcept>
#include <typeinfo>
#include <assert.h>
#include <time.h>
#include "dibigd.hpp"
using std::cout;
using std::endl;
using namespace dibigd;
/* TESTS */
void test_version_info() {
cout << "CompileTime=[" << dibigd::compile_time() << "]" << endl;
cout << "This C++ interface version is " << dibigd::version_interface() << endl;
cout << "using BigDigits core version " << dibigd::version_core() << endl;
}
void test_arithmetic() {
cout << endl << "Testing arithmetic..." << endl;
bool f;
// Assign two BigDigit objects
BigDigit bd1(666);
bd1.print("bd1=");
BigDigit bd2(333);
bd2.print("bd2=");
// Add them
BigDigit sum;
sum = bd1 + bd2;
sum.print("sum=");
// Copy a BigDigit object
BigDigit bd3;
bd3 = bd1;
bd3.print();
cout << "bd3 is " << bd3.to_str() << endl;
// Add an integer (maybe negative)
bd3 = bd3 + 5;
bd3.print("bd3+5=");
bd3 = -5 + bd3;
bd3.print("-5+bd3=");
bd3 = bd3 - 5;
bd3.print("bd3-5=");
sum = bd1 + bd2 + bd3;
sum.print("sum=");
bd3 = 0x1000;
bd3.print("bd3=");
bd3 = 1 << 24;
bd3.print("bd3=");
cout << "bd3 in hex is " << bd3.to_strhex() << endl;
BigDigit product = bd1 * bd2;
product.print("product=");
bd1 = 10;
bd1.print("bd1=");
sum = bd1 - 4;
sum.print("bd1-4=");
sum = bd1 - -4;
sum.print("bd1--4=");
sum = 21 - bd1;
sum.print("21-bd1=");
BigDigit a = 0x10000;
BigDigit b = 0x100;
sum = a / b;
sum.print("a/b=");
a.print("a=");
b.print("b=");
a += b;
a.print("a+=b=");
a += 10;
a.print("a+=b=");
a += 0;
a.print("a+=0=");
/* Test multiply equal and divide equal */
a = 0x1000;
b = 0x100;
a.print("a=");
b.print("b=");
a *= b;
a.print("a*=b=");
a *= b;
a.print("a*=b=");
a /= b;
a.print("a/=b=");
// Increment prefix and postfix
a.print("a=");
b = ++a;
a.print("++a=");
b.print("++a returns ");
b = a++;
a.print("a++=");
b.print("a++ returns ");
a.print("Before decrement a=");
b = --a;
a.print("--a=");
b.print("--a returns ");
b = a--;
a.print("a--=");
b.print("a-- returns ");
// Equality operator
f = (a == b);
cout << std::boolalpha << "a==b returns " << f << endl;
f = (a == a);
cout << std::boolalpha << "a==a returns " << f << endl;
a = 666;
f = (a == 666);
cout << std::boolalpha << "a==666 returns " << f << endl;
f = (666 == a);
cout << std::boolalpha << "666==a returns " << f << endl;
// Constant-time comparisons
cout << "Constant-time comparisons..." << endl;
a = 1000;
b = 999;
a.print("a="); b.print("b=");
int cmp;
cmp = a.cmp_ct(b);
cout << "a.cmp_ct(b) returns " << std::showpos << cmp << endl;
assert(cmp > 0);
cmp = b.cmp_ct(a);
cout << "b.cmp_ct(a) returns " << std::showpos << cmp << endl;
assert(cmp < 0);
cmp = a.cmp_ct(1000);
cout << "a.cmp_ct(1000) returns " << std::showpos << cmp << endl;
assert(cmp == 0);
BigDigit Z; // Set as zero
cmp = Z.cmp_ct(0);
cout << "Z.cmp_ct(0) returns " << std::showpos << cmp << endl;
assert(cmp == 0);
// Overflow digit boundary
a = 0xffffffff;
b = 0xffffffff;
a.printhex("a=");
b.printhex("b=");
sum = a + b;
sum.printhex("a+b="); // 0x1fffffffe
// Modulo operator
a = 101;
b = a % 9;
cout << a.to_str();
b.print(" % 9=");
a %= 9;
a.print("a %= 9=");
a = 0x10000001;
cout << a.to_str() << " is " << (a.is_even() ? "even" : "odd") << endl;
cout << a.to_str() << " is " << (a.is_odd() ? "odd" : "even") << endl;
a--;
cout << a.to_str() << " is " << (a.is_even() ? "even" : "odd") << endl;
cout << a.to_str() << " is " << (a.is_odd() ? "odd" : "even") << endl;
}
void test_mod_arithmetic() {
BigDigit u, v, w, m, x, y, p, q, r, g;
int jac;
size_t nbits;
cout << endl << "Test modular arithmetic..." << endl;
// Generate two random primes
cout << "Generate two random primes..." << endl;
p.set_prime(128);
q.set_prime(128);
p.printhex("p=");
q.printhex("q=");
// Check primality
cout << "p is " << (p.is_prime() ? "prime (OK)" : "NOT PRIME") << endl;
cout << "q is " << (q.is_prime() ? "prime (OK)" : "NOT PRIME") << endl;
// w = product pq
w = p * q;
w.printhex("pq=");
// Product pq should not be prime
cout << "pq is " << (w.is_prime() ? "prime" : "NOT PRIME (OK)") << endl;
assert(!w.is_prime());
// Check GCD: gcd(pq, p) == p
g = w.gcd(p);
g.printhex("gcd(pq,p)=");
assert(g == p);
// Alt way to call gcd()
g = BigDigit::gcd(w, p);
g.printhex("gcd(pq,p)=");
assert(g == p);
cout << "If p,q,r are distinct primes, then the gcd of u=pq and v=pr is p." << endl;
p.set_prime(128);
q.set_prime(128);
r.set_prime(128);
p.printhex("p="); q.printhex("q="); r.printhex("r=");
u = p * q;
v = p * r;
u.printhex("u=pq="); v.printhex("v=pr=");
g = BigDigit::gcd(u, v);
g.printhex("gcd(u,v)=");
assert(g == p);
v = 0;
cout << endl << "MODULAR INVERSION..." << endl;
cout << "If p is a prime, and u=pm-1 for some integer m, then w, the inverse of u modulo p, equals p-1 and wu mod p equals one." << endl;
p.printhex("p=");
// set m to be a small random multiplier
m.set_rand_number(0xffff);
m.printhex("multiplier, m=");
// Set u = pm - 1
u = m * p - 1;
u.printhex("u = pm-1 =");
// compute w = u^-1 mod p
w = u.mod_inv(p);
w.printhex("w = u^-1 mod p=");
// check that wu mod p == 1
x = w.mod_mult(u, p);
x.print("wu mod p=");
assert(x == 1); // Expecting 1
cout << "Try mod inversion that should fail (expected result == 0)..." << endl;
// Set u = pq so that gcd(u, p) != 1
u = p * q;
w = u.mod_inv(p);
w.print("(pq)^-1(mod p)=");
assert(w == 0);
cout << "Add and subtract modulo m..." << endl;
// mod_sub catches the case where v > u and returns u + p - v
u = 6;
v = 7;
m = 10;
cout << "u=" << u.to_str() << ", v=" << v.to_str() << ", m=" << m.to_str() << endl;
w = u.mod_sub(v, m);
w.print("w=u-v(mod m)=");
w = w.mod_add(v, m);
w.print("w=w+v(mod m)=");
assert(w == u);
// Select a 192-bit prime number
p = "0xfffffffffffffffffffffffffffffffeffffffffffffffff";
p.printhex("p=");
assert(p.is_prime());
nbits = p.bitlen();
cout << "p is " << nbits << " bits and is " << (p.is_prime() ? "prime" : "not prime") << endl;
// Pick two numbers just smaller than p with v > u
u.set_rand_bits(nbits - 2);
v.set_rand_bits(nbits - 1);
cout << "v > u is " << std::boolalpha << (v > u) << endl;
u.printhex("u=");
v.printhex("v=");
w = u.mod_add(v, p);
w.printhex("w=u+v(mod p)=");
// Subtract with borrow u - v < 0
w = u.mod_sub(v, p);
w.printhex("w=u-v(mod p)=");
// Check: add back v modulo p
w = w.mod_add(v, p);
w.printhex("w=w+v(mod p)=");
assert(w == u);
v <<= 8; // Set v' to be greater than p
v.printhex("v'=");
cout << "v' is " << (v > p ? "greater" : "less") << " than p" << endl;
w = u.mod_add(v, p);
w.printhex("w=u+v(mod p)=");
w = u.mod_sub(v, p);
w.printhex("w=u-v(mod p)=");
// Check: add back v modulo p
w = w.mod_add(v, p);
w.printhex("w=w+v(mod p)=");
cout << "w is " << (w == u ? "equal to u (OK)" : "NOT equal to u (NBG!!)") << endl;
assert(w == u);
// Test mod_sqrt
cout << "MODULAR SQUARE ROOT..." << endl;
u.printhex("u=");
// Set w = u * u (mod p)
w = u.mod_square(p);
w.printhex("w = u^2(mod p) = ");
/* Check we have a quadratic residue */
jac = w.jacobi(p);
cout << "Legendre symbol (w|p)=" << jac << " (expected 1)" << endl;
/* Compute one modular square root */
x = w.mod_sqrt(p);
x.printhex("x=sqrt(w)(mod p)=");
/* and the other */
y = p - x;
y.printhex("other root y=p-x=");
assert((x == u) || (y == u));
((x*x)%p).printhex("x*x%p=");
((y*y) % p).printhex("y*y%p=");
cout << endl << "Find a number that is not a quadratic residue mod p..." << endl;
do {
v.set_rand_bits(nbits);
} while (v.jacobi(p) != -1);
v.printhex("v=");
cout << "Legendre symbol (v|p)=" << v.jacobi(p) << " (expected -1)" << endl;
x = v.mod_sqrt(p);
x.printhex("v.mod_sqrt(p) returns ");
cout << "(0 ==> square root does not exist)" << endl;
assert(x == 0);
cout << "ADD AND SUBTRACT MODULO M ..." << endl;
p.printhex("p=");
/* Add two random numbers w = u + v mod p */
u.set_rand_bits(nbits - 1);
v.set_rand_bits(nbits - 1);
u.printhex("u=");
v.printhex("v=");
// w = u + v (mod p)
w = u.mod_add(v, p);
w.printhex("w=u+v(mod p)=");
// y = w - v (mod p)
y = w.mod_sub(v, p);
y.printhex("y=w-v(mod p)=");
// Check y == u
assert(y == u);
cout << "Divide an integer by 2 modulo p using mod_halve()..." << endl;
u.printhex("u=");
w = u.mod_halve(p);
w.printhex("w=u/2(mod p)=");
// Check result
v = w.mod_add(w, p);
v.printhex("v=w+w(mod p)=");
assert(u == v);
}
void test_exceptions() {
cout << endl << "Test exceptions..." << endl;
// cope with negative result
BigDigit a(2);
BigDigit b(5);
try {
cout << "About to compute a negative number..." << endl;
BigDigit sum = a - b; // A negative result
sum.print("sum=");
}
catch (const std::runtime_error& e) {
std::cerr << typeid(e).name() << ": " << e.what() << std::endl;
}
// divide by zero
BigDigit Z;
try {
cout << "About to divide by zero..." << endl;
BigDigit quotient = a / Z;
quotient.print("quotient=");
}
catch (const std::runtime_error& e) {
std::cerr << typeid(e).name() << ": " << e.what() << std::endl;
}
// Pass an invalid string
try {
cout << "Passing an invalid hex string..." << endl;
BigDigit X = "0xabcG123";
}
catch (const std::invalid_argument& e) {
std::cerr << typeid(e).name() << ": " << e.what() << std::endl;
}
}
void test_bits() {
cout << endl << "Testing bit related operations..." << endl;
BigDigit u, v, w, p, q, r;
w = 0xfffffffe;
w.printhex("w=");
cout << "bitlen(w)=" << w.bitlen() << endl;
u = w << 2;
u.printhex("w << 2 = ");
assert(u.getbit(33) == 1);
v = u >> 3;
v.printhex("(w << 2) >> 3 = ");
assert(v.getbit(31) == 0);
/* Bigger shift */
u = w << 128;
u.printhex("w << 128 = ");
assert(u.getbit(159) == 1);
v = u >> 129;
v.printhex("(w << 128) >> 129 = ");
assert(v.getbit(31) == 0);
w = "0b00110101011";
w.printbits("w= ");
// Shift Assign
w >>= 2;
w.printbits("w>>=2:");
w <<= 2;
w.printbits("w<<=2:");
w >>= 3;
w.printbits("w>>=3:");
/* Use XOR to swop two variables without a temp variable, i.e.
a = a XOR b; b = a XOR b; a = a XOR b; */
/* Generate 2 random numbers (u,w) each 144 bits long */
u.set_rand_bits(144);
w.set_rand_bits(144);
u.printhex("u=");
w.printhex("w=");
/* remember these for later (p=u, q=w) */
p = u;
q = w;
/* Swop using XOR */
cout << "Swopping u and w using XOR" << endl;
u = u ^ w;
w = u ^ w;
u = u ^ w;
u.printhex("u=");
w.printhex("w=");
/* check they have swopped accurately */
assert(u == q);
assert(w == p);
// Using XOR Assign
u ^= w;
u.printhex("u^=w:");
// Invert all bits
cout << "Bitwise NOT..." << endl;
p = 0xfffe;
p <<= 32;
p = p + 0xfffe;
p.printhex("p= "); // fffe0000fffe
// Bitwise NOT - NB up to the most significant *digit*
q = ~p;
q.printhex("NOT p="); // ffff0001ffff0001
u = p & q;
u.printhex("p AND (NOT p)="); // 0
assert(u == 0);
// Flip bits in p only up to the most significant *bit*
p = "0x1ffff5ff9";
p.printhex("p=");
p.printbits();
cout << "bitlen(p)=" << p.bitlen() << endl;
q = (~p);
q.printhex("NOT p=");
q.printbits("NOT p=");
q = q.mod_powerof2(p.bitlen());
q.printhex("(NOT p)(mod 2^" + std::to_string(p.bitlen()) + ")=");
// In one action
q = (~p).mod_powerof2(p.bitlen());
q.printhex("(NOT p)(mod 2^" + std::to_string(p.bitlen()) + ")=");
// Some simple AND and OR ops
cout << "Set every even bit in u and every odd bit in v..." << endl;
u = 0;
v = 0;
for (int i = 0; i < 144 / 2; i++) {
u.setbit((i * 2), 1);
v.setbit((i * 2) + 1, 1);
}
u.printbits("u=");
v.printbits("v=");
w = u & v;
w.print("u AND v=");
w = u | v;
w.printhex("u OR v =");
// Check that setbit returns the value it set
u = "0xffffffffffff";
u.printhex("u=");
w = u.setbit(10, 0);
cout << "Set bit 10 to zero" << endl;
u.printhex("u=");
w.printhex("w=");
assert(w == u);
/* Compose a 400-bit string by concatenating random 160-bit sections
and then truncating the result */
cout << endl << "Bit string concatenation and truncation:" << endl;
/*
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 to demonstrate */
int m, mc;
m = 400;
mc = (m + 160 - 1) / 160; // m'
u = 0;
for (int i = 0; i < mc; i++) {
r.set_rand_bits(160);
v.set_rand_bits(160);
// U = U + (R XOR V) * 2 ^ (160 * i)
r.printhex("r=");
v.printhex("v=");
u += (r ^ v) << (160 * i);
/* * 2^160i <=> shift left by 160i bits */
u.printhex("u=");
}
u = u.mod_powerof2(m); /* U = U mod (2^m) */
u.printhex("u mod (2^m)=");
/* q = U OR 2^(m-1) OR 1 */
q = u;
q.setbit(m - 1, 1);
q.setbit(0, 1);
q.printhex("q=u OR 2^(m-1) OR 1=");
cout << "bitlen(q)=" << q.bitlen() << endl;
/* Check that 2^(m-1) < q < 2^m */
p = 0;
p.setbit(m - 1, 1); /* p = 2^(m-1) */
assert(p < q);
r = 0;
r.setbit(m, 1); /* r = 2^m */
assert(q < r);
cout << "OK, checked that 2^(m-1) < q < 2^m\n" << endl;
}
void test_functions() {
cout << endl << "Testing functions..." << endl;
BigDigit a, b, pow, g, n, s;
a = 0x1000 * 0x1000;
a.printhex("a=");
b = a.sqrt();
b.printhex("a.sqrt()="); // 0x1000
// Set a = (0x10000)^3
a = 0x10000;
a = a * a * a;
/* NB a = 0x10000 * 0x10000 * 0x10000; // will fail (because > UINT32_MAX)
warning C4307: '*' : integral constant overflow
*/
a.printhex("a=");
b = a.cbrt();
b.printhex("a.cbrt()="); // 0x10000
a = 0x1000;
a.printhex("a=");
pow = a.pow(10);
pow.printhex("a^10="); // 0x1000000000000000000000000000000
s = a.square();
s.printhex("a^2=");
a = 0x1000;
b = 0x1001;
g = BigDigit::gcd(a * 3, b * 3);
g.print("gcd="); // 3
{
BigDigit g = BigDigit::gcd(10, 25, 30, 50);
g.print("gcd="); // 5
}
g = BigDigit::gcd(17 * 31, 17 * 59, 17 * 71, 17 * 101);
g.print("gcd(527,1003,1207,1717)="); // 17
g = BigDigit::gcd(13 * 31, 13 * 59);
g.print("gcd()="); // 13
g = a.gcd(b);
g.printhex("a.gcd(b)=");
// Jacobi - Use numbers from X9.31 Appendix D.5.2
BigDigit aa("0x6BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
"BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"
"BBBBBBBBBBBAA9993E364706816ABA3E25717850"
"C26C9CD0D89D33CC");
BigDigit nn("0xCCD34C2F4D95FFAD1420E666C07E39D1450A1330"
"4C3F5891EDE57595C772A3691AB51D2BECE1476B"
"8F22AE223365F183BC3EE2D4CACDBA3AD0C4D478"
"1C523A10EFE6203D6F3BC226BF9A459727B8F122"
"C482D8C86019F9A869329187096430A6C67CB103"
"742BCBC66906AD23836EBABB511D5D80AB8CB599"
"74E9AAC62D785C45");
aa.printhex("aa=");
nn.printhex("nn=");
int j;
j = aa.jacobi(nn);
cout << "Jacobi(a/n)=" << j << " expected -1" << endl;
assert(j == -1);
// Divide a by 2
aa /= 2;
aa.printhex("aa=");
j = aa.jacobi(nn);
cout << "Jacobi(a/n)=" << j << " expected +1" << endl;
// Make n|a
nn = aa * 7;
j = aa.jacobi(nn);
cout << "Jacobi(a/n)=" << j << " expected 0" << endl;
aa = 2183;
nn = 9907;
j = aa.jacobi(nn);
cout << "Jacobi(" << aa.to_str() << "|" << nn.to_str() << ")=" << j << " expected 1" << endl;
assert(j == 1);
aa = 1001;
j = aa.jacobi(nn);
cout << "Jacobi(" << aa.to_str() << "|" << nn.to_str() << ")=" << j << " expected -1" << endl;
assert(j == -1);
aa = 10000 * 9907;
j = aa.jacobi(nn);
cout << "Jacobi(" << aa.to_str() << "|" << nn.to_str() << ")=" << j << " expected 0" << endl;
assert(j == 0);
}
void test_from_str() {
cout << endl << "Test from_str() and constructor initialization" << endl;
// Use from_str() function
BigDigit a = from_str("0xdeadbeefcafebabe");
BigDigit b = from_str("16045690984503098046");
BigDigit c = from_str("0b1101111010101101101111101110111111001010111111101011101010111110");
a.printhex("a="); b.printhex("b="); c.printhex("c=");
// a=0xdeadbeefcafebabe
// b=0xdeadbeefcafebabe
// c=0xdeadbeefcafebabe
// Assign using string directly [v1.0.1]
a = "0xdeadbeefcafebabe";
b = "16045690984503098046";
c = "0b1101111010101101101111101110111111001010111111101011101010111110";
a.printhex("a="); b.printhex("b="); c.printhex("c=");
// Use BigDigit constructor
BigDigit A("0xdeadbeefcafebabe");
BigDigit B("16045690984503098046");
BigDigit C("0b1101111010101101101111101110111111001010111111101011101010111110");
A.printhex("A="); B.printhex("B="); C.printhex("C=");
// A=0xdeadbeefcafebabe
// B=0xdeadbeefcafebabe
// C=0xdeadbeefcafebabe
}
void test_octets() {
cout << endl << "Test from_octets and to_octets" << endl;
// Decode from byte array
std::vector<unsigned char> bv = { 0xde, 0xad, 0xbe, 0xef };
BigDigit b = from_octets(bv);
b.printhex("b=");
// Check we can do arithmetic on the resulting BigDigit
(--b).printhex("--b=");
// Encode from BigDigit
std::vector<unsigned char> barr = b.to_octets();
Bvec::print_hex("to_octets: ", barr);
{ // For documentation
BigDigit b(0xdeadbeef);
std::vector<unsigned char> barr = b.to_octets();
Bvec::print_hex(barr); // de ad be ef
Bvec::print_hex(barr, ""); // deadbeef
Bvec::print_hex(barr, ":"); // de:ad:be:ef
// Specify exact length
barr = b.to_octets(6);
Bvec::print_hex(barr); // 00 00 de ad be ef
}
BigDigit s("0x103808afb0db2fd4abff6af4149f51b");
s.printhex("s in network order: ");
// Set s as 128-bit little-endian number
s = s.reverse_octets(128 / 8);
s.printhex("s as 128-bit number: ");
// 0x1bf54941aff6bf4afdb20dfb8a800301
}
void test_RSA508() {
cout << endl << "Test RSA computations using 508-bit RSA key from 'Some Examples of the PKCS Standards'" << endl;
BigDigit n("0x0A66791DC6988168DE7AB77419BB7FB0C001C62710270075142942E19A8D8C51D053B3E3782A1DE5DC5AF4EBE99468170114A1DFE67CDC9A9AF55D655620BBAB");
BigDigit e("0x010001");
BigDigit m("0x0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003020300C06082A864886F70D020205000410DCA9ECF1C15C1BD266AFF9C8799365CD");
BigDigit d("0x0123C5B61BA36EDB1D3679904199A89EA80C09B9122E1400C09ADCF7784676D01D23356A7D44D6BD8BD50E94BFC723FA87D8862B75177691C11D757692DF8881");
m.printhex("m =");
// Sign, i.e. Encrypt with private key, s = m^d mod n
BigDigit s = m.mod_exp(d, n);
s.printhex("s =");
BigDigit s1("0x06DB36CB18D3475B9C01DB3C789528080279BBAEFF2B7D558ED6615987C851863F8A6C2CFFBC89C3F75A18D96B127C717D54D0D8048DA8A0544626D17A2A8FBE");
s1.printhex("ok=");
assert(s == s1);
/* Verify, i.e. Decrypt with public key m' = s^e mod n */
BigDigit m1 = s.mod_exp(e, n);
m1.printhex("m1=");
m.printhex("ok=");
assert(m == m1);
// Same again using constant time variant...
cout << "Using constant time..." << endl;
s = m.mod_exp_ct(d, n);
s.printhex("s =");
assert(s == s1);
/* Verify, i.e. Decrypt with public key m' = s^e mod n */
m1 = s.mod_exp_ct(e, n);
m1.printhex("m1=");
assert(m == m1);
}
void test_bvec() {
cout << endl << "Test Bvec functions..." << endl;
std::vector<unsigned char> bv;
bv = Bvec::from_hex("DEADBEEF");
Bvec::print_hex(bv);
bv = Bvec::from_hex("00DEADBEEF");
Bvec::print_hex(bv);
bv = Bvec::from_hex("000000DEADBEEF");
Bvec::print_hex(bv);
bv = Bvec::from_hex("0xDEADBEEF");
Bvec::print_hex(bv, "");
bv = Bvec::from_hex("0X0000DEADBEEF");
Bvec::print_hex(bv, "");
}
void do_test() {
test_version_info();
test_arithmetic();
test_exceptions();
test_mod_arithmetic();
test_functions();
test_bits();
test_RSA508();
test_from_str();
test_octets();
test_bvec();
}
int main() {
/* 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
/* Catch any exceptions */
try {
do_test();
}
catch (const std::exception& e) {
// Handle standard exceptions with a specific message
std::cerr << "Standard exception: " << e.what() << std::endl;
}
catch (...) {
std::cerr << "Caught unknown exception." << std::endl;
}
cout << endl << "ALL DONE." << endl << endl;
return 0;
}