xref: /dpdk/lib/hash/rte_thash_gf2_poly_math.c (revision f9773e6676950b986c2375d9ac0bcbce8ea1b469)
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