1*f9773e66SVladimir Medvedkin /* SPDX-License-Identifier: BSD-3-Clause 2*f9773e66SVladimir Medvedkin * Copyright(c) 2024 Intel Corporation 3*f9773e66SVladimir Medvedkin */ 4*f9773e66SVladimir Medvedkin #include <rte_random.h> 5*f9773e66SVladimir Medvedkin #include <rte_common.h> 6*f9773e66SVladimir Medvedkin #include <rte_bitops.h> 7*f9773e66SVladimir Medvedkin #include <rte_debug.h> 8*f9773e66SVladimir Medvedkin #include <rte_thash.h> 9*f9773e66SVladimir Medvedkin #include <rte_log.h> 10*f9773e66SVladimir Medvedkin 11*f9773e66SVladimir Medvedkin #define MAX_TOEPLITZ_KEY_LENGTH 64 12*f9773e66SVladimir Medvedkin RTE_LOG_REGISTER_SUFFIX(thash_poly_logtype, thash_poly, INFO); 13*f9773e66SVladimir Medvedkin #define RTE_LOGTYPE_HASH thash_poly_logtype 14*f9773e66SVladimir Medvedkin #define HASH_LOG(level, ...) \ 15*f9773e66SVladimir Medvedkin RTE_LOG_LINE(level, HASH, "" __VA_ARGS__) 16*f9773e66SVladimir Medvedkin 17*f9773e66SVladimir Medvedkin /* 18*f9773e66SVladimir Medvedkin * Finite field math for field extensions with irreducing polynomial 19*f9773e66SVladimir Medvedkin * of degree <= 32. 20*f9773e66SVladimir Medvedkin * Polynomials are represented with 2 arguments - uint32_t poly and int degree. 21*f9773e66SVladimir Medvedkin * poly argument does not hold the highest degree coefficient, 22*f9773e66SVladimir Medvedkin * so full polynomial can be expressed as poly|(1ULL << degree). 23*f9773e66SVladimir Medvedkin * The algorithm to produce random irreducible polynomial was inspired by: 24*f9773e66SVladimir Medvedkin * "Computation in finite fields" by John Kerl, Chapter 10.4. 25*f9773e66SVladimir Medvedkin */ 26*f9773e66SVladimir Medvedkin 27*f9773e66SVladimir Medvedkin static const uint32_t irreducible_poly_table[][3] = { 28*f9773e66SVladimir Medvedkin {0, 0, 0}, /* degree 0 */ 29*f9773e66SVladimir Medvedkin {0x1, 0x1, 0x1}, /* degree 1 */ 30*f9773e66SVladimir Medvedkin {0x3, 0x3, 0x3}, /* degree 2 and so on.. */ 31*f9773e66SVladimir Medvedkin {0x3, 0x5, 0x3}, /* x^3+x^2+1(0x5) is reverted x^3+x+1(0x3) */ 32*f9773e66SVladimir Medvedkin {0x3, 0x9, 0x3}, /* x^4+x^3+1(0x9) is reverted x^4+x+1(0x3) */ 33*f9773e66SVladimir Medvedkin {0x5, 0xf, 0x17}, /* 0x5 <-> 0x9; 0xf <-> 0x1d; 0x17 <-> 0x1b */ 34*f9773e66SVladimir Medvedkin {0x3, 0x27, 0x1b}, /* 0x3 <-> 0x21; 0x27 <-> 0x33; 0x1b <-> 0x2d*/ 35*f9773e66SVladimir Medvedkin }; 36*f9773e66SVladimir Medvedkin 37*f9773e66SVladimir Medvedkin /* 38*f9773e66SVladimir Medvedkin * Table of the monic lowest weight irreducible polynomials over GF(2) 39*f9773e66SVladimir Medvedkin * starting from degree 7 up to degree 32. 40*f9773e66SVladimir Medvedkin * Taken from Handbook of Finite Fields by Gary L. Mullen and 41*f9773e66SVladimir Medvedkin * Daniel Penario p.33 Table 2.2.1. 42*f9773e66SVladimir Medvedkin * https://people.math.carleton.ca/~daniel/hff/irred/F2-2to10000.txt 43*f9773e66SVladimir Medvedkin */ 44*f9773e66SVladimir Medvedkin static const uint32_t default_irreducible_poly[] = { 45*f9773e66SVladimir Medvedkin 0x3, /* x^7 + x + 1*/ 46*f9773e66SVladimir Medvedkin 0x1b, /* x^8 + x^4 + x^3 + x + 1 */ 47*f9773e66SVladimir Medvedkin 0x3, /* x^9 + x + 1*/ 48*f9773e66SVladimir Medvedkin 0x9, /* x^10 + x^3 + 1 */ 49*f9773e66SVladimir Medvedkin 0x5, /* x^11 + x^2 + 1 */ 50*f9773e66SVladimir Medvedkin 0x9, /* x^12 + x^3 + 1 */ 51*f9773e66SVladimir Medvedkin 0x1b, /* x^13 + x^4 + x^3 + x + 1 */ 52*f9773e66SVladimir Medvedkin 0x33, /* x^14 + x^5 + 1 */ 53*f9773e66SVladimir Medvedkin 0x3, /* x^15 + x + 1 */ 54*f9773e66SVladimir Medvedkin 0x2b, /* x^16 + x^5 + x^3 + x + 1 */ 55*f9773e66SVladimir Medvedkin 0x9, /* x^17 + x^3 + 1 */ 56*f9773e66SVladimir Medvedkin 0x9, /* x^18 + x^3 + 1 */ 57*f9773e66SVladimir Medvedkin 0x27, /* x^19 + x^5 + x^2 + x + 1 */ 58*f9773e66SVladimir Medvedkin 0x9, /* x^20 + x^3 + 1 */ 59*f9773e66SVladimir Medvedkin 0x5, /* x^21 + x^2 + 1 */ 60*f9773e66SVladimir Medvedkin 0x3, /* x^22 + x + 1 */ 61*f9773e66SVladimir Medvedkin 0x21, /* x^23 + x^5 + 1 */ 62*f9773e66SVladimir Medvedkin 0x1b, /* x^24 + x^4 + x^3 + x + 1 */ 63*f9773e66SVladimir Medvedkin 0x9, /* x^25 + x^3 + 1 */ 64*f9773e66SVladimir Medvedkin 0x1b, /* x^26 + x^4 + x^3 + x + 1 */ 65*f9773e66SVladimir Medvedkin 0x27, /* x^27 + x^5 + x^2 + x + 1 */ 66*f9773e66SVladimir Medvedkin 0x3, /* x^28 + x + 1 */ 67*f9773e66SVladimir Medvedkin 0x5, /* x^29 + x^2 + 1 */ 68*f9773e66SVladimir Medvedkin 0x3, /* x^30 + x + 1 */ 69*f9773e66SVladimir Medvedkin 0x9, /* x^31 + x^3 + 1 */ 70*f9773e66SVladimir Medvedkin 0x8d, /* x^32 + x^7 + x^3 + x^2 + 1 */ 71*f9773e66SVladimir Medvedkin }; 72*f9773e66SVladimir Medvedkin 73*f9773e66SVladimir Medvedkin #define MAX_DIVISORS 28 /* 2^24 - 1 */ 74*f9773e66SVladimir Medvedkin 75*f9773e66SVladimir Medvedkin struct divisors { 76*f9773e66SVladimir Medvedkin uint32_t n; /* number of divisors */ 77*f9773e66SVladimir Medvedkin uint32_t div_arr[MAX_DIVISORS]; 78*f9773e66SVladimir Medvedkin }; 79*f9773e66SVladimir Medvedkin 80*f9773e66SVladimir Medvedkin /* divisors of (2^n - 1) less than MIN(512, 2^n - 1) for all n in [7, 32] */ 81*f9773e66SVladimir Medvedkin static const struct divisors divisors[] = { 82*f9773e66SVladimir Medvedkin { .n = 0, .div_arr = {} }, /* 2^7-1 is Mersenne prime */ 83*f9773e66SVladimir Medvedkin { .n = 6, .div_arr = {3, 5, 15, 17, 51, 85} }, 84*f9773e66SVladimir Medvedkin { .n = 2, .div_arr = {7, 73} }, 85*f9773e66SVladimir Medvedkin { .n = 6, .div_arr = {3, 11, 31, 33, 93, 341} }, 86*f9773e66SVladimir Medvedkin { .n = 2, .div_arr = {23, 89} }, 87*f9773e66SVladimir Medvedkin { .n = 19, .div_arr = {3, 5, 7, 9, 13, 15, 21, 35, 39, 45, 63, 65, 91, 88*f9773e66SVladimir Medvedkin 105, 117, 195, 273, 315, 455} }, 89*f9773e66SVladimir Medvedkin { .n = 0, .div_arr = {} }, /* 2^13-1 is Mersenne prime */ 90*f9773e66SVladimir Medvedkin { .n = 5, .div_arr = {3, 43, 127, 129, 381} }, 91*f9773e66SVladimir Medvedkin { .n = 4, .div_arr = {7, 31, 151, 217} }, 92*f9773e66SVladimir Medvedkin { .n = 8, .div_arr = {3, 5, 15, 17, 51, 85, 255, 257} }, 93*f9773e66SVladimir Medvedkin { .n = 0, .div_arr = {} }, /* 2^17-1 is Mersenne prime */ 94*f9773e66SVladimir Medvedkin { .n = 14, .div_arr = {3, 7, 9, 19, 21, 27, 57, 63, 73, 133, 171, 189, 95*f9773e66SVladimir Medvedkin 219, 399} }, 96*f9773e66SVladimir Medvedkin { .n = 0, .div_arr = {0} }, /* 2^19-1 is Mersenne prime */ 97*f9773e66SVladimir Medvedkin { .n = 19, .div_arr = {3, 5, 11, 15, 25, 31, 33, 41, 55, 75, 93, 123, 98*f9773e66SVladimir Medvedkin 155, 165, 205, 275, 341, 451, 465} }, 99*f9773e66SVladimir Medvedkin { .n = 4, .div_arr = {7, 49, 127, 337} }, 100*f9773e66SVladimir Medvedkin { .n = 5, .div_arr = {3, 23, 69, 89, 267} }, 101*f9773e66SVladimir Medvedkin { .n = 1, .div_arr = {47} }, 102*f9773e66SVladimir Medvedkin { .n = 28, .div_arr = {3, 5, 7, 9, 13, 15, 17, 21, 35, 39, 45, 51, 63, 103*f9773e66SVladimir Medvedkin 65, 85, 91, 105, 117, 119, 153, 195, 221, 241, 255, 273, 315, 104*f9773e66SVladimir Medvedkin 357, 455} }, 105*f9773e66SVladimir Medvedkin { .n = 1, .div_arr = {31} }, 106*f9773e66SVladimir Medvedkin { .n = 1, .div_arr = {3} }, 107*f9773e66SVladimir Medvedkin { .n = 2, .div_arr = {7, 73} }, 108*f9773e66SVladimir Medvedkin { .n = 14, .div_arr = {3, 5, 15, 29, 43, 87, 113, 127, 129, 145, 215, 109*f9773e66SVladimir Medvedkin 339, 381, 435} }, 110*f9773e66SVladimir Medvedkin { .n = 1, .div_arr = {233} }, 111*f9773e66SVladimir Medvedkin { .n = 18, .div_arr = {3, 7, 9, 11, 21, 31, 33, 63, 77, 93, 99, 151, 112*f9773e66SVladimir Medvedkin 217, 231, 279, 331, 341, 453} }, 113*f9773e66SVladimir Medvedkin { .n = 0, .div_arr = {} },/* 2^31-1 is Mersenne prime */ 114*f9773e66SVladimir Medvedkin { .n = 8, .div_arr = {3, 5, 15, 17, 51, 85, 255, 257} }, 115*f9773e66SVladimir Medvedkin }; 116*f9773e66SVladimir Medvedkin 117*f9773e66SVladimir Medvedkin static uint32_t 118*f9773e66SVladimir Medvedkin gf2_mul(uint32_t a, uint32_t b, uint32_t r, int degree) 119*f9773e66SVladimir Medvedkin { 120*f9773e66SVladimir Medvedkin uint64_t product = 0; 121*f9773e66SVladimir Medvedkin uint64_t r_poly = r|(1ULL << degree); 122*f9773e66SVladimir Medvedkin 123*f9773e66SVladimir Medvedkin for (; b; b &= (b - 1)) 124*f9773e66SVladimir Medvedkin product ^= (uint64_t)a << (rte_bsf32(b)); 125*f9773e66SVladimir Medvedkin 126*f9773e66SVladimir Medvedkin for (int i = degree * 2 - 1; i >= degree; i--) 127*f9773e66SVladimir Medvedkin if (product & (1 << i)) 128*f9773e66SVladimir Medvedkin product ^= r_poly << (i - degree); 129*f9773e66SVladimir Medvedkin 130*f9773e66SVladimir Medvedkin return product; 131*f9773e66SVladimir Medvedkin } 132*f9773e66SVladimir Medvedkin 133*f9773e66SVladimir Medvedkin static uint32_t 134*f9773e66SVladimir Medvedkin gf2_pow(uint32_t a, uint32_t pow, uint32_t r, int degree) 135*f9773e66SVladimir Medvedkin { 136*f9773e66SVladimir Medvedkin uint32_t result = 1; 137*f9773e66SVladimir Medvedkin unsigned int i; 138*f9773e66SVladimir Medvedkin 139*f9773e66SVladimir Medvedkin for (i = 0; i < (sizeof(pow)*CHAR_BIT - rte_clz32(pow)); i++) { 140*f9773e66SVladimir Medvedkin if (pow & (1 << i)) 141*f9773e66SVladimir Medvedkin result = gf2_mul(result, a, r, degree); 142*f9773e66SVladimir Medvedkin 143*f9773e66SVladimir Medvedkin a = gf2_mul(a, a, r, degree); 144*f9773e66SVladimir Medvedkin } 145*f9773e66SVladimir Medvedkin 146*f9773e66SVladimir Medvedkin return result; 147*f9773e66SVladimir Medvedkin } 148*f9773e66SVladimir Medvedkin 149*f9773e66SVladimir Medvedkin static uint32_t 150*f9773e66SVladimir Medvedkin __thash_get_rand_poly(int poly_degree) 151*f9773e66SVladimir Medvedkin { 152*f9773e66SVladimir Medvedkin uint32_t roots[poly_degree]; 153*f9773e66SVladimir Medvedkin uint32_t rnd; 154*f9773e66SVladimir Medvedkin uint32_t ret_poly = 0; 155*f9773e66SVladimir Medvedkin int i, j; 156*f9773e66SVladimir Medvedkin bool short_orbit = false; 157*f9773e66SVladimir Medvedkin 158*f9773e66SVladimir Medvedkin /* special case for low degree */ 159*f9773e66SVladimir Medvedkin if (poly_degree < 7) 160*f9773e66SVladimir Medvedkin return irreducible_poly_table[poly_degree][rte_rand() % 161*f9773e66SVladimir Medvedkin RTE_DIM(irreducible_poly_table[poly_degree])]; 162*f9773e66SVladimir Medvedkin 163*f9773e66SVladimir Medvedkin uint32_t r = default_irreducible_poly[poly_degree - 7]; 164*f9773e66SVladimir Medvedkin 165*f9773e66SVladimir Medvedkin do { 166*f9773e66SVladimir Medvedkin short_orbit = false; 167*f9773e66SVladimir Medvedkin do { 168*f9773e66SVladimir Medvedkin rnd = rte_rand() & ((1 << poly_degree) - 1); 169*f9773e66SVladimir Medvedkin } while ((rnd == 0) || (rnd == 1)); 170*f9773e66SVladimir Medvedkin 171*f9773e66SVladimir Medvedkin /* 172*f9773e66SVladimir Medvedkin * Quick check if random returned one of the roots of 173*f9773e66SVladimir Medvedkin * the initial polynomial. 174*f9773e66SVladimir Medvedkin * In other words if we randomy got x, x^2, x^4, x^8 or x^16 175*f9773e66SVladimir Medvedkin */ 176*f9773e66SVladimir Medvedkin #define ROOT_POLY_MSK ((1 << 1)|(1 << 2)|(1 << 4)|(1 << 8)|(1 << 16)) 177*f9773e66SVladimir Medvedkin if ((rte_popcount32(rnd) == 1) && (rnd & ROOT_POLY_MSK)) 178*f9773e66SVladimir Medvedkin return default_irreducible_poly[poly_degree - 7]; 179*f9773e66SVladimir Medvedkin 180*f9773e66SVladimir Medvedkin /* 181*f9773e66SVladimir Medvedkin * init array with some random polynomial roots 182*f9773e66SVladimir Medvedkin * applying Frobenius automorphism (i.e. squaring them) 183*f9773e66SVladimir Medvedkin * also checking for short orbits (i.e. if there are repeated roots) 184*f9773e66SVladimir Medvedkin */ 185*f9773e66SVladimir Medvedkin roots[0] = rnd; 186*f9773e66SVladimir Medvedkin for (i = 1; i < poly_degree; i++) { 187*f9773e66SVladimir Medvedkin roots[i] = gf2_pow(roots[i - 1], 2, r, poly_degree); 188*f9773e66SVladimir Medvedkin if (roots[i] == roots[0]) 189*f9773e66SVladimir Medvedkin short_orbit = true; 190*f9773e66SVladimir Medvedkin } 191*f9773e66SVladimir Medvedkin } while (short_orbit); 192*f9773e66SVladimir Medvedkin 193*f9773e66SVladimir Medvedkin /* 194*f9773e66SVladimir Medvedkin * Get coefficients of the polynomial for 195*f9773e66SVladimir Medvedkin * (x - roots[0])(x - roots[1])...(x - roots[n]) 196*f9773e66SVladimir Medvedkin */ 197*f9773e66SVladimir Medvedkin uint32_t poly_coefficients[poly_degree + 1]; 198*f9773e66SVladimir Medvedkin for (i = 0; i <= poly_degree; i++) 199*f9773e66SVladimir Medvedkin poly_coefficients[i] = 0; 200*f9773e66SVladimir Medvedkin 201*f9773e66SVladimir Medvedkin poly_coefficients[0] = 1; /* highest degree term coefficient in the end */ 202*f9773e66SVladimir Medvedkin for (i = 0; i < (int)poly_degree; i++) { 203*f9773e66SVladimir Medvedkin /* multiply by x */ 204*f9773e66SVladimir Medvedkin for (j = i; j >= 0; j--) 205*f9773e66SVladimir Medvedkin poly_coefficients[j + 1] = poly_coefficients[j]; 206*f9773e66SVladimir Medvedkin 207*f9773e66SVladimir Medvedkin poly_coefficients[0] = 0; 208*f9773e66SVladimir Medvedkin 209*f9773e66SVladimir Medvedkin /* multiply by root */ 210*f9773e66SVladimir Medvedkin for (j = 0; j <= i; j++) 211*f9773e66SVladimir Medvedkin poly_coefficients[j] ^= 212*f9773e66SVladimir Medvedkin gf2_mul(poly_coefficients[j + 1], 213*f9773e66SVladimir Medvedkin roots[i], r, poly_degree); 214*f9773e66SVladimir Medvedkin } 215*f9773e66SVladimir Medvedkin 216*f9773e66SVladimir Medvedkin for (i = 0; i < poly_degree; i++) { 217*f9773e66SVladimir Medvedkin if (poly_coefficients[i]) { 218*f9773e66SVladimir Medvedkin RTE_ASSERT(poly_coefficients[i] == 1); 219*f9773e66SVladimir Medvedkin ret_poly |= 1 << i; 220*f9773e66SVladimir Medvedkin } 221*f9773e66SVladimir Medvedkin } 222*f9773e66SVladimir Medvedkin 223*f9773e66SVladimir Medvedkin return ret_poly; 224*f9773e66SVladimir Medvedkin } 225*f9773e66SVladimir Medvedkin 226*f9773e66SVladimir Medvedkin /* test an order of the multiplicative subgroup generated by x */ 227*f9773e66SVladimir Medvedkin static int 228*f9773e66SVladimir Medvedkin thash_test_poly_order(uint32_t poly, int degree) 229*f9773e66SVladimir Medvedkin { 230*f9773e66SVladimir Medvedkin unsigned int i; 231*f9773e66SVladimir Medvedkin int div_idx = degree - 7; 232*f9773e66SVladimir Medvedkin 233*f9773e66SVladimir Medvedkin if (degree < 7) 234*f9773e66SVladimir Medvedkin return 0; 235*f9773e66SVladimir Medvedkin 236*f9773e66SVladimir Medvedkin for (i = 0; i < divisors[div_idx].n; i++) { 237*f9773e66SVladimir Medvedkin if (gf2_pow(0x2, divisors[div_idx].div_arr[i], 238*f9773e66SVladimir Medvedkin poly, degree) == 1) 239*f9773e66SVladimir Medvedkin return 1; 240*f9773e66SVladimir Medvedkin } 241*f9773e66SVladimir Medvedkin 242*f9773e66SVladimir Medvedkin return 0; 243*f9773e66SVladimir Medvedkin } 244*f9773e66SVladimir Medvedkin 245*f9773e66SVladimir Medvedkin uint32_t 246*f9773e66SVladimir Medvedkin thash_get_rand_poly(uint32_t poly_degree) 247*f9773e66SVladimir Medvedkin { 248*f9773e66SVladimir Medvedkin uint32_t ret_poly; 249*f9773e66SVladimir Medvedkin 250*f9773e66SVladimir Medvedkin if (poly_degree > 32) { 251*f9773e66SVladimir Medvedkin HASH_LOG(ERR, "Wrong polynomial degree %d, must be in range [1, 32]", poly_degree); 252*f9773e66SVladimir Medvedkin return 0; 253*f9773e66SVladimir Medvedkin } 254*f9773e66SVladimir Medvedkin 255*f9773e66SVladimir Medvedkin do 256*f9773e66SVladimir Medvedkin ret_poly = __thash_get_rand_poly(poly_degree); 257*f9773e66SVladimir Medvedkin while (thash_test_poly_order(ret_poly, poly_degree)); 258*f9773e66SVladimir Medvedkin 259*f9773e66SVladimir Medvedkin return ret_poly; 260*f9773e66SVladimir Medvedkin } 261