#!/usr/bin/env python3 # SPDX-License-Identifier: GPL-2.0-or-later # # Script that generates constants for computing the given CRC variant(s). # # Copyright 2025 Google LLC # # Author: Eric Biggers <ebiggers@google.com>
import sys
# XOR (add) an iterable of polynomials. def xor(iterable):
res = 0 for val in iterable:
res ^= val return res
# Multiply two polynomials. def clmul(a, b): return xor(a << i for i in range(b.bit_length()) if (b & (1 << i)) != 0)
# Reduce the polynomial 'a' modulo the polynomial 'b'. def reduce(a, b): return a ^ clmul(div(a, b), b)
# Reflect the bits of a polynomial. def bitreflect(poly, num_bits): assert poly.bit_length() <= num_bits return xor(((poly >> i) & 1) << (num_bits - 1 - i) for i in range(num_bits))
# Format a polynomial as hex. Bit-reflect it if the CRC is lsb-first. def fmt_poly(variant, poly, num_bits): if variant.lsb:
poly = bitreflect(poly, num_bits) return f'0x{poly:0{2*num_bits//8}x}'
# Print a pair of 64-bit polynomial multipliers. They are always passed in the # order [HI64_TERMS, LO64_TERMS] but will be printed in the appropriate order. def print_mult_pair(variant, mults):
mults = list(mults if variant.lsb else reversed(mults))
terms = ['HI64_TERMS', 'LO64_TERMS'] if variant.lsb else ['LO64_TERMS', 'HI64_TERMS'] for i in range(2):
print(f'\t\t{fmt_poly(variant, mults[i]["val"], 64)},\t/* {terms[i]}: {mults[i]["desc"]} */')
# Pretty-print a polynomial. def pprint_poly(prefix, poly):
terms = [f'x^{i}'for i in reversed(range(poly.bit_length())) if (poly & (1 << i)) != 0]
j = 0 while j < len(terms):
s = prefix + terms[j] + (' +'if j < len(terms) - 1 else'')
j += 1 while j < len(terms) and len(s) < 73:
s += ' ' + terms[j] + (' +'if j < len(terms) - 1 else'')
j += 1
print(s)
prefix = ' * ' + (' ' * (len(prefix) - 3))
# Print a comment describing constants generated for the given CRC variant. def print_header(variant, what):
print('/*')
s = f'{"least" if variant.lsb else "most"}-significant-bit-first CRC-{variant.bits}'
print(f' * {what} generated for {s} using')
pprint_poly(' * G(x) = ', variant.G)
print(' */')
class CrcVariant: def __init__(self, bits, generator_poly, bit_order):
self.bits = bits if bit_order notin ['lsb', 'msb']: raise ValueError('Invalid value for bit_order')
self.lsb = bit_order == 'lsb'
self.name = f'crc{bits}_{bit_order}_0x{generator_poly:0{(2*bits+7)//8}x}' if self.lsb:
generator_poly = bitreflect(generator_poly, bits)
self.G = generator_poly ^ (1 << bits)
# Generate tables for CRC computation using the "slice-by-N" method. # N=1 corresponds to the traditional byte-at-a-time table. def gen_slicebyN_tables(variants, n): for v in variants:
print('')
print_header(v, f'Slice-by-{n} CRC table')
print(f'static const u{v.bits} __maybe_unused {v.name}_table[{256*n}] = {{')
s = '' for i in range(256 * n): # The i'th table entry is the CRC of the message consisting of byte # i % 256 followed by i // 256 zero bytes.
poly = (bitreflect(i % 256, 8) if v.lsb else i % 256) << (v.bits + 8*(i//256))
next_entry = fmt_poly(v, reduce(poly, v.G), v.bits) + ',' if len(s + next_entry) > 71:
print(f'\t{s}')
s = ''
s += (' 'if s else'') + next_entry if s:
print(f'\t{s}')
print('};')
val = G - (1 << n)
desc = f'G - x^{n}' if lsb:
val <<= bits_per_long - n
desc = f'({desc}) * x^{bits_per_long - n}'
print_riscv_const(v, bits_per_long, 'barrett_reduction_const_2', val, desc)
def gen_riscv_clmul_consts(variants):
print('')
print('struct crc_clmul_consts {');
print('\tunsigned long fold_across_2_longs_const_hi;');
print('\tunsigned long fold_across_2_longs_const_lo;');
print('\tunsigned long barrett_reduction_const_1;');
print('\tunsigned long barrett_reduction_const_2;');
print('};'); for v in variants:
print(''); if v.bits > 32:
print_header(v, 'Constants')
print('#ifdef CONFIG_64BIT')
print(f'static const struct crc_clmul_consts {v.name}_consts __maybe_unused = {{')
do_gen_riscv_clmul_consts(v, 64)
print('};')
print('#endif') else:
print_header(v, 'Constants')
print(f'static const struct crc_clmul_consts {v.name}_consts __maybe_unused = {{')
print('#ifdef CONFIG_64BIT')
do_gen_riscv_clmul_consts(v, 64)
print('#else')
do_gen_riscv_clmul_consts(v, 32)
print('#endif')
print('};')
# Generate constants for carryless multiplication based CRC computation. def gen_x86_pclmul_consts(variants): # These are the distances, in bits, to generate folding constants for.
FOLD_DISTANCES = [2048, 1024, 512, 256, 128]
for v in variants:
(G, n, lsb) = (v.G, v.bits, v.lsb)
print('')
print_header(v, 'CRC folding constants')
print('static const struct {') ifnot lsb:
print('\tu8 bswap_mask[16];') for i in FOLD_DISTANCES:
print(f'\tu64 fold_across_{i}_bits_consts[2];')
print('\tu8 shuf_table[48];')
print('\tu64 barrett_reduction_consts[2];')
print(f'}} {v.name}_consts ____cacheline_aligned __maybe_unused = {{')
# Byte-reflection mask, needed for msb-first CRCs ifnot lsb:
print('\t.bswap_mask = {' + ', '.join(str(i) for i in reversed(range(16))) + '},')
# Fold constants for all distances down to 128 bits for i in FOLD_DISTANCES:
print(f'\t.fold_across_{i}_bits_consts = {{') # Given 64x64 => 128 bit carryless multiplication instructions, two # 64-bit fold constants are needed per "fold distance" i: one for # HI64_TERMS that is basically x^(i+64) mod G and one for LO64_TERMS # that is basically x^i mod G. The exact values however undergo a # couple adjustments, described below.
mults = [] for j in [64, 0]:
pow_of_x = i + j if lsb: # Each 64x64 => 128 bit carryless multiplication instruction # actually generates a 127-bit product in physical bits 0 # through 126, which in the lsb-first case represent the # coefficients of x^1 through x^127, not x^0 through x^126. # Thus in the lsb-first case, each such instruction # implicitly adds an extra factor of x. The below removes a # factor of x from each constant to compensate for this. # For n < 64 the x could be removed from either the reduced # part or unreduced part, but for n == 64 the reduced part # is the only option. Just always use the reduced part.
pow_of_x -= 1 # Make a factor of x^(64-n) be applied unreduced rather than # reduced, to cause the product to use only the x^(64-n) and # higher terms and always be zero in the lower terms. Usually # this makes no difference as it does not affect the product's # congruence class mod G and the constant remains 64-bit, but # part of the final reduction from 128 bits does rely on this # property when it reuses one of the constants.
pow_of_x -= 64 - n
mults.append({ 'val': reduce(1 << pow_of_x, G) << (64 - n), 'desc': f'(x^{pow_of_x} mod G) * x^{64-n}' })
print_mult_pair(v, mults)
print('\t},')
# Shuffle table for handling 1..15 bytes at end
print('\t.shuf_table = {')
print('\t\t' + (16*'-1, ').rstrip())
print('\t\t' + ''.join(f'{i:2}, 'for i in range(16)).rstrip())
print('\t\t' + (16*'-1, ').rstrip())
print('\t},')
# Barrett reduction constants for reducing 128 bits to the final CRC
print('\t.barrett_reduction_consts = {')
mults = []
if len(sys.argv) != 3:
sys.stderr.write(f'Usage: {sys.argv[0]} CONSTS_TYPE[,CONSTS_TYPE]... CRC_VARIANT[,CRC_VARIANT]...\n')
sys.stderr.write(' CONSTS_TYPE can be sliceby[1-8], riscv_clmul, or x86_pclmul\n')
sys.stderr.write(' CRC_VARIANT is crc${num_bits}_${bit_order}_${generator_poly_as_hex}\n')
sys.stderr.write(' E.g. crc16_msb_0x8bb7 or crc32_lsb_0xedb88320\n')
sys.stderr.write(' Polynomial must use the given bit_order and exclude x^{num_bits}\n')
sys.exit(1)
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.