Skip to content

Commit

Permalink
Merge pull request #177 from animetosho/optimise_hashing
Browse files Browse the repository at this point in the history
CRC32/MD5 optimisations
  • Loading branch information
BlackIkeEagle authored May 31, 2023
2 parents 0b266b5 + fae76a7 commit 277cda9
Show file tree
Hide file tree
Showing 9 changed files with 140 additions and 125 deletions.
79 changes: 57 additions & 22 deletions src/crc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,46 @@ static char THIS_FILE[]=__FILE__;
// https://en.wikipedia.org/wiki/Cyclic_redundancy_check
crc32table ccitttable(0xEDB88320L);


// GF32 multiplication
#define NEGATE32(n) (u32)(-((i32)(n)))
static u32 GF32Multiply(u32 a, u32 b, u32 polynomial)
{
u32 product = 0;
for (u32 i=0; i<31; i++)
{
product ^= NEGATE32(b >> 31) & a;
a = ((a >> 1) ^ (polynomial & NEGATE32(a & 1)));
b <<= 1;
}
product ^= NEGATE32(b >> 31) & a;
return product;
}

// Compute 2^(8n) in CRC's GF
static u32 CRCExp8(u64 n)
{
u32 result = 0x80000000;
u32 power = 0;
n %= 0xffffffff;
while (n)
{
if (n & 1)
result = GF32Multiply(result, ccitttable.power[power], ccitttable.polynom);
n >>= 1;
power = (power + 1) & 31;
}
return result;
}


// Construct the CRC32 lookup table from the specified polynomial
//
// This seems to follow:
// http://www.efg2.com/Lab/Library/UseNet/1999/0117.txt
void GenerateCRC32Table(u32 polynomial, u32 (&table)[256])
crc32table::crc32table(u32 polynomial)
{
polynom = polynomial;
for (u32 i = 0; i <= 255 ; i++)
{
u32 crc = i;
Expand All @@ -52,36 +86,37 @@ void GenerateCRC32Table(u32 polynomial, u32 (&table)[256])

table[i] = crc;
}

// Also construct the table used for computing power
// Note that the table is rotated by 3 entries, since we operate on bytes, i.e. 1<<3 bits
u32 k = 0x80000000 >> 1;
for (u32 i = 0; i < 32; i++)
{
power[(i - 3) & 31] = k;
k = GF32Multiply(k, k, polynomial);
}
}

// Construct a CRC32 lookup table for windowing
void GenerateWindowTable(u64 window, u32 (&target)[256])
{
#pragma omp parallel for
// Window coefficient
u32 coeff = CRCExp8(window);
// Extend initial CRC to window length
u32 mask = GF32Multiply(~0, coeff, ccitttable.polynom);
// Xor initial CRC with that extended by one byte
mask = GF32Multiply(mask, 0x80800000, ccitttable.polynom);
// Since we have a table, may as well invert all bits to save doing it later
mask ^= ~0;

// Generate table
for (i16 i=0; i<=255; i++)
{
u32 crc = ccitttable.table[i];

for (u64 j=0; j<window; j++)
{
crc = ((crc >> 8) & 0x00ffffffL) ^ ccitttable.table[(u8)crc];
}

target[i] = crc;
target[i] = GF32Multiply(ccitttable.table[i], coeff, ccitttable.polynom) ^ mask;
}
}

// Construct the mask value to apply to the CRC when windowing
u32 ComputeWindowMask(u64 window)
u32 CRCUpdateBlock(u32 crc, u64 length)
{
u32 result = ~0;
while (window > 0)
{
result = CRCUpdateChar(result, (char)0);

window--;
}
result ^= ~0;

return result;
return GF32Multiply(crc, CRCExp8(length), ccitttable.polynom);
}
26 changes: 6 additions & 20 deletions src/crc.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,18 +32,14 @@
// same size but offset one character later in the buffer.


// Construct the CRC32 lookup table from the specified polynomial
void GenerateCRC32Table(u32 polynomial, u32 (&table)[256]);

// A CRC32 lookup table
struct crc32table
{
crc32table(u32 polynomial)
{
GenerateCRC32Table(polynomial, table);
}
u32 polynom;
crc32table(u32 polynomial);

u32 table[256];
u32 power[32];
};

// The one and only CCITT CRC32 lookup table
Expand Down Expand Up @@ -72,26 +68,17 @@ inline u32 CRCUpdateBlock(u32 crc, size_t length, const void *buffer)
}

// Update the CRC using a block of 0s.
inline u32 CRCUpdateBlock(u32 crc, size_t length)
{
while (length-- > 0)
{
crc = ((crc >> 8) & 0x00ffffffL) ^ ccitttable.table[(u8)crc];
}

return crc;
}
u32 CRCUpdateBlock(u32 crc, u64 length);

// Construct a CRC32 lookup table for windowing
void GenerateWindowTable(u64 window, u32 (&windowtable)[256]);
// Construct the mask value to apply to the CRC when windowing
u32 ComputeWindowMask(u64 window);

// Slide the CRC along a buffer by one character (removing the old and adding the new).
// The new character is added using the main CCITT CRC32 table, and the old character
// is removed using the windowtable.
inline u32 CRCSlideChar(u32 crc, u8 chNew, u8 chOld, const u32 (&windowtable)[256])
{
crc ^= ~0;
return ((crc >> 8) & 0x00ffffffL) ^ ccitttable.table[(u8)crc ^ chNew] ^ windowtable[chOld];
}

Expand All @@ -104,10 +91,9 @@ inline u32 CRCSlideChar(u32 crc, u8 chNew, u8 chOld, const u32 (&windowtable)[25
u32 windowtable[256];
GenerateWindowTable(window, windowtable);
u32 windowmask = ComputeWindowMask(window);
u32 crc = ~0 ^ CRCUpdateBlock(~0, window, buffer);
crc = windowmask ^ CRCSlideChar(windowmask ^ crc, buffer[window], buffer[0], windowtable);
crc = CRCSlideChar(crc, buffer[window], buffer[0], windowtable);
assert(crc == ~0 ^ CRCUpdateBlock(~0, window, buffer+1));
Expand Down
5 changes: 2 additions & 3 deletions src/crc_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,6 @@ int test5() {

u32 windowtable[256];
GenerateWindowTable(window, windowtable);
u32 windowmask = ComputeWindowMask(window);

int result = 0;

Expand All @@ -186,7 +185,7 @@ int test5() {
}

// slide window
crc = windowmask ^ CRCSlideChar(windowmask ^ crc, buffer[offset + window], buffer[offset], windowtable);
crc = CRCSlideChar(crc, buffer[offset + window], buffer[offset], windowtable);
}

return result;
Expand All @@ -197,7 +196,7 @@ int test5() {
// stolen from:
// http://www.efg2.com/Lab/Mathematics/CRC.htm
int test6() {
u32 checksum1 = ~0 ^ CRCUpdateBlock(~0, sizeof(ccitttable), &ccitttable);
u32 checksum1 = ~0 ^ CRCUpdateBlock(~0, sizeof(ccitttable.table), &ccitttable.table);
u32 expected = 0x6FCF9E13;
if (checksum1 != expected) {
cerr << "error when computing checksum of checksum table " << endl;
Expand Down
4 changes: 1 addition & 3 deletions src/filechecksummer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,10 @@ static char THIS_FILE[]=__FILE__;

FileCheckSummer::FileCheckSummer(DiskFile *_diskfile,
u64 _blocksize,
const u32 (&_windowtable)[256],
u32 _windowmask)
const u32 (&_windowtable)[256])
: diskfile(_diskfile)
, blocksize(_blocksize)
, windowtable(_windowtable)
, windowmask(_windowmask)
, filesize(_diskfile->FileSize())
, currentoffset(0)
, buffer(0)
Expand Down
6 changes: 2 additions & 4 deletions src/filechecksummer.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,7 @@ class FileCheckSummer
public:
FileCheckSummer(DiskFile *diskfile,
u64 blocksize,
const u32 (&windowtable)[256],
u32 windowmask);
const u32 (&windowtable)[256]);
~FileCheckSummer(void);

// Start reading the file at the beginning
Expand Down Expand Up @@ -79,7 +78,6 @@ class FileCheckSummer
DiskFile *diskfile;
u64 blocksize;
const u32 (&windowtable)[256];
u32 windowmask;

u64 filesize;

Expand Down Expand Up @@ -162,7 +160,7 @@ inline bool FileCheckSummer::Step(void)
char outch = *outpointer++;

// Update the checksum
checksum = windowmask ^ CRCSlideChar(windowmask ^ checksum, inch, outch, windowtable);
checksum = CRCSlideChar(checksum, inch, outch, windowtable);

// Can the window slide further
if (outpointer < &buffer[blocksize])
Expand Down
Loading

0 comments on commit 277cda9

Please sign in to comment.