56 for(
int i = 0; i < 255; i++)
64 if(x & 0x100) x ^= 0x11D;
79 if(a == 0 || b == 0)
return 0;
117 for(
int i = 0; i < 16; i++)
119 low_tbl[i] =
gf256_mul((uint8_t)i, coeff);
120 hi_tbl[i] =
gf256_mul((uint8_t)(i << 4), coeff);
128 uint8_t low_tbl[16], hi_tbl[16];
131 for(
size_t i = 0; i < len; i++)
132 dst[i] ^= low_tbl[src[i] & 0x0F] ^ hi_tbl[src[i] >> 4];
140 for(; i + 8 <= len; i += 8)
143 memcpy(&d, dst + i, 8);
144 memcpy(&s, src + i, 8);
146 memcpy(dst + i, &d, 8);
155#if defined(__x86_64__) || defined(__amd64) || defined(_M_AMD64) || defined(_M_X64) || \
156 defined(__I386__) || defined(__i386__) || defined(__THW_INTEL) || defined(_M_IX86)
158#include <tmmintrin.h>
160SSSE3
static void gf256_mul_region_ssse3(uint8_t *dst,
const uint8_t *src, uint8_t coeff,
size_t len)
162 uint8_t low_tbl[16], hi_tbl[16];
165 const __m128i low_v = _mm_loadu_si128((
const __m128i *)low_tbl);
166 const __m128i hi_v = _mm_loadu_si128((
const __m128i *)hi_tbl);
167 const __m128i mask = _mm_set1_epi8(0x0F);
170 for(; i + 16 <= len; i += 16)
172 __m128i s = _mm_loadu_si128((
const __m128i *)(src + i));
173 __m128i d = _mm_loadu_si128((
const __m128i *)(dst + i));
174 __m128i s_lo = _mm_and_si128(s, mask);
175 __m128i s_hi = _mm_and_si128(_mm_srli_epi16(s, 4), mask);
176 __m128i lo = _mm_shuffle_epi8(low_v, s_lo);
177 __m128i hi = _mm_shuffle_epi8(hi_v, s_hi);
178 __m128i r = _mm_xor_si128(_mm_xor_si128(lo, hi), d);
179 _mm_storeu_si128((__m128i *)(dst + i), r);
184 dst[i] ^= low_tbl[src[i] & 0x0F] ^ hi_tbl[src[i] >> 4];
187SSSE3
static void gf256_xor_region_ssse3(uint8_t *dst,
const uint8_t *src,
size_t len)
190 for(; i + 16 <= len; i += 16)
192 __m128i d = _mm_loadu_si128((
const __m128i *)(dst + i));
193 __m128i s = _mm_loadu_si128((
const __m128i *)(src + i));
194 _mm_storeu_si128((__m128i *)(dst + i), _mm_xor_si128(d, s));
196 for(; i < len; i++) dst[i] ^= src[i];
201#include <immintrin.h>
203AVX2
static void gf256_mul_region_avx2(uint8_t *dst,
const uint8_t *src, uint8_t coeff,
size_t len)
205 uint8_t low_tbl[16], hi_tbl[16];
209 const __m128i low_128 = _mm_loadu_si128((
const __m128i *)low_tbl);
210 const __m128i hi_128 = _mm_loadu_si128((
const __m128i *)hi_tbl);
211 const __m256i low_v = _mm256_broadcastsi128_si256(low_128);
212 const __m256i hi_v = _mm256_broadcastsi128_si256(hi_128);
213 const __m256i mask = _mm256_set1_epi8(0x0F);
216 for(; i + 32 <= len; i += 32)
218 __m256i s = _mm256_loadu_si256((
const __m256i *)(src + i));
219 __m256i d = _mm256_loadu_si256((
const __m256i *)(dst + i));
220 __m256i s_lo = _mm256_and_si256(s, mask);
221 __m256i s_hi = _mm256_and_si256(_mm256_srli_epi16(s, 4), mask);
222 __m256i lo = _mm256_shuffle_epi8(low_v, s_lo);
223 __m256i hi = _mm256_shuffle_epi8(hi_v, s_hi);
224 __m256i r = _mm256_xor_si256(_mm256_xor_si256(lo, hi), d);
225 _mm256_storeu_si256((__m256i *)(dst + i), r);
229 const __m128i low_v2 = low_128;
230 const __m128i hi_v2 = hi_128;
231 const __m128i mask2 = _mm_set1_epi8(0x0F);
232 for(; i + 16 <= len; i += 16)
234 __m128i s = _mm_loadu_si128((
const __m128i *)(src + i));
235 __m128i d = _mm_loadu_si128((
const __m128i *)(dst + i));
236 __m128i s_lo = _mm_and_si128(s, mask2);
237 __m128i s_hi = _mm_and_si128(_mm_srli_epi16(s, 4), mask2);
238 __m128i lo = _mm_shuffle_epi8(low_v2, s_lo);
239 __m128i hi = _mm_shuffle_epi8(hi_v2, s_hi);
240 __m128i r = _mm_xor_si128(_mm_xor_si128(lo, hi), d);
241 _mm_storeu_si128((__m128i *)(dst + i), r);
245 dst[i] ^= low_tbl[src[i] & 0x0F] ^ hi_tbl[src[i] >> 4];
248AVX2
static void gf256_xor_region_avx2(uint8_t *dst,
const uint8_t *src,
size_t len)
251 for(; i + 32 <= len; i += 32)
253 __m256i d = _mm256_loadu_si256((
const __m256i *)(dst + i));
254 __m256i s = _mm256_loadu_si256((
const __m256i *)(src + i));
255 _mm256_storeu_si256((__m256i *)(dst + i), _mm256_xor_si256(d, s));
257 for(; i + 16 <= len; i += 16)
259 __m128i d = _mm_loadu_si128((
const __m128i *)(dst + i));
260 __m128i s = _mm_loadu_si128((
const __m128i *)(src + i));
261 _mm_storeu_si128((__m128i *)(dst + i), _mm_xor_si128(d, s));
263 for(; i < len; i++) dst[i] ^= src[i];
274#if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM)
278TARGET_WITH_SIMD
static void gf256_mul_region_neon(uint8_t *dst,
const uint8_t *src, uint8_t coeff,
size_t len)
280 uint8_t low_tbl[16], hi_tbl[16];
283 const uint8x16_t low_v = vld1q_u8(low_tbl);
284 const uint8x16_t hi_v = vld1q_u8(hi_tbl);
285 const uint8x16_t mask = vdupq_n_u8(0x0F);
288 for(; i + 16 <= len; i += 16)
290 uint8x16_t s = vld1q_u8(src + i);
291 uint8x16_t d = vld1q_u8(dst + i);
292 uint8x16_t s_lo = vandq_u8(s, mask);
293 uint8x16_t s_hi = vandq_u8(vshrq_n_u8(s, 4), mask);
294 uint8x16_t lo = vqtbl1q_u8(low_v, s_lo);
295 uint8x16_t hi = vqtbl1q_u8(hi_v, s_hi);
296 uint8x16_t r = veorq_u8(veorq_u8(lo, hi), d);
297 vst1q_u8(dst + i, r);
301 dst[i] ^= low_tbl[src[i] & 0x0F] ^ hi_tbl[src[i] >> 4];
304TARGET_WITH_SIMD
static void gf256_xor_region_neon(uint8_t *dst,
const uint8_t *src,
size_t len)
307 for(; i + 16 <= len; i += 16)
309 uint8x16_t d = vld1q_u8(dst + i);
310 uint8x16_t s = vld1q_u8(src + i);
311 vst1q_u8(dst + i, veorq_u8(d, s));
313 for(; i < len; i++) dst[i] ^= src[i];
326 if(coeff == 0)
return;
331#if defined(__x86_64__) || defined(__amd64) || defined(_M_AMD64) || defined(_M_X64) || \
332 defined(__I386__) || defined(__i386__) || defined(__THW_INTEL) || defined(_M_IX86)
333 if(have_avx2()) { gf256_mul_region_avx2(dst, src, coeff, len);
return; }
334 if(have_ssse3()) { gf256_mul_region_ssse3(dst, src, coeff, len);
return; }
337#if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM)
338 if(have_neon()) { gf256_mul_region_neon(dst, src, coeff, len);
return; }
346#if defined(__x86_64__) || defined(__amd64) || defined(_M_AMD64) || defined(_M_X64) || \
347 defined(__I386__) || defined(__i386__) || defined(__THW_INTEL) || defined(_M_IX86)
348 if(have_avx2()) { gf256_xor_region_avx2(dst, src, len);
return; }
349 if(have_ssse3()) { gf256_xor_region_ssse3(dst, src, len);
return; }
352#if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM)
353 if(have_neon()) { gf256_xor_region_neon(dst, src, len);
return; }
uint8_t gf256_div(uint8_t a, uint8_t b)
Divide two elements in GF(2^8).
void gf256_xor_region(uint8_t *dst, const uint8_t *src, size_t len)
XOR a region: dst[i] ^= src[i] for all i.
uint8_t gf256_inv(uint8_t a)
Compute multiplicative inverse in GF(2^8).
static uint8_t gf256_log_table[256]
Log table: gf256_log[x] = discrete log base 2 of x in GF(2^8).
static int gf256_tables_initialized
Flag to ensure tables are initialized exactly once.
static void gf256_init_tables(void)
Initialize log/antilog tables for GF(2^8) with polynomial 0x11D.
static void gf256_mul_region_scalar(uint8_t *dst, const uint8_t *src, uint8_t coeff, size_t len)
static void gf256_xor_region_scalar(uint8_t *dst, const uint8_t *src, size_t len)
static uint8_t gf256_exp_table[512]
Anti-log (exp) table: gf256_exp[i] = 2^i mod P.
void gf256_mul_region(uint8_t *dst, const uint8_t *src, uint8_t coeff, size_t len)
Multiply-accumulate a region: dst[i] ^= GF_mul(src[i], coeff) for all i.
static void gf256_build_mul_tables(uint8_t coeff, uint8_t low_tbl[16], uint8_t hi_tbl[16])
Build the two 16-byte nibble lookup tables for a given coefficient.
uint8_t gf256_mul(uint8_t a, uint8_t b)
Multiply two elements in GF(2^8) with polynomial 0x11D.