| 1 | // Standard CRC64-ECMA reference implementation in C |
| 2 | // Compiles with: gcc -std=c99 crc64_ref.c -o crc64_ref |
| 3 | |
| 4 | #include <stdio.h> |
| 5 | #include <stdint.h> |
| 6 | #include <string.h> |
| 7 | #include <stdlib.h> |
| 8 | |
| 9 | #define CRC64_ECMA 0x42F0E1EBA9EA3693ULL |
| 10 | |
| 11 | static uint64_t crc64_table[256]; |
| 12 | |
| 13 | void crc64_init_table(void) { |
| 14 | for (int i = 0; i < 256; i++) { |
| 15 | uint64_t crc = (uint64_t)i << 56; |
| 16 | for (int j = 0; j < 8; j++) { |
| 17 | if (crc & 0x8000000000000000ULL) { |
| 18 | crc = (crc << 1) ^ CRC64_ECMA; |
| 19 | } else { |
| 20 | crc <<= 1; |
| 21 | } |
| 22 | } |
| 23 | crc64_table[i] = crc; |
| 24 | } |
| 25 | } |
| 26 | |
| 27 | uint64_t crc64_checksum(const uint8_t *data, size_t len) { |
| 28 | uint64_t crc = 0ULL; |
| 29 | for (size_t i = 0; i < len; i++) { |
| 30 | uint8_t byte = data[i]; |
| 31 | crc = crc64_table[(uint8_t)((crc >> 56) ^ byte)] ^ (crc << 8); |
| 32 | } |
| 33 | return crc; |
| 34 | } |
| 35 | |
| 36 | int main(int argc, char *argv[]) { |
| 37 | crc64_init_table(); |
| 38 | |
| 39 | if (argc < 2) { |
| 40 | fprintf(stderr, "Usage: %s <action> [data...]\n", argv[0]); |
| 41 | fprintf(stderr, " checksum <hexstring> - compute CRC64 of hex data\n"); |
| 42 | fprintf(stderr, " table - print first 16 table entries\n"); |
| 43 | return 1; |
| 44 | } |
| 45 | |
| 46 | const char *action = argv[1]; |
| 47 | |
| 48 | if (strcmp(action, "table") == 0) { |
| 49 | printf("CRC64_ECMA table (first 16):\n"); |
| 50 | for (int i = 0; i < 16; i++) { |
| 51 | printf(" [%d] = 0x%016llx\n", i, (unsigned long long)crc64_table[i]); |
| 52 | } |
| 53 | return 0; |
| 54 | } |
| 55 | |
| 56 | if (strcmp(action, "checksum") == 0) { |
| 57 | const char *hexstr = (argc > 2) ? argv[2] : ""; |
| 58 | size_t hexlen = strlen(hexstr); |
| 59 | |
| 60 | if (hexlen == 0) { |
| 61 | // Empty input |
| 62 | uint64_t crc = crc64_checksum(NULL, 0); |
| 63 | printf("%016llx\n", (unsigned long long)crc); |
| 64 | return 0; |
| 65 | } |
| 66 | |
| 67 | if (hexlen % 2 != 0) { |
| 68 | fprintf(stderr, "Error: hex string must have even length\n"); |
| 69 | return 1; |
| 70 | } |
| 71 | |
| 72 | size_t datalen = hexlen / 2; |
| 73 | uint8_t *data = malloc(datalen); |
| 74 | if (!data) { |
| 75 | fprintf(stderr, "Error: memory allocation failed\n"); |
| 76 | return 1; |
| 77 | } |
| 78 | |
| 79 | for (size_t i = 0; i < datalen; i++) { |
| 80 | unsigned int byte; |
| 81 | if (sscanf(&hexstr[i * 2], "%2x", &byte) != 1) { |
| 82 | fprintf(stderr, "Error: invalid hex character\n"); |
| 83 | free(data); |
| 84 | return 1; |
| 85 | } |
| 86 | data[i] = (uint8_t)byte; |
| 87 | } |
| 88 | |
| 89 | uint64_t crc = crc64_checksum(data, datalen); |
| 90 | printf("%016llx\n", (unsigned long long)crc); |
| 91 | free(data); |
| 92 | return 0; |
| 93 | } |
| 94 | |
| 95 | fprintf(stderr, "Error: unknown action '%s'\n", action); |
| 96 | return 1; |
| 97 | } |
| 98 | |
| 99 | |