Commit 8827948b authored by Rusty Russell's avatar Rusty Russell

Convert to 64 bit crcs: change semantics of crcbits field to be *upper* not *lower* bits.

parent 86b394d9
...@@ -76,6 +76,7 @@ int main(int argc, char *argv[]) ...@@ -76,6 +76,7 @@ int main(int argc, char *argv[])
if (strcmp(argv[1], "depends") == 0) { if (strcmp(argv[1], "depends") == 0) {
printf("ccan/crc\n"); printf("ccan/crc\n");
printf("ccan/array_size\n");
return 0; return 0;
} }
......
...@@ -4,68 +4,75 @@ ...@@ -4,68 +4,75 @@
#include <assert.h> #include <assert.h>
#include <stdbool.h> #include <stdbool.h>
/* FIXME: That 64-bit CRC takes a while to warm the lower bits. Do
* some quantitative tests and replace it? Meanwhile, use upper bits. */
static uint64_t mask_of(unsigned int crcbits)
{
return -1ULL << (64 - crcbits);
}
void crc_of_blocks(const void *data, size_t len, unsigned int block_size, void crc_of_blocks(const void *data, size_t len, unsigned int block_size,
unsigned int crcbits, uint32_t crc[]) unsigned int crcbits, uint64_t crc[])
{ {
unsigned int i; unsigned int i;
const uint8_t *buf = data; const uint8_t *buf = data;
uint32_t crcmask = crcbits < 32 ? (1 << crcbits) - 1 : 0xFFFFFFFF; uint64_t crcmask = mask_of(crcbits);
for (i = 0; len >= block_size; i++) { for (i = 0; len >= block_size; i++) {
crc[i] = (crc32c(0, buf, block_size) & crcmask); crc[i] = (crc64_iso(0, buf, block_size) & crcmask);
buf += block_size; buf += block_size;
len -= block_size; len -= block_size;
} }
if (len) if (len)
crc[i] = (crc32c(0, buf, len) & crcmask); crc[i] = (crc64_iso(0, buf, len) & crcmask);
} }
struct crc_context { struct crc_context {
size_t block_size; size_t block_size;
uint32_t crcmask; uint64_t crcmask;
/* Saved old buffer bytes (block_size bytes). */ /* Saved old buffer bytes (block_size bytes). */
void *buffer; void *buffer;
size_t buffer_start, buffer_end; size_t buffer_start, buffer_end;
/* Progress so far. */ /* Progress so far. */
uint32_t running_crc; uint64_t running_crc;
size_t literal_bytes; size_t literal_bytes;
size_t total_bytes; size_t total_bytes;
int have_match; int have_match;
/* Final block is special (if a different size) */ /* Final block is special (if a different size) */
size_t tail_size; size_t tail_size;
uint32_t tail_crc; uint64_t tail_crc;
/* Uncrc tab. */ /* Uncrc tab. */
uint32_t uncrc_tab[256]; uint64_t uncrc_tab[256];
/* This doesn't count the last CRC. */ /* This doesn't count the last CRC. */
unsigned int num_crcs; unsigned int num_crcs;
uint32_t crc[]; uint64_t crc[];
}; };
/* Calculate the how the crc changes when we take a give char out of the /* Calculate the how the crc changes when we take a give char out of the
* crc'd area. */ * crc'd area. */
static void init_uncrc_tab(uint32_t uncrc_tab[], unsigned int wsize) static void init_uncrc_tab(uint64_t uncrc_tab[], unsigned int wsize)
{ {
unsigned int i; unsigned int i;
uint32_t part_crc; uint64_t part_crc;
uint8_t buffer[wsize]; uint8_t buffer[wsize];
/* Calculate crc(buffer+1, wsize-1) once, since it doesn't change. */ /* Calculate crc(buffer+1, wsize-1) once, since it doesn't change. */
memset(buffer, 0, wsize); memset(buffer, 0, wsize);
part_crc = crc32c(0, buffer+1, wsize-1); part_crc = crc64_iso(0, buffer+1, wsize-1);
for (i = 0; i < 256; i++) { for (i = 0; i < 256; i++) {
buffer[0] = i; buffer[0] = i;
uncrc_tab[i] = (crc32c(0, buffer, wsize) ^ part_crc); uncrc_tab[i] = (crc64_iso(0, buffer, wsize) ^ part_crc);
} }
} }
struct crc_context *crc_context_new(size_t block_size, unsigned crcbits, struct crc_context *crc_context_new(size_t block_size, unsigned crcbits,
const uint32_t crc[], unsigned num_crcs, const uint64_t crc[], unsigned num_crcs,
size_t tail_size) size_t tail_size)
{ {
struct crc_context *ctx; struct crc_context *ctx;
...@@ -81,11 +88,7 @@ struct crc_context *crc_context_new(size_t block_size, unsigned crcbits, ...@@ -81,11 +88,7 @@ struct crc_context *crc_context_new(size_t block_size, unsigned crcbits,
if (tail_size) if (tail_size)
ctx->tail_crc = crc[--num_crcs]; ctx->tail_crc = crc[--num_crcs];
/* Technically, 1 << 32 is undefined. */ ctx->crcmask = mask_of(crcbits);
if (crcbits >= 32)
ctx->crcmask = 0xFFFFFFFF;
else
ctx->crcmask = (1 << crcbits)-1;
ctx->num_crcs = num_crcs; ctx->num_crcs = num_crcs;
memcpy(ctx->crc, crc, sizeof(crc[0])*num_crcs); memcpy(ctx->crc, crc, sizeof(crc[0])*num_crcs);
ctx->buffer_end = 0; ctx->buffer_end = 0;
...@@ -126,19 +129,19 @@ static bool tail_matches(const struct crc_context *ctx) ...@@ -126,19 +129,19 @@ static bool tail_matches(const struct crc_context *ctx)
return (ctx->running_crc & ctx->crcmask) == ctx->tail_crc; return (ctx->running_crc & ctx->crcmask) == ctx->tail_crc;
} }
static uint32_t crc_add_byte(uint32_t crc, uint8_t newbyte) static uint64_t crc_add_byte(uint64_t crc, uint8_t newbyte)
{ {
return crc32c(crc, &newbyte, 1); return crc64_iso(crc, &newbyte, 1);
} }
static uint32_t crc_remove_byte(uint32_t crc, uint8_t oldbyte, static uint64_t crc_remove_byte(uint64_t crc, uint8_t oldbyte,
const uint32_t uncrc_tab[]) const uint64_t uncrc_tab[])
{ {
return crc ^ uncrc_tab[oldbyte]; return crc ^ uncrc_tab[oldbyte];
} }
static uint32_t crc_roll(uint32_t crc, uint8_t oldbyte, uint8_t newbyte, static uint64_t crc_roll(uint64_t crc, uint8_t oldbyte, uint8_t newbyte,
const uint32_t uncrc_tab[]) const uint64_t uncrc_tab[])
{ {
return crc_add_byte(crc_remove_byte(crc, oldbyte, uncrc_tab), newbyte); return crc_add_byte(crc_remove_byte(crc, oldbyte, uncrc_tab), newbyte);
} }
......
...@@ -8,19 +8,19 @@ ...@@ -8,19 +8,19 @@
* @data: pointer to the buffer to CRC * @data: pointer to the buffer to CRC
* @len: length of the buffer * @len: length of the buffer
* @blocksize: CRC of each block (final block may be shorter) * @blocksize: CRC of each block (final block may be shorter)
* @crcbits: the number of bits of crc you want (currently 32 maximum) * @crcbits: the number of bits of crc you want (currently 64 maximum)
* @crc: the crcs (array will have (len + blocksize-1)/blocksize entries). * @crc: the crcs (array will have (len + blocksize-1)/blocksize entries).
* *
* Calculates the CRC of each block, and output the lower @crcbits to * Calculates the CRC of each block, and output the lower @crcbits to
* @crc array. * @crc array.
*/ */
void crc_of_blocks(const void *data, size_t len, unsigned int blocksize, void crc_of_blocks(const void *data, size_t len, unsigned int blocksize,
unsigned int crcbits, uint32_t crc[]); unsigned int crcbits, uint64_t crc[]);
/** /**
* crc_context_new - allocate and initialize state for crc_find_block * crc_context_new - allocate and initialize state for crc_find_block
* @blocksize: the size of each block * @blocksize: the size of each block
* @crcbits: the bits valid in the CRCs (<= 32) * @crcbits: the bits valid in the CRCs (<= 64)
* @crc: array of block crcs (including final block, if any) * @crc: array of block crcs (including final block, if any)
* @num_crcs: number of block crcs * @num_crcs: number of block crcs
* @tail_size: the size of final partial block, if any (< blocksize). * @tail_size: the size of final partial block, if any (< blocksize).
...@@ -29,7 +29,7 @@ void crc_of_blocks(const void *data, size_t len, unsigned int blocksize, ...@@ -29,7 +29,7 @@ void crc_of_blocks(const void *data, size_t len, unsigned int blocksize,
* or NULL. Makes a copy of @crc. * or NULL. Makes a copy of @crc.
*/ */
struct crc_context *crc_context_new(size_t blocksize, unsigned crcbits, struct crc_context *crc_context_new(size_t blocksize, unsigned crcbits,
const uint32_t crc[], unsigned num_crcs, const uint64_t crc[], unsigned num_crcs,
size_t final_size); size_t final_size);
/** /**
......
...@@ -11,14 +11,14 @@ ...@@ -11,14 +11,14 @@
typedef struct { typedef struct {
int block_count; int block_count;
unsigned int *crcs; uint64_t *crcs;
} crc_info_t; } crc_info_t;
static void crcblocks(crc_info_t *crc_info, char *data, int datalen, int blocksize) static void crcblocks(crc_info_t *crc_info, char *data, int datalen, int blocksize)
{ {
crc_info->block_count = (datalen+blocksize-1)/blocksize; crc_info->block_count = (datalen+blocksize-1)/blocksize;
crc_info->crcs = malloc(sizeof(unsigned int)*(crc_info->block_count + 1)); crc_info->crcs = malloc(sizeof(uint64_t)*(crc_info->block_count + 1));
crc_of_blocks(data, datalen, blocksize, 30, crc_info->crcs); crc_of_blocks(data, datalen, blocksize, 60, crc_info->crcs);
} }
#define BLOCKSIZE 5 #define BLOCKSIZE 5
...@@ -61,7 +61,7 @@ int main(int argc, char *argv[]) ...@@ -61,7 +61,7 @@ int main(int argc, char *argv[])
plan_tests(ARRAY_SIZE(expected) + 2); plan_tests(ARRAY_SIZE(expected) + 2);
crcblocks(&crc_info1, data1, strlen(data1), BLOCKSIZE); crcblocks(&crc_info1, data1, strlen(data1), BLOCKSIZE);
crcctx = crc_context_new(BLOCKSIZE, 30, crc_info1.crcs, crc_info1.block_count, crcctx = crc_context_new(BLOCKSIZE, 60, crc_info1.crcs, crc_info1.block_count,
tailsize); tailsize);
while ( offset < len2) while ( offset < len2)
{ {
......
...@@ -6,29 +6,29 @@ int main(int argc, char *argv[]) ...@@ -6,29 +6,29 @@ int main(int argc, char *argv[])
{ {
char buffer[1024]; char buffer[1024];
unsigned int i, j; unsigned int i, j;
uint32_t crcs[12] = { 0xFFFFF, 0xdeadf00d }; uint64_t crcs[12] = { 0xFFFFF, 0xdeadf00d };
plan_tests(3 + 8192); plan_tests(3 + 8192);
/* Simple test (we know currently crc of 0s is 0) */ /* Simple test (we know currently crc of 0s is 0) */
memset(buffer, 0, sizeof(buffer)); memset(buffer, 0, sizeof(buffer));
crc_of_blocks(buffer, sizeof(buffer), sizeof(buffer), 32, crcs); crc_of_blocks(buffer, sizeof(buffer), sizeof(buffer), 64, crcs);
ok1(crcs[0] == 0); ok1(crcs[0] == 0);
crc_of_blocks(buffer, sizeof(buffer), sizeof(buffer)/2, 32, crcs); crc_of_blocks(buffer, sizeof(buffer), sizeof(buffer)/2, 64, crcs);
ok1(crcs[0] == 0); ok1(crcs[0] == 0);
ok1(crcs[1] == 0); ok1(crcs[1] == 0);
/* We know they're using crc32c. */ /* We know they're using crc64_iso. */
for (i = 0; i < sizeof(buffer); i++) { for (i = 0; i < sizeof(buffer); i++) {
buffer[i] = i; buffer[i] = i;
crc_of_blocks(buffer, sizeof(buffer), sizeof(buffer)/7, crc_of_blocks(buffer, sizeof(buffer), sizeof(buffer)/7,
32, crcs); 64, crcs);
for (j = 0; j < sizeof(buffer); j += sizeof(buffer)/7) { for (j = 0; j < sizeof(buffer); j += sizeof(buffer)/7) {
unsigned int len = sizeof(buffer)/7; unsigned int len = sizeof(buffer)/7;
if (j + len > sizeof(buffer)) if (j + len > sizeof(buffer))
len = sizeof(buffer) - j; len = sizeof(buffer) - j;
ok1(crc32c(0, buffer + j, len) == crcs[j/(sizeof(buffer)/7)]); ok1(crc64_iso(0, buffer + j, len) == crcs[j/(sizeof(buffer)/7)]);
} }
} }
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
static void test_roll(unsigned int wsize) static void test_roll(unsigned int wsize)
{ {
uint8_t data[wsize * 2]; uint8_t data[wsize * 2];
uint32_t uncrc_tab[256]; uint64_t uncrc_tab[256];
unsigned int i; unsigned int i;
init_uncrc_tab(uncrc_tab, wsize); init_uncrc_tab(uncrc_tab, wsize);
...@@ -19,10 +19,10 @@ static void test_roll(unsigned int wsize) ...@@ -19,10 +19,10 @@ static void test_roll(unsigned int wsize)
data[i] = random(); data[i] = random();
for (i = 1; i < ARRAY_SIZE(data) - wsize; i++) { for (i = 1; i < ARRAY_SIZE(data) - wsize; i++) {
uint32_t rollcrc, crc; uint64_t rollcrc, crc;
crc = crc32c(0, data+i, wsize); crc = crc64_iso(0, data+i, wsize);
rollcrc = crc_roll(crc32c(0, data+i-1, wsize), rollcrc = crc_roll(crc64_iso(0, data+i-1, wsize),
data[i-1], data[i+wsize-1], uncrc_tab); data[i-1], data[i+wsize-1], uncrc_tab);
ok(crc == rollcrc, "wsize %u, i %u", wsize, i); ok(crc == rollcrc, "wsize %u, i %u", wsize, i);
......
...@@ -67,14 +67,14 @@ static void test_sync(const char *buffer1, size_t len1, ...@@ -67,14 +67,14 @@ static void test_sync(const char *buffer1, size_t len1,
struct crc_context *ctx; struct crc_context *ctx;
size_t used, ret, i, curr_literal, tailsize; size_t used, ret, i, curr_literal, tailsize;
long result; long result;
uint32_t crcs[num_blocks(len1, block_size)]; uint64_t crcs[num_blocks(len1, block_size)];
crc_of_blocks(buffer1, len1, block_size, 32, crcs); crc_of_blocks(buffer1, len1, block_size, 64, crcs);
tailsize = len1 % block_size; tailsize = len1 % block_size;
/* Normal method. */ /* Normal method. */
ctx = crc_context_new(block_size, 32, crcs, ARRAY_SIZE(crcs), ctx = crc_context_new(block_size, 64, crcs, ARRAY_SIZE(crcs),
tailsize); tailsize);
curr_literal = 0; curr_literal = 0;
...@@ -93,7 +93,7 @@ static void test_sync(const char *buffer1, size_t len1, ...@@ -93,7 +93,7 @@ static void test_sync(const char *buffer1, size_t len1,
crc_context_free(ctx); crc_context_free(ctx);
/* Byte-at-a-time method. */ /* Byte-at-a-time method. */
ctx = crc_context_new(block_size, 32, crcs, ARRAY_SIZE(crcs), ctx = crc_context_new(block_size, 64, crcs, ARRAY_SIZE(crcs),
tailsize); tailsize);
curr_literal = 0; curr_literal = 0;
...@@ -121,7 +121,7 @@ int main(int argc, char *argv[]) ...@@ -121,7 +121,7 @@ int main(int argc, char *argv[])
{ {
char *buffer1, *buffer2; char *buffer1, *buffer2;
unsigned int i; unsigned int i;
uint32_t crcs1[NUM_BLOCKS], crcs2[NUM_BLOCKS]; uint64_t crcs1[NUM_BLOCKS], crcs2[NUM_BLOCKS];
plan_tests(664); plan_tests(664);
...@@ -130,9 +130,9 @@ int main(int argc, char *argv[]) ...@@ -130,9 +130,9 @@ int main(int argc, char *argv[])
/* Truncated end block test. */ /* Truncated end block test. */
crcs1[ARRAY_SIZE(crcs1)-1] = 0xdeadbeef; crcs1[ARRAY_SIZE(crcs1)-1] = 0xdeadbeef;
crc_of_blocks(buffer1, BUFFER_SIZE-BLOCK_SIZE-1, BLOCK_SIZE, 32, crcs1); crc_of_blocks(buffer1, BUFFER_SIZE-BLOCK_SIZE-1, BLOCK_SIZE, 64, crcs1);
ok1(crcs1[ARRAY_SIZE(crcs1)-1] == 0xdeadbeef); ok1(crcs1[ARRAY_SIZE(crcs1)-1] == 0xdeadbeef);
crc_of_blocks(buffer2, BUFFER_SIZE-BLOCK_SIZE-1, BLOCK_SIZE, 32, crcs2); crc_of_blocks(buffer2, BUFFER_SIZE-BLOCK_SIZE-1, BLOCK_SIZE, 64, crcs2);
ok1(memcmp(crcs1, crcs2, sizeof(crcs1[0])*(ARRAY_SIZE(crcs1)-1)) == 0); ok1(memcmp(crcs1, crcs2, sizeof(crcs1[0])*(ARRAY_SIZE(crcs1)-1)) == 0);
/* Fill with non-zero pattern, retest. */ /* Fill with non-zero pattern, retest. */
...@@ -140,16 +140,16 @@ int main(int argc, char *argv[]) ...@@ -140,16 +140,16 @@ int main(int argc, char *argv[])
buffer1[i] = buffer2[i] = i + i/BLOCK_SIZE; buffer1[i] = buffer2[i] = i + i/BLOCK_SIZE;
crcs1[ARRAY_SIZE(crcs1)-1] = 0xdeadbeef; crcs1[ARRAY_SIZE(crcs1)-1] = 0xdeadbeef;
crc_of_blocks(buffer1, BUFFER_SIZE-BLOCK_SIZE-1, BLOCK_SIZE, 32, crcs1); crc_of_blocks(buffer1, BUFFER_SIZE-BLOCK_SIZE-1, BLOCK_SIZE, 64, crcs1);
ok1(crcs1[ARRAY_SIZE(crcs1)-1] == 0xdeadbeef); ok1(crcs1[ARRAY_SIZE(crcs1)-1] == 0xdeadbeef);
crc_of_blocks(buffer2, BUFFER_SIZE-BLOCK_SIZE-1, BLOCK_SIZE, 32, crcs2); crc_of_blocks(buffer2, BUFFER_SIZE-BLOCK_SIZE-1, BLOCK_SIZE, 64, crcs2);
ok1(memcmp(crcs1, crcs2, sizeof(crcs1[0])*(ARRAY_SIZE(crcs1)-1)) == 0); ok1(memcmp(crcs1, crcs2, sizeof(crcs1[0])*(ARRAY_SIZE(crcs1)-1)) == 0);
/* Check that it correctly masks bits. */ /* Check that it correctly masks bits. */
crc_of_blocks(buffer1, BUFFER_SIZE, BLOCK_SIZE, 32, crcs1); crc_of_blocks(buffer1, BUFFER_SIZE, BLOCK_SIZE, 64, crcs1);
crc_of_blocks(buffer2, BUFFER_SIZE, BLOCK_SIZE, 8, crcs2); crc_of_blocks(buffer2, BUFFER_SIZE, BLOCK_SIZE, 8, crcs2);
for (i = 0; i < NUM_BLOCKS; i++) for (i = 0; i < NUM_BLOCKS; i++)
ok1(crcs2[i] == (crcs1[i] & 0xFF)); ok1(crcs2[i] == (crcs1[i] & 0xFF00000000000000ULL));
/* Now test the "exact match" "round blocks" case. */ /* Now test the "exact match" "round blocks" case. */
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment