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#if defined(__aarch64__) || defined(_M_ARM64)
285 const uint8x16_t low_v = vld1q_u8(low_tbl);
286 const uint8x16_t hi_v = vld1q_u8(hi_tbl);
287 const uint8x16_t mask = vdupq_n_u8(0x0F);
290 for(; i + 16 <= len; i += 16)
292 uint8x16_t s = vld1q_u8(src + i);
293 uint8x16_t d = vld1q_u8(dst + i);
294 uint8x16_t s_lo = vandq_u8(s, mask);
295 uint8x16_t s_hi = vandq_u8(vshrq_n_u8(s, 4), mask);
296 uint8x16_t lo = vqtbl1q_u8(low_v, s_lo);
297 uint8x16_t hi = vqtbl1q_u8(hi_v, s_hi);
298 uint8x16_t r = veorq_u8(veorq_u8(lo, hi), d);
299 vst1q_u8(dst + i, r);
305 low_v2.val[0] = vld1_u8(low_tbl);
306 low_v2.val[1] = vld1_u8(low_tbl + 8);
308 hi_v2.val[0] = vld1_u8(hi_tbl);
309 hi_v2.val[1] = vld1_u8(hi_tbl + 8);
310 const uint8x8_t mask8 = vdup_n_u8(0x0F);
313 for(; i + 8 <= len; i += 8)
315 uint8x8_t s = vld1_u8(src + i);
316 uint8x8_t d = vld1_u8(dst + i);
317 uint8x8_t s_lo = vand_u8(s, mask8);
318 uint8x8_t s_hi = vand_u8(vshr_n_u8(s, 4), mask8);
319 uint8x8_t lo = vtbl2_u8(low_v2, s_lo);
320 uint8x8_t hi = vtbl2_u8(hi_v2, s_hi);
321 uint8x8_t r = veor_u8(veor_u8(lo, hi), d);
327 dst[i] ^= low_tbl[src[i] & 0x0F] ^ hi_tbl[src[i] >> 4];
330TARGET_WITH_SIMD
static void gf256_xor_region_neon(uint8_t *dst,
const uint8_t *src,
size_t len)
333 for(; i + 16 <= len; i += 16)
335 uint8x16_t d = vld1q_u8(dst + i);
336 uint8x16_t s = vld1q_u8(src + i);
337 vst1q_u8(dst + i, veorq_u8(d, s));
339 for(; i < len; i++) dst[i] ^= src[i];
352 if(coeff == 0)
return;
357#if defined(__x86_64__) || defined(__amd64) || defined(_M_AMD64) || defined(_M_X64) || \
358 defined(__I386__) || defined(__i386__) || defined(__THW_INTEL) || defined(_M_IX86)
359 if(have_avx2()) { gf256_mul_region_avx2(dst, src, coeff, len);
return; }
360 if(have_ssse3()) { gf256_mul_region_ssse3(dst, src, coeff, len);
return; }
363#if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM)
364 if(have_neon()) { gf256_mul_region_neon(dst, src, coeff, len);
return; }
372#if defined(__x86_64__) || defined(__amd64) || defined(_M_AMD64) || defined(_M_X64) || \
373 defined(__I386__) || defined(__i386__) || defined(__THW_INTEL) || defined(_M_IX86)
374 if(have_avx2()) { gf256_xor_region_avx2(dst, src, len);
return; }
375 if(have_ssse3()) { gf256_xor_region_ssse3(dst, src, len);
return; }
378#if defined(__aarch64__) || defined(_M_ARM64) || defined(__arm__) || defined(_M_ARM)
379 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.