#include #include #include // CRC Constants. #define BYTE_WIDTH 8 #define POLY_WIDTH 64 #define TWO_UP_EIGHT 256 #define LEFT_BYTE_SHIFT 56 #define W_BYTES 8 // The pre-compiled CRC-64 lookup-table is stored in this file. #define LOOKUP_TABLE_FILE "CRC-64.dat" // 17x17 4-Colouring Constants. #define POSITION_COUNT 289 #define CHAR_COUNT 73 #define COLOURS 4 #define POSITIONS_PER_NODE 4 // These values are used to decode unsigned long ints into binary format for output. const unsigned long int PowersOfTwo[POLY_WIDTH] = {1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 2048, 4096, 8192, 16384, 32768, 65536, 131072, 262144, 524288, 1048576, 2097152, 4194304, 8388608, 16777216, 33554432, 67108864, 134217728, 268435456, 536870912, 1073741824, 2147483648, 4294967296, 8589934592, 17179869184, 34359738368, 68719476736, 137438953472, 274877906944, 549755813888, 1099511627776, 2199023255552, 4398046511104, 8796093022208, 17592186044416, 35184372088832, 70368744177664, 140737488355328, 281474976710656, 562949953421312, 1125899906842624, 2251799813685248, 4503599627370496, 9007199254740992, 18014398509481984, 36028797018963968, 72057594037927936, 144115188075855872, 288230376151711744, 576460752303423488, 1152921504606846976, 2305843009213693952, 4611686018427387904, 9223372036854775808}; // This value is integrated into "CrcLookupTable", but it will not be needed explicitly. const unsigned long int Poly = 4823603603198064275; // The CRC-64 lookup-table will have global scope. unsigned long int CrcLookupTable[TWO_UP_EIGHT]; const unsigned int Modulus[POSITIONS_PER_NODE + 1] = { 0, 1, 2, 3, 0 }; const char TheColours[COLOURS] = { '0', '1', '2', '3' }; const unsigned int PositionShift[POSITIONS_PER_NODE] = { 6, 4, 2, 0 }; // This function uses "NumberOfBytes" Bytes starting at "DataMessage" to compute the CRC-Digest, by way of a Byte-wise "CrcLookupTable" based on the CRC-64 "Poly". unsigned long int LookupTableColouringCrc(const unsigned char *DataMessage, unsigned long int NumberOfBytes){ int X; // Because looking up a "0" in the table returns "0", it is safe to use table-lookups for filling the "WorkingRegister" with its initial "DataMessage" values. register unsigned long int WorkingRegister = 0; // Query the "CrcLookupTable" exactly "NumberOfBytes" times. Perform lookups using the leftmost Byte of "WorkingRegister" as the index. // After each table query, "XOR" the value returned by "CrcLookupTable" with the value inside "WorkingRegister" as soon as the next "DataMessage" Byte has been drawn in from the right-hand-side. // "X" represents the location of the next "DataMessage" Byte to pull into the calculation. for ( X = 0; X < NumberOfBytes; X++ ) WorkingRegister = CrcLookupTable[WorkingRegister >> LEFT_BYTE_SHIFT] ^ ((WorkingRegister << BYTE_WIDTH) ^ DataMessage[X]); return WorkingRegister; } // Read the "POSITION_COUNT" printable characters from "ThisImport" Colouring, and compress them into the "CHAR_COUNT" characters of "ThisColouringString". Compression has a factor of 4. void ImportMasterColouringSeedString(unsigned char *ThisColouringString, const char *ThisImport){ unsigned int X; unsigned int CurrentPosition = 3; // Zero the destination Bytes. memset(ThisColouringString, 0, sizeof(unsigned char)*CHAR_COUNT); // Place the colour at position "X" of "ThisImport", into the correct two-bit slot within "ThisColouringString". Position shifting and modulus lookup-tables are used to speed this up. for ( X = 0; X < POSITION_COUNT; X++ ) ThisColouringString[X >> 2] += ((ThisImport[X] - TheColours[0]) << PositionShift[CurrentPosition = Modulus[CurrentPosition + 1]]); } // Simply print out "ThisLong" using "1"s and "0"s. void PrintUnsignedLongInBinary(unsigned long int ThisLong){ unsigned int X; char HoldOut[POLY_WIDTH + 1]; for ( X = 0; X < POLY_WIDTH; X++ ) HoldOut[X] = (ThisLong & PowersOfTwo[POLY_WIDTH - 1 - X])? '1': '0'; HoldOut[POLY_WIDTH] = '\0'; printf("%s", HoldOut); } // Simply print out "ThisByte" using "1"s and "0"s. void PrintByteInBinary(unsigned char ThisByte){ unsigned int X; char HoldOut[BYTE_WIDTH + 1]; for ( X = 0; X < BYTE_WIDTH; X++ ) HoldOut[X] = (ThisByte & PowersOfTwo[BYTE_WIDTH - 1 - X])? '1': '0'; HoldOut[BYTE_WIDTH] = '\0'; printf("%s", HoldOut); } int main(){ int X; unsigned char *CompactString = (unsigned char*)calloc(CHAR_COUNT + W_BYTES, sizeof(unsigned char)); unsigned char *TheFinalW = CompactString + CHAR_COUNT; unsigned long int TheDigest; // These 289-character strings are all different, but it is extremely tedious to find the differences, just by looking at them. Hence we use CRC-64 to help us out. char *FirstImport = "11302023023013131" "20301312322310210" "23123320133011020" "32211100023332301" "00231221230301103" "03022131011312230" "20232030313120111" "31333021100223210" "01103201302122333" "22013233101030102" "33200110302101222" "01220012331233001" "12001332110123023" "30131322001132032" "10020303221021312" "32112103232200013" "13310211020230323\0"; char *SecondImport = "11302023023013131" "20301312322310210" "23123320133011020" "32211100023332301" "00231221230301103" "03022131011312230" "20232030313120111" "31333001100223210" "01103201302122333" "22013233101030102" "33200110302101222" "01220012331233001" "12001332110123023" "30131322001232032" "10020303221021312" "32112103232200013" "13310211020230323\0"; char *ThirdImport = "11302023023013131" "20301312322310210" "23123320133011020" "32211100023332301" "00231221230301103" "03022131011312230" "20232030313120111" "31333021100223210" "01103201302122333" "22013233101030102" "33200110302101222" "01220012331233001" "12001332110123023" "10131322001232032" "10020303221021312" "32112103232200013" "13310211020230323\0"; FILE *LookupTableData; LookupTableData = fopen(LOOKUP_TABLE_FILE, "rb"); fread(CrcLookupTable, sizeof(unsigned long int), TWO_UP_EIGHT, LookupTableData); fclose(LookupTableData); // Process the "FirstImport". printf("\n---------------------------------------------------------------------------------\n\n"); ImportMasterColouringSeedString(CompactString, FirstImport); TheDigest = LookupTableColouringCrc(CompactString, CHAR_COUNT); printf("TheDigest for FirstImport over CHAR_COUNT Bytes -|%lu|\n", TheDigest); TheDigest = LookupTableColouringCrc(CompactString, CHAR_COUNT + W_BYTES); printf("TheDigest for FirstImport plus W zero bits -|%lu|\n", TheDigest); // Copy the (CRC-Digest with W extra zeros) into the extra positions in "CompactString". // It turns out that this is a rather tedious operation, because "unsigned long int"s are stored in "Little Endian Byte Order" in the X86-X64 architecture. // The statement below amounts to reversing the Byte order while copying, so that the most significant Bytes get processed first. for ( X = 0; X < W_BYTES; X++ ) *(TheFinalW + X) = ((unsigned char *)&TheDigest)[W_BYTES - X - 1]; // Verify the the copied Bytes have arrived in the correct order. printf("From TheDigest |"); PrintUnsignedLongInBinary(TheDigest); printf("|\n"); printf("From CompactString|"); for( X = 0; X < W_BYTES; X++ ) { PrintByteInBinary(CompactString[CHAR_COUNT + X]); printf("|"); } printf("\n"); TheDigest = LookupTableColouringCrc(CompactString, CHAR_COUNT + W_BYTES); printf("TheDigest for FirstImport with previous digest appended -|%lu|\n", TheDigest); // Process the "SecondImport". printf("\n---------------------------------------------------------------------------------\n\n"); ImportMasterColouringSeedString(CompactString, SecondImport); TheDigest = LookupTableColouringCrc(CompactString, CHAR_COUNT); printf("TheDigest for SecondImport over CHAR_COUNT Bytes -|%lu|\n", TheDigest); memset(CompactString + CHAR_COUNT, 0, W_BYTES); TheDigest = LookupTableColouringCrc(CompactString, CHAR_COUNT + W_BYTES); printf("TheDigest for SecondImport plus W zero bits -|%lu|\n", TheDigest); // Copy the (CRC-Digest with W extra zeros) into the extra positions in "CompactString". // It turns out that this is a rather tedious operation, because "unsigned long int"s are stored in "Little Endian Byte Order" in the X86-X64 architecture. // The statement below amounts to reversing the Byte order while copying, so that the most significant Bytes get processed first. for ( X = 0; X < W_BYTES; X++ ) *(TheFinalW + X) = ((unsigned char *)&TheDigest)[W_BYTES - X - 1]; // Verify the the copied Bytes have arrived in the correct order. printf("From TheDigest |"); PrintUnsignedLongInBinary(TheDigest); printf("|\n"); printf("From CompactString|"); for( X = 0; X < W_BYTES; X++ ) { PrintByteInBinary(CompactString[CHAR_COUNT + X]); printf("|"); } printf("\n"); TheDigest = LookupTableColouringCrc(CompactString, CHAR_COUNT + W_BYTES); printf("TheDigest for SecondImport with previous digest appended -|%lu|\n", TheDigest); // Process the "ThirdImport". printf("\n---------------------------------------------------------------------------------\n\n"); ImportMasterColouringSeedString(CompactString, ThirdImport); TheDigest = LookupTableColouringCrc(CompactString, CHAR_COUNT); printf("TheDigest for ThirdImport over CHAR_COUNT Bytes -|%lu|\n", TheDigest); memset(CompactString + CHAR_COUNT, 0, W_BYTES); TheDigest = LookupTableColouringCrc(CompactString, CHAR_COUNT + W_BYTES); printf("TheDigest for ThirdImport plus W zero bits -|%lu|\n", TheDigest); // Copy the (CRC-Digest with W extra zeros) into the extra positions in "CompactString". // It turns out that this is a rather tedious operation, because "unsigned long int"s are stored in "Little Endian Byte Order" in the X86-X64 architecture. // The statement below amounts to reversing the Byte order while copying, so that the most significant Bytes get processed first. for ( X = 0; X < W_BYTES; X++ ) *(TheFinalW + X) = ((unsigned char *)&TheDigest)[W_BYTES - X - 1]; // Verify the the copied Bytes have arrived in the correct order. printf("From TheDigest |"); PrintUnsignedLongInBinary(TheDigest); printf("|\n"); printf("From CompactString|"); for( X = 0; X < W_BYTES; X++ ) { PrintByteInBinary(CompactString[CHAR_COUNT + X]); printf("|"); } printf("\n"); TheDigest = LookupTableColouringCrc(CompactString, CHAR_COUNT + W_BYTES); printf("TheDigest for ThirdImport with previous digest appended -|%lu|\n", TheDigest); printf("\n---------------------------------------------------------------------------------\n\n"); return 0; }