mirror of
https://github.com/RGBCube/serenity
synced 2025-07-25 05:57:44 +00:00
test-crypto: Add more tests for the modular power operator
Also addresses a fixup in the test suite by moving the NumberTheory tests out of the RSA suite and into the BigInteger suite.
This commit is contained in:
parent
485adb5e29
commit
ac6bd3a7a4
1 changed files with 202 additions and 120 deletions
|
@ -590,7 +590,6 @@ static void rsa_test_encrypt();
|
|||
static void rsa_test_der_parse();
|
||||
static void rsa_test_encrypt_decrypt();
|
||||
static void rsa_emsa_pss_test_create();
|
||||
static void bigint_test_number_theory(); // FIXME: we should really move these num theory stuff out
|
||||
|
||||
static void tls_test_client_hello();
|
||||
|
||||
|
@ -603,6 +602,11 @@ static void bigint_base10();
|
|||
static void bigint_import_export();
|
||||
static void bigint_bitwise();
|
||||
|
||||
static void bigint_theory_modular_inverse();
|
||||
static void bigint_theory_modular_power();
|
||||
static void bigint_theory_primality();
|
||||
static void bigint_theory_random_number();
|
||||
|
||||
static void bigint_test_signed_fibo500();
|
||||
static void bigint_signed_addition_edgecases();
|
||||
static void bigint_signed_subtraction();
|
||||
|
@ -1783,7 +1787,6 @@ static int rsa_tests()
|
|||
{
|
||||
rsa_test_encrypt();
|
||||
rsa_test_der_parse();
|
||||
bigint_test_number_theory();
|
||||
rsa_test_encrypt_decrypt();
|
||||
rsa_emsa_pss_test_create();
|
||||
return g_some_test_failed ? 1 : 0;
|
||||
|
@ -1831,124 +1834,6 @@ static void rsa_test_encrypt()
|
|||
}
|
||||
}
|
||||
|
||||
static void bigint_test_number_theory()
|
||||
{
|
||||
{
|
||||
I_TEST((Number Theory | Modular Inverse));
|
||||
if (Crypto::NumberTheory::ModularInverse(7, 87) == 25) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Invalid result);
|
||||
}
|
||||
}
|
||||
{
|
||||
struct {
|
||||
Crypto::UnsignedBigInteger base;
|
||||
Crypto::UnsignedBigInteger exp;
|
||||
Crypto::UnsignedBigInteger mod;
|
||||
Crypto::UnsignedBigInteger expected;
|
||||
} mod_pow_tests[] = {
|
||||
{ "2988348162058574136915891421498819466320163312926952423791023078876139"_bigint, "2351399303373464486466122544523690094744975233415544072992656881240319"_bigint, "10000"_bigint, "3059"_bigint },
|
||||
{ "24231"_bigint, "12448"_bigint, "14679"_bigint, "4428"_bigint },
|
||||
{ "1005404"_bigint, "8352654"_bigint, "8161408"_bigint, "2605696"_bigint },
|
||||
{ "3665005778"_bigint, "3244425589"_bigint, "565668506"_bigint, "524766494"_bigint },
|
||||
{ "10662083169959689657"_bigint, "11605678468317533000"_bigint, "1896834583057209739"_bigint, "1292743154593945858"_bigint },
|
||||
{ "99667739213529524852296932424683448520"_bigint, "123394910770101395416306279070921784207"_bigint, "238026722756504133786938677233768788719"_bigint, "197165477545023317459748215952393063201"_bigint },
|
||||
{ "49368547511968178788919424448914214709244872098814465088945281575062739912239"_bigint, "25201856190991298572337188495596990852134236115562183449699512394891190792064"_bigint, "45950460777961491021589776911422805972195170308651734432277141467904883064645"_bigint, "39917885806532796066922509794537889114718612292469285403012781055544152450051"_bigint },
|
||||
{ "48399385336454791246880286907257136254351739111892925951016159217090949616810"_bigint, "5758661760571644379364752528081901787573279669668889744323710906207949658569"_bigint, "32812120644405991429173950312949738783216437173380339653152625840449006970808"_bigint, "7948464125034399875323770213514649646309423451213282653637296324080400293584"_bigint },
|
||||
};
|
||||
|
||||
for (auto test_case : mod_pow_tests) {
|
||||
I_TEST((Number Theory | Modular Power));
|
||||
auto actual = Crypto::NumberTheory::ModularPower(
|
||||
test_case.base, test_case.exp, test_case.mod);
|
||||
|
||||
if (actual == test_case.expected) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Wrong result);
|
||||
printf("b: %s\ne: %s\nm: %s\nexpect: %s\nactual: %s\n",
|
||||
test_case.base.to_base10().characters(), test_case.exp.to_base10().characters(), test_case.mod.to_base10().characters(), test_case.expected.to_base10().characters(), actual.to_base10().characters());
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
struct {
|
||||
Crypto::UnsignedBigInteger candidate;
|
||||
bool expected_result;
|
||||
} primality_tests[] = {
|
||||
{ "1180591620717411303424"_bigint, false }, // 2**70
|
||||
{ "620448401733239439360000"_bigint, false }, // 25!
|
||||
{ "953962166440690129601298432"_bigint, false }, // 12**25
|
||||
{ "620448401733239439360000"_bigint, false }, // 25!
|
||||
{ "147926426347074375"_bigint, false }, // 35! / 2**32
|
||||
{ "340282366920938429742726440690708343523"_bigint, false }, // 2 factors near 2^64
|
||||
{ "73"_bigint, true },
|
||||
{ "6967"_bigint, true },
|
||||
{ "787649"_bigint, true },
|
||||
{ "73513949"_bigint, true },
|
||||
{ "6691236901"_bigint, true },
|
||||
{ "741387182759"_bigint, true },
|
||||
{ "67466615915827"_bigint, true },
|
||||
{ "9554317039214687"_bigint, true },
|
||||
{ "533344522150170391"_bigint, true },
|
||||
{ "18446744073709551557"_bigint, true }, // just below 2**64
|
||||
};
|
||||
|
||||
for (auto test_case : primality_tests) {
|
||||
I_TEST((Number Theory | Primality));
|
||||
bool actual_result = Crypto::NumberTheory::is_probably_prime(test_case.candidate);
|
||||
if (test_case.expected_result == actual_result) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Wrong primality guess);
|
||||
printf("The number %s is %sa prime, but the test said it is %sa prime!\n",
|
||||
test_case.candidate.to_base10().characters(), test_case.expected_result ? "" : "not ", actual_result ? "" : "not ");
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
struct {
|
||||
Crypto::UnsignedBigInteger min;
|
||||
Crypto::UnsignedBigInteger max;
|
||||
} primality_tests[] = {
|
||||
{ "1"_bigint, "1000000"_bigint },
|
||||
{ "10000000000"_bigint, "20000000000"_bigint },
|
||||
{ "1000"_bigint, "200000000000000000"_bigint },
|
||||
{ "200000000000000000"_bigint, "200000000000010000"_bigint },
|
||||
};
|
||||
|
||||
for (auto test_case : primality_tests) {
|
||||
I_TEST((Number Theory | Random numbers));
|
||||
auto actual_result = Crypto::NumberTheory::random_number(test_case.min, test_case.max);
|
||||
if (actual_result < test_case.min) {
|
||||
FAIL(Too small);
|
||||
printf("The generated number %s is smaller than the requested minimum %s. (max = %s)\n", actual_result.to_base10().characters(), test_case.min.to_base10().characters(), test_case.max.to_base10().characters());
|
||||
} else if (!(actual_result < test_case.max)) {
|
||||
FAIL(Too large);
|
||||
printf("The generated number %s is larger-or-equal to the requested maximum %s. (min = %s)\n", actual_result.to_base10().characters(), test_case.max.to_base10().characters(), test_case.min.to_base10().characters());
|
||||
} else {
|
||||
PASS;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
I_TEST((Number Theory | Random distribution));
|
||||
auto actual_result = Crypto::NumberTheory::random_number(
|
||||
"1"_bigint,
|
||||
"100000000000000000000000000000"_bigint); // 10**29
|
||||
if (actual_result < "100000000000000000000"_bigint) { // 10**20
|
||||
FAIL(Too small);
|
||||
printf("The generated number %s is extremely small. This *can* happen by pure chance, but should happen only once in a billion times. So it's probably an error.\n", actual_result.to_base10().characters());
|
||||
} else if ("99999999900000000000000000000"_bigint < actual_result) { // 10**29 - 10**20
|
||||
FAIL(Too large);
|
||||
printf("The generated number %s is extremely large. This *can* happen by pure chance, but should happen only once in a billion times. So it's probably an error.\n", actual_result.to_base10().characters());
|
||||
} else {
|
||||
PASS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void rsa_emsa_pss_test_create()
|
||||
{
|
||||
{
|
||||
|
@ -2170,6 +2055,11 @@ static int bigint_tests()
|
|||
bigint_import_export();
|
||||
bigint_bitwise();
|
||||
|
||||
bigint_theory_modular_inverse();
|
||||
bigint_theory_modular_power();
|
||||
bigint_theory_primality();
|
||||
bigint_theory_random_number();
|
||||
|
||||
bigint_test_signed_fibo500();
|
||||
bigint_signed_addition_edgecases();
|
||||
bigint_signed_subtraction();
|
||||
|
@ -2502,6 +2392,198 @@ static void bigint_base10()
|
|||
}
|
||||
}
|
||||
|
||||
static void bigint_theory_modular_inverse()
|
||||
{
|
||||
{
|
||||
I_TEST((Number Theory | Modular Inverse));
|
||||
if (Crypto::NumberTheory::ModularInverse(7, 87) == 25) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Invalid result);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bigint_theory_modular_power()
|
||||
{
|
||||
{
|
||||
I_TEST((BigInteger | Simple Modular Power | Even));
|
||||
Crypto::UnsignedBigInteger base { 7 };
|
||||
Crypto::UnsignedBigInteger exponent { 2 };
|
||||
Crypto::UnsignedBigInteger modulo { 10 };
|
||||
auto result = Crypto::NumberTheory::ModularPower(base, exponent, modulo);
|
||||
if (result.words() == Vector<u32> { 9 }) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Incorrect Result);
|
||||
}
|
||||
}
|
||||
{
|
||||
I_TEST((BigInteger | Simple Modular Power | Odd));
|
||||
Crypto::UnsignedBigInteger base { 10 };
|
||||
Crypto::UnsignedBigInteger exponent { 2 };
|
||||
Crypto::UnsignedBigInteger modulo { 9 };
|
||||
auto result = Crypto::NumberTheory::ModularPower(base, exponent, modulo);
|
||||
if (result.words() == Vector<u32> { 1 }) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Incorrect Result);
|
||||
}
|
||||
}
|
||||
{
|
||||
I_TEST((BigInteger | Large Modular Power | Even Fibonacci));
|
||||
Crypto::UnsignedBigInteger base = bigint_fibonacci(200);
|
||||
Crypto::UnsignedBigInteger exponent = bigint_fibonacci(100);
|
||||
Crypto::UnsignedBigInteger modulo = bigint_fibonacci(150);
|
||||
// Result according to Wolfram Alpha : 7195284628716783672927396027925
|
||||
auto result = Crypto::NumberTheory::ModularPower(base, exponent, modulo);
|
||||
if (result.words() == Vector<u32> { 2042093077, 1351416233, 3510104665, 90 }) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Incorrect Result);
|
||||
}
|
||||
}
|
||||
{
|
||||
I_TEST((BigInteger | Large Modular Power | Odd Fibonacci));
|
||||
Crypto::UnsignedBigInteger base = bigint_fibonacci(200);
|
||||
Crypto::UnsignedBigInteger exponent = bigint_fibonacci(100);
|
||||
Crypto::UnsignedBigInteger modulo = bigint_fibonacci(149);
|
||||
// Result according to Wolfram Alpha : 1136278609611966596838389694992
|
||||
auto result = Crypto::NumberTheory::ModularPower(base, exponent, modulo);
|
||||
if (result.words() == Vector<u32> { 2106049040, 2169509253, 1468244710, 14 }) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Incorrect Result);
|
||||
}
|
||||
}
|
||||
{
|
||||
I_TEST((BigInteger | Large Modular Power | Odd Fibonacci with carry));
|
||||
Crypto::UnsignedBigInteger base = bigint_fibonacci(200);
|
||||
Crypto::UnsignedBigInteger exponent = bigint_fibonacci(100);
|
||||
Crypto::UnsignedBigInteger modulo = bigint_fibonacci(185);
|
||||
// Result according to Wolfram Alpha : 55094573983071006678665780782730672080
|
||||
auto result = Crypto::NumberTheory::ModularPower(base, exponent, modulo);
|
||||
if (result.words() == Vector<u32> { 1988720592, 2097784252, 347129583, 695391288 }) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Incorrect Result);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct {
|
||||
Crypto::UnsignedBigInteger base;
|
||||
Crypto::UnsignedBigInteger exp;
|
||||
Crypto::UnsignedBigInteger mod;
|
||||
Crypto::UnsignedBigInteger expected;
|
||||
} mod_pow_tests[] = {
|
||||
{ "2988348162058574136915891421498819466320163312926952423791023078876139"_bigint, "2351399303373464486466122544523690094744975233415544072992656881240319"_bigint, "10000"_bigint, "3059"_bigint },
|
||||
{ "24231"_bigint, "12448"_bigint, "14679"_bigint, "4428"_bigint },
|
||||
{ "1005404"_bigint, "8352654"_bigint, "8161408"_bigint, "2605696"_bigint },
|
||||
{ "3665005778"_bigint, "3244425589"_bigint, "565668506"_bigint, "524766494"_bigint },
|
||||
{ "10662083169959689657"_bigint, "11605678468317533000"_bigint, "1896834583057209739"_bigint, "1292743154593945858"_bigint },
|
||||
{ "99667739213529524852296932424683448520"_bigint, "123394910770101395416306279070921784207"_bigint, "238026722756504133786938677233768788719"_bigint, "197165477545023317459748215952393063201"_bigint },
|
||||
{ "49368547511968178788919424448914214709244872098814465088945281575062739912239"_bigint, "25201856190991298572337188495596990852134236115562183449699512394891190792064"_bigint, "45950460777961491021589776911422805972195170308651734432277141467904883064645"_bigint, "39917885806532796066922509794537889114718612292469285403012781055544152450051"_bigint },
|
||||
{ "48399385336454791246880286907257136254351739111892925951016159217090949616810"_bigint, "5758661760571644379364752528081901787573279669668889744323710906207949658569"_bigint, "32812120644405991429173950312949738783216437173380339653152625840449006970808"_bigint, "7948464125034399875323770213514649646309423451213282653637296324080400293584"_bigint },
|
||||
};
|
||||
|
||||
for (auto test_case : mod_pow_tests) {
|
||||
I_TEST((BigInteger | Modular Power | Several other test cases));
|
||||
auto actual = Crypto::NumberTheory::ModularPower(
|
||||
test_case.base, test_case.exp, test_case.mod);
|
||||
|
||||
if (actual == test_case.expected) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Wrong result);
|
||||
printf("b: %s\ne: %s\nm: %s\nexpect: %s\nactual: %s\n",
|
||||
test_case.base.to_base10().characters(), test_case.exp.to_base10().characters(), test_case.mod.to_base10().characters(), test_case.expected.to_base10().characters(), actual.to_base10().characters());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bigint_theory_primality()
|
||||
{
|
||||
struct {
|
||||
Crypto::UnsignedBigInteger candidate;
|
||||
bool expected_result;
|
||||
} primality_tests[] = {
|
||||
{ "1180591620717411303424"_bigint, false }, // 2**70
|
||||
{ "620448401733239439360000"_bigint, false }, // 25!
|
||||
{ "953962166440690129601298432"_bigint, false }, // 12**25
|
||||
{ "620448401733239439360000"_bigint, false }, // 25!
|
||||
{ "147926426347074375"_bigint, false }, // 35! / 2**32
|
||||
{ "340282366920938429742726440690708343523"_bigint, false }, // 2 factors near 2^64
|
||||
{ "73"_bigint, true },
|
||||
{ "6967"_bigint, true },
|
||||
{ "787649"_bigint, true },
|
||||
{ "73513949"_bigint, true },
|
||||
{ "6691236901"_bigint, true },
|
||||
{ "741387182759"_bigint, true },
|
||||
{ "67466615915827"_bigint, true },
|
||||
{ "9554317039214687"_bigint, true },
|
||||
{ "533344522150170391"_bigint, true },
|
||||
{ "18446744073709551557"_bigint, true }, // just below 2**64
|
||||
};
|
||||
|
||||
for (auto test_case : primality_tests) {
|
||||
I_TEST((BigInteger | Primality));
|
||||
bool actual_result = Crypto::NumberTheory::is_probably_prime(test_case.candidate);
|
||||
if (test_case.expected_result == actual_result) {
|
||||
PASS;
|
||||
} else {
|
||||
FAIL(Wrong primality guess);
|
||||
printf("The number %s is %sa prime, but the test said it is %sa prime!\n",
|
||||
test_case.candidate.to_base10().characters(), test_case.expected_result ? "" : "not ", actual_result ? "" : "not ");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bigint_theory_random_number()
|
||||
{
|
||||
{
|
||||
struct {
|
||||
Crypto::UnsignedBigInteger min;
|
||||
Crypto::UnsignedBigInteger max;
|
||||
} random_number_tests[] = {
|
||||
{ "1"_bigint, "1000000"_bigint },
|
||||
{ "10000000000"_bigint, "20000000000"_bigint },
|
||||
{ "1000"_bigint, "200000000000000000"_bigint },
|
||||
{ "200000000000000000"_bigint, "200000000000010000"_bigint },
|
||||
};
|
||||
|
||||
for (auto test_case : random_number_tests) {
|
||||
I_TEST((BigInteger | Random numbers));
|
||||
auto actual_result = Crypto::NumberTheory::random_number(test_case.min, test_case.max);
|
||||
if (actual_result < test_case.min) {
|
||||
FAIL(Too small);
|
||||
printf("The generated number %s is smaller than the requested minimum %s. (max = %s)\n", actual_result.to_base10().characters(), test_case.min.to_base10().characters(), test_case.max.to_base10().characters());
|
||||
} else if (!(actual_result < test_case.max)) {
|
||||
FAIL(Too large);
|
||||
printf("The generated number %s is larger-or-equal to the requested maximum %s. (min = %s)\n", actual_result.to_base10().characters(), test_case.max.to_base10().characters(), test_case.min.to_base10().characters());
|
||||
} else {
|
||||
PASS;
|
||||
}
|
||||
}
|
||||
}
|
||||
{
|
||||
I_TEST((BigInteger | Random distribution));
|
||||
auto actual_result = Crypto::NumberTheory::random_number(
|
||||
"1"_bigint,
|
||||
"100000000000000000000000000000"_bigint); // 10**29
|
||||
if (actual_result < "100000000000000000000"_bigint) { // 10**20
|
||||
FAIL(Too small);
|
||||
printf("The generated number %s is extremely small. This *can* happen by pure chance, but should happen only once in a billion times. So it's probably an error.\n", actual_result.to_base10().characters());
|
||||
} else if ("99999999900000000000000000000"_bigint < actual_result) { // 10**29 - 10**20
|
||||
FAIL(Too large);
|
||||
printf("The generated number %s is extremely large. This *can* happen by pure chance, but should happen only once in a billion times. So it's probably an error.\n", actual_result.to_base10().characters());
|
||||
} else {
|
||||
PASS;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void bigint_import_export()
|
||||
{
|
||||
{
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue