Add more tests

This commit is contained in:
Frank Denis
2026-01-05 23:20:32 +01:00
parent 5aff9f2d89
commit dc12719756
7 changed files with 449 additions and 7 deletions
+50 -6
View File
@@ -17,16 +17,16 @@ static int
compare_states(const char *label, const unsigned char *actual, const unsigned char *expected,
size_t len)
{
size_t i;
size_t i, j;
for (i = 0; i < len; i++) {
if (actual[i] != expected[i]) {
printf("FAIL: %s mismatch at byte %u\n", label, (unsigned int) i);
printf(" Expected: ");
for (size_t j = 0; j < len; j++) {
for (j = 0; j < len; j++) {
printf("%02x", expected[j]);
}
printf("\n Got: ");
for (size_t j = 0; j < len; j++) {
for (j = 0; j < len; j++) {
printf("%02x", actual[j]);
}
printf("\n");
@@ -42,8 +42,13 @@ main(void)
{
unsigned char state[crypto_core_keccak1600_STATEBYTES];
unsigned char extracted[64];
unsigned char test_data[64];
unsigned char sentinel[64];
unsigned char state_12[200], state_24[200];
unsigned char last_byte;
size_t i;
int test_failures = 0;
int differs;
/* Test vectors for Keccak-f[1600] (24 rounds) */
/* Test vector 1: All-zero input for Keccak-f[1600] */
@@ -145,10 +150,50 @@ main(void)
/* Test 3: XOR and extract functions */
printf("Test 3: crypto_core_keccak1600_xor_bytes and extract_bytes\n");
crypto_core_keccak1600_init(state);
unsigned char test_data[64];
for (i = 0; i < sizeof test_data; i++) {
test_data[i] = (unsigned char) i;
}
/* Edge case: zero-length XOR/extract should be a no-op (test at offset 0 and at end) */
{
static const size_t offsets[] = { 0, crypto_core_keccak1600_STATEBYTES };
size_t t;
for (t = 0; t < sizeof offsets / sizeof offsets[0]; t++) {
crypto_core_keccak1600_init(state);
memset(extracted, 0xA5, sizeof extracted);
memset(sentinel, 0xA5, sizeof sentinel);
crypto_core_keccak1600_xor_bytes(state, test_data, offsets[t], 0);
crypto_core_keccak1600_extract_bytes(state, extracted, offsets[t], 0);
for (i = 0; i < sizeof state; i++) {
if (state[i] != 0) {
printf(" FAIL: XOR length 0 at offset %u modified state\n\n",
(unsigned) offsets[t]);
test_failures++;
break;
}
}
if (memcmp(extracted, sentinel, sizeof extracted) != 0) {
printf(" FAIL: extract length 0 at offset %u modified output\n\n",
(unsigned) offsets[t]);
test_failures++;
}
}
}
/* Edge case: XOR/extract last byte */
crypto_core_keccak1600_init(state);
memset(extracted, 0, sizeof extracted);
last_byte = 0x5A;
crypto_core_keccak1600_xor_bytes(state, &last_byte,
crypto_core_keccak1600_STATEBYTES - 1, 1);
crypto_core_keccak1600_extract_bytes(state, extracted,
crypto_core_keccak1600_STATEBYTES - 1, 1);
if (extracted[0] != last_byte) {
printf(" FAIL: XOR/extract last byte mismatch\n\n");
test_failures++;
}
crypto_core_keccak1600_init(state);
crypto_core_keccak1600_xor_bytes(state, test_data, 0, sizeof test_data);
crypto_core_keccak1600_extract_bytes(state, extracted, 0, sizeof test_data);
if (memcmp(extracted, test_data, sizeof test_data) == 0) {
@@ -184,13 +229,12 @@ main(void)
/* Test 7: Verify 12 and 24 rounds produce different outputs */
printf("Test 7: Verify 12-round and 24-round differ\n");
unsigned char state_12[200], state_24[200];
crypto_core_keccak1600_init(state_12);
crypto_core_keccak1600_init(state_24);
crypto_core_keccak1600_permute_12(state_12);
crypto_core_keccak1600_permute_24(state_24);
int differs = 0;
differs = 0;
for (i = 0; i < 200; i++) {
if (state_12[i] != state_24[i]) {
differs = 1;
+162 -1
View File
@@ -1,7 +1,7 @@
#define TEST_NAME "ipcrypt"
#include "cmptest.h"
static const unsigned char ipv4_mapped_prefix[12] = { 0U, 0U, 0U, 0U, 0U, 0U,
static const unsigned char ipv4_mapped_prefix[12] = { 0U, 0U, 0U, 0U, 0U, 0U,
0U, 0U, 0U, 0U, 0xffU, 0xffU };
static int
@@ -21,6 +21,39 @@ check_expected(const char *test_name, const unsigned char *actual, const char *e
return 0;
}
static void
flip_bit_msb(unsigned char buf[16], unsigned int bit_index)
{
unsigned int byte_index;
unsigned int bit_in_byte;
if (bit_index >= 128U) {
return;
}
byte_index = bit_index / 8U;
bit_in_byte = 7U - (bit_index % 8U);
buf[byte_index] ^= (unsigned char) (1U << bit_in_byte);
}
static int
prefix_equal_msb(const unsigned char *a, const unsigned char *b, unsigned int prefix_len_bits)
{
unsigned int full_bytes = prefix_len_bits / 8U;
unsigned int rem_bits = prefix_len_bits % 8U;
if (prefix_len_bits == 0U) {
return 1;
}
if (memcmp(a, b, full_bytes) != 0) {
return 0;
}
if (rem_bits == 0U) {
return 1;
}
return (a[full_bytes] & (unsigned char) (0xffU << (8U - rem_bits))) ==
(b[full_bytes] & (unsigned char) (0xffU << (8U - rem_bits)));
}
int
main(void)
{
@@ -42,6 +75,7 @@ main(void)
unsigned char encrypted1[crypto_ipcrypt_PFX_BYTES];
unsigned char encrypted2[crypto_ipcrypt_PFX_BYTES];
size_t i;
unsigned int prefix_len_bits;
printf("crypto_ipcrypt_BYTES: %zu\n", crypto_ipcrypt_bytes());
printf("crypto_ipcrypt_KEYBYTES: %zu\n", crypto_ipcrypt_keybytes());
@@ -552,6 +586,49 @@ main(void)
}
printf("OK: IPv6 /32 prefix preserved for 2001:db8::/32\n");
printf("\nsystematic prefix-length coverage\n");
memset(pfx_key, 0x6a, sizeof pfx_key);
for (prefix_len_bits = 0; prefix_len_bits <= 128U; prefix_len_bits++) {
unsigned char in1[16];
unsigned char in2[16];
unsigned char out1[16];
unsigned char out2[16];
randombytes_buf(in1, sizeof in1);
in1[0] = 0x20;
in1[1] = 0x01;
memcpy(in2, in1, sizeof in1);
flip_bit_msb(in2, prefix_len_bits);
crypto_ipcrypt_pfx_encrypt(out1, in1, pfx_key);
crypto_ipcrypt_pfx_encrypt(out2, in2, pfx_key);
if (prefix_equal_msb(out1, out2, prefix_len_bits) == 0) {
printf("FAILED: IPv6 prefix length %u\n", prefix_len_bits);
return 1;
}
}
printf("OK: IPv6 prefix preservation for /0..128\n");
for (prefix_len_bits = 0; prefix_len_bits <= 32U; prefix_len_bits++) {
unsigned char in1[16];
unsigned char in2[16];
unsigned char out1[16];
unsigned char out2[16];
memset(in1, 0, sizeof in1);
memcpy(in1, ipv4_mapped_prefix, 12);
randombytes_buf(in1 + 12, 4U);
memcpy(in2, in1, sizeof in1);
flip_bit_msb(in2, 96U + prefix_len_bits);
crypto_ipcrypt_pfx_encrypt(out1, in1, pfx_key);
crypto_ipcrypt_pfx_encrypt(out2, in2, pfx_key);
if (prefix_equal_msb(out1, out2, 96U + prefix_len_bits) == 0) {
printf("FAILED: IPv4-mapped prefix length %u\n", prefix_len_bits);
return 1;
}
}
printf("OK: IPv4-mapped prefix preservation for /0..32\n");
printf("\nfunctional tests\n");
crypto_ipcrypt_keygen(key);
@@ -740,6 +817,90 @@ main(void)
}
printf("OK: IPv6 all-ones round-trips\n");
printf("\nrandomized property tests\n");
for (i = 0; i < 128U; i++) {
randombytes_buf(key, sizeof key);
randombytes_buf(ndx_key, sizeof ndx_key);
randombytes_buf(pfx_key, sizeof pfx_key);
randombytes_buf(tweak_nd, sizeof tweak_nd);
randombytes_buf(tweak_ndx, sizeof tweak_ndx);
randombytes_buf(input, sizeof input);
crypto_ipcrypt_encrypt(output, input, key);
crypto_ipcrypt_decrypt(decrypted, output, key);
if (memcmp(input, decrypted, sizeof input) != 0) {
printf("FAILED: randomized ipcrypt round-trip\n");
return 1;
}
crypto_ipcrypt_nd_encrypt(nd_output, input, tweak_nd, key);
crypto_ipcrypt_nd_decrypt(decrypted, nd_output, key);
if (memcmp(input, decrypted, sizeof input) != 0) {
printf("FAILED: randomized nd round-trip\n");
return 1;
}
crypto_ipcrypt_ndx_encrypt(ndx_output, input, tweak_ndx, ndx_key);
crypto_ipcrypt_ndx_decrypt(decrypted, ndx_output, ndx_key);
if (memcmp(input, decrypted, sizeof input) != 0) {
printf("FAILED: randomized ndx round-trip\n");
return 1;
}
crypto_ipcrypt_pfx_encrypt(pfx_output, input, pfx_key);
crypto_ipcrypt_pfx_decrypt(decrypted, pfx_output, pfx_key);
if (memcmp(input, decrypted, sizeof input) != 0) {
printf("FAILED: randomized pfx round-trip\n");
return 1;
}
}
printf("OK: randomized round-trip tests\n");
for (i = 0; i < 128U; i++) {
unsigned char in1[16];
unsigned char in2[16];
unsigned char out1[16];
unsigned char out2[16];
randombytes_buf(pfx_key, sizeof pfx_key);
randombytes_buf(in1, sizeof in1);
in1[0] = 0x20;
in1[1] = 0x01;
memcpy(in2, in1, sizeof in1);
prefix_len_bits = (unsigned int) randombytes_uniform(129U);
flip_bit_msb(in2, prefix_len_bits);
crypto_ipcrypt_pfx_encrypt(out1, in1, pfx_key);
crypto_ipcrypt_pfx_encrypt(out2, in2, pfx_key);
if (prefix_equal_msb(out1, out2, prefix_len_bits) == 0) {
printf("FAILED: randomized IPv6 prefix length %u\n", prefix_len_bits);
return 1;
}
}
printf("OK: randomized IPv6 prefix preservation\n");
for (i = 0; i < 128U; i++) {
unsigned char in1[16];
unsigned char in2[16];
unsigned char out1[16];
unsigned char out2[16];
randombytes_buf(pfx_key, sizeof pfx_key);
memset(in1, 0, sizeof in1);
memcpy(in1, ipv4_mapped_prefix, 12);
randombytes_buf(in1 + 12, 4U);
memcpy(in2, in1, sizeof in1);
prefix_len_bits = (unsigned int) randombytes_uniform(33U);
flip_bit_msb(in2, 96U + prefix_len_bits);
crypto_ipcrypt_pfx_encrypt(out1, in1, pfx_key);
crypto_ipcrypt_pfx_encrypt(out2, in2, pfx_key);
if (prefix_equal_msb(out1, out2, 96U + prefix_len_bits) == 0) {
printf("FAILED: randomized IPv4-mapped prefix length %u\n", prefix_len_bits);
return 1;
}
}
printf("OK: randomized IPv4-mapped prefix preservation\n");
printf("\nAll specification test vectors passed!\n");
return 0;
+9
View File
@@ -51,6 +51,10 @@ OK: pfx /32 test (2001:db8:9f27:0:b4e2:7a3d:5f91:c8e6)
OK: pfx /32 test (2001:db8:d8b4:0:193c:a5e7:8b2f:46d1)
OK: IPv6 /32 prefix preserved for 2001:db8::/32
systematic prefix-length coverage
OK: IPv6 prefix preservation for /0..128
OK: IPv4-mapped prefix preservation for /0..32
functional tests
OK: Key generation functions
OK: In-place encryption/decryption
@@ -66,4 +70,9 @@ OK: pfx in-place encryption/decryption
OK: IPv6 :: round-trips
OK: IPv6 all-ones round-trips
randomized property tests
OK: randomized round-trip tests
OK: randomized IPv6 prefix preservation
OK: randomized IPv4-mapped prefix preservation
All specification test vectors passed!
+55
View File
@@ -210,6 +210,61 @@ main(void)
}
}
/* Test zero-length update and squeeze are no-ops */
crypto_xof_shake128_init(&state);
crypto_xof_shake128_update(&state, msg_abc, 1);
crypto_xof_shake128_update(&state, msg_abc, 0);
crypto_xof_shake128_update(&state, msg_abc + 1, 2);
crypto_xof_shake128_squeeze(&state, out, 0);
crypto_xof_shake128_squeeze(&state, out, 32);
if (memcmp(out, out_abc_32, 32) != 0) {
printf("Zero-length update/squeeze test failed\n");
return 1;
}
/* Test rate-sized input and long output (padding after full block) */
{
unsigned char out_manual[crypto_xof_shake128_BLOCKBYTES + 7];
unsigned char out_impl[crypto_xof_shake128_BLOCKBYTES + 7];
shake128_manual_with_domain(out_manual, sizeof out_manual, msg_rate_block,
sizeof msg_rate_block, crypto_xof_shake128_domain_standard());
crypto_xof_shake128_init(&state);
crypto_xof_shake128_update(&state, msg_rate_block, sizeof msg_rate_block);
crypto_xof_shake128_squeeze(&state, out_impl, sizeof out_impl);
if (memcmp(out_manual, out_impl, sizeof out_manual) != 0) {
printf("Rate block long output test failed\n");
return 1;
}
}
/* Test chunked update across block boundary */
{
unsigned char msg_rate_plus1[crypto_xof_shake128_BLOCKBYTES + 1];
unsigned char out_manual[32];
unsigned char out_impl[32];
for (i = 0; i < sizeof msg_rate_plus1; i++) {
msg_rate_plus1[i] = (unsigned char) i;
}
shake128_manual_with_domain(out_manual, sizeof out_manual, msg_rate_plus1,
sizeof msg_rate_plus1, crypto_xof_shake128_domain_standard());
crypto_xof_shake128_init(&state);
crypto_xof_shake128_update(&state, msg_rate_plus1, 1);
crypto_xof_shake128_update(&state, msg_rate_plus1 + 1, crypto_xof_shake128_BLOCKBYTES - 1);
crypto_xof_shake128_update(&state, msg_rate_plus1 + crypto_xof_shake128_BLOCKBYTES, 1);
crypto_xof_shake128_squeeze(&state, out_impl, sizeof out_impl);
if (memcmp(out_manual, out_impl, sizeof out_manual) != 0) {
printf("Chunked update boundary test failed\n");
return 1;
}
}
printf("All SHAKE-128 tests passed\n");
return 0;
}
+55
View File
@@ -211,6 +211,61 @@ main(void)
}
}
/* Test zero-length update and squeeze are no-ops */
crypto_xof_shake256_init(&state);
crypto_xof_shake256_update(&state, msg_abc, 1);
crypto_xof_shake256_update(&state, msg_abc, 0);
crypto_xof_shake256_update(&state, msg_abc + 1, 2);
crypto_xof_shake256_squeeze(&state, out, 0);
crypto_xof_shake256_squeeze(&state, out, 32);
if (memcmp(out, out_abc_32, 32) != 0) {
printf("Zero-length update/squeeze test failed\n");
return 1;
}
/* Test rate-sized input and long output (padding after full block) */
{
unsigned char out_manual[crypto_xof_shake256_BLOCKBYTES + 7];
unsigned char out_impl[crypto_xof_shake256_BLOCKBYTES + 7];
shake256_manual_with_domain(out_manual, sizeof out_manual, msg_rate_block,
sizeof msg_rate_block, crypto_xof_shake256_domain_standard());
crypto_xof_shake256_init(&state);
crypto_xof_shake256_update(&state, msg_rate_block, sizeof msg_rate_block);
crypto_xof_shake256_squeeze(&state, out_impl, sizeof out_impl);
if (memcmp(out_manual, out_impl, sizeof out_manual) != 0) {
printf("Rate block long output test failed\n");
return 1;
}
}
/* Test chunked update across block boundary */
{
unsigned char msg_rate_plus1[crypto_xof_shake256_BLOCKBYTES + 1];
unsigned char out_manual[32];
unsigned char out_impl[32];
for (i = 0; i < sizeof msg_rate_plus1; i++) {
msg_rate_plus1[i] = (unsigned char) i;
}
shake256_manual_with_domain(out_manual, sizeof out_manual, msg_rate_plus1,
sizeof msg_rate_plus1, crypto_xof_shake256_domain_standard());
crypto_xof_shake256_init(&state);
crypto_xof_shake256_update(&state, msg_rate_plus1, 1);
crypto_xof_shake256_update(&state, msg_rate_plus1 + 1, crypto_xof_shake256_BLOCKBYTES - 1);
crypto_xof_shake256_update(&state, msg_rate_plus1 + crypto_xof_shake256_BLOCKBYTES, 1);
crypto_xof_shake256_squeeze(&state, out_impl, sizeof out_impl);
if (memcmp(out_manual, out_impl, sizeof out_manual) != 0) {
printf("Chunked update boundary test failed\n");
return 1;
}
}
printf("All SHAKE-256 tests passed\n");
return 0;
}
+59
View File
@@ -210,6 +210,65 @@ main(void)
}
}
/* Test zero-length update and squeeze are no-ops */
crypto_xof_turboshake128_init(&state);
crypto_xof_turboshake128_update(&state, msg_abc, 1);
crypto_xof_turboshake128_update(&state, msg_abc, 0);
crypto_xof_turboshake128_update(&state, msg_abc + 1, 2);
crypto_xof_turboshake128_squeeze(&state, out, 0);
crypto_xof_turboshake128_squeeze(&state, out, 32);
if (memcmp(out, out_abc_32, 32) != 0) {
printf("Zero-length update/squeeze test failed\n");
return 1;
}
/* Test rate-sized input and long output (padding after full block) */
{
unsigned char out_manual[crypto_xof_turboshake128_BLOCKBYTES + 7];
unsigned char out_impl[crypto_xof_turboshake128_BLOCKBYTES + 7];
turboshake128_manual_with_domain(out_manual, sizeof out_manual, msg_rate_block,
sizeof msg_rate_block,
crypto_xof_turboshake128_domain_standard());
crypto_xof_turboshake128_init(&state);
crypto_xof_turboshake128_update(&state, msg_rate_block, sizeof msg_rate_block);
crypto_xof_turboshake128_squeeze(&state, out_impl, sizeof out_impl);
if (memcmp(out_manual, out_impl, sizeof out_manual) != 0) {
printf("Rate block long output test failed\n");
return 1;
}
}
/* Test chunked update across block boundary */
{
unsigned char msg_rate_plus1[crypto_xof_turboshake128_BLOCKBYTES + 1];
unsigned char out_manual[32];
unsigned char out_impl[32];
for (i = 0; i < sizeof msg_rate_plus1; i++) {
msg_rate_plus1[i] = (unsigned char) i;
}
turboshake128_manual_with_domain(out_manual, sizeof out_manual, msg_rate_plus1,
sizeof msg_rate_plus1,
crypto_xof_turboshake128_domain_standard());
crypto_xof_turboshake128_init(&state);
crypto_xof_turboshake128_update(&state, msg_rate_plus1, 1);
crypto_xof_turboshake128_update(&state, msg_rate_plus1 + 1,
crypto_xof_turboshake128_BLOCKBYTES - 1);
crypto_xof_turboshake128_update(&state,
msg_rate_plus1 + crypto_xof_turboshake128_BLOCKBYTES, 1);
crypto_xof_turboshake128_squeeze(&state, out_impl, sizeof out_impl);
if (memcmp(out_manual, out_impl, sizeof out_manual) != 0) {
printf("Chunked update boundary test failed\n");
return 1;
}
}
printf("All TurboSHAKE-128 tests passed\n");
return 0;
}
+59
View File
@@ -210,6 +210,65 @@ main(void)
}
}
/* Test zero-length update and squeeze are no-ops */
crypto_xof_turboshake256_init(&state);
crypto_xof_turboshake256_update(&state, msg_abc, 1);
crypto_xof_turboshake256_update(&state, msg_abc, 0);
crypto_xof_turboshake256_update(&state, msg_abc + 1, 2);
crypto_xof_turboshake256_squeeze(&state, out, 0);
crypto_xof_turboshake256_squeeze(&state, out, 32);
if (memcmp(out, out_abc_32, 32) != 0) {
printf("Zero-length update/squeeze test failed\n");
return 1;
}
/* Test rate-sized input and long output (padding after full block) */
{
unsigned char out_manual[crypto_xof_turboshake256_BLOCKBYTES + 7];
unsigned char out_impl[crypto_xof_turboshake256_BLOCKBYTES + 7];
turboshake256_manual_with_domain(out_manual, sizeof out_manual, msg_rate_block,
sizeof msg_rate_block,
crypto_xof_turboshake256_domain_standard());
crypto_xof_turboshake256_init(&state);
crypto_xof_turboshake256_update(&state, msg_rate_block, sizeof msg_rate_block);
crypto_xof_turboshake256_squeeze(&state, out_impl, sizeof out_impl);
if (memcmp(out_manual, out_impl, sizeof out_manual) != 0) {
printf("Rate block long output test failed\n");
return 1;
}
}
/* Test chunked update across block boundary */
{
unsigned char msg_rate_plus1[crypto_xof_turboshake256_BLOCKBYTES + 1];
unsigned char out_manual[32];
unsigned char out_impl[32];
for (i = 0; i < sizeof msg_rate_plus1; i++) {
msg_rate_plus1[i] = (unsigned char) i;
}
turboshake256_manual_with_domain(out_manual, sizeof out_manual, msg_rate_plus1,
sizeof msg_rate_plus1,
crypto_xof_turboshake256_domain_standard());
crypto_xof_turboshake256_init(&state);
crypto_xof_turboshake256_update(&state, msg_rate_plus1, 1);
crypto_xof_turboshake256_update(&state, msg_rate_plus1 + 1,
crypto_xof_turboshake256_BLOCKBYTES - 1);
crypto_xof_turboshake256_update(&state,
msg_rate_plus1 + crypto_xof_turboshake256_BLOCKBYTES, 1);
crypto_xof_turboshake256_squeeze(&state, out_impl, sizeof out_impl);
if (memcmp(out_manual, out_impl, sizeof out_manual) != 0) {
printf("Chunked update boundary test failed\n");
return 1;
}
}
printf("All TurboSHAKE-256 tests passed\n");
return 0;
}