622 lines
30 KiB
Python
622 lines
30 KiB
Python
#!/usr/bin/env python3.7
|
|
# -*- coding: utf-8 -*-
|
|
|
|
"""
|
|
# Copyright (c) 2012-2015 Tomer Filiba <tomerfiliba@gmail.com>
|
|
# Copyright (c) 2015 rotorgit
|
|
# Copyright (c) 2015 Stephen Larroque <LRQ3000@gmail.com>
|
|
|
|
The Reed Solomon erasure code library has been released to the public domain.
|
|
|
|
https://github.com/lrq3000/reedsolomon/blob/master/LICENSE
|
|
https://github.com/tomerfiliba/reedsolomon/blob/master/LICENSE
|
|
"""
|
|
|
|
import unittest
|
|
|
|
from random import sample
|
|
|
|
from src.common.reed_solomon import (RSCodec, ReedSolomonError, find_prime_polys, gf_add, gf_div, gf_mul, gf_mult_nolut,
|
|
gf_mult_nolut_slow, gf_neg, gf_poly_mul, gf_poly_mul_simple, gf_poly_neg, gf_sub,
|
|
init_tables, itertools, rs_check, rs_correct_msg, rs_correct_msg_nofsynd,
|
|
rs_encode_msg, rs_generator_poly, rs_generator_poly_all, rs_simple_encode_msg)
|
|
|
|
|
|
class TestReedSolomon(unittest.TestCase):
|
|
|
|
def test_simple(self):
|
|
rs = RSCodec()
|
|
msg = bytearray("hello world " * 10, "latin1")
|
|
enc = rs.encode(msg)
|
|
dec, dec_enc = rs.decode(enc)
|
|
self.assertEqual(dec, msg)
|
|
self.assertEqual(dec_enc, enc)
|
|
|
|
def test_correction(self):
|
|
rs = RSCodec()
|
|
msg = bytearray("hello world " * 10, "latin1")
|
|
enc = rs.encode(msg)
|
|
rmsg, renc = rs.decode(enc)
|
|
self.assertEqual(rmsg, msg)
|
|
self.assertEqual(renc, enc)
|
|
for i in [27, -3, -9, 7, 0]:
|
|
enc[i] = 99
|
|
rmsg, renc = rs.decode(enc)
|
|
self.assertEqual(rmsg, msg)
|
|
enc[82] = 99
|
|
self.assertRaises(ReedSolomonError, rs.decode, enc)
|
|
|
|
def test_check(self):
|
|
rs = RSCodec()
|
|
msg = bytearray("hello world " * 10, "latin1")
|
|
enc = rs.encode(msg)
|
|
rmsg, renc = rs.decode(enc)
|
|
self.assertEqual(rs.check(enc), [True])
|
|
self.assertEqual(rs.check(renc), [True])
|
|
for i in [27, -3, -9, 7, 0]:
|
|
enc[i] = 99
|
|
rmsg, renc = rs.decode(enc)
|
|
self.assertEqual(rs.check(enc), [False])
|
|
self.assertEqual(rs.check(renc), [True])
|
|
|
|
def test_long(self):
|
|
rs = RSCodec()
|
|
msg = bytearray("a" * 10000, "latin1")
|
|
enc = rs.encode(msg)
|
|
dec, dec_enc = rs.decode(enc)
|
|
self.assertEqual(dec, msg)
|
|
self.assertEqual(dec_enc, enc)
|
|
enc2 = list(enc)
|
|
enc2[177] = 99
|
|
enc2[2212] = 88
|
|
dec2, dec_enc2 = rs.decode(bytes(enc2))
|
|
self.assertEqual(dec2, msg)
|
|
self.assertEqual(dec_enc2, enc)
|
|
|
|
def test_prim_fcr_basic(self):
|
|
nn = 30
|
|
kk = 18
|
|
tt = nn - kk
|
|
rs = RSCodec(tt, fcr=120, prim=0x187)
|
|
hexencmsg = ('00faa123555555c000000354064432'
|
|
'c02800fe97c434e1ff5365cf8fafe4')
|
|
strf = str
|
|
encmsg = bytearray.fromhex(strf(hexencmsg))
|
|
decmsg = encmsg[:kk]
|
|
tem = rs.encode(decmsg)
|
|
self.assertEqual(encmsg, tem, msg="encoded does not match expected")
|
|
|
|
tdm, rtem = rs.decode(tem)
|
|
self.assertEqual(tdm, decmsg, msg="decoded does not match original")
|
|
self.assertEqual(rtem, tem, msg="decoded mesecc does not match original")
|
|
|
|
tem1 = bytearray(tem) # Clone a copy
|
|
|
|
# Encoding and decoding intact message seem OK, so test errors
|
|
numerrs = tt >> 1 # Inject tt/2 errors (expected to recover fully)
|
|
for i in sample(range(nn), numerrs): # inject errors in random places
|
|
tem1[i] ^= 0xff # flip all 8 bits
|
|
tdm, _ = rs.decode(tem1)
|
|
self.assertEqual(tdm, decmsg, msg="decoded with errors does not match original")
|
|
|
|
tem1 = bytearray(tem) # Clone another copy
|
|
numerrs += 1 # Inject tt/2 + 1 errors (expected to fail and detect it)
|
|
for i in sample(range(nn), numerrs): # Inject errors in random places
|
|
tem1[i] ^= 0xff # Flip all 8 bits
|
|
# If this fails, it means excessive errors not detected
|
|
self.assertRaises(ReedSolomonError, rs.decode, tem1)
|
|
|
|
def test_prim_fcr_long(self):
|
|
nn = 48
|
|
kk = 34
|
|
tt = nn - kk
|
|
rs = RSCodec(tt, fcr=120, prim=0x187)
|
|
hexencmsg = ('08faa123555555c000000354064432c0280e1b4d090cfc04'
|
|
'887400000003500000000e1985ff9c6b33066ca9f43d12e8')
|
|
strf = str
|
|
encmsg = bytearray.fromhex(strf(hexencmsg))
|
|
decmsg = encmsg[:kk]
|
|
tem = rs.encode(decmsg)
|
|
self.assertEqual(encmsg, tem, msg="encoded does not match expected")
|
|
|
|
tdm, rtem = rs.decode(tem)
|
|
self.assertEqual(tdm, decmsg, msg="decoded does not match original")
|
|
self.assertEqual(rtem, tem, msg="decoded mesecc does not match original")
|
|
|
|
tem1 = bytearray(tem)
|
|
numerrs = tt >> 1
|
|
for i in sample(range(nn), numerrs):
|
|
tem1[i] ^= 0xff
|
|
tdm, rtem = rs.decode(tem1)
|
|
self.assertEqual(tdm, decmsg, msg="decoded with errors does not match original")
|
|
self.assertEqual(rtem, tem, msg="decoded mesecc with errors does not match original")
|
|
|
|
tem1 = bytearray(tem)
|
|
numerrs += 1
|
|
for i in sample(range(nn), numerrs):
|
|
tem1[i] ^= 0xff
|
|
self.assertRaises(ReedSolomonError, rs.decode, tem1)
|
|
|
|
def test_generator_poly(self):
|
|
"""\
|
|
Test if generator poly finder is working correctly and if
|
|
the all generators poly finder does output the same result
|
|
"""
|
|
n = 11
|
|
k = 3
|
|
|
|
# Base 2 test
|
|
fcr = 120
|
|
generator = 2
|
|
prim = 0x11d
|
|
init_tables(generator=generator, prim=prim)
|
|
g = rs_generator_poly_all(n, fcr=fcr, generator=generator)
|
|
self.assertEqual(list(g[n-k]), list(rs_generator_poly(n-k, fcr=fcr, generator=generator)))
|
|
self.assertEqual(list(g[n-k]), [1, 106, 9, 105, 86, 5, 166, 76, 9])
|
|
|
|
# Base 3 test
|
|
fcr = 0
|
|
generator = 3
|
|
prim = 0x11b
|
|
init_tables(generator=generator, prim=prim)
|
|
g = rs_generator_poly_all(n, fcr=fcr, generator=generator)
|
|
self.assertEqual(list(g[n-k]), list(rs_generator_poly(n-k, fcr=fcr, generator=generator)))
|
|
self.assertEqual(list(g[n-k]), [1, 128, 13, 69, 36, 145, 199, 165, 30])
|
|
|
|
def test_prime_poly_build(self):
|
|
"""\
|
|
Try if the prime polynomials finder works correctly for
|
|
different GFs (ie, GF(2^6) to GF(2^10)) and with different
|
|
generators.
|
|
"""
|
|
params = {"count": 7,
|
|
"c_exp": [6, 7, 7, 8, 8, 9, 10],
|
|
"generator": [2, 2, 3, 2, 3, 2, 2],
|
|
"expected":
|
|
[
|
|
[67, 91, 97, 103, 109, 115],
|
|
[131, 137, 143, 145, 157, 167, 171, 185, 191, 193, 203, 211, 213, 229, 239, 241, 247, 253],
|
|
[131, 137, 143, 145, 157, 167, 171, 185, 191, 193, 203, 211, 213, 229, 239, 241, 247, 253],
|
|
[285, 299, 301, 333, 351, 355, 357, 361, 369, 391, 397, 425, 451, 463, 487, 501],
|
|
[283, 313, 319, 333, 351, 355, 357, 361, 375, 397, 415, 419, 425, 451, 501, 505],
|
|
|
|
[529, 539, 545, 557, 563, 601, 607, 617, 623, 631, 637, 647, 661, 675, 677, 687,
|
|
695, 701, 719, 721, 731, 757, 761, 787, 789, 799, 803, 817, 827, 847, 859, 865,
|
|
875, 877, 883, 895, 901, 911, 949, 953, 967, 971, 973, 981, 985, 995, 1001, 1019],
|
|
|
|
[1033, 1051, 1063, 1069, 1125, 1135, 1153, 1163, 1221, 1239, 1255, 1267, 1279, 1293, 1305,
|
|
1315, 1329, 1341, 1347, 1367, 1387, 1413, 1423, 1431, 1441, 1479, 1509, 1527, 1531, 1555,
|
|
1557, 1573, 1591, 1603, 1615, 1627, 1657, 1663, 1673, 1717, 1729, 1747, 1759, 1789, 1815,
|
|
1821, 1825, 1849, 1863, 1869, 1877, 1881, 1891, 1917, 1933, 1939, 1969, 2011, 2035, 2041]
|
|
]
|
|
}
|
|
|
|
for i in range(params['count']):
|
|
self.assertEqual(find_prime_polys(generator=params['generator'][i],
|
|
c_exp=params['c_exp'][i]),
|
|
params["expected"][i])
|
|
|
|
def test_init_tables(self):
|
|
"""\
|
|
Try if the look up table generator (galois field generator)
|
|
works correctly for different parameters.
|
|
"""
|
|
params = [
|
|
[0x11d, 2, 8],
|
|
[0x11b, 3, 8],
|
|
[0xfd, 3, 7]
|
|
]
|
|
expected = [
|
|
[
|
|
[0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52,
|
|
141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33,
|
|
53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154,
|
|
9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179,
|
|
16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56,
|
|
70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202,
|
|
94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192,
|
|
247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38,
|
|
184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207,
|
|
205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132,
|
|
60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236,
|
|
127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204,
|
|
62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215,
|
|
79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175],
|
|
|
|
[1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90,
|
|
180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148,
|
|
53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186,
|
|
105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15,
|
|
30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91,
|
|
182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103,
|
|
206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133,
|
|
23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41,
|
|
82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145,
|
|
63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196,
|
|
149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112,
|
|
224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172,
|
|
69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22,
|
|
44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4, 8, 16,
|
|
32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201,
|
|
143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181,
|
|
119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111,
|
|
222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240,
|
|
253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217,
|
|
175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124,
|
|
248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109,
|
|
218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73,
|
|
146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229,
|
|
215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220,
|
|
165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83,
|
|
166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36,
|
|
72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125,
|
|
250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142],
|
|
|
|
255
|
|
],
|
|
[
|
|
[0, 0, 25, 1, 50, 2, 26, 198, 75, 199, 27, 104, 51, 238, 223, 3, 100, 4, 224, 14, 52,
|
|
141, 129, 239, 76, 113, 8, 200, 248, 105, 28, 193, 125, 194, 29, 181, 249, 185, 39,
|
|
106, 77, 228, 166, 114, 154, 201, 9, 120, 101, 47, 138, 5, 33, 15, 225, 36, 18, 240,
|
|
130, 69, 53, 147, 218, 142, 150, 143, 219, 189, 54, 208, 206, 148, 19, 92, 210, 241,
|
|
64, 70, 131, 56, 102, 221, 253, 48, 191, 6, 139, 98, 179, 37, 226, 152, 34, 136, 145,
|
|
16, 126, 110, 72, 195, 163, 182, 30, 66, 58, 107, 40, 84, 250, 133, 61, 186, 43, 121,
|
|
10, 21, 155, 159, 94, 202, 78, 212, 172, 229, 243, 115, 167, 87, 175, 88, 168, 80,
|
|
244, 234, 214, 116, 79, 174, 233, 213, 231, 230, 173, 232, 44, 215, 117, 122, 235,
|
|
22, 11, 245, 89, 203, 95, 176, 156, 169, 81, 160, 127, 12, 246, 111, 23, 196, 73,
|
|
236, 216, 67, 31, 45, 164, 118, 123, 183, 204, 187, 62, 90, 251, 96, 177, 134, 59,
|
|
82, 161, 108, 170, 85, 41, 157, 151, 178, 135, 144, 97, 190, 220, 252, 188, 149, 207,
|
|
205, 55, 63, 91, 209, 83, 57, 132, 60, 65, 162, 109, 71, 20, 42, 158, 93, 86, 242,
|
|
211, 171, 68, 17, 146, 217, 35, 32, 46, 137, 180, 124, 184, 38, 119, 153, 227, 165,
|
|
103, 74, 237, 222, 197, 49, 254, 24, 13, 99, 140, 128, 192, 247, 112, 7],
|
|
|
|
[1, 3, 5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, 95, 225, 56, 72,
|
|
216, 115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, 229, 52, 92, 228, 55, 89, 235,
|
|
38, 106, 190, 217, 112, 144, 171, 230, 49, 83, 245, 4, 12, 20, 60, 68, 204, 79, 209,
|
|
104, 184, 211, 110, 178, 205, 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8,
|
|
24, 40, 120, 136, 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73,
|
|
219, 118, 154, 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97,
|
|
163, 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, 251,
|
|
22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, 195, 94, 226, 61,
|
|
71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172, 239,
|
|
42, 126, 130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193, 88, 232, 35, 101,
|
|
175, 234, 37, 111, 177, 200, 67, 197, 84, 252, 31, 33, 99, 165, 244, 7, 9, 27, 45,
|
|
119, 153, 176, 203, 70, 202, 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62, 66,
|
|
198, 81, 243, 14, 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167, 242,
|
|
13, 23, 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246, 1, 3,
|
|
5, 15, 17, 51, 85, 255, 26, 46, 114, 150, 161, 248, 19, 53, 95, 225, 56, 72, 216,
|
|
115, 149, 164, 247, 2, 6, 10, 30, 34, 102, 170, 229, 52, 92, 228, 55, 89, 235, 38,
|
|
106, 190, 217, 112, 144, 171, 230, 49, 83, 245, 4, 12, 20, 60, 68, 204, 79, 209,
|
|
104, 184, 211, 110, 178, 205, 76, 212, 103, 169, 224, 59, 77, 215, 98, 166, 241, 8,
|
|
24, 40, 120, 136, 131, 158, 185, 208, 107, 189, 220, 127, 129, 152, 179, 206, 73,
|
|
219, 118, 154, 181, 196, 87, 249, 16, 48, 80, 240, 11, 29, 39, 105, 187, 214, 97,
|
|
163, 254, 25, 43, 125, 135, 146, 173, 236, 47, 113, 147, 174, 233, 32, 96, 160, 251,
|
|
22, 58, 78, 210, 109, 183, 194, 93, 231, 50, 86, 250, 21, 63, 65, 195, 94, 226, 61,
|
|
71, 201, 64, 192, 91, 237, 44, 116, 156, 191, 218, 117, 159, 186, 213, 100, 172,
|
|
239, 42, 126, 130, 157, 188, 223, 122, 142, 137, 128, 155, 182, 193, 88, 232, 35,
|
|
101, 175, 234, 37, 111, 177, 200, 67, 197, 84, 252, 31, 33, 99, 165, 244, 7, 9, 27,
|
|
45, 119, 153, 176, 203, 70, 202, 69, 207, 74, 222, 121, 139, 134, 145, 168, 227, 62,
|
|
66, 198, 81, 243, 14, 18, 54, 90, 238, 41, 123, 141, 140, 143, 138, 133, 148, 167,
|
|
242, 13, 23, 57, 75, 221, 124, 132, 151, 162, 253, 28, 36, 108, 180, 199, 82, 246],
|
|
|
|
255
|
|
],
|
|
[
|
|
[0, 0, 7, 1, 14, 2, 8, 56, 21, 57, 9, 90, 15, 31, 63, 3, 28, 4, 64, 67, 16, 112, 97,
|
|
32, 22, 47, 38, 58, 70, 91, 10, 108, 35, 109, 11, 87, 71, 79, 74, 92, 23, 82, 119,
|
|
48, 104, 59, 39, 100, 29, 19, 54, 5, 45, 68, 65, 95, 77, 33, 98, 117, 17, 43, 115,
|
|
113, 42, 114, 116, 76, 18, 53, 94, 44, 78, 73, 86, 34, 81, 118, 99, 103, 30, 62, 89,
|
|
20, 126, 6, 55, 13, 111, 96, 66, 27, 46, 37, 107, 69, 36, 106, 26, 110, 61, 88, 12,
|
|
125, 52, 93, 75, 41, 72, 85, 102, 80, 84, 101, 40, 51, 105, 25, 124, 60, 24, 123, 50,
|
|
83, 122, 49, 120, 121],
|
|
|
|
[1, 3, 5, 15, 17, 51, 85, 2, 6, 10, 30, 34, 102, 87, 4, 12, 20, 60, 68, 49, 83, 8, 24,
|
|
40, 120, 117, 98, 91, 16, 48, 80, 13, 23, 57, 75, 32, 96, 93, 26, 46, 114, 107, 64,
|
|
61, 71, 52, 92, 25, 43, 125, 122, 115, 104, 69, 50, 86, 7, 9, 27, 45, 119, 100, 81,
|
|
14, 18, 54, 90, 19, 53, 95, 28, 36, 108, 73, 38, 106, 67, 56, 72, 37, 111, 76, 41,
|
|
123, 112, 109, 74, 35, 101, 82, 11, 29, 39, 105, 70, 55, 89, 22, 58, 78, 47, 113,
|
|
110, 79, 44, 116, 97, 94, 31, 33, 99, 88, 21, 63, 65, 62, 66, 59, 77, 42, 126, 127,
|
|
124, 121, 118, 103, 84, 1, 3, 5, 15, 17, 51, 85, 2, 6, 10, 30, 34, 102, 87, 4, 12,
|
|
20, 60, 68, 49, 83, 8, 24, 40, 120, 117, 98, 91, 16, 48, 80, 13, 23, 57, 75, 32, 96,
|
|
93, 26, 46, 114, 107, 64, 61, 71, 52, 92, 25, 43, 125, 122, 115, 104, 69, 50, 86, 7,
|
|
9, 27, 45, 119, 100, 81, 14, 18, 54, 90, 19, 53, 95, 28, 36, 108, 73, 38, 106, 67,
|
|
56, 72, 37, 111, 76, 41, 123, 112, 109, 74, 35, 101, 82, 11, 29, 39, 105, 70, 55, 89,
|
|
22, 58, 78, 47, 113, 110, 79, 44, 116, 97, 94, 31, 33, 99, 88, 21, 63, 65, 62, 66,
|
|
59, 77, 42, 126, 127, 124, 121, 118, 103, 84],
|
|
|
|
127
|
|
]
|
|
]
|
|
|
|
for i in range(len(params)):
|
|
p = params[i]
|
|
expected_log_t, expected_exp_t, expected_field_charac_t = expected[i]
|
|
log_t, exp_t, field_charac_t = init_tables(prim=p[0], generator=p[1], c_exp=p[2])
|
|
self.assertEqual(field_charac_t, expected_field_charac_t)
|
|
self.assertEqual(list(log_t), expected_log_t)
|
|
self.assertEqual(list(exp_t), expected_exp_t)
|
|
|
|
|
|
class TestBigReedSolomon(unittest.TestCase):
|
|
|
|
def test_find_prime_polys(self):
|
|
self.assertEqual(find_prime_polys(c_exp=4), [19, 25])
|
|
self.assertEqual(find_prime_polys(),
|
|
[285, 299, 301, 333, 351, 355, 357, 361, 369, 391, 397, 425, 451, 463, 487, 501])
|
|
|
|
self.assertEqual(find_prime_polys(fast_primes=True), [397, 463, 487])
|
|
self.assertEqual(find_prime_polys(c_exp=9, fast_primes=True, single=True), 557)
|
|
|
|
def test_c_exp_9(self):
|
|
rsc = RSCodec(12, c_exp=9)
|
|
rsc2 = RSCodec(12, nsize=511)
|
|
self.assertEqual(rsc.c_exp, rsc2.c_exp)
|
|
self.assertEqual(rsc.nsize, rsc2.nsize)
|
|
|
|
mes = 'a'*((511-12)*2)
|
|
mesecc = rsc.encode(mes)
|
|
mesecc[2] = 1
|
|
mesecc[-1] = 1
|
|
rmes, rmesecc = rsc.decode(mesecc)
|
|
self.assertEqual(rsc.check(mesecc), [False, False])
|
|
self.assertEqual(rsc.check(rmesecc), [True, True])
|
|
self.assertEqual([x for x in rmes], [ord(x) for x in mes])
|
|
|
|
def test_c_exp_12(self):
|
|
rsc = RSCodec(12, c_exp=12)
|
|
rsc2 = RSCodec(12, nsize=4095)
|
|
self.assertEqual(rsc.c_exp, rsc2.c_exp)
|
|
self.assertEqual(rsc.nsize, rsc2.nsize)
|
|
|
|
mes = 'a'*(4095-12)
|
|
mesecc = rsc.encode(mes)
|
|
mesecc[2] = 1
|
|
mesecc[-1] = 1
|
|
rmes, rmesecc = rsc.decode(mesecc)
|
|
self.assertEqual(rsc.check(mesecc), [False])
|
|
self.assertEqual(rsc.check(rmesecc), [True])
|
|
self.assertEqual([x for x in rmes], [ord(x) for x in mes])
|
|
|
|
def test_multiple_rs_codec(self):
|
|
"""Test multiple RSCodec instances with different parameters."""
|
|
mes = 'A' * 30
|
|
rs_256 = RSCodec(102)
|
|
rs_1024 = RSCodec(900, c_exp=10)
|
|
bytearray(rs_1024.decode(rs_1024.encode(mes))[0])
|
|
rs_256.encode(mes)
|
|
rs_1024.encode(mes)
|
|
bytearray(rs_256.decode(rs_256.encode(mes))[0])
|
|
# At this point, there should not have been any exception raised!
|
|
|
|
|
|
class TestGFArithmetics(unittest.TestCase):
|
|
"""Test Galois Field arithmetics."""
|
|
|
|
def test_multiply_nolut(self):
|
|
"""\
|
|
Try to multiply without look-up tables
|
|
(necessary to build the look-up tables!)
|
|
"""
|
|
a = 30
|
|
b = 19
|
|
|
|
generator = 2
|
|
prim = 0x11d
|
|
|
|
# Compare the LUT multiplication and noLUT.
|
|
init_tables(prim=prim, generator=generator)
|
|
self.assertEqual(gf_mul(a, b), gf_mult_nolut(a, b, prim=prim))
|
|
|
|
# More Galois Field multiplications
|
|
self.assertEqual(gf_mult_nolut(5, 6, prim=0x11b), 30)
|
|
self.assertEqual(gf_mult_nolut(3, 125, prim=0x11b), 135)
|
|
self.assertEqual(gf_mult_nolut(2, 200, prim=0x11d), 141)
|
|
self.assertEqual(gf_mult_nolut_slow(2, 200, prim=0x11d), 141)
|
|
|
|
# Multiplications in GF(2^7)
|
|
self.assertEqual(gf_mult_nolut(3, 125, prim=0xfd, field_charac_full=128), 122)
|
|
|
|
# Multiplications outside of the finite field (we revert to
|
|
# standard integer multiplications just to see if it works).
|
|
self.assertEqual(gf_mult_nolut(3, 125, carryless=False), 375)
|
|
|
|
# The second method, just to check that everything's alright
|
|
self.assertEqual(gf_mult_nolut_slow(4, 125), 500)
|
|
|
|
def test_gf_operations(self):
|
|
"""Try various Galois Field 2 operations"""
|
|
init_tables()
|
|
|
|
a = 30
|
|
b = 19
|
|
|
|
# Addition and subtraction (they are the same in GF(2^p)
|
|
self.assertEqual(gf_add(0, 0), 0)
|
|
self.assertEqual(gf_add(0, 0), gf_sub(0, 0))
|
|
self.assertEqual(gf_add(1, 0), 1)
|
|
self.assertEqual(gf_add(1, 0), gf_sub(1, 0))
|
|
self.assertEqual(gf_add(0, 1), 1)
|
|
self.assertEqual(gf_add(0, 1), gf_sub(0, 1))
|
|
self.assertEqual(gf_add(1, 1), 0)
|
|
self.assertEqual(gf_add(1, 1), gf_sub(1, 1))
|
|
self.assertEqual(gf_add(a, b), 13)
|
|
self.assertEqual(gf_add(a, b), gf_sub(a, b))
|
|
self.assertEqual(gf_add(0, b), b)
|
|
self.assertEqual(gf_add(0, b), gf_sub(0, b))
|
|
self.assertEqual(gf_add(a, 0), a)
|
|
self.assertEqual(gf_add(a, 0), gf_sub(a, 0))
|
|
self.assertEqual(gf_add(a, 1), (a+1))
|
|
self.assertEqual(gf_add(a, 1), gf_sub(a, 1))
|
|
self.assertEqual(gf_add(1, a), (a+1))
|
|
self.assertEqual(gf_add(1, a), gf_sub(1, a))
|
|
self.assertEqual(gf_add(255, 1), 254)
|
|
|
|
# Negation
|
|
self.assertEqual(gf_neg(a), a)
|
|
self.assertEqual(gf_neg(b), b)
|
|
|
|
# Division
|
|
self.assertEqual(gf_div(a, 1), a)
|
|
self.assertEqual(gf_div(12, 3), 4)
|
|
self.assertEqual(gf_div(a, b), 222)
|
|
self.assertEqual(gf_div(b, a), 25)
|
|
self.assertEqual(gf_div(0, a), 0)
|
|
self.assertRaises(ZeroDivisionError, gf_div, *[a, 0])
|
|
|
|
|
|
class TestSimpleFuncs(unittest.TestCase):
|
|
"""\
|
|
Test simple functions and see if the results
|
|
are equivalent with optimized functions
|
|
"""
|
|
|
|
def test_gf_poly_mul_simple(self):
|
|
a = [1, 12, 14, 9]
|
|
b = [0, 23, 2, 15]
|
|
self.assertEqual(gf_poly_mul(a, b), gf_poly_mul_simple(a, b))
|
|
|
|
def test_gf_poly_neg(self):
|
|
a = [1, 12, 14, 9]
|
|
self.assertEqual(gf_poly_neg(a), a)
|
|
|
|
def test_rs_simple_encode_msg(self):
|
|
a = bytearray("hello world", "latin1")
|
|
nsym = 10
|
|
init_tables()
|
|
self.assertEqual(rs_simple_encode_msg(a, nsym),
|
|
rs_encode_msg(a, nsym))
|
|
|
|
|
|
class TestRSCodecUniversalCrossValidation(unittest.TestCase):
|
|
"""\
|
|
Ultimate set of tests of a full set of different parameters for
|
|
encoding and decoding. If this passes, the codec is universal and
|
|
can correctly interface with any other RS codec!
|
|
"""
|
|
|
|
def test_main(self):
|
|
|
|
def cartesian_product_dict_items(dicts):
|
|
"""Return dictionary of cartesian products."""
|
|
return (dict(zip(dicts, x)) for x in itertools.product(*dicts.values()))
|
|
|
|
orig_mes = bytearray("hello world", "latin1")
|
|
n = len(orig_mes)*2
|
|
k = len(orig_mes)
|
|
istart = 0
|
|
|
|
params = {"count": 5,
|
|
"fcr": [120, 0, 1, 1, 1],
|
|
"prim": [0x187, 0x11d, 0x11b, 0xfd, 0xfd],
|
|
"generator": [2, 2, 3, 3, 2],
|
|
"c_exponent": [8, 8, 8, 7, 7]}
|
|
|
|
cases = {
|
|
"errmode": [1, 2, 3, 4],
|
|
# Errata number (errors+erasures), erasures number and
|
|
# only_erasures: the last item is the value for only_erasures
|
|
# (True/False)
|
|
"erratasnb_errorsnb_onlyeras": [[8, 3, False],
|
|
[6, 5, False],
|
|
[5, 5, False],
|
|
[11, 0, True],
|
|
[11, 0, False],
|
|
[0, 0, False]]}
|
|
|
|
results_br = []
|
|
|
|
it = 0
|
|
for p in range(params["count"]):
|
|
fcr = params["fcr"][p]
|
|
prim = params["prim"][p]
|
|
generator = params["generator"][p]
|
|
c_exponent = params["c_exponent"][p]
|
|
|
|
for case in cartesian_product_dict_items(cases):
|
|
errmode = case["errmode"]
|
|
erratanb = case["erratasnb_errorsnb_onlyeras"][0]
|
|
errnb = case["erratasnb_errorsnb_onlyeras"][1]
|
|
only_erasures = case["erratasnb_errorsnb_onlyeras"][2]
|
|
|
|
it += 1
|
|
# Reed-Solomon
|
|
|
|
# Init the RS codec
|
|
init_tables(generator=generator, prim=prim, c_exp=c_exponent)
|
|
g = rs_generator_poly_all(n, fcr=fcr, generator=generator)
|
|
|
|
# Encode the message
|
|
rmesecc = rs_encode_msg(orig_mes, n-k, gen=g[n-k])
|
|
|
|
# Make a copy of the original message to check later if
|
|
# fully corrected (because the syndrome may be wrong
|
|
# sometimes).
|
|
rmesecc_orig = rmesecc[:]
|
|
|
|
# Tamper the message.
|
|
|
|
if erratanb > 0:
|
|
if errmode == 1:
|
|
sl = slice(istart, istart+erratanb)
|
|
elif errmode == 2:
|
|
sl = slice(-istart-erratanb-(n-k), -(n-k))
|
|
elif errmode == 3:
|
|
sl = slice(-istart-erratanb-1, -1)
|
|
elif errmode == 4:
|
|
sl = slice(-istart-erratanb, None)
|
|
else:
|
|
raise ValueError
|
|
|
|
rmesecc[sl] = [0] * erratanb # Replace with null bytes.
|
|
|
|
# Generate the erasures positions (if any).
|
|
erase_pos = [x for x in range(len(rmesecc)) if rmesecc[x] == 0]
|
|
|
|
# Remove the errors positions (must not be known by definition).
|
|
if errnb > 0:
|
|
erase_pos = erase_pos[:-errnb]
|
|
|
|
# Decoding the corrupted codeword.
|
|
|
|
# Forney syndrome method.
|
|
try:
|
|
rmes, recc = rs_correct_msg(rmesecc,
|
|
n-k,
|
|
fcr=fcr,
|
|
generator=generator,
|
|
erase_pos=erase_pos,
|
|
only_erasures=only_erasures)
|
|
|
|
# Check if correct by syndrome analysis (can be wrong).
|
|
results_br.append(rs_check(rmes + recc, n-k, fcr=fcr, generator=generator))
|
|
|
|
# Check if correct by comparing to the original message (always correct).
|
|
results_br.append(rmesecc_orig == (rmes+recc))
|
|
|
|
except ReedSolomonError:
|
|
results_br.append(False)
|
|
results_br.append(False)
|
|
|
|
# Without Forney syndrome method
|
|
try:
|
|
rmes, recc = rs_correct_msg_nofsynd(rmesecc,
|
|
n-k,
|
|
fcr=fcr,
|
|
generator=generator,
|
|
erase_pos=erase_pos,
|
|
only_erasures=only_erasures)
|
|
results_br.append(rs_check(rmes + recc,
|
|
n-k,
|
|
fcr=fcr,
|
|
generator=generator))
|
|
results_br.append(rmesecc_orig == (rmes+recc))
|
|
except ReedSolomonError:
|
|
results_br.append(False)
|
|
results_br.append(False)
|
|
|
|
self.assertTrue(results_br.count(True) == len(results_br))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
unittest.main()
|