6"""Native Python (slow) reimplementation of libminisketch' algorithms."""
26 2**8 + 2**4 + 2**3 + 2**1 + 1,
31 2**13 + 2**4 + 2**3 + 2**1 + 1,
34 2**16 + 2**5 + 2**3 + 2**1 + 1,
37 2**19 + 2**5 + 2**2 + 2**1 + 1,
42 2**24 + 2**4 + 2**3 + 2**1 + 1,
44 2**26 + 2**4 + 2**3 + 2**1 + 1,
45 2**27 + 2**5 + 2**2 + 2**1 + 1,
50 2**32 + 2**7 + 2**3 + 2**2 + 1,
55 2**37 + 2**6 + 2**4 + 2**1 + 1,
56 2**38 + 2**6 + 2**5 + 2**1 + 1,
58 2**40 + 2**5 + 2**4 + 2**3 + 1,
61 2**43 + 2**6 + 2**4 + 2**3 + 1,
63 2**45 + 2**4 + 2**3 + 2**1 + 1,
66 2**48 + 2**5 + 2**3 + 2**2 + 1,
68 2**50 + 2**4 + 2**3 + 2**2 + 1,
69 2**51 + 2**6 + 2**3 + 2**1 + 1,
71 2**53 + 2**6 + 2**2 + 2**1 + 1,
74 2**56 + 2**7 + 2**4 + 2**2 + 1,
77 2**59 + 2**7 + 2**4 + 2**2 + 1,
79 2**61 + 2**5 + 2**2 + 2**1 + 1,
82 2**64 + 2**4 + 2**3 + 2**1 + 1
86 """Class to perform GF(2^field_size) operations on elements represented as integers.
88 Given that elements are represented as integers, addition is simply xor, and not
93 """Construct a GF2Ops object for the specified field size."""
99 """Multiply x by 2 in GF(2^field_size)."""
106 """Multiply x by y in GF(2^field_size)."""
116 """Square x in GF(2^field_size)."""
117 return self.
mul(x, x)
120 """Compute the inverse of x in GF(2^field_size)."""
140 """Test class for basic arithmetic properties of GF2Ops."""
143 """Test operations for given field_size."""
151 self.assertEqual(x2,
gf.mul(x, 2))
152 self.assertEqual(x2,
gf.mul(2, x))
153 self.assertEqual(xy == 0, x == 0
or y == 0)
154 self.assertEqual(xy == x, y == 1
or x == 0)
155 self.assertEqual(xy == y, x == 1
or y == 0)
156 self.assertEqual(xy,
gf.mul(y, x))
159 for _
in range(field_size):
161 self.assertEqual(xp, x)
164 self.assertEqual(y == yi, y == 1)
165 self.assertEqual(
gf.mul(y, yi), 1)
167 self.assertEqual(y, yii)
171 self.assertEqual(xyi,
gf.mul(xi, yi))
175 for field_size
in range(2, 65):
192 """Return a monic version of the polynomial poly."""
195 return [
gf.mul(inv, v)
for v
in poly]
198 """Return the polynomial (quotient, remainder) of poly divided by mod."""
199 assert len(mod) > 0
and mod[-1] == 1
200 if len(poly) < len(mod):
203 div = [0
for _
in range(len(val) - len(mod) + 1)]
204 while len(val) >= len(mod):
206 div[len(val) - len(mod)] = term
210 for x
in range(len(mod) - 1):
211 val[1 + x - len(mod)] ^=
gf.mul(term, mod[x])
213 while len(val) > 0
and val[-1] == 0:
218 """Return the polynomial GCD of a and b."""
229 """Return the square of polynomial poly."""
236 return [0
if i & 1
else gf.sqr(poly[i // 2])
for i
in range(2 * len(poly) - 1)]
239 """Compute y + y^2 + y^4 + ... + y^(2^(field_size-1)) mod poly, where y = param*x."""
254 """Compute x^(2^field_size) mod poly."""
261 """Find the roots of poly if fully factorizable with unique roots, [] otherwise."""
279 """Recursively split poly using the Berlekamp trace algorithm."""
281 assert len(poly) > 1
and poly[-1] == 1
300 if len(gcd) != len(poly)
and len(gcd) > 1:
313 """Test class for poly_find_roots."""
316 """Run tests for given field_size."""
318 for test_size
in [0, 1, 2, 3, 10]:
320 roots_set = set(roots)
324 new_poly = [0] + poly
326 new_poly[n] ^=
gf.mul(c, root)
331 if len(roots) == len(roots_set):
332 self.assertEqual(found_roots,
sorted(roots))
334 self.assertEqual(found_roots, [])
338 for field_size
in range(2, 65):
342 """Implement the Berlekamp-Massey algorithm.
344 Takes as input a sequence of GF(2^field_size) elements, and returns the shortest LSFR
345 that generates it, represented as a polynomial.
351 for n, discrepancy
in enumerate(syndromes):
353 for i
in range(1, len(current)):
354 discrepancy ^=
gf.mul(syndromes[n - i], current[i])
358 x = n + 1 - (len(current) - 1) - (len(prev) - 1)
359 if 2 * (len(current) - 1) <= n:
362 mul =
gf.mul(discrepancy, b_inv)
364 current[i + x] ^=
gf.mul(mul, v)
366 b_inv =
gf.inv(discrepancy)
368 mul =
gf.mul(discrepancy, b_inv)
370 current[i + x] ^=
gf.mul(mul, v)
374 """A Minisketch sketch.
376 This represents a sketch of a certain capacity, with elements of a certain bit size.
380 """Initialize an empty sketch with the specified field_size size and capacity."""
387 """Add an element to this sketch. 1 <= element < 2**field_size."""
388 sqr = self.
gf.sqr(element)
391 element = self.
gf.mul(sqr, element)
394 """Compute how many bytes a serialization of this sketch will be in size."""
398 """Serialize this sketch to bytes."""
405 """Deserialize a byte array into this sketch, overwriting its contents."""
412 """Return a clone of this sketch."""
419 """Merge a sketch with another sketch. Corresponds to XOR'ing their serializations."""
426 """Decode the contents of this sketch.
428 Returns either a list of elements or None if undecodable.
438 all_syndromes[i * 2 + 1] = self.
gf.sqr(all_syndromes[i])
446 if max_count
is not None and len(poly) > 1 + max_count:
458 """Test class for Minisketch."""
462 """Construct two random lists of elements in [1..2**field_size-1].
464 Each list will have unique elements that don't appear in the other (num_a_only in the first
465 and num_b_only in the second), and num_both elements will appear in both."""
468 for _
in range(num_a_only + num_b_only + num_both):
474 full_a = sample[:num_a_only + num_both]
475 full_b = sample[num_a_only:]
478 return full_a, full_b
481 """Test Minisketch methods for a specific field and capacity."""
484 num_both =
random.randrange(min(2 * capacity, (1 << field_size) - 1 - used_capacity) + 1)
485 full_a, full_b = self.
construct_data(field_size, num_a, used_capacity - num_a, num_both)
494 sketch_b_received =
Minisketch(field_size, capacity)
498 self.assertEqual(decode,
sorted(set(full_a) ^ set(full_b)))
502 for field_size
in range(2, 65):
503 for capacity
in [0, 1, 2, 5, 10, field_size]:
506if __name__ ==
'__main__':
__init__(self, field_size)
__init__(self, field_size, capacity)
decode(self, max_count=None)
field_size_test(self, field_size)
field_size_capacity_test(self, field_size, capacity)
construct_data(cls, field_size, num_a_only, num_b_only, num_both)
field_size_test(self, field_size)
berlekamp_massey(syndromes, gf)
poly_tracemod(poly, param, gf)
poly_find_roots(poly, gf)
poly_divmod(poly, mod, gf)
poly_frobeniusmod(poly, gf)
constexpr deserialize_type deserialize
constexpr auto Ticks(Dur2 d)
Helper to count the seconds of a duration/time_point.