diff --git a/include/crucible/crc64.h b/include/crucible/crc64.h index 0bd8d11..d4d4612 100644 --- a/include/crucible/crc64.h +++ b/include/crucible/crc64.h @@ -3,6 +3,7 @@ #include #include +#include namespace crucible { namespace Digest { diff --git a/lib/crc64.cc b/lib/crc64.cc index 90dc87d..90ef5d7 100644 --- a/lib/crc64.cc +++ b/lib/crc64.cc @@ -1,3 +1,31 @@ +/* crc64.c -- compute CRC-64 + * Copyright (C) 2013 Mark Adler + * Version 1.4 16 Dec 2013 Mark Adler + */ + +/* + This software is provided 'as-is', without any express or implied + warranty. In no event will the author be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. + + Mark Adler + madler@alumni.caltech.edu + */ + +/* Substantially modified by Paul Jones for usage in bees */ + #include "crucible/crc64.h" #define POLY64REV 0xd800000000000000ULL @@ -5,13 +33,16 @@ namespace crucible { static bool init = false; - static uint64_t CRCTable[256]; + static uint64_t CRCTable[8][256]; static void init_crc64_table() { if (!init) { - for (int i = 0; i <= 255; i++) { - uint64_t part = i; + uint64_t crc; + + // Generate CRCs for all single byte sequences + for (int n = 0; n < 256; n++) { + uint64_t part = n; for (int j = 0; j < 8; j++) { if (part & 1) { part = (part >> 1) ^ POLY64REV; @@ -19,37 +50,60 @@ namespace crucible { part >>= 1; } } - CRCTable[i] = part; + CRCTable[0][n] = part; + } + + // Generate nested CRC table for slice-by-8 lookup + for (int n = 0; n < 256; n++) { + crc = CRCTable[0][n]; + for (int k = 1; k < 8; k++) { + crc = CRCTable[0][crc & 0xff] ^ (crc >> 8); + CRCTable[k][n] = crc; + } } init = true; } } + // This function is only used for tests uint64_t Digest::CRC::crc64(const char *s) { - init_crc64_table(); - - uint64_t crc = 0; - for (; *s; s++) { - uint64_t temp1 = crc >> 8; - uint64_t temp2 = CRCTable[(crc ^ static_cast(*s)) & 0xff]; - crc = temp1 ^ temp2; - } - - return crc; + return crc64(static_cast(s), strlen(s)); } uint64_t Digest::CRC::crc64(const void *p, size_t len) { init_crc64_table(); - + const unsigned char *next = static_cast(p); uint64_t crc = 0; - for (const unsigned char *s = static_cast(p); len; --len) { - uint64_t temp1 = crc >> 8; - uint64_t temp2 = CRCTable[(crc ^ *s++) & 0xff]; - crc = temp1 ^ temp2; + + // Process individual bytes until we reach an 8-byte aligned pointer + while (len && (reinterpret_cast(next) & 7) != 0) { + crc = CRCTable[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); + len--; + } + + // Fast middle processing, 8 bytes (aligned!) per loop + while (len >= 8) { + crc ^= *(reinterpret_cast< const uint64_t *>(next)); + crc = CRCTable[7][crc & 0xff] ^ + CRCTable[6][(crc >> 8) & 0xff] ^ + CRCTable[5][(crc >> 16) & 0xff] ^ + CRCTable[4][(crc >> 24) & 0xff] ^ + CRCTable[3][(crc >> 32) & 0xff] ^ + CRCTable[2][(crc >> 40) & 0xff] ^ + CRCTable[1][(crc >> 48) & 0xff] ^ + CRCTable[0][crc >> 56]; + next += 8; + len -= 8; + } + + // Process remaining bytes (can't be larger than 8) + while (len) { + crc = CRCTable[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); + len--; } return crc;