/src/netcdf-c/libdispatch/dcrc64.c
| Line | Count | Source | 
| 1 |  | /* crc64.c -- compute CRC-64 | 
| 2 |  |  * Copyright (C) 2013 Mark Adler | 
| 3 |  |  * Version 1.4  16 Dec 2013  Mark Adler | 
| 4 |  |  */ | 
| 5 |  |  | 
| 6 |  | /* | 
| 7 |  |   This software is provided 'as-is', without any express or implied | 
| 8 |  |   warranty.  In no event will the author be held liable for any damages | 
| 9 |  |   arising from the use of this software. | 
| 10 |  |  | 
| 11 |  |   Permission is granted to anyone to use this software for any purpose, | 
| 12 |  |   including commercial applications, and to alter it and redistribute it | 
| 13 |  |   freely, subject to the following restrictions: | 
| 14 |  |  | 
| 15 |  |   1. The origin of this software must not be misrepresented; you must not | 
| 16 |  |      claim that you wrote the original software. If you use this software | 
| 17 |  |      in a product, an acknowledgment in the product documentation would be | 
| 18 |  |      appreciated but is not required. | 
| 19 |  |   2. Altered source versions must be plainly marked as such, and must not be | 
| 20 |  |      misrepresented as being the original software. | 
| 21 |  |   3. This notice may not be removed or altered from any source distribution. | 
| 22 |  |  | 
| 23 |  |   Mark Adler | 
| 24 |  |   madler@alumni.caltech.edu | 
| 25 |  |  */ | 
| 26 |  |  | 
| 27 |  | /* Compute CRC-64 in the manner of xz, using the ECMA-182 polynomial, | 
| 28 |  |    bit-reversed, with one's complement pre and post processing.  Provide a | 
| 29 |  |    means to combine separately computed CRC-64's. */ | 
| 30 |  |  | 
| 31 |  | /* Version history: | 
| 32 |  |    1.0  13 Dec 2013  First version | 
| 33 |  |    1.1  13 Dec 2013  Fix comments in test code | 
| 34 |  |    1.2  14 Dec 2013  Determine endianess at run time | 
| 35 |  |    1.3  15 Dec 2013  Add eight-byte processing for big endian as well | 
| 36 |  |                      Make use of the pthread library optional | 
| 37 |  |    1.4  16 Dec 2013  Make once variable volatile for limited thread protection | 
| 38 |  |  */ | 
| 39 |  |  | 
| 40 |  | #include "config.h" | 
| 41 |  | #include <stdio.h> | 
| 42 |  | #include <inttypes.h> | 
| 43 |  | #include <assert.h> | 
| 44 |  |  | 
| 45 |  | #include "ncexternl.h" | 
| 46 |  |  | 
| 47 |  | /* The include of pthread.h below can be commented out in order to not use the | 
| 48 |  |    pthread library for table initialization.  In that case, the initialization | 
| 49 |  |    will not be thread-safe.  That's fine, so long as it can be assured that | 
| 50 |  |    there is only one thread using crc64(). */ | 
| 51 |  | #if 0 | 
| 52 |  | #include <pthread.h>            /* link with -lpthread */ | 
| 53 |  | #endif | 
| 54 |  |  | 
| 55 |  | /* 64-bit CRC polynomial with these coefficients, but reversed: | 
| 56 |  |     64, 62, 57, 55, 54, 53, 52, 47, 46, 45, 40, 39, 38, 37, 35, 33, 32, | 
| 57 |  |     31, 29, 27, 24, 23, 22, 21, 19, 17, 13, 12, 10, 9, 7, 4, 1, 0 */ | 
| 58 | 1.02k | #define POLY UINT64_C(0xc96c5795d7870f42) | 
| 59 |  |  | 
| 60 |  | /* Tables for CRC calculation -- filled in by initialization functions that are | 
| 61 |  |    called once.  These could be replaced by constant tables generated in the | 
| 62 |  |    same way.  There are two tables, one for each endianess.  Since these are | 
| 63 |  |    static, i.e. local, one should be compiled out of existence if the compiler | 
| 64 |  |    can evaluate the endianess check in crc64() at compile time. */ | 
| 65 |  | static uint64 crc64_little_table[8][256]; | 
| 66 |  | static uint64 crc64_big_table[8][256]; | 
| 67 |  |  | 
| 68 |  | /* Fill in the CRC-64 constants table. */ | 
| 69 |  | static void crc64_init(uint64 table[][256]) | 
| 70 | 1 | { | 
| 71 | 1 |     unsigned n, k; | 
| 72 | 1 |     uint64 crc; | 
| 73 |  |  | 
| 74 |  |     /* generate CRC-64's for all single byte sequences */ | 
| 75 | 257 |     for (n = 0; n < 256; n++) { | 
| 76 | 256 |         crc = n; | 
| 77 | 2.30k |         for (k = 0; k < 8; k++) | 
| 78 | 2.04k |             crc = crc & 1 ? POLY ^ (crc >> 1) : crc >> 1; | 
| 79 | 256 |         table[0][n] = crc; | 
| 80 | 256 |     } | 
| 81 |  |  | 
| 82 |  |     /* generate CRC-64's for those followed by 1 to 7 zeros */ | 
| 83 | 257 |     for (n = 0; n < 256; n++) { | 
| 84 | 256 |         crc = table[0][n]; | 
| 85 | 2.04k |         for (k = 1; k < 8; k++) { | 
| 86 | 1.79k |             crc = table[0][crc & 0xff] ^ (crc >> 8); | 
| 87 | 1.79k |             table[k][n] = crc; | 
| 88 | 1.79k |         } | 
| 89 | 256 |     } | 
| 90 | 1 | } | 
| 91 |  |  | 
| 92 |  | /* This function is called once to initialize the CRC-64 table for use on a | 
| 93 |  |    little-endian architecture. */ | 
| 94 |  | static void crc64_little_init(void) | 
| 95 | 1 | { | 
| 96 | 1 |     crc64_init(crc64_little_table); | 
| 97 | 1 | } | 
| 98 |  |  | 
| 99 |  | /* Reverse the bytes in a 64-bit word. */ | 
| 100 |  | static inline uint64 rev8(uint64 a) | 
| 101 | 0 | { | 
| 102 | 0 |     uint64 m; | 
| 103 |  | 
 | 
| 104 | 0 |     m = UINT64_C(0xff00ff00ff00ff); | 
| 105 | 0 |     a = ((a >> 8) & m) | (a & m) << 8; | 
| 106 | 0 |     m = UINT64_C(0xffff0000ffff); | 
| 107 | 0 |     a = ((a >> 16) & m) | (a & m) << 16; | 
| 108 | 0 |     return a >> 32 | a << 32; | 
| 109 | 0 | } | 
| 110 |  |  | 
| 111 |  | /* This function is called once to initialize the CRC-64 table for use on a | 
| 112 |  |    big-endian architecture. */ | 
| 113 |  | static void crc64_big_init(void) | 
| 114 | 0 | { | 
| 115 | 0 |     unsigned k, n; | 
| 116 |  | 
 | 
| 117 | 0 |     crc64_init(crc64_big_table); | 
| 118 | 0 |     for (k = 0; k < 8; k++) | 
| 119 | 0 |         for (n = 0; n < 256; n++) | 
| 120 | 0 |             crc64_big_table[k][n] = rev8(crc64_big_table[k][n]); | 
| 121 | 0 | } | 
| 122 |  |  | 
| 123 |  | /* Run the init() function exactly once.  If pthread.h is not included, then | 
| 124 |  |    this macro will use a simple static state variable for the purpose, which is | 
| 125 |  |    not thread-safe.  The init function must be of the type void init(void). */ | 
| 126 |  | #ifdef PTHREAD_ONCE_INIT | 
| 127 |  | #  define ONCE(init) \ | 
| 128 |  |     do { \ | 
| 129 |  |         static pthread_once_t once = PTHREAD_ONCE_INIT; \ | 
| 130 |  |         pthread_once(&once, init); \ | 
| 131 |  |     } while (0) | 
| 132 |  | #else | 
| 133 |  | #  define ONCE(init) \ | 
| 134 | 990 |     do { \ | 
| 135 | 990 |         static volatile int once = 1; \ | 
| 136 | 990 |         if (once) { \ | 
| 137 | 1 |             if (once++ == 1) { \ | 
| 138 | 1 |                 init(); \ | 
| 139 | 1 |                 once = 0; \ | 
| 140 | 1 |             } \ | 
| 141 | 1 |             else \ | 
| 142 | 1 |                 while (once) \ | 
| 143 | 0 |                     ; \ | 
| 144 | 1 |         } \ | 
| 145 | 990 |     } while (0) | 
| 146 |  | #endif | 
| 147 |  |  | 
| 148 |  | /* Calculate a CRC-64 eight bytes at a time on a little-endian architecture. */ | 
| 149 |  | static inline uint64 crc64_little(uint64 crc, void *buf, size_t len) | 
| 150 | 990 | { | 
| 151 | 990 |     unsigned char *next = buf; | 
| 152 |  |  | 
| 153 | 990 |     ONCE(crc64_little_init); | 
| 154 | 990 |     crc = ~crc; | 
| 155 | 990 |     while (len && ((uintptr_t)next & 7) != 0) { | 
| 156 | 0 |         crc = crc64_little_table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); | 
| 157 | 0 |         len--; | 
| 158 | 0 |     } | 
| 159 | 27.3k |     while (len >= 8) { | 
| 160 | 26.3k |         crc ^= *(uint64 *)next; | 
| 161 | 26.3k |         crc = crc64_little_table[7][crc & 0xff] ^ | 
| 162 | 26.3k |               crc64_little_table[6][(crc >> 8) & 0xff] ^ | 
| 163 | 26.3k |               crc64_little_table[5][(crc >> 16) & 0xff] ^ | 
| 164 | 26.3k |               crc64_little_table[4][(crc >> 24) & 0xff] ^ | 
| 165 | 26.3k |               crc64_little_table[3][(crc >> 32) & 0xff] ^ | 
| 166 | 26.3k |               crc64_little_table[2][(crc >> 40) & 0xff] ^ | 
| 167 | 26.3k |               crc64_little_table[1][(crc >> 48) & 0xff] ^ | 
| 168 | 26.3k |               crc64_little_table[0][crc >> 56]; | 
| 169 | 26.3k |         next += 8; | 
| 170 | 26.3k |         len -= 8; | 
| 171 | 26.3k |     } | 
| 172 | 1.99k |     while (len) { | 
| 173 | 1.00k |         crc = crc64_little_table[0][(crc ^ *next++) & 0xff] ^ (crc >> 8); | 
| 174 | 1.00k |         len--; | 
| 175 | 1.00k |     } | 
| 176 | 990 |     return ~crc; | 
| 177 | 990 | } | 
| 178 |  |  | 
| 179 |  | /* Calculate a CRC-64 eight bytes at a time on a big-endian architecture. */ | 
| 180 |  | static inline uint64 crc64_big(uint64 crc, void *buf, size_t len) | 
| 181 | 0 | { | 
| 182 | 0 |     unsigned char *next = buf; | 
| 183 |  | 
 | 
| 184 | 0 |     ONCE(crc64_big_init); | 
| 185 | 0 |     crc = ~rev8(crc); | 
| 186 | 0 |     while (len && ((uintptr_t)next & 7) != 0) { | 
| 187 | 0 |         crc = crc64_big_table[0][(crc >> 56) ^ *next++] ^ (crc << 8); | 
| 188 | 0 |         len--; | 
| 189 | 0 |     } | 
| 190 | 0 |     while (len >= 8) { | 
| 191 | 0 |         crc ^= *(uint64 *)next; | 
| 192 | 0 |         crc = crc64_big_table[0][crc & 0xff] ^ | 
| 193 | 0 |               crc64_big_table[1][(crc >> 8) & 0xff] ^ | 
| 194 | 0 |               crc64_big_table[2][(crc >> 16) & 0xff] ^ | 
| 195 | 0 |               crc64_big_table[3][(crc >> 24) & 0xff] ^ | 
| 196 | 0 |               crc64_big_table[4][(crc >> 32) & 0xff] ^ | 
| 197 | 0 |               crc64_big_table[5][(crc >> 40) & 0xff] ^ | 
| 198 | 0 |               crc64_big_table[6][(crc >> 48) & 0xff] ^ | 
| 199 | 0 |               crc64_big_table[7][crc >> 56]; | 
| 200 | 0 |         next += 8; | 
| 201 | 0 |         len -= 8; | 
| 202 | 0 |     } | 
| 203 | 0 |     while (len) { | 
| 204 | 0 |         crc = crc64_big_table[0][(crc >> 56) ^ *next++] ^ (crc << 8); | 
| 205 | 0 |         len--; | 
| 206 | 0 |     } | 
| 207 | 0 |     return ~rev8(crc); | 
| 208 | 0 | } | 
| 209 |  |  | 
| 210 |  | /* Return the CRC-64 of buf[0..len-1] with initial crc, processing eight bytes | 
| 211 |  |    at a time.  This selects one of two routines depending on the endianess of | 
| 212 |  |    the architecture.  A good optimizing compiler will determine the endianess | 
| 213 |  |    at compile time if it can, and get rid of the unused code and table.  If the | 
| 214 |  |    endianess can be changed at run time, then this code will handle that as | 
| 215 |  |    well, initializing and using two tables, if called upon to do so. */ | 
| 216 |  |  | 
| 217 |  | static int littleendian = -1; | 
| 218 |  |  | 
| 219 |  | EXTERNL uint64 | 
| 220 |  | NC_crc64(uint64 crc, void *buf, unsigned int len) | 
| 221 | 990 | { | 
| 222 |  |     /* Is this machine big vs little endian? */ | 
| 223 | 990 |     if(littleendian < 0) { | 
| 224 | 1 |   unsigned char* p = (void*)&littleendian; | 
| 225 | 1 |   littleendian = 1; | 
| 226 | 1 |   if(*p == 0) littleendian = 0; /* big endian */ | 
| 227 | 1 |     } | 
| 228 |  |  | 
| 229 | 990 |     return littleendian ? crc64_little(crc, buf, (size_t)len) : | 
| 230 | 990 |                           crc64_big(crc, buf, (size_t)len); | 
| 231 | 990 | } | 
| 232 |  |  | 
| 233 | 0 | #define GF2_DIM 64      /* dimension of GF(2) vectors (length of CRC) */ | 
| 234 |  |  | 
| 235 |  | static uint64 gf2_matrix_times(uint64 *mat, uint64 vec) | 
| 236 | 0 | { | 
| 237 | 0 |     uint64 sum; | 
| 238 |  | 
 | 
| 239 | 0 |     sum = 0; | 
| 240 | 0 |     while (vec) { | 
| 241 | 0 |         if (vec & 1) | 
| 242 | 0 |             sum ^= *mat; | 
| 243 | 0 |         vec >>= 1; | 
| 244 | 0 |         mat++; | 
| 245 | 0 |     } | 
| 246 | 0 |     return sum; | 
| 247 | 0 | } | 
| 248 |  |  | 
| 249 |  | static void gf2_matrix_square(uint64 *square, uint64 *mat) | 
| 250 | 0 | { | 
| 251 | 0 |     unsigned n; | 
| 252 |  | 
 | 
| 253 | 0 |     for (n = 0; n < GF2_DIM; n++) | 
| 254 | 0 |         square[n] = gf2_matrix_times(mat, mat[n]); | 
| 255 | 0 | } | 
| 256 |  |  | 
| 257 |  | /* Return the CRC-64 of two sequential blocks, where crc1 is the CRC-64 of the | 
| 258 |  |    first block, crc2 is the CRC-64 of the second block, and len2 is the length | 
| 259 |  |    of the second block. */ | 
| 260 |  | uint64 crc64_combine(uint64 crc1, uint64 crc2, uintmax_t len2) | 
| 261 | 0 | { | 
| 262 | 0 |     unsigned n; | 
| 263 | 0 |     uint64 row; | 
| 264 | 0 |     uint64 even[GF2_DIM];     /* even-power-of-two zeros operator */ | 
| 265 | 0 |     uint64 odd[GF2_DIM];      /* odd-power-of-two zeros operator */ | 
| 266 |  |  | 
| 267 |  |     /* degenerate case */ | 
| 268 | 0 |     if (len2 == 0) | 
| 269 | 0 |         return crc1; | 
| 270 |  |  | 
| 271 |  |     /* put operator for one zero bit in odd */ | 
| 272 | 0 |     odd[0] = POLY;              /* CRC-64 polynomial */ | 
| 273 | 0 |     row = 1; | 
| 274 | 0 |     for (n = 1; n < GF2_DIM; n++) { | 
| 275 | 0 |         odd[n] = row; | 
| 276 | 0 |         row <<= 1; | 
| 277 | 0 |     } | 
| 278 |  |  | 
| 279 |  |     /* put operator for two zero bits in even */ | 
| 280 | 0 |     gf2_matrix_square(even, odd); | 
| 281 |  |  | 
| 282 |  |     /* put operator for four zero bits in odd */ | 
| 283 | 0 |     gf2_matrix_square(odd, even); | 
| 284 |  |  | 
| 285 |  |     /* apply len2 zeros to crc1 (first square will put the operator for one | 
| 286 |  |        zero byte, eight zero bits, in even) */ | 
| 287 | 0 |     do { | 
| 288 |  |         /* apply zeros operator for this bit of len2 */ | 
| 289 | 0 |         gf2_matrix_square(even, odd); | 
| 290 | 0 |         if (len2 & 1) | 
| 291 | 0 |             crc1 = gf2_matrix_times(even, crc1); | 
| 292 | 0 |         len2 >>= 1; | 
| 293 |  |  | 
| 294 |  |         /* if no more bits set, then done */ | 
| 295 | 0 |         if (len2 == 0) | 
| 296 | 0 |             break; | 
| 297 |  |  | 
| 298 |  |         /* another iteration of the loop with odd and even swapped */ | 
| 299 | 0 |         gf2_matrix_square(odd, even); | 
| 300 | 0 |         if (len2 & 1) | 
| 301 | 0 |             crc1 = gf2_matrix_times(odd, crc1); | 
| 302 | 0 |         len2 >>= 1; | 
| 303 |  |  | 
| 304 |  |         /* if no more bits set, then done */ | 
| 305 | 0 |     } while (len2 != 0); | 
| 306 |  |  | 
| 307 |  |     /* return combined crc */ | 
| 308 | 0 |     crc1 ^= crc2; | 
| 309 | 0 |     return crc1; | 
| 310 | 0 | } | 
| 311 |  |  | 
| 312 |  | #if 0 | 
| 313 |  | /* Test crc64() on vector[0..len-1] which should have CRC-64 crc.  Also test | 
| 314 |  |    crc64_combine() on vector[] split in two. */ | 
| 315 |  | static void crc64_test(void *vector, size_t len, uint64 crc) | 
| 316 |  | { | 
| 317 |  |     uint64 crc1, crc2; | 
| 318 |  |  | 
| 319 |  |     /* test crc64() */ | 
| 320 |  |     crc1 = crc64(0, vector, len); | 
| 321 |  |     if (crc1 ^ crc) | 
| 322 |  |         printf("mismatch: %" PRIx64 ", should be %" PRIx64 "n", (ulong)crc1, (ulong)crc); | 
| 323 |  |  | 
| 324 |  |     /* test crc64_combine() */ | 
| 325 |  |     crc1 = crc64(0, vector, (len + 1) >> 1); | 
| 326 |  |     crc2 = crc64(0, vector + ((len + 1) >> 1), len >> 1); | 
| 327 |  |     crc1 = crc64_combine(crc1, crc2, len >> 1); | 
| 328 |  |     if (crc1 ^ crc) | 
| 329 |  |         printf("mismatch: %" PRIx64 ", should be %" PRIx64 "n", (ulong)crc1, (ulong)crc); | 
| 330 |  | } | 
| 331 |  |  | 
| 332 |  | /* Test vectors. */ | 
| 333 |  | #define TEST1 "123456789" | 
| 334 |  | #define TESTLEN1 9 | 
| 335 |  | #define TESTCRC1 UINT64_C(0x995dc9bbdf1939fa) | 
| 336 |  | #define TEST2 "This is a test of the emergency broadcast system." | 
| 337 |  | #define TESTLEN2 49 | 
| 338 |  | #define TESTCRC2 UINT64_C(0x27db187fc15bbc72) | 
| 339 |  |  | 
| 340 |  | int main(void) | 
| 341 |  | { | 
| 342 |  |     crc64_test(TEST1, TESTLEN1, TESTCRC1); | 
| 343 |  |     crc64_test(TEST2, TESTLEN2, TESTCRC2); | 
| 344 |  |     return 0; | 
| 345 |  | } | 
| 346 |  | #endif |