1// SPDX-License-Identifier: 0BSD 2 3/////////////////////////////////////////////////////////////////////////////// 4// 5/// \file crc64.c 6/// \brief CRC64 calculation 7// 8// Authors: Lasse Collin 9// Ilya Kurdyukov 10// 11/////////////////////////////////////////////////////////////////////////////// 12 13#include "check.h" 14#include "crc_common.h" 15 16#if defined(CRC_X86_CLMUL) 17# define BUILDING_CRC64_CLMUL 18# include "crc_x86_clmul.h" 19#endif 20 21 22#ifdef CRC64_GENERIC 23 24///////////////////////////////// 25// Generic slice-by-four CRC64 // 26///////////////////////////////// 27 28#ifdef WORDS_BIGENDIAN 29# define A1(x) ((x) >> 56) 30#else 31# define A1 A 32#endif 33 34 35// See the comments in crc32_fast.c. They aren't duplicated here. 36static uint64_t 37crc64_generic(const uint8_t *buf, size_t size, uint64_t crc) 38{ 39 crc = ~crc; 40 41#ifdef WORDS_BIGENDIAN 42 crc = byteswap64(crc); 43#endif 44 45 if (size > 4) { 46 while ((uintptr_t)(buf) & 3) { 47 crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc); 48 --size; 49 } 50 51 const uint8_t *const limit = buf + (size & ~(size_t)(3)); 52 size &= (size_t)(3); 53 54 while (buf < limit) { 55#ifdef WORDS_BIGENDIAN 56 const uint32_t tmp = (uint32_t)(crc >> 32) 57 ^ aligned_read32ne(buf); 58#else 59 const uint32_t tmp = (uint32_t)crc 60 ^ aligned_read32ne(buf); 61#endif 62 buf += 4; 63 64 crc = lzma_crc64_table[3][A(tmp)] 65 ^ lzma_crc64_table[2][B(tmp)] 66 ^ S32(crc) 67 ^ lzma_crc64_table[1][C(tmp)] 68 ^ lzma_crc64_table[0][D(tmp)]; 69 } 70 } 71 72 while (size-- != 0) 73 crc = lzma_crc64_table[0][*buf++ ^ A1(crc)] ^ S8(crc); 74 75#ifdef WORDS_BIGENDIAN 76 crc = byteswap64(crc); 77#endif 78 79 return ~crc; 80} 81#endif 82 83 84#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED) 85 86////////////////////////// 87// Function dispatching // 88////////////////////////// 89 90// If both the generic and arch-optimized implementations are usable, then 91// the function that is used is selected at runtime. See crc32_fast.c. 92 93typedef uint64_t (*crc64_func_type)( 94 const uint8_t *buf, size_t size, uint64_t crc); 95 96static crc64_func_type 97crc64_resolve(void) 98{ 99 return is_arch_extension_supported() 100 ? &crc64_arch_optimized : &crc64_generic; 101} 102 103#ifdef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR 104# define CRC64_SET_FUNC_ATTR __attribute__((__constructor__)) 105static crc64_func_type crc64_func; 106#else 107# define CRC64_SET_FUNC_ATTR 108static uint64_t crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc); 109static crc64_func_type crc64_func = &crc64_dispatch; 110#endif 111 112 113CRC64_SET_FUNC_ATTR 114static void 115crc64_set_func(void) 116{ 117 crc64_func = crc64_resolve(); 118 return; 119} 120 121 122#ifndef HAVE_FUNC_ATTRIBUTE_CONSTRUCTOR 123static uint64_t 124crc64_dispatch(const uint8_t *buf, size_t size, uint64_t crc) 125{ 126 crc64_set_func(); 127 return crc64_func(buf, size, crc); 128} 129#endif 130#endif 131 132 133extern LZMA_API(uint64_t) 134lzma_crc64(const uint8_t *buf, size_t size, uint64_t crc) 135{ 136#if defined(CRC64_GENERIC) && defined(CRC64_ARCH_OPTIMIZED) 137 138#ifdef CRC_USE_GENERIC_FOR_SMALL_INPUTS 139 if (size <= 16) 140 return crc64_generic(buf, size, crc); 141#endif 142 return crc64_func(buf, size, crc); 143 144#elif defined(CRC64_ARCH_OPTIMIZED) 145 // If arch-optimized version is used unconditionally without runtime 146 // CPU detection then omitting the generic version and its 8 KiB 147 // lookup table makes the library smaller. 148 // 149 // FIXME: Lookup table isn't currently omitted on 32-bit x86, 150 // see crc64_table.c. 151 return crc64_arch_optimized(buf, size, crc); 152 153#else 154 return crc64_generic(buf, size, crc); 155#endif 156} 157