Rewrite unit tests for the Fletcher and Adler checksums to exercise

boundary conditions (low and high word overflow).
This commit is contained in:
Dag-Erling Smørgrav 2015-08-28 08:38:49 +00:00 committed by des
parent 8351719b84
commit 0961e4b2e0
2 changed files with 257 additions and 111 deletions

View file

@ -30,97 +30,95 @@
#include "cryb/impl.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <cryb/endian.h>
#include <cryb/hash.h>
#include "t.h"
#define ADLER32_INVALID 0xffffffffLU
#define TRI(n) (n * (n + 1) / 2)
static uint8_t ones8[65536];
struct t_case {
const char *desc;
const char *data;
const void *data;
size_t len;
uint32_t sum;
};
/***************************************************************************
* Test cases
*
* Most of these test cases use input sequences where each word has the
* value 1. To understand the test cases, it helps to realize that (until
* it overflows) the low word of the Adler checksum of such a sequence of
* length n is equal to n + 1, while the high word is equal to the nth
* triangular number plus n, i.e. (n*(n+1))/2+n. Also, unlike Fletcher32,
* the input width for Adler32 is always 8 bits.
*/
#define TRIpN(n) ((n * (n + 1) / 2) + n)
static struct t_case t_cases[] = {
/* trivial cases */
{
.desc = "len == 0",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.desc = "all-zeroes message",
.data = t_zero,
.len = sizeof t_zero,
.sum = sizeof t_zero << 16 | 0x0001U,
},
{
.desc = "length 0",
.data = ones8,
.len = 0,
.sum = 0x00000001,
},
/* overflow */
{
.desc = "len == 1",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.len = 1,
.sum = 0x00020002,
.desc = "high overflow - 1",
.data = ones8,
.len = 359,
.sum = (TRIpN(359U) % 65521U) << 16 | 360U,
},
{
.desc = "len == 2",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.len = 2,
.sum = 0x00060004,
.desc = "high overflow",
.data = ones8,
.len = 363,
.sum = (TRIpN(363U) % 65521U) << 16 | 364U,
},
{
.desc = "len == 3",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.len = 3,
.sum = 0x000d0007,
.desc = "low overflow - 1",
.data = ones8,
.len = 65519,
.sum = (TRIpN(65519U) % 65521U) << 16 | 65520U,
},
{
.desc = "len == 4",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.len = 4,
.sum = 0x0018000b,
.desc = "low overflow",
.data = ones8,
.len = 65520,
.sum = (TRIpN(65520U) % 65521U) << 16 | 0U,
},
{
.desc = "len == 5",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.len = 5,
.sum = 0x00280010,
.desc = "low overflow + 1",
.data = ones8,
.len = 65521,
.sum = ((TRIpN(65520U) + 1) % 65521U) << 16 | 1U,
},
{
.desc = "len == 6",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.len = 6,
.sum = 0x003e0016,
},
{
.desc = "len == 7",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.len = 7,
.sum = 0x005b001d,
},
{
.desc = "len == 8",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.len = 8,
.sum = 0x00800025,
},
{
.desc = "zeroes",
.data = (const char *)t_zero,
.len = sizeof t_zero,
.sum = (sizeof t_zero << 16) | 1,
},
/* XXX need non-zero cases which exercise modulo */
};
/***************************************************************************
* Test function
*/
static int
t_adler(char **desc CRYB_UNUSED, void *arg)
t_adler32(char **desc CRYB_UNUSED, void *arg)
{
struct t_case *t = arg;
int ret;
ret = t_compare_x32(t->sum, adler32_hash(t->data, t->len));
return (ret);
return (t_compare_x32(t->sum, adler32_hash(t->data, t->len)));
}
@ -131,13 +129,20 @@ t_adler(char **desc CRYB_UNUSED, void *arg)
int
t_prepare(int argc, char *argv[])
{
int i, n;
unsigned int i, n;
(void)argc;
(void)argv;
ones8[0] = 1;
be16enc(&ones16[0], 1);
for (i = 1; i < 65536; ++i) {
ones8[i] = ones8[0];
ones16[i] = ones16[0];
}
n = sizeof t_cases / sizeof t_cases[0];
for (i = 0; i < n; ++i)
t_add_test(t_adler, &t_cases[i], t_cases[i].desc);
if (t_cases[i].sum != 0xffffffffLU)
t_add_test(t_adler32, &t_cases[i], t_cases[i].desc);
return (0);
}

View file

@ -30,15 +30,25 @@
#include "cryb/impl.h"
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <cryb/endian.h>
#include <cryb/hash.h>
#include "t.h"
#define FLETCHER16_INVALID 0xffffU
#define FLETCHER32_INVALID 0xffffffffLU
#define FLETCHER64_INVALID 0xffffffffffffffffLLU
static uint8_t ones8[65536];
static uint16_t ones16[65536];
static uint32_t ones32[65536];
struct t_case {
const char *desc;
const char *data;
const void *data;
size_t len;
uint16_t sum16;
uint32_t sum32;
@ -47,105 +57,221 @@ struct t_case {
/***************************************************************************
* Test cases
*
* Most of these test cases use input sequences where each word has the
* value 1. To understand the test cases, it helps to realize that (until
* it overflows) the low word of the Fletcher checksum of such a sequence
* of length n is equal to n, while the high word is equal to the nth
* triangular number, i.e. (n*(n+1))/2+n. Also, remember that the input
* width for Fletcher is half the checksum width.
*/
#define TRI(n) (n * (n + 1) / 2)
static struct t_case t_cases[] = {
/* trivial cases */
{
.desc = "len == 0",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.len = 0,
.desc = "all-zeroes message",
.data = t_zero,
.len = sizeof t_zero,
.sum16 = 0x00,
.sum32 = 0x0000,
.sum64 = 0x00000000,
},
{
.desc = "len == 1",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.desc = "length 0",
.data = ones8,
.len = 0,
.sum16 = 0x00,
.sum32 = 0x0000,
.sum64 = 0x00000000,
},
/* padding */
{
.desc = "length 1",
.data = ones8,
.len = 1,
.sum16 = 0x0101,
.sum32 = 0x01000100,
.sum64 = 0x0100000001000000,
},
{
.desc = "len == 2",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.desc = "length 2",
.data = ones8,
.len = 2,
.sum16 = 0x0403,
.sum32 = 0x01020102,
.sum64 = 0x0102000001020000,
.sum16 = 0x0302,
.sum32 = 0x01010101,
.sum64 = 0x0101000001010000,
},
{
.desc = "len == 3",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.desc = "length 3",
.data = ones8,
.len = 3,
.sum16 = 0x0a06,
.sum32 = 0x05040402,
.sum64 = 0x102030001020300,
.sum16 = 0x0603,
.sum32 = 0x03020201,
.sum64 = 0x0101010001010100,
},
{
.desc = "len == 4",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.desc = "length 4",
.data = ones8,
.len = 4,
.sum16 = 0x140a,
.sum32 = 0x05080406,
.sum64 = 0x0102030401020304,
.sum16 = 0x0a04,
.sum32 = 0x03030202,
.sum64 = 0x0101010101010101,
},
{
.desc = "len == 5",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.desc = "length 5",
.data = ones8,
.len = 5,
.sum16 = 0x230f,
.sum32 = 0x0e0e0906,
.sum64 = 0x0704060806020304,
.sum16 = 0x0f05,
.sum32 = 0x06050302,
.sum64 = 0x0302020202010101,
},
{
.desc = "len == 6",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.desc = "length 6",
.data = ones8,
.len = 6,
.sum16 = 0x3815,
.sum32 = 0x0e14090c,
.sum64 = 0x070a060806080304,
.sum16 = 0x1506,
.sum32 = 0x06060303,
.sum64 = 0x0303020202020101,
},
{
.desc = "len == 7",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.desc = "length 7",
.data = ones8,
.len = 7,
.sum16 = 0x541c,
.sum32 = 0x1e20100c,
.sum64 = 0x070a0d0806080a04,
.sum16 = 0x1c07,
.sum32 = 0x0a090403,
.sum64 = 0x0303030202020201,
},
{
.desc = "len == 8",
.data = "\x01\x02\x03\x04\x05\x06\x07\x08",
.desc = "length 8",
.data = ones8,
.len = 8,
.sum16 = 0x7824,
.sum32 = 0x1e281014,
.sum64 = 0x070a0d1006080a0c,
.sum16 = 0x2408,
.sum32 = 0x0a0a0404,
.sum64 = 0x0303030302020202,
},
/* not really useful... */
/* overflow (16-bit checksum) */
{
.desc = "zeroes",
.data = (const char *)t_zero,
.len = sizeof t_zero,
.sum16 = 0x00,
.sum32 = 0x0000,
.sum64 = 0x00000000,
.desc = "high overflow - 1",
.data = ones8,
.len = 22,
.sum16 = (TRI(22) % 255) << 8 | 22,
.sum32 = FLETCHER32_INVALID,
.sum64 = FLETCHER64_INVALID,
},
/* XXX need non-zero cases which exercise modulo */
{
.desc = "high overflow",
.data = ones8,
.len = 23,
.sum16 = (TRI(23) % 255) << 8 | 23,
.sum32 = FLETCHER32_INVALID,
.sum64 = FLETCHER64_INVALID,
},
{
.desc = "low overflow - 1",
.data = ones8,
.len = 254,
.sum16 = (TRI(254) % 255) << 8 | 254,
.sum32 = FLETCHER32_INVALID,
.sum64 = FLETCHER64_INVALID,
},
{
.desc = "low overflow",
.data = ones8,
.len = 255,
.sum16 = (TRI(254) % 255) << 8 | 0,
.sum32 = FLETCHER32_INVALID,
.sum64 = FLETCHER64_INVALID,
},
{
.desc = "low overflow + 1",
.data = ones8,
.len = 256,
.sum16 = ((TRI(254) + 1) % 255) << 8 | 1,
.sum32 = FLETCHER32_INVALID,
.sum64 = FLETCHER64_INVALID,
},
/* overflow (32-bit checksum) */
{
.desc = "high overflow - 1",
.data = ones16,
.len = 362 * sizeof ones16[0],
.sum16 = FLETCHER16_INVALID,
.sum32 = (TRI(362U) % 65535U) << 16 | 362U,
.sum64 = FLETCHER64_INVALID,
},
{
.desc = "high overflow",
.data = ones16,
.len = 363 * sizeof ones16[0],
.sum16 = FLETCHER16_INVALID,
.sum32 = (TRI(363U) % 65535U) << 16 | 363U,
.sum64 = FLETCHER64_INVALID,
},
{
.desc = "low overflow - 1",
.data = ones16,
.len = 65534 * sizeof ones16[0],
.sum16 = FLETCHER16_INVALID,
.sum32 = (TRI(65534U) % 65535U) << 16 | 65534U,
.sum64 = FLETCHER64_INVALID,
},
{
.desc = "low overflow",
.data = ones16,
.len = 65535 * sizeof ones16[0],
.sum16 = FLETCHER16_INVALID,
.sum32 = (TRI(65534U) % 65535U) << 16 | 0U,
.sum64 = FLETCHER64_INVALID,
},
{
.desc = "low overflow + 1",
.data = ones16,
.len = 65536 * sizeof ones16[0],
.sum16 = FLETCHER16_INVALID,
.sum32 = ((TRI(65534U) + 1) % 65535U) << 16 | 1U,
.sum64 = FLETCHER64_INVALID,
},
/* overflow (64-bit checksum */
/*
* This is currently not realistic. We need to change the
* fletcher*() API to take a seed so it can do partial /
* incremental checksums, and provide a precomputed seed just
* below the overflow point.
*/
};
/***************************************************************************
* Test function
*/
static int
t_fletcher(char **desc CRYB_UNUSED, void *arg)
t_fletcher16(char **desc, void *arg)
{
struct t_case *t = arg;
int ret;
ret = t_compare_x16(t->sum16, fletcher16_hash(t->data, t->len)) &
t_compare_x32(t->sum32, fletcher32_hash(t->data, t->len)) &
t_compare_x64(t->sum64, fletcher64_hash(t->data, t->len));
return (ret);
asprintf(desc, "(16-bit) %s", t->desc);
return (t_compare_x16(t->sum16, fletcher16_hash(t->data, t->len)));
}
static int
t_fletcher32(char **desc, void *arg)
{
struct t_case *t = arg;
asprintf(desc, "(32-bit) %s", t->desc);
return (t_compare_x32(t->sum32, fletcher32_hash(t->data, t->len)));
}
static int
t_fletcher64(char **desc, void *arg)
{
struct t_case *t = arg;
asprintf(desc, "(64-bit) %s", t->desc);
return (t_compare_x64(t->sum64, fletcher64_hash(t->data, t->len)));
}
@ -156,13 +282,28 @@ t_fletcher(char **desc CRYB_UNUSED, void *arg)
int
t_prepare(int argc, char *argv[])
{
int i, n;
unsigned int i, n;
(void)argc;
(void)argv;
ones8[0] = 1;
be16enc(&ones16[0], 1);
be32enc(&ones32[0], 1);
for (i = 1; i < 65536; ++i) {
ones8[i] = ones8[0];
ones16[i] = ones16[0];
ones32[i] = ones32[0];
}
n = sizeof t_cases / sizeof t_cases[0];
for (i = 0; i < n; ++i)
t_add_test(t_fletcher, &t_cases[i], t_cases[i].desc);
if (t_cases[i].sum16 != 0xffffU)
t_add_test(t_fletcher16, &t_cases[i], t_cases[i].desc);
for (i = 0; i < n; ++i)
if (t_cases[i].sum32 != 0xffffffffLU)
t_add_test(t_fletcher32, &t_cases[i], t_cases[i].desc);
for (i = 0; i < n; ++i)
if (t_cases[i].sum64 != 0xffffffffffffffffLLU)
t_add_test(t_fletcher64, &t_cases[i], t_cases[i].desc);
return (0);
}