1#[derive(Debug, Clone, Copy)]
33pub struct LdpcCode {
34 pub n: usize,
36 pub k: usize,
38 pub punctured: usize,
40 pub circulant_size: usize,
42 pub submatrix_size: usize,
44 pub mb: usize,
46 pub nb: usize,
48 pub generator: &'static [u64],
50 pub h_matrix: &'static [[[u8; 11]; 4]; 3],
52 pub theta: &'static [u8; 26],
54 pub phi: &'static [[u16; 26]; 4],
56}
57
58impl LdpcCode {
59 pub fn parity_bits(&self) -> usize {
61 self.n - self.k
62 }
63
64 pub fn info_bytes(&self) -> usize {
66 self.k / 8
67 }
68
69 pub fn codeword_bytes(&self) -> usize {
71 self.n / 8
72 }
73
74 pub fn parity_bytes(&self) -> usize {
76 self.parity_bits() / 8
77 }
78}
79
80#[derive(Debug, Copy, Clone, Eq, PartialEq)]
82pub enum LdpcError {
83 WrongSize {
85 expected: usize,
87 provided: usize,
89 },
90 DecodingFailed,
92}
93
94const HZ: u8 = 0 << 6;
98const HI: u8 = 1 << 6;
100const HP: u8 = 2 << 6;
102
103const TYPE_MASK: u8 = 0xC0;
105const INDEX_MASK: u8 = 0x3F;
107
108fn pi_k(
115 i: usize,
116 k_idx: usize,
117 m: usize,
118 theta: &[u8; 26],
119 phi: &[[u16; 26]; 4],
120) -> usize {
121 let m4 = m / 4;
122 let j = 4 * i / m; let theta_val = theta[k_idx] as usize;
124 let phi_val = phi[j][k_idx] as usize;
125 m4 * ((theta_val + j) % 4) + (phi_val + i) % m4
126}
127
128static THETA_K: [u8; 26] = [
133 3, 0, 1, 2, 2, 3, 0, 1, 0, 1, 2, 0, 2,
134 3, 0, 1, 2, 0, 1, 2, 0, 1, 2, 1, 2, 3,
135];
136
137static PHI_M128: [[u16; 26]; 4] = [
139 [1, 22, 0, 26, 0, 10, 5, 18, 3, 22, 3, 8, 25, 25, 2, 27, 7, 7, 15, 10, 4,
140 19, 7, 9, 26, 17],
141 [0, 27, 30, 28, 7, 1, 8, 20, 26, 24, 4, 12, 23, 15, 15, 22, 31, 3, 29, 21,
142 2, 5, 11, 26, 9, 17],
143 [0, 12, 30, 18, 10, 16, 13, 9, 7, 15, 16, 18, 4, 23, 5, 3, 29, 11, 4, 8, 2,
144 11, 11, 3, 15, 13],
145 [0, 13, 19, 14, 15, 20, 17, 4, 4, 11, 17, 20, 8, 22, 19, 15, 5, 21, 17, 9,
146 20, 18, 31, 13, 2, 18],
147];
148
149static PHI_M256: [[u16; 26]; 4] = [
151 [59, 18, 52, 23, 11, 7, 22, 25, 27, 30, 43, 14, 46, 62, 44, 12, 38, 47, 1,
152 52, 61, 10, 55, 7, 12, 2],
153 [0, 32, 21, 36, 30, 29, 44, 29, 39, 14, 22, 15, 48, 55, 39, 11, 1, 50, 40,
154 62, 27, 38, 40, 15, 11, 18],
155 [0, 46, 45, 27, 48, 37, 41, 13, 9, 49, 36, 10, 11, 18, 54, 40, 27, 35, 25,
156 46, 24, 33, 18, 37, 35, 21],
157 [0, 44, 51, 12, 15, 12, 4, 7, 2, 30, 53, 23, 29, 37, 42, 48, 4, 10, 18, 56,
158 9, 11, 23, 8, 7, 24],
159];
160
161static PHI_M512: [[u16; 26]; 4] = [
163 [16, 103, 105, 0, 50, 29, 115, 30, 92, 78, 70, 66, 39, 84, 79, 70, 29, 32,
164 45, 113, 86, 1, 42, 118, 33, 126],
165 [0, 53, 74, 45, 47, 0, 59, 102, 25, 3, 88, 65, 62, 68, 91, 70, 115, 31,
166 121, 45, 56, 54, 108, 14, 30, 116],
167 [0, 8, 119, 89, 31, 122, 1, 69, 92, 47, 11, 31, 19, 66, 49, 81, 96, 38, 83,
168 42, 58, 24, 25, 92, 38, 120],
169 [0, 35, 97, 112, 64, 93, 99, 94, 103, 91, 3, 6, 39, 113, 92, 119, 74, 73,
170 116, 31, 127, 98, 23, 38, 18, 62],
171];
172
173static PHI_M1024: [[u16; 26]; 4] = [
175 [160, 241, 185, 251, 209, 103, 90, 184, 248, 12, 111, 66, 173, 42, 157,
176 174, 104, 144, 43, 181, 250, 202, 68, 177, 170, 89],
177 [0, 182, 249, 65, 70, 141, 237, 77, 55, 12, 227, 42, 52, 243, 179, 250,
178 247, 164, 17, 31, 149, 105, 183, 153, 177, 19],
179 [0, 35, 167, 214, 84, 206, 122, 67, 147, 54, 23, 93, 20, 197, 46, 162, 101,
180 76, 78, 253, 124, 143, 63, 41, 214, 70],
181 [0, 162, 7, 31, 164, 11, 237, 125, 133, 99, 105, 17, 97, 91, 211, 128, 82,
182 115, 248, 62, 26, 140, 121, 12, 41, 249],
183];
184
185static PHI_M2048: [[u16; 26]; 4] = [
187 [108, 126, 238, 481, 96, 28, 59, 225, 323, 28, 386, 305, 34, 510, 147, 199,
188 347, 391, 165, 414, 97, 158, 86, 168, 506, 489],
189 [0, 375, 436, 350, 260, 84, 318, 382, 169, 213, 67, 313, 242, 188, 1, 306,
190 397, 80, 33, 7, 447, 336, 424, 134, 152, 492],
191 [0, 219, 16, 263, 415, 403, 184, 279, 198, 307, 432, 240, 454, 294, 479,
192 289, 373, 104, 141, 270, 439, 333, 399, 14, 277, 412],
193 [0, 312, 503, 388, 48, 7, 185, 328, 254, 202, 285, 11, 168, 127, 8, 437,
194 475, 85, 419, 459, 468, 209, 311, 211, 510, 320],
195];
196
197#[rustfmt::skip]
201static TM_R12_H: [[[u8; 11]; 4]; 3] = [
202 [
203 [HZ , HZ , HI , HZ , HI , 0, 0, 0, 0, 0, 0],
204 [HI , HI , HZ , HI , HP| 1, 0, 0, 0, 0, 0, 0],
205 [HI , HP| 4, HZ , HP| 6, HI , 0, 0, 0, 0, 0, 0],
206 [0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0],
207 ], [
208 [0 , 0 , 0 , 0 , HP| 0, 0, 0, 0, 0, 0, 0],
209 [0 , 0 , 0 , 0 , HP| 2, 0, 0, 0, 0, 0, 0],
210 [0 , HP| 5, 0 , HP| 7, 0 , 0, 0, 0, 0, 0, 0],
211 [0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0],
212 ], [
213 [0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0],
214 [0 , 0 , 0 , 0 , HP| 3, 0, 0, 0, 0, 0, 0],
215 [0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0],
216 [0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0, 0, 0],
217 ]
218];
219
220#[rustfmt::skip]
222static TM_R23_H: [[[u8; 11]; 4]; 3] = [
223 [
224 [HZ , HZ , HZ , HZ , HI , HZ , HI , 0, 0, 0, 0],
225 [HP| 8, HI , HI , HI , HZ , HI , HP| 1, 0, 0, 0, 0],
226 [HI , HP|11, HI , HP| 4, HZ , HP| 6, HI , 0, 0, 0, 0],
227 [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0],
228 ], [
229 [0 , 0 , 0 , 0 , 0 , 0 , HP| 0, 0, 0, 0, 0],
230 [HP| 9, 0 , 0 , 0 , 0 , 0 , HP| 2, 0, 0, 0, 0],
231 [0 , HP|12, 0 , HP| 5, 0 , HP| 7, 0 , 0, 0, 0, 0],
232 [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0],
233 ], [
234 [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0],
235 [HP|10, 0 , 0 , 0 , 0 , 0 , HP| 3, 0, 0, 0, 0],
236 [0 , HP|13, 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0],
237 [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0, 0, 0, 0],
238 ]
239];
240
241#[rustfmt::skip]
243static TM_R45_H: [[[u8; 11]; 4]; 3] = [
244 [
245 [HZ , HZ , HZ , HZ , HZ , HZ , HZ , HZ , HI , HZ , HI ],
246 [HP|20, HI , HP|14, HI , HP| 8, HI , HI , HI , HZ , HI , HP| 1],
247 [HI , HP|23, HI , HP|17, HI , HP|11, HI , HP| 4, HZ , HP| 6, HI ],
248 [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
249 ], [
250 [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , HP| 0],
251 [HP|21, 0 , HP|15, 0 , HP| 9, 0 , 0 , 0 , 0 , 0 , HP| 2],
252 [0 , HP|24, 0 , HP|18, 0 , HP|12, 0 , HP| 5, 0 , HP| 7, 0 ],
253 [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
254 ], [
255 [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
256 [HP|22, 0 , HP|16, 0 , HP|10, 0 , 0 , 0 , 0 , 0 , HP| 3],
257 [0 , HP|25, 0 , HP|19, 0 , HP|13, 0 , 0 , 0 , 0 , 0 ],
258 [0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 ],
259 ]
260];
261
262#[rustfmt::skip]
274static TM2048_G: [u64; 8 * 16] = [
275 0xCFA794F49FA5A0D8, 0x8BB31D8FCA7EA8BB, 0xA7AE7EE8A68580E3, 0xE922F9E13359B284,
276 0x91F72AE8F2D6BF78, 0x30A1F83B3CDBD463, 0xCE95C0EC1F609370, 0xD7E791C870229C1E,
277 0x71EF3FDF60E28784, 0x78934DB285DEC9DC, 0x0E95C103008B6BCD, 0xD2DAF85CAE732210,
278 0x8326EE83C1FBA56F, 0xDD15B2DDB31FE7F2, 0x3BA0BB43F83C67BD, 0xA1F6AEE46AEF4E62,
279 0x565083780CA89ACA, 0xA70CCFB4A888AE35, 0x1210FAD0EC9602CC, 0x8C96B0A86D3996A3,
280 0xC0B07FDDA73454C2, 0x5295F72BD5004E80, 0xACCF973FC30261C9, 0x90525AA0CBA006BD,
281 0x9F079F09A405F7F8, 0x7AD98429096F2A7E, 0xEB8C9B13B84C06E4, 0x2843A47689A9C528,
282 0xDAAA1A175F598DCF, 0xDBAD426CA43AD479, 0x1BA78326E75F38EB, 0x6ED09A45303A6425,
283 0x48F42033B7B9A051, 0x49DC839C90291E98, 0x9B2CEBE50A7C2C26, 0x4FC6E7D674063589,
284 0xF5B6DEAEBF72106B, 0xA9E6676564C17134, 0x6D5954558D235191, 0x50AAF88D7008E634,
285 0x1FA962FBAB864A5F, 0x867C9D6CF4E087AA, 0x5D7AA674BA4B1D8C, 0xD7AE9186F1D3B23B,
286 0x047F112791EE97B6, 0x3FB7B58FF3B94E95, 0x93BE39A6365C66B8, 0x77AD316965A72F5B,
287 0x1B58F88E49C00DC6, 0xB35855BFF228A088, 0x5C8ED47B61EEC66B, 0x5004FB6E65CBECF3,
288 0x77789998FE80925E, 0x0237F570E04C5F5B, 0xED677661EB7FC382, 0x5AB5D5D968C0808C,
289 0x2BDB828B19593F41, 0x671B8D0D41DF136C, 0xCB47553C9B3F0EA0, 0x16CC1554C35E6A7D,
290 0x97587FEA91D2098E, 0x126EA73CC78658A6, 0xADE19711208186CA, 0x95C7417A15690C45,
291 0xBE9C169D889339D9, 0x654C976A85CFD9F7, 0x47C4148E3B4712DA, 0xA3BAD1AD71873D3A,
292 0x1CD630C342C5EBB9, 0x183ADE9BEF294E8E, 0x7014C077A5F96F75, 0xBE566C866964D01C,
293 0xE72AC43A35AD2166, 0x72EBB3259B77F9BB, 0x18DA8B09194FA1F0, 0xE876A080C9D6A39F,
294 0x809B168A3D88E8E9, 0x3D995CE5232C2DC2, 0xC7CFA44A363F628A, 0x668D46C398CAF96F,
295 0xD57DBB24AE27ACA1, 0x716F8EA1B8AA1086, 0x7B7796F4A86F1FD5, 0x4C7576AD01C68953,
296 0xE75BE79902448236, 0x8F069658F7AAAFB0, 0x975F3AF795E78D25, 0x5871C71B4F4B77F6,
297 0x65CD9C359BB2A82D, 0x5353E007166BDD41, 0x2C5447314DB027B1, 0x0B130071AD0398D1,
298 0xDE19BC7A6BBCF6A0, 0xFF021AABF12920A5, 0x58BAED484AF89E29, 0xD4DBC170CEF1D369,
299 0x4C330B2D11E15B5C, 0xB3815E09605338A6, 0x75E3D1A3541E0E28, 0x4F6556D68D3C8A9E,
300 0xE5BB3B297DB62CD2, 0x907F09996967A0F4, 0xFF33AEEE2C8A4A52, 0xFCCF5C39D355C39C,
301 0x5FE5F09ABA6BCCE0, 0x2A73401E5F87EAC2, 0xD75702F4F57670DF, 0xA70B1C002F523EEA,
302 0x6CE1CE2E05D420CB, 0x867EC0166B8E53A9, 0x9DF9801A1C33058D, 0xD116A0AE7278BBB9,
303 0x4CF0B0C792DD8FDB, 0x3ECEAE6F2B7F663D, 0x106A1C296E47C14C, 0x1498B045D57DEFB5,
304 0x968F6D8C790263C3, 0x53CF307EF90C1F21, 0x66E6B632F6614E58, 0x267EF096C37718A3,
305 0x3D46E5D10E993EB6, 0xDF81518F885EDA1B, 0x6FF518FD48BB8E9D, 0xDBED4AC0F4F5EB89,
306 0xBCC64D21A65DB379, 0xABE2E4DC21F109FF, 0x2EC0CE7B5D40973D, 0x13ECF713B01C6F10,
307];
308
309#[rustfmt::skip]
312static TM1536_G: [u64; 16 * 8] = [
313 0x51236781781D416A, 0xB0C8419FA21559A8, 0x5F14E1E4D88726F1, 0x762F6ED6CF32F06D,
314 0x8ABFD971E17A0BE9, 0xA5D147741B698D14, 0x2A58AB30E2BC32D3, 0x9F251FBC5DB8C768,
315 0xD73C205BBEB231CB, 0xCAB5EFF5B2C76C71, 0xFA70FAD48828355F, 0x68C6138FA5524A61,
316 0xBB20031D7AA8FE69, 0x432ADE446F49CE27, 0x5E5DB9CCCEBD1326, 0xE8782B1B01F2ABA2,
317 0x4748E9513B41147A, 0x17B1FBB78B4F914C, 0x281F5680BA56DE50, 0x74B0FB0817E33E2B,
318 0xDD166CFB774B5959, 0xAC7FDCEA4FECB5BE, 0xED747C81B540D66A, 0xB2A6A2039A87967F,
319 0x4780DCB2DC5CBFAE, 0x55BC8FF84EC89440, 0xE5D411223F09979F, 0xDDDE9D940A15A801,
320 0x194064639D254969, 0x1BE32DDC829B0032, 0x1326515A22EE88A2, 0x0EC664DD2D701891,
321 0x69748DFE6372F2EF, 0x15F3B0D400ACD68A, 0xCF4144CE1FE2581C, 0x79B1A55BA59E54AE,
322 0x65A2B47EEBAB0CF3, 0x24DD87572CB0F71D, 0xF24ABF15590F4DA6, 0x9C3BAE51969C6502,
323 0xD3A714B60B22789B, 0x3DF5504D80F54C5A, 0x9D75CF1465031211, 0x09834A0C9F659C99,
324 0xB9241BDF76EB3788, 0x6F927251C86DECF1, 0x390BE9F5BBB93D05, 0xC6F435BFA1FF96B6,
325 0x222461B658DC3E91, 0xB01DF2A2EAD2DAA6, 0x5572EE6278F6F63A, 0x17B63CB2FDA3B97F,
326 0xB233BB259F3D83F7, 0xF64760C774989384, 0x46F57E03F55B1C0B, 0x5AC8A6CEA05466C1,
327 0xAE8825521F85CA31, 0x37BEED74B5303407, 0x751FC9A15FCEE486, 0x93F0F69BD04E72A4,
328 0xC0EBFA3F49DF4DBB, 0x03E52D815DC99A1D, 0x98FE8BF01BB2CD6D, 0x009C5290D81A18F6,
329 0x4FFBAD88545CAA95, 0x0C74659FA4828CA3, 0x60CE56E32DA28B2E, 0x299D4BF82FE54B81,
330 0x51047BE3B3AE4F4B, 0xF3AC9578B9477A4C, 0x3730F81F92767E11, 0x04E84EC3A3AD1F19,
331 0x2D0E0CAB8EDD2185, 0xCEFBE8F2F538522A, 0x92DAEDC22C441893, 0xBCB999157B35619D,
332 0x069951BFB90A08E1, 0x54C7E270CBA1656E, 0x7FBBB806B6A06FB3, 0x7224943B1C3A5723,
333 0x1BAA14752EFCEBC0, 0xCFF0894975557623, 0xFA95908DC3F34D48, 0xFECA650999A26E91,
334 0x245433EBBE9CDA13, 0x5771EAFF9B02D8FC, 0xBCEBCA573D3775C8, 0x1E46F2B951D0EAAB,
335 0x32942F7F4743DDF4, 0x8FA2F60AD62095EF, 0x80E4A736B5E1A3A3, 0x0119062872DAEDF4,
336 0xE78006958CD99F95, 0xD20625057C99C7A3, 0xB569736DE2167610, 0x0E1C6183ADF09FD0,
337 0xE5C492DBB48B319A, 0xE2D83ADEFEBBDEFE, 0xAA944EEA53C77DB3, 0x0FAA85D9C13B1F73,
338 0x8ACED57F3BE4E807, 0x33CB72627624F426, 0xA0C6E669B5C74980, 0xABBAEFEA2D3B69AA,
339 0xF8366DDAE56A6DDC, 0xFDED5582F4EA6525, 0x4C9628278ED17036, 0x6E711B6D20A67966,
340 0x3B28BDF004C21B93, 0x1BC37B730FFC1786, 0x5D20C81D345FE4B9, 0x1D14A5663D369A93,
341 0x5EBD4BD39B2217D0, 0x56833BE1CDDBA6BC, 0xB288169B4E3BB726, 0xC2ED28FBFC395D1F,
342 0x035B30C68F9A6B6F, 0x539836A6E56A7B16, 0xCEB1525C6ADB65A5, 0x5F71754AA458B11A,
343 0x0DB9D180B21C0B13, 0x417D86C59DF33E49, 0x183A8F6C44DAFA24, 0x4E224C180C1F0B45,
344 0xC93CD9CA23658555, 0x7DDEC5E9451AD519, 0xB122C72A6177EE99, 0x1290B4C6B007D973,
345];
346
347#[rustfmt::skip]
350static TM1280_G: [u64; 32 * 4] = [
351 0x678ECB51FE821D5C, 0xFA5F424BF55927AA, 0x3E82691332E04B0C, 0x4F88862B803432EF,
352 0x42B276259F8DA1E1, 0xF8472D1BD943D394, 0x29261575BA434C68, 0x18EF349A27CA1CC4,
353 0xEC90039764A4A063, 0x9BCEC4A6D05BA70F, 0xE7155BE17FF09CC1, 0x6E2E20597F1567E5,
354 0x5616101CEA060E2B, 0xB673068B923BDF8B, 0xB9B9343D049C63A8, 0x333E9CFE809B362D,
355 0x9D41634C404E17DA, 0x3B4161F25235992E, 0xEA4B4B8B4690BCE1, 0xF9DA36A116439BB1,
356 0x5D7254B515B4978B, 0x00D05224107BD904, 0xC85D7E580451F1A5, 0xEE9D1897913DA6F9,
357 0x42819F61343773CA, 0x11A6492A4832F43F, 0x849C11EDF0FE864F, 0xCC2704009726D66E,
358 0x89EE2A44685C1F67, 0x1DF6E416507BF2EF, 0x8759C2FB52162ABF, 0x2B61D3FB988708C4,
359 0x4A8FEA0953452354, 0xA33E2E73271E8211, 0x16DF62E503DF81F4, 0x8848BD0FF95DF357,
360 0x9BE0A7B3617256EB, 0x9A4D0BB4FE3A3A19, 0xFAA63D9E65328918, 0xD699BA354CDE6FE0,
361 0x848B1FE50AB58A6F, 0x341707F1EF36474B, 0xF623A7A5A35EC9BA, 0x24909B6E64A7A898,
362 0xBDDF3BAE7202FA26, 0x86F90C57A0399F20, 0x972B9A3187B245AE, 0xE0C5A3384959AAD9,
363 0xCF726C277B38429A, 0xBA37C244EE7717DB, 0xE45C99CA7E3E013B, 0x7B800CA46527F2E7,
364 0x75C637821CC40137, 0x51E69F16414B155F, 0xDF1964DEF13C71F7, 0x6E9E80446C5CEC86,
365 0x6F2A6DF89FF2BF82, 0xD362535524466981, 0xD5F14AC1E1C24AEA, 0xA8850D837A3C5120,
366 0xBAABADC31ECF066D, 0x76538348FC5D4D54, 0x43AD46CF3342012C, 0x63EBE2DCD832EF8E,
367 0xE6EC82F14AAFE782, 0x14D89E3823C83402, 0x8B48D6BFC823B89A, 0x68A35626E89FE121,
368 0x4BBAA33120EC16C9, 0x6ADABE06D803DA6D, 0xFCC89D41E57B10E8, 0xCC3FF0144DB74206,
369 0x503FD58652F68B91, 0x97D69DF3129C764E, 0x8B2143F7A36EF3BA, 0x7C27896C560F67B5,
370 0xD70390E698B337EA, 0x895683632A1681DF, 0x4B4E928C41EC3D9C, 0xDFD92EB2A5D5C85C,
371 0x2A5088BD76CB6810, 0xCB693D21C0E9EFD5, 0xF992506E299CE082, 0x901155A60B93AA16,
372 0x18FEFECEB0063536, 0x954870894BB31BB9, 0x66F3FD97E32B58A0, 0x2A39427A5CD8DE9F,
373 0x1A8F8616C5F7D2B2, 0x5AD2BC4EBF1E86DB, 0xACF7BFFAF3589597, 0xA777654C12DD1364,
374 0xFFC03A59DC450527, 0x33B4C871BAA2EA33, 0x93A751A6F9D72E4D, 0x69B50C7FF74151F9,
375 0x7BE8519DAF6FFAFA, 0x268DBA73A356128C, 0x0418BE2C1A43465A, 0x60C6DF650E2438A0,
376 0xEC25DC0566AEE4A8, 0xA72A030AB11FB610, 0xDD74DAF762F6D565, 0x554EAEB715F7AE6C,
377 0x5147F90AFF0EEC01, 0x12A9966C871705B1, 0xE935FF3046E32957, 0x546D69FCB8A1BD06,
378 0x6A80EA6F71A29506, 0xEF78AACF8D52B5ED, 0x9F0A496661B3B68E, 0x4B17AF965B282C2E,
379 0x7558227216E54299, 0x7D070B9CAB130157, 0x76C619D25500E2D5, 0x1F9804595D9C7F83,
380 0x6A0DDA1DF6E8B610, 0x25D0E0A1242749E0, 0xFEDA4A06072D69D6, 0x03C7DA7951AA3355,
381 0x6E9FEFF00797CBF1, 0xE936C824C9C1EAF5, 0xD4607E4688ED7B0E, 0x92E160AD731140AD,
382 0x32FEFCAF70863B75, 0x3846F110C4E23DFF, 0x79D3F753064648FA, 0x830452F5B9ED8445,
383];
384
385#[rustfmt::skip]
388static TM5120_G: [u64; 32 * 16] = [
389 0x473BC533A12C3596, 0xF642673D0DBF1142, 0x079A3868E1A6F556, 0xF0DF3DCA4493AE54,
390 0xAE4C50F12AEF6EED, 0xEA9BB30605F4A24C, 0xB0B2B4B9035331AB, 0xF53DE4752E7EDABF,
391 0xE7E08EF3E22EE7EF, 0xE645E9E59507A206, 0x52E4A2C06270B2D1, 0xA418134BC0D58678,
392 0x0A84E53303F4092D, 0xB47056AD3C0847AD, 0x2DEF73813B17101E, 0x79A3A58A7E91C4E2,
393 0x667AA815610234DB, 0xA0FFA951CABB8BA7, 0xA3271642E4BCDD24, 0xF8D89BD783317ABB,
394 0xCC64FA95F06AE45C, 0x7E38935D78BF5F80, 0x510CE9ABC6156F00, 0x8B317C79E0122B09,
395 0x3CB09E20016A5F93, 0xE207C144E889F3B9, 0xAE6185E4345C5971, 0xE03AD499EF850D33,
396 0xFA8B392CE78B5712, 0x290CB2F518F3E0CC, 0x429C39F0915EB60C, 0xA0545B6AB2967149,
397 0xFE9FF6C26898CB92, 0x6F9BCD129AA52083, 0x3FC159DB58B64D39, 0xCB27847434F177E2,
398 0xE040D71365D96A1D, 0x54FD20051D3A50E7, 0xE8AC736B6D2BB546, 0x8FBF68DDF5789C2F,
399 0x4954E4153CFF0F52, 0xF8F8F5B243A03E2B, 0x99A1DDD23204D103, 0xE323158E0FEE7673,
400 0x43C2A07046BA1B43, 0x07BA6CEC7D740CFE, 0xCB4E113F94C6CAA4, 0x652EFD867B43D199,
401 0x081E779BF01F34C9, 0x7337A3ABC8698644, 0x9C9E794155E27547, 0x283C1AB2706A388D,
402 0xFB9DFD194731EC2A, 0xE99EA6B641B309A2, 0x258D45A1BBEAFFC7, 0x87E61289A54A2473,
403 0xFDF3E96C7679E979, 0x911C4BE65A333250, 0x178259F846AA9557, 0x7C2EC448EE709423,
404 0xA61BE7CCED034296, 0x5CA234AF02914916, 0xE045B3C585714F27, 0x2D40C8085AE5E8F4,
405 0x7FB352B26E544BDC, 0x18D76B323C3CE1BB, 0x8421967EE08A6F71, 0x9B675F06F13FF05B,
406 0x672C29DC5B80E18E, 0x2F4C42D0F6D5D6D4, 0x7DE072F73A801586, 0x2A275B2CEA2FFC1C,
407 0x284B87ABA22362D9, 0x8952442BBDFBF4A3, 0x2B798BCD5D8C0B02, 0xBBE5DE4A96569F99,
408 0x409E72F4138595F8, 0xB3C14074BD8E33E0, 0x3B07838358BBAE63, 0x1C8258D6B07D2E1C,
409 0x403149A1C88E4D48, 0x93FE719B2638B7FF, 0x9886F3E90FC01869, 0x9F3B39183F2219DC,
410 0xF5B0D3AA45122586, 0x7913FF8FF979BBE0, 0x795DFCBCC98210C0, 0x28FD21380EBDDABF,
411 0x0BBE0D91FA504DC4, 0xDC8848AEA001577F, 0x51653E755F6CB4F7, 0x5ACE347EC899304D,
412 0x1D0EE239D8A6C2E2, 0xEA13D4CFB3394FCA, 0xBF707E3ACD882B91, 0xFDDD44A7EA0D1F3D,
413 0x14EB386A5A452498, 0x3682993353F8D76E, 0xF9850534D2FB4F19, 0xF787897435C5EB0F,
414 0xB680840F8D34A099, 0x5BA0A94E309A9194, 0x6C66CAA0567BFFD6, 0x09B6484BCD477702,
415 0xB62A4053A6916719, 0x693D50608EC1D717, 0x23C38E6F64963EE8, 0x36ADC6BBF39F4CD1,
416 0xA40947C16AEAD43F, 0x621457BDB766A157, 0xDD6118ACF503356D, 0x0B3479828C296016,
417 0xAAB1061EC9FA6BA2, 0x1E81D7E22D3A7ED2, 0xF902B6C336258F5B, 0x6B54628AC96116DE,
418 0x5968E3167BB1E221, 0x714B0F4B3B9D7E0A, 0xF12374361559D0F0, 0xE0C7FCC959B1A9D8,
419 0xC103B779B3A769AA, 0x8D955160E4B9F9B7, 0x231B28E0B7490C8E, 0xB883F29AF6CC4F12,
420 0xA7D1FA32F82AAF12, 0x8FBC6AC53532AB89, 0x17AC06392CDAC681, 0x817D2F5475016296,
421 0x434D8612F27169A4, 0x9ED244393B87DB5E, 0xB66D806A5A9ADF46, 0xD83C7DCFDB4B72CA,
422 0xA78E0C64307885C6, 0xE67C870BD21EC431, 0x11B79B0BB0B977D9, 0x792535C16AA7D982,
423 0xB597FD60982B8C42, 0xD019390EFA14B3D5, 0xC57FF5CFA1C438AC, 0x576782A5B48B78AA,
424 0xAE278E95DA048F72, 0x0B7DB5FB6488287B, 0x893C7E7E8DCB6E5E, 0xD5DB819D8901B32C,
425 0xB7BA8906FC3AEADE, 0x22254872ECA99117, 0x74F39404FA2779F4, 0xC55D649E5A6AA628,
426 0x4A1F8910EBF76F2F, 0x4E3EF686266CEBB8, 0x8363A57CF1377C68, 0x419BEFE6C848FEDA,
427 0x8F141154BFA88D31, 0x446EF367ED965F98, 0x1242B3F840426E98, 0x010B84A957090390,
428 0x9CE9E0B619E61C4A, 0x481F1DD44360BCAC, 0x0938AE511B2B47A4, 0x2F5F59FBF547D991,
429 0x85B68FFC07A32A49, 0x5D9A708FAECD2C41, 0x69CFDFFD21D6B2CF, 0x3F91CF5820823B83,
430 0x7D62406050908C82, 0xC21CF32B862166F2, 0x82AF2DF8E6CADB5D, 0x043FBF863ACE6599,
431 0x700097EE5FDDD825, 0x468C544985C983CE, 0x69EE0178288A8E1A, 0x12009EBF2E4382DE,
432 0x2B8D59DE631991AE, 0x1B67C70786B43BE2, 0x860FC3354C9FE425, 0x3EBF307D1C643E22,
433 0x905330D76B163401, 0x20BB399A08061CBE, 0x9D5765CE993D7092, 0xA8150DE46D6CA810,
434 0xE03534D4DA2B66A0, 0xBF2AEF3B833E18DF, 0x6C1C0D9EAB1E26FD, 0x2481F6BB6AB674C6,
435 0xD98BD8D3FC0E0557, 0x352CF52EEA654A92, 0x0DF8D4B0FD41AD3E, 0xE547119C2446F840,
436 0x4C1F458D1E2F4B70, 0xD9023F0DFC06EFE9, 0x24349C5D9DE2B048, 0xDC74D3E888043526,
437 0xE864E5EE002EB3B4, 0xC31A8D3B3E22D2C6, 0xB3C4136542237F8E, 0x3C75AA228AB1B2F5,
438 0x43DF20DF407EAC80, 0xCAF22FDDADD586C9, 0x9414219FF8074265, 0x2531AC5CC0E52866,
439 0x1A68E6BC5CA7FCA3, 0x86396D0F56A2E7A3, 0xD9EC25B8DEA08EDB, 0x6A9E6CFFEC7B15C1,
440 0xCD48176480B2E0FE, 0xD349142BE9888043, 0x9A70BAD89B53A446, 0x1301DF6C1763EB67,
441 0x5C9B0F852875D4B0, 0x6EFA7FF418710592, 0x6F7C0712083341F6, 0xA97F398A275243DC,
442 0x3D046D9B0B0B6AB3, 0xFEB99F72A70BAF35, 0x50F7B484C2530BEF, 0x63537B68EBDCF01C,
443 0x672E8B1DD9564310, 0x36302F8557CBB4E0, 0xC9CAD206AB0AD88C, 0x655E0F52C70AEEA1,
444 0xFF7EC97F9439C9D4, 0xCD71487F10065DE0, 0x532339617D706AEF, 0xA50A23B90B57978C,
445 0xB7E0C9A5F3EF66B9, 0xABA49150144FCBEF, 0x2C9E63DC18BE8ADD, 0xA0FD7E7E8F7FC5FE,
446 0x5C55C60E14C3D7AC, 0x4D00D9F6C827E1EC, 0x4E40D57E1740089D, 0xB1248707D195C038,
447 0x4500AD976DD321E6, 0x133113D244711330, 0x0260379D0A20D10A, 0x899019157631007D,
448 0x4DF741A808694A99, 0x56E493B4668B67FD, 0xF89442CABAA2262C, 0x398171D62E938504,
449 0xCCF8A4E13D655D55, 0x91DC40D2C6607CEF, 0x353E539A020B0C60, 0x8F843A855BA9B7AE,
450 0xCD31CCCB9388FECD, 0xEBEE1CCF42943E77, 0x9CA39E64D8AC9E23, 0xF15A0CB4C73ACB80,
451 0x3BF0F0DA9576923D, 0x95089979081ACA77, 0x359B090725B62278, 0xF00D0222CAD4C0FF,
452 0x4ABA29056D55C5AA, 0xD990AA10A9A1A9B2, 0x27A09750826682C1, 0x57BD7CD2178FDC96,
453 0xAFC3076AF8AFB82B, 0x45FE8F2628F489F1, 0x2CFA95663A96A30F, 0xB3831F756D9E666A,
454 0x011EE24F6C5EE283, 0xC3EE09A1D5FAF1B9, 0x7B49CB7B94EDEB20, 0x7221A9436E1FFDF5,
455 0x5D36302EEBDD74AD, 0x27158F4D9DF0FA6E, 0x497015959B333E79, 0x885FBE22B9B72707,
456 0xE330EEAD520B31BA, 0xD1A5DC55EF54193A, 0xD6C112F89677E27A, 0x26F1DC62E08DF49C,
457 0x2DF5B0291E619A18, 0xD802502086037C46, 0x730D20AE9364A6AD, 0x090B789D8AA6C6CC,
458 0xEA476A585503E90B, 0xCAAD943DD30E1BCC, 0x1D5C236ED01E9E5C, 0x8E94E96FA7252ABF,
459 0x3EB2DB84FB4837EA, 0x5153CA825D11F86B, 0x574E63C92DD0E75A, 0xD8DDFF2B37CC97C9,
460 0x5E83299E60C44293, 0xBF0824C62EB7980C, 0x5678B852002834EB, 0x2D630EAC536FFB78,
461 0x9A41F048C1C68187, 0x734BFB916EC3BFAF, 0x4B23BDA1162B30CB, 0x7AEA9F03BEBCF597,
462 0xC65460BFAF9C8913, 0x608F9888E738F4A1, 0x017AEE470FCA60F9, 0x711E9BE5EB98E7C9,
463 0x4EE8869A59EDF8BD, 0xD52C5B5388B35249, 0x8EB0D25B439273CA, 0x6545E82E69D8677C,
464 0x5B23991A53041EA4, 0xB276405C156A9DE5, 0xA90889BC74530A5F, 0x87CCF024E591E18F,
465 0x22735E1E720A8B3C, 0x29A80F3696D6F157, 0xF68ED2F2389D5D2C, 0xDC59D706495D815F,
466 0xD0EE25B73218D571, 0x7572387BFA03A7C2, 0xA0717B27763FE223, 0xBDA3EB0DAFBEF276,
467 0x9DBB8235D11298BE, 0xE28B39772ED91A35, 0x92DE6FED2F6766E0, 0x1DBA188153DEA205,
468 0x48930E9A21873E62, 0x863CA15D6DB058D9, 0x61A29088FE3983D0, 0xE1699EF0AAFA5FD1,
469 0xA730056900988893, 0x82252873E627D6FB, 0x7862DE8A3D0F1A93, 0x87963F38A82E4703,
470 0x78BAB9252EE72FB0, 0xC798C7C684B6E789, 0xB7480D9712BFA72D, 0x122F243674AD887F,
471 0xEC1851EB80A37133, 0xB68F0F709DB32E05, 0xA809CB3638414FD6, 0xE156821BDAC256E0,
472 0xB75342B6CFF7ED42, 0x8521AB48A4C55D66, 0xC9AB047D79A48428, 0x9C820E8FADD87251,
473 0xA69C02525644F41D, 0x03197EF26112D606, 0x3DF71AD0410035AE, 0x1AE7B0AB310B6967,
474 0xC4F82E31B4D9B491, 0xEF8E4992FDBA61B0, 0xB6B367CDE8DE0CAE, 0x22875F641288E733,
475 0x5C142A9C7C2E259B, 0xD38D66117E9E861C, 0xD27BF85E8EEE1920, 0xB57D0C62B512E2D6,
476 0x68B4500340B7B92E, 0xDD05A44D36AC1651, 0x4E77C4ABE92FE174, 0xB5D9F79070685288,
477 0xA22B2A6C9A75D7A6, 0xEEA5A0DF8A4950E2, 0x24C4830123FAE1EB, 0x6EB0AC9C2D8C508E,
478 0x1BB99D6785EBCCDD, 0x9CD6A50CF53CCA00, 0x0624E36FD0817F2E, 0x198340098E60DFBF,
479 0xA4EB92DD48085594, 0xC6F755C563F35020, 0x04BDFF9A2309C6E6, 0x73CE08D94A45BBC4,
480 0x8B8EC43906C28869, 0xAD4E41FB147A7696, 0x8AB66E9B68FA00BE, 0xF90D3E078D0C6FFC,
481 0x89A79E9CF0BE90A3, 0xD86305B6491A49B9, 0x222A27A68236765A, 0xB32D41B1E0616C83,
482 0x99931668E57EB637, 0x8C8F4ED1C27BEDD3, 0x35166846D0C673B9, 0xA8D2184C1901433A,
483 0x4D768A5E0109B5CB, 0xC198869334D81C43, 0x2C6A48CC47FD21F9, 0x608107FF80FE37AA,
484 0x4DD3A7395630BE4B, 0x64F776C5FC6B2C31, 0x4DC16B1E2B2A7F6E, 0x0E9FDAE3B60F8FAA,
485 0xCFA794F49FA5A0D8, 0x8BB31D8FCA7EA8BB, 0xA7AE7EE8A68580E3, 0xE922F9E13359B284,
486 0x91F72AE8F2D6BF78, 0x30A1F83B3CDBD463, 0xCE95C0EC1F609370, 0xD7E791C870229C1E,
487 0x71EF3FDF60E28784, 0x78934DB285DEC9DC, 0x0E95C103008B6BCD, 0xD2DAF85CAE732210,
488 0x8326EE83C1FBA56F, 0xDD15B2DDB31FE7F2, 0x3BA0BB43F83C67BD, 0xA1F6AEE46AEF4E62,
489 0x565083780CA89ACA, 0xA70CCFB4A888AE35, 0x1210FAD0EC9602CC, 0x8C96B0A86D3996A3,
490 0xC0B07FDDA73454C2, 0x5295F72BD5004E80, 0xACCF973FC30261C9, 0x90525AA0CBA006BD,
491 0x9F079F09A405F7F8, 0x7AD98429096F2A7E, 0xEB8C9B13B84C06E4, 0x2843A47689A9C528,
492 0xDAAA1A175F598DCF, 0xDBAD426CA43AD479, 0x1BA78326E75F38EB, 0x6ED09A45303A6425,
493 0x48F42033B7B9A051, 0x49DC839C90291E98, 0x9B2CEBE50A7C2C26, 0x4FC6E7D674063589,
494 0xF5B6DEAEBF72106B, 0xA9E6676564C17134, 0x6D5954558D235191, 0x50AAF88D7008E634,
495 0x1FA962FBAB864A5F, 0x867C9D6CF4E087AA, 0x5D7AA674BA4B1D8C, 0xD7AE9186F1D3B23B,
496 0x047F112791EE97B6, 0x3FB7B58FF3B94E95, 0x93BE39A6365C66B8, 0x77AD316965A72F5B,
497 0x1B58F88E49C00DC6, 0xB35855BFF228A088, 0x5C8ED47B61EEC66B, 0x5004FB6E65CBECF3,
498 0x77789998FE80925E, 0x0237F570E04C5F5B, 0xED677661EB7FC382, 0x5AB5D5D968C0808C,
499 0x2BDB828B19593F41, 0x671B8D0D41DF136C, 0xCB47553C9B3F0EA0, 0x16CC1554C35E6A7D,
500 0x97587FEA91D2098E, 0x126EA73CC78658A6, 0xADE19711208186CA, 0x95C7417A15690C45,
501 0xBE9C169D889339D9, 0x654C976A85CFD9F7, 0x47C4148E3B4712DA, 0xA3BAD1AD71873D3A,
502 0x1CD630C342C5EBB9, 0x183ADE9BEF294E8E, 0x7014C077A5F96F75, 0xBE566C866964D01C,
503 0xE72AC43A35AD2166, 0x72EBB3259B77F9BB, 0x18DA8B09194FA1F0, 0xE876A080C9D6A39F,
504 0x809B168A3D88E8E9, 0x3D995CE5232C2DC2, 0xC7CFA44A363F628A, 0x668D46C398CAF96F,
505 0xD57DBB24AE27ACA1, 0x716F8EA1B8AA1086, 0x7B7796F4A86F1FD5, 0x4C7576AD01C68953,
506 0xE75BE79902448236, 0x8F069658F7AAAFB0, 0x975F3AF795E78D25, 0x5871C71B4F4B77F6,
507 0x65CD9C359BB2A82D, 0x5353E007166BDD41, 0x2C5447314DB027B1, 0x0B130071AD0398D1,
508 0xDE19BC7A6BBCF6A0, 0xFF021AABF12920A5, 0x58BAED484AF89E29, 0xD4DBC170CEF1D369,
509 0x4C330B2D11E15B5C, 0xB3815E09605338A6, 0x75E3D1A3541E0E28, 0x4F6556D68D3C8A9E,
510 0xE5BB3B297DB62CD2, 0x907F09996967A0F4, 0xFF33AEEE2C8A4A52, 0xFCCF5C39D355C39C,
511 0x5FE5F09ABA6BCCE0, 0x2A73401E5F87EAC2, 0xD75702F4F57670DF, 0xA70B1C002F523EEA,
512 0x6CE1CE2E05D420CB, 0x867EC0166B8E53A9, 0x9DF9801A1C33058D, 0xD116A0AE7278BBB9,
513 0x4CF0B0C792DD8FDB, 0x3ECEAE6F2B7F663D, 0x106A1C296E47C14C, 0x1498B045D57DEFB5,
514 0x968F6D8C790263C3, 0x53CF307EF90C1F21, 0x66E6B632F6614E58, 0x267EF096C37718A3,
515 0x3D46E5D10E993EB6, 0xDF81518F885EDA1B, 0x6FF518FD48BB8E9D, 0xDBED4AC0F4F5EB89,
516 0xBCC64D21A65DB379, 0xABE2E4DC21F109FF, 0x2EC0CE7B5D40973D, 0x13ECF713B01C6F10,
517];
518
519#[rustfmt::skip]
522static TM6144_G: [u64; 16 * 32] = [
523 0x80924F648C014F2C, 0x73889C8B87D0491F, 0xA9FA060D2902D7AC, 0xC8B679CF61EEB5D9,
524 0x6BB9E90F5C157AA1, 0xBF03EF756245D917, 0x9063F2CD999EF1E7, 0xF7925B3FB7AC7B2D,
525 0x6CD39516B201F491, 0xE2BDCA4E34542B5A, 0xF3703B3C8EE753FB, 0xE998E87323F0B228,
526 0xD1F551B2D7E7822F, 0x201E24066584D63C, 0xAA00E8DB909EB41C, 0x4157EBA0F5C76A50,
527 0xF7C5731746C6DAC2, 0x60A345189009C0B2, 0x3372F1E9E0C5A079, 0xD00B09158E164B22,
528 0x33D5F8A268041CAB, 0x66317898CD0024E3, 0x106EED5C2171B3F6, 0x276B8EA59AA981E0,
529 0x010BFF3F52A49ED9, 0xA6FA7F151FCC72B2, 0xAF3BD932065043F7, 0x447B4D0FC4A2B93B,
530 0xF8D345E6D2B0008D, 0x1B363BFE296B55AF, 0x38E3E16EC5856A12, 0x2E4931CB3F2424B1,
531 0xA099B776C642FF1D, 0x84B0DB797098E17E, 0x75FE9BB5CF7FA873, 0x9711A89660DAF24D,
532 0x3CA8DE5500F68DB4, 0x49BFF74251B24E46, 0x91EAF386C81014C9, 0x1AC700298E095F0B,
533 0x12CEE8B5F6B93C11, 0xAD628CB6CB81F76B, 0xE095C2C994A8BDDB, 0x4E2C48C942B4D481,
534 0x1F7E191B30E8FFD6, 0xD4A7E9BEF81BBB0A, 0xE6608F647B1AED9C, 0xCA7FEC5498C03F0F,
535 0x1132E816BDFA0C34, 0x50C3993911E10EB1, 0x097CD7A1F32C54C8, 0xB009654E56B25A2D,
536 0x5FD58EEAED460CEF, 0xC18E2FBAD2954467, 0xE32118F01D05456D, 0xEA2926A1E761DF76,
537 0x4C6C7BF3A2245C1B, 0x4630775DC59EA74A, 0x14EBCD8B5D72E343, 0xBC6F7FEA452F2CC2,
538 0xC09CE802B35EBF46, 0xD1F3069957DF1D15, 0x2377F45ADF614CC0, 0xF5DAB8FCF394CCD0,
539 0xFEFBA8CE169FD377, 0x5B2280EF3BD870FD, 0xDF7CB95F2943D0EE, 0xA84529FF0D1B1C19,
540 0x0CA5DB06A87541C8, 0x1BEF913D5145F20E, 0xFAD861F673B32028, 0xB4713377C056CE97,
541 0xCA3F213365EE380F, 0x7E90466945BDE9F4, 0x4087C8C73A7CC5F9, 0xDE71B7683D018D86,
542 0xA6CDFD8D8117748A, 0x4B41C3F5A6676549, 0x5711EDC02F9581F3, 0xE7C2E0FD9004B03B,
543 0x77D0EF5DE2ACACA2, 0xA4371A5B111B877D, 0x0EDDF83C3341A5AA, 0x51261FA4B5A0D7EA,
544 0x7C563512A6B73B3B, 0x43F8D1D113D751D6, 0xB2CABBC350FF0F8C, 0x29361DCE5EB87C8F,
545 0xF6DFA5C672C25179, 0x31371ACB6462A596, 0xD41419CD4F0F84EF, 0xF98DCBBE610AE03E,
546 0x05FF840FB320DD5C, 0x3FB4FE4A58585109, 0x14A5161B2AD3C3E7, 0xFD02358505190F0F,
547 0x5B6D534EDE13068A, 0x2459CB07007121B0, 0xF07B08B8227047C1, 0xA629DCA5A4E30D28,
548 0x5D00E72E5B6AD57A, 0x9F0F9E0608702BDE, 0x8BDBFA371C06D96B, 0xFE0E603775A875CB,
549 0x692EB7DA76BD0D4A, 0xFE92FCB5B5184BAA, 0x3EEE37900144CA03, 0xB7A22EADE2F061FF,
550 0xB3CDE2464AF12129, 0x79A99380340974A9, 0xF85478E5A2E8B907, 0xE74EEFA4CB7625E5,
551 0x41AF736E0AA1416E, 0xA676E43CF5DFF372, 0xCFFC30D6C0A58A33, 0x3268136A3020033F,
552 0xF50111382FEBA594, 0xC255896AB59C0663, 0x8406956F19B67F80, 0xA3A7276060D4E7F6,
553 0xDCB75287BE9A2620, 0xA1F594570B269097, 0xA51A32548BAA6DD9, 0xB429B8AAF992C8C0,
554 0x6210A36B63DE9C73, 0x2339DC1AFA94CAB4, 0x75574A6D1C4D0C17, 0xF148B8AD12816B47,
555 0xE24D7C17BCC46297, 0xEDC41AA9B5C9D936, 0x89843027C6A78449, 0xF8D151E1F42BE98F,
556 0x4544BD9E6975DDD4, 0xBC9B3EFAD50AFC58, 0x2CAE269677B130FE, 0xD2C39D5EBDEE56B8,
557 0x6A13BB53C03B0C8A, 0x4E0D1697322A1A30, 0x55054229A69B6CCB, 0x7E1FB0B885B90CD2,
558 0xBE5C66B252E5C51D, 0x7D9E9E25922566C1, 0x8F0234F2A330041A, 0xEC6A4F2729A2A30B,
559 0x1E04A65CF0BA05C6, 0x2B15FEF9967ECD97, 0x5EC43C035DE4EE64, 0x22237F56834AC746,
560 0x4FD0C1AF8A61F566, 0x86326F93EF63E2C1, 0x14D55726A5F74BFD, 0x99AE7713DF2DE6CF,
561 0xA9CC4B50995A682C, 0x6F6F12C80929FF20, 0x8C72007D6A253FD3, 0x6DE363E8EBF2B614,
562 0x95F6F59DA4CE4BA4, 0xD6D4D371A2484F16, 0xEFA33CD34F71B817, 0x02F0E99C031B089D,
563 0xE16A7B75AB838252, 0xD1840EF2935AA1CC, 0xA5C8470F98202BAB, 0xA93EEACE43EE56E1,
564 0xB2D767F35B0F34FC, 0xE855B53B6B8DB8DD, 0x08BCF47684E904FA, 0x47965D72107897D1,
565 0x3D38403A0D2696A7, 0x67679C6F9CC37537, 0xA93A125CE7041EC4, 0xF39AD7452597ED13,
566 0xA0CCD841B7CA93DB, 0x6F7039B929A820F5, 0x5A95AA3786C96E04, 0x34DA46A084653B1A,
567 0x08A907831A27892D, 0x0DD5B6C9FCB5229C, 0x0C03663794A4E94E, 0x3FB22E4068ED0EE8,
568 0x53BCBD15AA8DEC34, 0x51CEF53541B04056, 0xE4DCA0393836E9B6, 0xDFCF9B01E901D933,
569 0xBD160166307B70BE, 0x5618C6E0B4ADEBA4, 0x6F65C69080D4C3FA, 0xADF1AA22911C2C69,
570 0x42FB1575074655AB, 0xD1EFF5784CBE7FA0, 0xB110981C8A0BDF01, 0xC650189C2DC9FC74,
571 0xB403563011DDE16F, 0x92630CF312B3F7F4, 0x95E74B3B582DFB94, 0x01F509A35BD2528C,
572 0xA81600F6437FBD00, 0xFCF0E4AD41DE3598, 0x434EE3903CD1A17C, 0xF618E8E2A47EBC4C,
573 0xA1D7816AE33BA46E, 0x3A9D5B3CBDACF93D, 0x538802ED0FCCEFF1, 0x93DB9D6B79C7E508,
574 0x54B42DDFAA7DE9B5, 0x299F4C1B5DA05487, 0x562D20349282F706, 0x1E3159E4EAB09D03,
575 0xE15D45F2D1694FF3, 0xFF1AA1FC1E58E3FB, 0xD6875B71B982AD57, 0xAC96CD3B7BE8ACC6,
576 0x90CADDAD41374E4B, 0xCA29AAB22CAD6198, 0x9158C474E0725B4C, 0x4C5442D6A12D94D8,
577 0x2827752CE49CB9C3, 0x85AD35C129110989, 0x2EF85A7A6C043BD8, 0xE3BA4AC3D5146FB7,
578 0x87002794AC4020B7, 0xD229EAE70E01E72F, 0x1772B0DA401ABE2C, 0x2D487EF60724DC83,
579 0x413A0F58974C76AB, 0x4C17AB24F37CB105, 0x5FC1827A1DDB0456, 0xCCAA7F9477CA64FC,
580 0x904E1D9338D0795C, 0x6844F79ED8B26A9D, 0x306F66975CE704A9, 0x25E72EC95509188B,
581 0x2B5EC3212ADF3595, 0x4F1CDA9CB6CCC28E, 0x422F23AF81659F6E, 0x4AFDD03EFB8AD730,
582 0x84D1CCA3B5036F03, 0x1EEDE0F1121E6F62, 0xD232DFB74A0582EB, 0x3303D1E98810A6C9,
583 0x221F0EFCA2C81259, 0xB57F8E6943D0CD36, 0x088A64DA7FE2E6E7, 0xE0F63EAF873B8A79,
584 0x57E9B39245C61730, 0x88B024F34ED7B64F, 0x8784413FF95E4764, 0x74FECDAE7BD62E5A,
585 0x807A807832F6AC83, 0xBC7CA7F754BBC7DE, 0x72CCC85425068F50, 0xED52419643561832,
586 0x1B9CF54C055FB01B, 0x40740A0D46985529, 0x2AE8A0C58756BDD3, 0xC6DABE268551FD5F,
587 0xDD8CE660B7403DC8, 0x672EA620E65301B0, 0x865A23FE568C1736, 0x69EE1D7F7A1BD748,
588 0x3CCFAC84AB188D90, 0x6D70525D092C3E2B, 0x46C6675C1CF4B30A, 0xB346022E43DA20B8,
589 0xA01DC1159652EA26, 0x0B411971B0E3D039, 0x3C1E75AB0EA462E1, 0xD07D0847EFA9CFBA,
590 0x4153E6B4F4687D43, 0x4414BAA200FA38CE, 0x46B28D3B4055C633, 0xAAD0ED2FACD6B415,
591 0x5234FA7B72F478A1, 0x93EC14698C611F3C, 0xB70BF72C15E0DCE9, 0xCC048A526AC1F46A,
592 0x969C10820390DF8D, 0x90AD0138202A3218, 0x2398B70405520538, 0xD08C1F799FBC0755,
593 0x53D8304A8B5213FF, 0x88DD1620B1A5125A, 0xF1CC9A07F95C61C5, 0xC6C625F64FFCDBE6,
594 0xED1E06EC959FF323, 0xFD3E8AF3553D90BD, 0x529D699B08B873F1, 0x64F59B1CD522AC0F,
595 0xA5C8A02849509DEC, 0xECFADD4C89C03A78, 0xE1564A548D89DECD, 0x90DDBCAC7964E9F0,
596 0x545B207877BBAFB5, 0xDED6AEAD3967CA72, 0x272E128C97B06868, 0xFD3BB85996640432,
597 0x2995ED49B525D47C, 0xE868EFD6FDBB0BB6, 0x975DC82C8580D00A, 0xBCB9FFC6F532A0CB,
598 0x9F0B1EC3BC16C2E7, 0xC94F5149D03677AD, 0x039452180B24DA43, 0x4F5BBAA0BCEE64ED,
599 0x910009CE6C11178F, 0x5BC794754EBA7200, 0x3E9A53CDA988B33C, 0xE2D0A0965DAACA23,
600 0xBF8A7AE5330F4813, 0xAE7F8E4F25666EAB, 0x3F0351BD34ABBFA8, 0x874D88D5FC4E9385,
601 0x45A0C20F7DFD3928, 0x72ABDCB19E4F6F09, 0x7044266B9EA6F0B3, 0x18A5011D0E51E735,
602 0xEE58F5FC44AE8595, 0x64B64F3D173C58FA, 0xE938AFB934CBB972, 0x45F7B1A1DDD4C559,
603 0xC7DF1E821B249BE3, 0x5E6CAB842F3DFCD0, 0x141E428141C28BDC, 0xF54B0985329F6E2A,
604 0xD8C083075232BDEA, 0xDEA797B6C9E15606, 0xA72B8B48502B1C04, 0x4BA89A8DBC54EB6E,
605 0x718EF66E726EA72E, 0x631B9B22E193F012, 0xF3FB2D112468B0DB, 0x89F0C3C8A143E9B1,
606 0x7D6BE8EA6A522A10, 0xF46EC5A56E3F5725, 0x86884547536AFFAD, 0x0C82A42D88AAA64B,
607 0x0B740E17EEF10A80, 0x0DE1916C291C1535, 0x845114313E908D31, 0x3B58018EB77DED61,
608 0x9A5F7429731308EF, 0xAB68D1725D8F9501, 0x234F9035869415A6, 0x2262095D77A9613A,
609 0x9BDCBC26ABDE4672, 0xBE5F130E1089BE8B, 0xF5CA0ED3FCD9F28B, 0x75CC07E9822AA2EF,
610 0x6AC735D6621C86CE, 0xA203E9E1FC993207, 0xEDC164396C7C8FF2, 0x27F92979A313914D,
611 0x8E1D4E308C03F66D, 0x73D76A715F859BED, 0xBC8D709D4BEFC155, 0x8D74B49860A90ABA,
612 0xB67C75041BFB3A61, 0xBBBB73DE2B3D7BB5, 0xCB254F10257495E3, 0x185C71C3559D9CD0,
613 0xACB7A163EB1E0886, 0x24F946909B29B2C7, 0x373C5CF4F6B1F3A7, 0x5DC49B1574B3AAB8,
614 0x327C55142CE3D138, 0x2EA917A7C6730E01, 0xBA6BA43767D53E84, 0xFFB7D61D6EAD24AD,
615 0xCFAAC26024A1D642, 0xC795400B8646533A, 0x435A4FE899704FAF, 0xAE2BF452BD9AF093,
616 0x53759538B5F4A861, 0x4F1AB4840CFC1EFD, 0x8CAFCB067C991FDF, 0x2658ABA23F8B0B93,
617 0x6B3A35CDECD26C58, 0xB9F1318AF46F1376, 0x7758FC0F74B7DD05, 0x0A9B1A1C7F98B930,
618 0x4B4C20D040F3A8C7, 0x46453ECE10C0A1F4, 0xF74BDDB1A8FCFE1D, 0xE2C19148A5E88F1C,
619 0xA98B4DE68DDB2434, 0x893BEF8F2CF8DB58, 0x4CEE8F0E39D30CD4, 0xC87017E7EE6886F8,
620 0x23024E83F777D7DF, 0x0D7E46A8B5F9B133, 0x1D0BC2F79BF5559C, 0x3241D5BDC7E7A665,
621 0x9E1DD50373C16CC9, 0x7A5E390921B471EF, 0x5B39731CCC2CBDD0, 0x8876080680F9D974,
622 0x9DF22EE3AB758F85, 0xFD490012FCFF20B3, 0x329A5648D2585903, 0x6C0586C65F46236C,
623 0xB009BA2650ABAFC4, 0x5653D61D2BFA255D, 0xE767D0B25AC7736E, 0x8E5200D21EE3E28F,
624 0xFD96F63D0A22CD57, 0x4ED61899ECDEB4BE, 0xB333F994AC7791FF, 0x89EC600B857D4DDD,
625 0xC2773C7DCE36709F, 0x70180CFFAE22AD44, 0xA4A20211224F8ECF, 0xB336A54A681A1F59,
626 0x5C00C419C78A79AD, 0xA49562EFB784ECE4, 0x4BAF45C1E75BD84D, 0xE7C1C69100F8B93A,
627 0xDAB0C7C65F0D0963, 0x51BF8A0EE9CEF5F7, 0x756A9A47B4EE8042, 0x0DEFA16B0E74CF18,
628 0x0FAB86E762595261, 0x852E38F9D797D4F7, 0x96DA18169AFAC99E, 0x8235D4DD6C2BB887,
629 0x15D0F65E9ADB2C67, 0xA887E5D8EF4E1080, 0xAC968F4C0D673CA7, 0xA74759A7F1B4E383,
630 0x1B5641CE5FADE005, 0xEB947BE5E20E7DDA, 0xF6372655825B3516, 0xF2EC5B36D687895F,
631 0x2C0BB35E3C3EDA32, 0xC19BFF6F3A2397A8, 0xE25C646059359D90, 0xA1372FCAEE250A43,
632 0x8AABBF162C4499F2, 0xFECFA27F8D7582FB, 0x607B88D04F4A6100, 0xA3D2F8A88A2E5E80,
633 0xD9C26C2A023943BC, 0x62F3C18658A0F5C6, 0x4130BFF0D74BBB85, 0xEBFFFE197C94C6EC,
634 0x0AED385393F69FA9, 0xF7E69DDC061B85E4, 0xE77D0BE2013061E9, 0x4A0DB8AC2995096F,
635 0x775369B59AA940DA, 0x96B47429C339536B, 0x51ECC59C60BAD762, 0xFA275A6A8F90885A,
636 0x922A84AE2B06B400, 0x3C0A7BE22FB21136, 0x5376C3FBFC03EB0D, 0xEA264F6769B57EE2,
637 0xE518ED3DD8553DC8, 0x815E57F23DADC1A3, 0xE99030AA02A35296, 0x04EE4BD66D770F8E,
638 0x8AB3C94077F85772, 0x647897A76CFE4EC5, 0x6FCAA7A28968065C, 0xC73BDD88ADA4D60C,
639 0x9430F05CFEF8ACBB, 0xA73038463A9AD3BD, 0xE5BA4E94FDA81C6C, 0x51AB3C69201906E1,
640 0x2613EFCF23567038, 0x3ED865C6161C8A89, 0x58DC09289EA03658, 0x376277BE6E4E62AA,
641 0x3C90B273B9870A06, 0x9FE0F5164AA8F837, 0xB9905EEE7D3AEB79, 0x4BA2F4CAA4F1EB01,
642 0x01C2973BD37D564B, 0x7D21243A206BD8A7, 0xB435428BA8DD3DB7, 0x045541BCCE000F5F,
643 0xCEA89305914BEB1B, 0xE84B59A4A18CC1AE, 0xB5CC96326ADC69F3, 0xB4957198C60BB6E7,
644 0xDB38C42E2947EFC3, 0x9D2BBFA07C18C320, 0xA22C7B9C6CBFB72E, 0x6909BDC131B2E15E,
645 0xABECA69DD1395554, 0xC852ED7EE6817A61, 0x52B39B42F6D7D56B, 0x781D1803B8307C79,
646 0x386FFC16B79E3092, 0x55E7D5933870D116, 0xDE3828C68348493D, 0x8E288C8A3FBF741F,
647 0x0936252D32CDEC49, 0xACFE91F2BA885044, 0xE0A9ADFEA526F536, 0x41F97B86668C5972,
648 0xF9D8560A97AFA428, 0x2DBCC4250B75A871, 0x276434FFA80959F0, 0x4D3400D81937617D,
649 0x799C3EDF3F134590, 0x8B306D8372A740E9, 0x6707761FCCA9B861, 0x402134AE9488387F,
650 0xF2DA86FE2BAA7E67, 0x5DFDED45499AF1B4, 0x0AE292B1DE6B7A7D, 0x4799C3B88177704D,
651];
652
653#[rustfmt::skip]
656static TM8192_G: [u64; 8 * 64] = [
657 0x616DB583006DB999, 0x54780CD6DFC99087, 0x72D8260D390B1D46, 0x2A8F62DE88092161,
658 0x94BE0531EE408AEA, 0xF27F50F3AD71865A, 0xC7910EEF8824A858, 0xCA7B13FC843DAFB1,
659 0xBA3E0B010860D090, 0x66A8632E2B273DAB, 0xDF90C26FCDD989C2, 0x831874EA7FBA23D9,
660 0x40A294111C1B0C1C, 0xF62F56A376B94CF6, 0x4FA594B987B19226, 0xE525704D7F2BC66E,
661 0x226C671C22A59AC0, 0x62490596EB1536C9, 0xF66AE799C2489FAD, 0x2C131E29ED64A25C,
662 0xB0ADC88D04C5EC8F, 0xECD7F78B3825E626, 0x858CFAA0DE77772C, 0xE8822C7AA39628A0,
663 0x123B1C426E2A9336, 0x6D067D26DE51362E, 0xA0BA916EBD122952, 0x1B1B044459B32578,
664 0x5F3F3E24199B2460, 0x151E4CAA9FD26A5D, 0xC46BE0D6DA907EFA, 0xF38F413642F702F5,
665 0x324AFD5D62F4CC25, 0x1FF5C0FD95DE0FAB, 0x061F0C92CA5BC97F, 0x976118AD84E0663A,
666 0x3BF1B4F07D1CCCC2, 0xDF9E09D506B073DE, 0xD87CC0653C944FC7, 0xD438223C0DF3EB67,
667 0xE62AE13F8D4000D6, 0x16E814045495F6E9, 0x69C473B059386F5D, 0xDBCC25F4002EB132,
668 0xD73A98414D85346F, 0x55DEBFF875F7CB9D, 0x2466A412D180E0A1, 0xADA18D281376A671,
669 0x8EB0FB6BB7B9AD2A, 0x2132010511077F6B, 0xD424B6F5B578C11D, 0x0076B781930F755E,
670 0xBB72C41ED1751947, 0x6C257C31C3159BF3, 0x1FADA2755F1B8A23, 0xB22D6A428AA290E2,
671 0x54CC73C7599AB67C, 0x6807C4286BECF842, 0x3F3216EF04E1B6DE, 0x61349DDB23E3A0EB,
672 0x0EF70C5BE1AD91D3, 0x1B0BB532C1098DC6, 0x19BF80F3853EEA35, 0x7091C05D95170A7E,
673 0x5E6381A718C0A817, 0xF8101ECDCDBF825E, 0x732E4356CEC42C22, 0x2DBC476BD704837C,
674 0x382B7FBF282B739E, 0xDC22B5EEA2909F0E, 0xB3ACB9E41FE2AC79, 0x1130A36A9CBFC1D9,
675 0xD4F8DE28FA77F37E, 0x4A6B5A82A58CE917, 0xCA74C8397E9DB8ED, 0xCB2BF65DB9195445,
676 0x7707FE876DFF812D, 0x4B99466DF479A001, 0x14F27E702249DB3E, 0x9311301E9CE98703,
677 0x74FEAD0013FD861D, 0x67D7CE69D3635ECC, 0x6266E862D08B6307, 0x7B45D3098306EA74,
678 0x159DAEA2263E5870, 0x5EA5ABE58B7FD418, 0x62B9EC1D0F1BD47C, 0xD6CB42739C24F7FE,
679 0x7ACFF6D64C8E8F94, 0xBEABE280CFDCFCFB, 0x26AC7330073C25E0, 0x313DCB75E6C5261F,
680 0x15D82AFA665F73A4, 0xB4DA4E5D1648EAB0, 0x51EDEB9857C13C2F, 0x019FCBBA4F9DF2E1,
681 0x9CEFF1147D792C14, 0xAA2E211C3B9B94B2, 0xC9F24F49B0B1ED6E, 0x200C88D743F5AC1E,
682 0xE283C3A0AC79B9F1, 0xF496BDE74A2AA591, 0xACF2F526FB24413A, 0x58B495F91905F596,
683 0xD8F1469BCA9CC504, 0x1C50F1FB479CF268, 0x0503AD85BA2C0C6D, 0x01D2D739F3129315,
684 0xE49A9F57236D9585, 0xCC0B8A9B4BFE9ADC, 0xD97BED9006C33976, 0xACC00468693D56FA,
685 0x1EE66371B0EA6C4E, 0x1E172C2C5D76806C, 0xB7376B8CDEAD96B1, 0x4A1EC2B656298B94,
686 0x25EA2F0671082D70, 0xAA23C267D1F215C5, 0x9239AEB40186DF0A, 0xB284625DC6BAF45E,
687 0xFBFBE26BED98BB3B, 0x697764A6F82C9403, 0x9CBF14CB538A7D87, 0x801ACBD3A444A858,
688 0xBB74F0A4707592EE, 0x6B7DC6D21B8F6B4A, 0x184B567C8AA4CD82, 0x5EBF7F1EDCE015A5,
689 0x25453670647D23C5, 0xE445A705953F3BF4, 0xA5AF02E7BC46C969, 0xC8141D8782F171C9,
690 0xCFF7EBB20945DE5D, 0x363AD36D3BD5A0BA, 0x081C079CDD04B6E5, 0x968187C8A665344A,
691 0x23E9B1897A6FDF42, 0x7B5E910AA8D71F9C, 0xC6351474BC4563C2, 0x0FD38953295D3BA1,
692 0x5E7D1010503B7BA1, 0xC148251DB8A88AC6, 0x4E6AF8C1CC056E4E, 0xEF1C927FEC40C35D,
693 0x57140969483D9E33, 0x429FAFD177D031A4, 0x3B727CF832C8DFFE, 0x8D8960CB55BE4BE2,
694 0x7B69CC26F2FB731B, 0x53250D6F8EE7DFDA, 0x98812B9AAE9C02AE, 0x2FEDEA598D6B6E2F,
695 0x22B6CCA50541BD9F, 0x5D48565E551B310E, 0x10A0DFCB8035A5EC, 0x86EB9CD8C811CDCB,
696 0xCCCEC3732EF93EE8, 0xC9418E25CA5744E0, 0x7C45F9B161E277BC, 0xECE388B9B84AAEC4,
697 0xDA37FE277C72CB5C, 0xB1BE92AD37386740, 0x3E46B3535159687A, 0xDC79C39DEF7005C1,
698 0xF11F1CBD5F8877DA, 0x66AAC156EF27BB89, 0x3F5F1132336D52E8, 0xAEB60EACF9BEB3CF,
699 0xD204D92DFA496DAF, 0x564272E3FEC51CE5, 0x3C8F2DF6ACB191E6, 0x0E14CDEA28FD5ED0,
700 0xEBE09672ED11A3F6, 0x466FE3A967A4EC83, 0x90303059AE00DD83, 0x102A9F33B2943E4E,
701 0x6E56928E7FEE3333, 0xA36FF3EE7598744C, 0xF7C298FEF3EACC7C, 0xCC0F36DCBA6D87BD,
702 0xD441081163A65E27, 0xC958AF79C33A98B8, 0x1814015E77F82EF5, 0x120FBDAB540893B4,
703 0x7BEB68CC37F23835, 0xC91F5D36D6BA6F0A, 0x5E68FEBB6E6A2F24, 0x7EB5CF57684D0770,
704 0x249460788DFDC4A1, 0x218652BF881B4BB0, 0x6308EF86484E7070, 0xAACC72D3977CF5D0,
705 0x6230DEF1ACD4425F, 0x7B155A2A285CB2A3, 0x2CB9D46DA09B2816, 0x7826E77AEBD85F0C,
706 0x416595E136184841, 0x451F5B3E1F17D02C, 0x3DB32C2AF50091D6, 0x376406D8CB78A9E3,
707 0xD3B19911ACC45067, 0x9EAE25B0F290FF37, 0x2300F1A4BC91A43C, 0xB79DB270133D41DC,
708 0x4970F1420E71C0F8, 0x16EF938C3C17F0FC, 0xBB6E920ED853EAF6, 0xD2DC6792BF87098A,
709 0xB94C2E5DDE78C974, 0xAD6F423CD5ACA01E, 0xC9420AAF3FE83BEC, 0x31D47AACD3D62FA2,
710 0x476C38595BD66639, 0x368181E75B44BAA7, 0xADBC2B42E1D82D7A, 0x59312BB9A16F7D35,
711 0x0B13B44D828071E6, 0x9DD90DCD9B713A05, 0xFD8C21AA5E6E6D8D, 0xA49A5C3B34F98A4E,
712 0x5E822513F0DA2002, 0x35C65BFCA1DC2CE4, 0xAB21D146B778F680, 0x6680B8AC75285760,
713 0xFEF66B861AA67C76, 0x8A76D585DFADC8EB, 0x6556AD841DEA9F44, 0xACB42B6016142B6B,
714 0x69F1833474FADEB0, 0x400CE4D9F3BD62AD, 0x96E57F3E93DD2291, 0x80F2D4B5E77D098F,
715 0xEEBE2DFA4D4D86EC, 0xB07EEE9565FB5898, 0x55E1F53BA1B9784A, 0x8D195A0E37215512,
716 0x70089C535216636F, 0xBEB4D9E50A9EAC3D, 0xCB27891A7005A2AD, 0x87427E6B8326F6B3,
717 0xCA225C7B2A9EABFF, 0xDDDBC130B5342917, 0x848B029917BA98FF, 0xD6EF2389006A6B41,
718 0x7F678C61458EF625, 0xC96C0D3D07945ABB, 0x9836CF80823EB624, 0x4D86D114CC5DC2B1,
719 0x94F5D55C398B16A7, 0x1497C4CF102C2F10, 0x35C19D5DFC8A301B, 0x8DE33D41D909C15A,
720 0x3093B09E7489CE6A, 0xA14B331B70E76637, 0xFE6DDFFFA6DC4C51, 0x0371CB0D2A6EA3DA,
721 0xAC5F866DD75CD4C2, 0xD5959AC37DE4E1E8, 0x70313A5B2902F234, 0xCD939FE39F31FEBF,
722 0x8B46DAC906E3EBA9, 0xC3A74DE46E7A9140, 0xD3716667BB1EC22A, 0x87D5F8D048BDC5BA,
723 0x57B6024327CDDFF3, 0x296BE6508C48045B, 0x71FA519156F8C125, 0xF4E3B7356576F32C,
724 0x63BC588908C4E8B3, 0xF9F2D12A9E8F35B6, 0xFCF296C17FD8E8D0, 0x76406FA11D16175F,
725 0xCC45AE82D672979E, 0x8A0A359B2328C79A, 0xE61F87EBE04DAC93, 0x4303054865973200,
726 0x0CE627417B3F8CFD, 0x4A992E7F2B680216, 0xAF773385B9337E17, 0x43D43FD965282CF5,
727 0xAE71B0CAFEB4DA3E, 0x0B95F1341667C519, 0xFB9F89D7CEC711E5, 0x7485F04A965CDC83,
728 0x2CBEC0BE1B2A3E23, 0xB5EAF4C5DAD8767E, 0x054B2225A60B88BE, 0x1DB6A35E0BAEB237,
729 0xA206BC721B252D52, 0xEA1F8E311203DFF0, 0xAE8D65BD19860557, 0x01A3C7FEB2DDEDD2,
730 0xD57C3BBA6A2BC56A, 0x9157677D7B48AD29, 0x07927176F6B22E8A, 0x92F6E9863C9E16D9,
731 0x11B6209E06EFE6AC, 0xBBBA2214EF5AEAB9, 0xD76645476B2C16B8, 0xD14E1AE3F3A85188,
732 0x835922B914D3F32F, 0xE05B7987A2516B3D, 0x3C8983AE176DFD04, 0x349A45359B422E1E,
733 0x01CC2266F2B68A43, 0x23F8931D7AA37B1C, 0xBD70DC2FEE915923, 0x27207AA612179515,
734 0x0A0DC918704A1A29, 0x3778FE75A99FDCE7, 0x7E820D0905EF7AC7, 0x2A682F2487A6E0FE,
735 0x03F42D94FDE1C13F, 0x958DF61112DB4A27, 0xA8A8EF35087FD089, 0x729F0864C2706CCB,
736 0x2B6CBD91A9A7B7B3, 0x1E08EA3570A6E1BE, 0xD495FC84FACD829F, 0x3234B1D1DC574B67,
737 0x900AA49643295914, 0x1795C615CBAEA980, 0x02440A0D447EF990, 0x435E452CC690203B,
738 0xDEBCBA3EEFC7A7CE, 0x71EB54B1728AEA9E, 0xDE70A7E6A1A8AE86, 0x168709A899738CCB,
739 0xC5B7A094AEBEA8EC, 0x95A414A8DE5D3DBE, 0x6745CB0D330B7843, 0x5AC2BB6666BB2D43,
740 0xA19EAD3B3D9536D0, 0xBB92DB949570981C, 0x22805E7DEA452FA6, 0x49C84EDC4324A7FB,
741 0xE6A9CAF4EE484007, 0x20B8F84CAC3A4248, 0x3B7E571846E2A5F7, 0x7A983EE311179CEC,
742 0x2D99878FF5AA06AC, 0xA0CBBA63B36985E0, 0x970761E7F837650B, 0xC46C9A2EB1AEFA95,
743 0xAC4D8AA5C970BB55, 0xFDF3408356C9EB26, 0x83B6FEE593736B66, 0xB49C055BD6503EEF,
744 0x3C7CADD15C9B86DC, 0xA626E1ABF4B971D0, 0x4C0A9A5AEF8305C3, 0xD0E4CC02C32FA91E,
745 0xD8949EF8FEADF7DA, 0x39D395B52D2779A0, 0xB305C4FD10C33A43, 0x4878967D9321B483,
746 0x5C035CA5802C37F6, 0xDC1E39AC30337253, 0x114176BBB2657631, 0x7C72E9548F179A5A,
747 0xA200FC35B6A0934D, 0x57543A60F6114B7B, 0x0D78D8DD8932538E, 0x545D806A1D9E4739,
748 0x0F092501F4A470CF, 0x7B1F9144D0A8F1B0, 0xC3D607930A75E5A1, 0x50233DCEEDB4C10B,
749 0x217C8EB38D4D2A0E, 0xF12557321D504ECA, 0x670B41E496441FDE, 0x341F0232101D4E3F,
750 0x4158FF6F4EAECC07, 0x3AA811DD450F528B, 0xC6095868B7BF9539, 0x26056BD409E5FE36,
751 0xB82831B150B80A73, 0x6D6CF7B16660ADCD, 0x5E1F4DB96E36E33D, 0xCC2F1506C7B8B0F2,
752 0xA4EC362FB0CF7B8B, 0x3B08D6CD1AF74407, 0x29D4C3C02627AD87, 0x33A0C94B2EBAF526,
753 0xFDB4463E6F8FBAF5, 0x65B1C3320F5704A8, 0x7309E529842378EC, 0xB733784F1CBD85F4,
754 0xF87FB0525C7C4D30, 0x7061F74DE2FB3BDF, 0xBC77E04EAB75A64F, 0xFE51203AB925E807,
755 0x1D1101A16A2C41DB, 0xDCA94C128560BEFD, 0xA4ECA6F22B44C6E5, 0x085A23F84106E4FD,
756 0x870FAA789E03FC37, 0x086E67B69FC8EB64, 0x21AA57FBA27866DF, 0xF712D5FEDA21FC51,
757 0x76EE3CB2C4A8629C, 0x20FC646A7ADF2A4B, 0xE73DCEF53FC92606, 0x7EB9964996BCEE40,
758 0x3C5642CD2F8084E0, 0xC14D3627FAD9F018, 0x0DADF07331246C00, 0x7F3AF95CC9B451CC,
759 0x3638887EB493F5EE, 0x3361F07E00F115BC, 0x04AF404BE6BA3467, 0x322B37A8E6ABF477,
760 0x10D56C3BC751892C, 0xFD12F29CC4319D05, 0x62005562D05261D3, 0x9FDF528A11E65BBE,
761 0xA0BF07C52E9A9ED7, 0xAC3F0FB9196A450E, 0x162009509F20BEE7, 0x4FCC6316BC4824D9,
762 0x3CBAC25E470A7468, 0xA629EB520E980DE3, 0x1F8C8873F4ED21B5, 0x7AAEBF43A5754359,
763 0xCD089ABE54897567, 0x8C2123223CF3F345, 0xAE0CECF0A3726BFB, 0xB130E34169A874B6,
764 0xC4CDEFC0A05D7DA1, 0xEE475E5407F15353, 0x99086700874C1300, 0x0E2EE21DF3EEFB65,
765 0x4BEF6F2B4137DC6E, 0xF197D514E904B8F3, 0x1BAD6C846D6BD7D7, 0x480F4818C3C57B4C,
766 0x7F53F168E4802027, 0x3702071EE48EC534, 0x22C71C90AA026298, 0x2B82BB6FF3100D8A,
767 0xEB3E8F033DA73FA8, 0x2B3B93E50C60E593, 0x6A07D3218946588D, 0x0EFB39E1A55C0FB9,
768 0xDBA87DA50C4697EE, 0x2ED72B004301019E, 0x595B92A2F55F7F1B, 0x37C2030B79057F52,
769 0x59CA13359E16B10A, 0x7F8778BBAF5D45E3, 0x2C643B524022FE77, 0x7A8F557C14141D63,
770 0x8E84BC4DBB1CE586, 0x6CD0B89C1CC5C6F7, 0xBF7E25D2B4FC28A1, 0x6E67CF8BFAC4F4BD,
771 0xA612F30067700487, 0xB6584B1AD578659F, 0xC2B7443228B2B7B4, 0x43882DABBF55739C,
772 0xB9660F530631A2CF, 0xDCBE94D21692CAC0, 0x1DA9EB5048FFF17B, 0xC4FB5957E8C9DF1F,
773 0x29E0573D85359FB7, 0x924AABBDDDCD26F5, 0x740FFA6824FCFCBD, 0x53BF1DFB587E0667,
774 0x641DD3F82962F5E6, 0xEA26461279B0F694, 0x79645462983DBBBC, 0xC544DA90255121EA,
775 0xA97C7B71923F0382, 0xDF60C9E34D84CAC2, 0x89B578899EBCF924, 0xF4304B80581C9887,
776 0xB1198F074143DCC4, 0x324D7DF301466AC9, 0x7903E688DD2E9186, 0xEDD2D90C34202AA3,
777 0x90815D489B715FF6, 0x04788F335322DF5C, 0x8856FD85F753785A, 0x96F4B2561990F458,
778 0xC69D3F99A8ED1BE9, 0x9C3F5A14B19B37AC, 0x729B3F35ABF52006, 0xE814B597145FA3FD,
779 0x86A5A2038BB67CF8, 0x225BCCF7A587E0D0, 0x9B47D26BC4DB017F, 0x6A77B6DEC5AF5B11,
780 0x7E399D8A336358D4, 0xAABE9C8E7EAAF644, 0x7638F2DC66EF65C1, 0x00D06EE202013042,
781 0xAD845A43D23E66FB, 0xA72D9D56457D66C7, 0xE44D98ED1E5F1D06, 0x3A5D01043930E9C2,
782 0xEDED8BA9DEE5F9DF, 0xF91CD887F097B9A2, 0xDF0099E278C253E0, 0xA549C7A2D81078C6,
783 0x680566EA7A1E724A, 0x99B5D7099AED278A, 0x3065BBC64BED4411, 0x54DCD346D38C9771,
784 0x648D55656B16CF01, 0x2D0C6EC8F616D3B7, 0x58089A8147D731AE, 0x077D557204256F93,
785];
786pub static CODE_TM2048: LdpcCode = LdpcCode {
790 n: 2048, k: 1024, punctured: 512,
791 circulant_size: 128, submatrix_size: 512,
792 mb: 3, nb: 5,
793 generator: &TM2048_G,
794 h_matrix: &TM_R12_H,
795 theta: &THETA_K,
796 phi: &PHI_M512,
797};
798
799pub static CODE_TM1536: LdpcCode = LdpcCode {
801 n: 1536, k: 1024, punctured: 256,
802 circulant_size: 64, submatrix_size: 256,
803 mb: 3, nb: 7,
804 generator: &TM1536_G,
805 h_matrix: &TM_R23_H,
806 theta: &THETA_K,
807 phi: &PHI_M256,
808};
809
810pub static CODE_TM1280: LdpcCode = LdpcCode {
812 n: 1280, k: 1024, punctured: 128,
813 circulant_size: 32, submatrix_size: 128,
814 mb: 3, nb: 11,
815 generator: &TM1280_G,
816 h_matrix: &TM_R45_H,
817 theta: &THETA_K,
818 phi: &PHI_M128,
819};
820
821pub static CODE_TM8192: LdpcCode = LdpcCode {
823 n: 8192, k: 4096, punctured: 2048,
824 circulant_size: 512, submatrix_size: 2048,
825 mb: 3, nb: 5,
826 generator: &TM8192_G,
827 h_matrix: &TM_R12_H,
828 theta: &THETA_K,
829 phi: &PHI_M2048,
830};
831
832pub static CODE_TM6144: LdpcCode = LdpcCode {
834 n: 6144, k: 4096, punctured: 1024,
835 circulant_size: 256, submatrix_size: 1024,
836 mb: 3, nb: 7,
837 generator: &TM6144_G,
838 h_matrix: &TM_R23_H,
839 theta: &THETA_K,
840 phi: &PHI_M1024,
841};
842
843pub static CODE_TM5120: LdpcCode = LdpcCode {
845 n: 5120, k: 4096, punctured: 512,
846 circulant_size: 128, submatrix_size: 512,
847 mb: 3, nb: 11,
848 generator: &TM5120_G,
849 h_matrix: &TM_R45_H,
850 theta: &THETA_K,
851 phi: &PHI_M512,
852};
853
854pub fn encode(
861 code: &LdpcCode,
862 info: &[u8],
863 output: &mut [u8],
864) -> Result<(), LdpcError> {
865 let k_bytes = code.info_bytes();
866 let n_bytes = code.codeword_bytes();
867
868 if info.len() < k_bytes {
869 return Err(LdpcError::WrongSize {
870 expected: k_bytes,
871 provided: info.len(),
872 });
873 }
874 if output.len() < n_bytes {
875 return Err(LdpcError::WrongSize {
876 expected: n_bytes,
877 provided: output.len(),
878 });
879 }
880
881 output[..k_bytes].copy_from_slice(&info[..k_bytes]);
883 output[k_bytes..n_bytes].fill(0);
884
885 let parity = &mut output[k_bytes..n_bytes];
886 let b = code.circulant_size;
887 let k = code.k;
888 let r = code.parity_bits();
889 let gc = code.generator;
890 let row_len = r / 64;
891
892 for offset in 0..b {
894 for crow in 0..k / b {
895 let bit = crow * b + offset;
896 let byte = bit / 8;
897 let mask = 0x80u8 >> (bit % 8);
898 if info[byte] & mask != 0 {
899 let row_start = crow * row_len;
901 for (idx, &circ) in
902 gc[row_start..row_start + row_len].iter().enumerate()
903 {
904 parity[idx * 8 + 7] ^= (circ >> 0) as u8;
905 parity[idx * 8 + 6] ^= (circ >> 8) as u8;
906 parity[idx * 8 + 5] ^= (circ >> 16) as u8;
907 parity[idx * 8 + 4] ^= (circ >> 24) as u8;
908 parity[idx * 8 + 3] ^= (circ >> 32) as u8;
909 parity[idx * 8 + 2] ^= (circ >> 40) as u8;
910 parity[idx * 8 + 1] ^= (circ >> 48) as u8;
911 parity[idx * 8 + 0] ^= (circ >> 56) as u8;
912 }
913 }
914 }
915 for block in 0..r / b {
917 let start = block * b / 8;
918 let end = (block + 1) * b / 8;
919 let pblock = &mut parity[start..end];
920 let mut carry = pblock[0] >> 7;
921 for x in pblock.iter_mut().rev() {
922 let c = *x >> 7;
923 *x = (*x << 1) | carry;
924 carry = c;
925 }
926 }
927 }
928
929 Ok(())
930}
931
932const MAX_PUNCT_BYTES: usize = 256;
937
938pub fn syndrome_check(code: &LdpcCode, codeword: &[u8]) -> bool {
946 let m = code.submatrix_size;
947 let punct_bytes = m / 8;
948 assert!(punct_bytes <= MAX_PUNCT_BYTES);
949
950 let mut punct = [0u8; MAX_PUNCT_BYTES];
955 for pos in 0..m {
956 let mut par = 0u8;
957 for col in 0..code.nb - 1 {
958 for layer in 0..3 {
959 let entry = code.h_matrix[layer][2][col];
960 if entry == 0 {
961 continue;
962 }
963 let mapped =
964 block_map(entry, pos, m, code.theta, code.phi);
965 if let Some(var_pos) = mapped {
966 let bit_idx = col * m + var_pos;
967 let byte = bit_idx / 8;
968 let mask = 0x80 >> (bit_idx % 8);
969 if codeword[byte] & mask != 0 {
970 par ^= 1;
971 }
972 }
973 }
974 }
975 if par != 0 {
977 let byte = pos / 8;
978 let mask = 0x80 >> (pos % 8);
979 punct[byte] |= mask;
980 }
981 }
982
983 for row in 0..2 {
985 for pos in 0..m {
986 let mut parity = 0u8;
987 for col in 0..code.nb {
988 for layer in 0..3 {
989 let entry = code.h_matrix[layer][row][col];
990 if entry == 0 {
991 continue;
992 }
993 let mapped = block_map(
994 entry, pos, m, code.theta, code.phi,
995 );
996 if let Some(var_pos) = mapped {
997 if col == code.nb - 1 {
998 let byte = var_pos / 8;
1000 let mask = 0x80 >> (var_pos % 8);
1001 if punct[byte] & mask != 0 {
1002 parity ^= 1;
1003 }
1004 } else {
1005 let bit_idx = col * m + var_pos;
1006 let byte = bit_idx / 8;
1007 let mask = 0x80 >> (bit_idx % 8);
1008 if codeword[byte] & mask != 0 {
1009 parity ^= 1;
1010 }
1011 }
1012 }
1013 }
1014 }
1015 if parity != 0 {
1016 return false;
1017 }
1018 }
1019 }
1020 true
1021}
1022
1023fn block_map(
1028 entry: u8,
1029 pos: usize,
1030 m: usize,
1031 theta: &[u8; 26],
1032 phi: &[[u16; 26]; 4],
1033) -> Option<usize> {
1034 let block_type = entry & TYPE_MASK;
1035 match block_type {
1036 _ if block_type == HZ || entry == 0 => None,
1037 _ if block_type == HI => Some(pos),
1038 _ if block_type == HP => {
1039 let k_idx = (entry & INDEX_MASK) as usize;
1040 Some(pi_k(pos, k_idx, m, theta, phi))
1041 }
1042 _ => None,
1043 }
1044}
1045
1046const MAX_EDGES_PER_CHECK: usize = 18;
1050
1051const MAX_ENTRIES: usize = 54;
1053
1054const MAX_C2V: usize = 30720;
1056
1057const MAX_TOTAL_VARS: usize = 10240;
1059
1060fn parity_ok(
1062 code: &LdpcCode,
1063 llr: &[i16],
1064 edges: &[(u8, u8)],
1065 row_start: &[usize; 3],
1066 row_count: &[usize; 3],
1067 m: usize,
1068) -> bool {
1069 let n = code.n;
1070 for row in 0..code.mb {
1071 let rs = row_start[row];
1072 let rc = row_count[row];
1073 for pos in 0..m {
1074 let mut parity = 0u8;
1075 for j in 0..rc {
1076 let (entry, col) = edges[rs + j];
1077 let mapped = block_map(
1078 entry, pos, m, code.theta, code.phi,
1079 )
1080 .unwrap();
1081 let vi = if (col as usize) == code.nb - 1 {
1082 n + mapped
1083 } else {
1084 (col as usize) * m + mapped
1085 };
1086 if llr[vi] < 0 {
1087 parity ^= 1;
1088 }
1089 }
1090 if parity != 0 {
1091 return false;
1092 }
1093 }
1094 }
1095 true
1096}
1097
1098pub fn decode(
1111 code: &LdpcCode,
1112 llr: &mut [i16],
1113 max_iters: usize,
1114) -> Result<usize, LdpcError> {
1115 let m = code.submatrix_size;
1116 let n = code.n;
1117 let total_vars = n + code.punctured;
1118
1119 if llr.len() < total_vars {
1120 return Err(LdpcError::WrongSize {
1121 expected: total_vars,
1122 provided: llr.len(),
1123 });
1124 }
1125
1126 let mut edges = [(0u8, 0u8); MAX_ENTRIES];
1128 let mut row_start = [0usize; 3];
1129 let mut row_count = [0usize; 3];
1130 let mut total_entries = 0usize;
1131
1132 for row in 0..code.mb {
1133 row_start[row] = total_entries;
1134 for layer in 0..3 {
1135 for col in 0..code.nb {
1136 let e = code.h_matrix[layer][row][col];
1137 if e == 0 {
1138 continue;
1139 }
1140 let btype = e & TYPE_MASK;
1141 if btype == HI || btype == HP {
1142 edges[total_entries] = (e, col as u8);
1143 total_entries += 1;
1144 }
1145 }
1146 }
1147 row_count[row] = total_entries - row_start[row];
1148 }
1149
1150 assert!(total_entries * m <= MAX_C2V);
1151
1152 let mut c2v = [0i16; MAX_C2V];
1154
1155 for iter in 0..max_iters {
1156 if parity_ok(
1158 code,
1159 llr,
1160 &edges[..total_entries],
1161 &row_start,
1162 &row_count,
1163 m,
1164 ) {
1165 return Ok(iter);
1166 }
1167
1168 for row in 0..code.mb {
1170 let rs = row_start[row];
1171 let rc = row_count[row];
1172
1173 for pos in 0..m {
1174 let mut v2c = [0i16; MAX_EDGES_PER_CHECK];
1176 let mut vi = [0usize; MAX_EDGES_PER_CHECK];
1177
1178 for j in 0..rc {
1179 let (entry, col) = edges[rs + j];
1180 let mapped = block_map(
1181 entry, pos, m, code.theta, code.phi,
1182 )
1183 .unwrap();
1184 vi[j] = if (col as usize) == code.nb - 1 {
1185 n + mapped
1186 } else {
1187 (col as usize) * m + mapped
1188 };
1189 let ci = (rs + j) * m + pos;
1190 v2c[j] =
1191 llr[vi[j]].saturating_sub(c2v[ci]);
1192 }
1193
1194 let mut sign_bits = 0u32;
1196 let mut min1: u16 = u16::MAX;
1197 let mut min2: u16 = u16::MAX;
1198 let mut min1_j: usize = 0;
1199
1200 for j in 0..rc {
1201 if v2c[j] < 0 {
1202 sign_bits |= 1 << j;
1203 }
1204 let mag = v2c[j].unsigned_abs();
1205 if mag < min1 {
1206 min2 = min1;
1207 min1 = mag;
1208 min1_j = j;
1209 } else if mag < min2 {
1210 min2 = mag;
1211 }
1212 }
1213
1214 let total_sign =
1215 (sign_bits.count_ones() & 1) as u8;
1216
1217 for j in 0..rc {
1219 let mag =
1220 if j == min1_j { min2 } else { min1 };
1221 let scaled =
1223 ((mag as u32 * 3) >> 2) as i16;
1224 let j_sign =
1225 ((sign_bits >> j) & 1) as u8;
1226 let neg = total_sign ^ j_sign;
1227 let new_c2v = if neg != 0 {
1228 -scaled
1229 } else {
1230 scaled
1231 };
1232
1233 let ci = (rs + j) * m + pos;
1234 let old = c2v[ci];
1235 c2v[ci] = new_c2v;
1236 llr[vi[j]] = llr[vi[j]]
1237 .saturating_sub(old)
1238 .saturating_add(new_c2v);
1239 }
1240 }
1241 }
1242 }
1243
1244 if parity_ok(
1246 code,
1247 llr,
1248 &edges[..total_entries],
1249 &row_start,
1250 &row_count,
1251 m,
1252 ) {
1253 Ok(max_iters)
1254 } else {
1255 Err(LdpcError::DecodingFailed)
1256 }
1257}
1258
1259pub fn decode_hard(
1265 code: &LdpcCode,
1266 received: &[u8],
1267 decoded: &mut [u8],
1268 max_iters: usize,
1269) -> Result<usize, LdpcError> {
1270 let n_bytes = code.codeword_bytes();
1271 if received.len() < n_bytes {
1272 return Err(LdpcError::WrongSize {
1273 expected: n_bytes,
1274 provided: received.len(),
1275 });
1276 }
1277 let k_bytes = code.info_bytes();
1278 if decoded.len() < k_bytes {
1279 return Err(LdpcError::WrongSize {
1280 expected: k_bytes,
1281 provided: decoded.len(),
1282 });
1283 }
1284
1285 let total = code.n + code.punctured;
1286 assert!(total <= MAX_TOTAL_VARS);
1287 let mut llr = [0i16; MAX_TOTAL_VARS];
1288 bytes_to_llr(received, &mut llr, code.n);
1289 let iters = decode(code, &mut llr[..total], max_iters)?;
1292 llr_to_bytes(&llr, decoded, code.k);
1293 Ok(iters)
1294}
1295
1296pub fn bytes_to_llr(bytes: &[u8], llr: &mut [i16], n_bits: usize) {
1302 for bit in 0..n_bits {
1303 let byte = bit / 8;
1304 let mask = 0x80 >> (bit % 8);
1305 llr[bit] = if bytes[byte] & mask != 0 { -127 } else { 127 };
1306 }
1307}
1308
1309pub fn llr_to_bytes(llr: &[i16], bytes: &mut [u8], n_bits: usize) {
1313 let n_bytes = (n_bits + 7) / 8;
1314 bytes[..n_bytes].fill(0);
1315 for bit in 0..n_bits {
1316 if llr[bit] < 0 {
1317 bytes[bit / 8] |= 0x80 >> (bit % 8);
1318 }
1319 }
1320}
1321
1322pub struct LdpcFecEncoder {
1324 code: &'static LdpcCode,
1325}
1326
1327impl LdpcFecEncoder {
1328 pub fn new(code: &'static LdpcCode) -> Self {
1330 Self { code }
1331 }
1332}
1333
1334impl crate::coding::FecEncoder for LdpcFecEncoder {
1335 type Error = LdpcError;
1336
1337 fn encode(&self, data: &[u8], output: &mut [u8]) -> Result<usize, Self::Error> {
1338 encode(self.code, data, output)?;
1339 Ok(self.code.codeword_bytes())
1340 }
1341}
1342
1343pub struct LdpcFecDecoder {
1345 code: &'static LdpcCode,
1346 max_iters: usize,
1347}
1348
1349impl LdpcFecDecoder {
1350 pub fn new(code: &'static LdpcCode, max_iters: usize) -> Self {
1352 Self { code, max_iters }
1353 }
1354}
1355
1356impl crate::coding::FecDecoder for LdpcFecDecoder {
1357 type Error = LdpcError;
1358
1359 fn decode(&self, data: &mut [u8]) -> Result<usize, Self::Error> {
1360 let mut decoded = [0u8; 512]; let iters = decode_hard(self.code, data, &mut decoded, self.max_iters)?;
1362 let k_bytes = self.code.info_bytes();
1363 data[..k_bytes].copy_from_slice(&decoded[..k_bytes]);
1364 Ok(iters)
1365 }
1366}
1367
1368#[cfg(test)]
1369mod tests {
1370 use super::*;
1371
1372 #[test]
1373 fn encode_all_zeros_tm2048() {
1374 let code = &CODE_TM2048;
1375 let info = [0u8; 128];
1376 let mut codeword = [0u8; 256];
1377 encode(code, &info, &mut codeword).unwrap();
1378 assert!(codeword.iter().all(|&b| b == 0));
1380 }
1381
1382 #[test]
1383 fn encode_all_zeros_tm1536() {
1384 let code = &CODE_TM1536;
1385 let info = [0u8; 128];
1386 let mut codeword = [0u8; 192];
1387 encode(code, &info, &mut codeword).unwrap();
1388 assert!(codeword.iter().all(|&b| b == 0));
1389 }
1390
1391 #[test]
1392 fn encode_all_zeros_tm1280() {
1393 let code = &CODE_TM1280;
1394 let info = [0u8; 128];
1395 let mut codeword = [0u8; 160];
1396 encode(code, &info, &mut codeword).unwrap();
1397 assert!(codeword.iter().all(|&b| b == 0));
1398 }
1399
1400 #[test]
1401 fn encode_systematic_tm2048() {
1402 let code = &CODE_TM2048;
1403 let mut info = [0u8; 128];
1404 info[0] = 0xA5;
1405 info[1] = 0x3C;
1406 info[127] = 0x01;
1407
1408 let mut codeword = [0u8; 256];
1409 encode(code, &info, &mut codeword).unwrap();
1410
1411 assert_eq!(&codeword[..128], &info[..]);
1413 assert!(codeword[128..].iter().any(|&b| b != 0));
1415 }
1416
1417 #[test]
1418 fn syndrome_check_valid_tm2048() {
1419 let code = &CODE_TM2048;
1420 let mut info = [0u8; 128];
1421 info[5] = 0x42;
1422
1423 let mut codeword = [0u8; 256];
1424 encode(code, &info, &mut codeword).unwrap();
1425
1426 assert!(syndrome_check(code, &codeword));
1427 }
1428
1429 #[test]
1430 fn syndrome_check_detects_error_tm2048() {
1431 let code = &CODE_TM2048;
1432 let mut info = [0u8; 128];
1433 info[5] = 0x42;
1434
1435 let mut codeword = [0u8; 256];
1436 encode(code, &info, &mut codeword).unwrap();
1437
1438 codeword[0] ^= 0x80;
1440 assert!(!syndrome_check(code, &codeword));
1441 }
1442
1443 #[test]
1444 fn syndrome_check_valid_tm1536() {
1445 let code = &CODE_TM1536;
1446 let mut info = [0u8; 128];
1447 info[10] = 0xAB;
1448 let mut codeword = [0u8; 192];
1449 encode(code, &info, &mut codeword).unwrap();
1450 assert!(syndrome_check(code, &codeword));
1451 }
1452
1453 #[test]
1454 fn syndrome_check_valid_tm1280() {
1455 let code = &CODE_TM1280;
1456 let mut info = [0u8; 128];
1457 info[10] = 0xAB;
1458 let mut codeword = [0u8; 160];
1459 encode(code, &info, &mut codeword).unwrap();
1460 assert!(syndrome_check(code, &codeword));
1461 }
1462
1463 #[test]
1464 fn pi_k_permutation_is_bijective() {
1465 let m = 512;
1467 let mut seen = [false; 512];
1468 for i in 0..m {
1469 let j = pi_k(i, 0, m, &THETA_K, &PHI_M512);
1470 assert!(j < m, "pi_k({i}, 0) = {j} >= M={m}");
1471 assert!(!seen[j], "pi_k maps two inputs to {j}");
1472 seen[j] = true;
1473 }
1474 assert!(seen.iter().all(|&s| s));
1475 }
1476
1477 #[test]
1478 fn wrong_size_errors() {
1479 let code = &CODE_TM2048;
1480 let info = [0u8; 64]; let mut output = [0u8; 256];
1482 assert!(matches!(
1483 encode(code, &info, &mut output),
1484 Err(LdpcError::WrongSize { .. })
1485 ));
1486 }
1487
1488 #[test]
1489 fn encode_matches_labrador_tm1280() {
1490 let code = &CODE_TM1280;
1491 let mut info = [0u8; 128];
1492 for i in 0..128 {
1493 info[i] = i as u8;
1494 }
1495 let mut codeword = [0u8; 160];
1496 encode(code, &info, &mut codeword).unwrap();
1497 let expected: [u8; 32] = [
1498 0xF1, 0x68, 0xE0, 0x79, 0x45, 0xE3, 0x08, 0xAE,
1499 0xEF, 0xD1, 0x68, 0x56, 0x60, 0x0A, 0x90, 0xFA,
1500 0xF6, 0x55, 0xA2, 0x01, 0x60, 0x77, 0xF7, 0xE0,
1501 0xFA, 0xB5, 0x49, 0x06, 0xDD, 0x6D, 0xCD, 0x7D,
1502 ];
1503 assert_eq!(&codeword[128..], &expected[..]);
1504 }
1505
1506 #[test]
1507 fn encode_matches_labrador_tm1536() {
1508 let code = &CODE_TM1536;
1509 let mut info = [0u8; 128];
1510 for i in 0..128 {
1511 info[i] = i as u8;
1512 }
1513 let mut codeword = [0u8; 192];
1514 encode(code, &info, &mut codeword).unwrap();
1515 let expected: [u8; 64] = [
1516 0x99, 0x4D, 0x02, 0x17, 0x53, 0x87, 0xC8, 0xDD,
1517 0x42, 0x2E, 0x46, 0x29, 0x06, 0x6A, 0x02, 0x6D,
1518 0xE1, 0xAB, 0xB9, 0xA2, 0xAA, 0xE0, 0xF2, 0xE9,
1519 0xF6, 0xAA, 0xE6, 0xF0, 0x42, 0x1E, 0x52, 0x44,
1520 0x5F, 0x62, 0xD1, 0xA8, 0x8F, 0xB2, 0x01, 0x78,
1521 0xB1, 0xD6, 0x2D, 0x0B, 0xD6, 0xB1, 0x4A, 0x6C,
1522 0x93, 0x26, 0x69, 0xAA, 0xE0, 0x55, 0x1A, 0xD9,
1523 0x9B, 0x94, 0x35, 0x27, 0x3F, 0x30, 0x91, 0x83,
1524 ];
1525 assert_eq!(&codeword[128..], &expected[..]);
1526 }
1527
1528 #[test]
1530 fn encode_matches_labrador_tm2048() {
1531 let code = &CODE_TM2048;
1532 let mut info = [0u8; 128];
1533 for i in 0..128 {
1534 info[i] = i as u8;
1535 }
1536 let mut codeword = [0u8; 256];
1537 encode(code, &info, &mut codeword).unwrap();
1538
1539 let expected_parity: [u8; 128] = [
1540 0xEE, 0xA9, 0xAA, 0xAF, 0x98, 0xD9, 0x16, 0xCE,
1541 0x6C, 0x2B, 0x28, 0x2D, 0x1A, 0x5B, 0x94, 0x4C,
1542 0xA4, 0xF1, 0xB3, 0xD3, 0x1A, 0xEC, 0x58, 0x5A,
1543 0xB3, 0xE6, 0xA4, 0xC4, 0x0D, 0xFB, 0x4F, 0x4D,
1544 0xD8, 0x07, 0xA1, 0xAD, 0x0A, 0xE9, 0x62, 0xC4,
1545 0xD4, 0x0B, 0xAD, 0xA1, 0x06, 0xE5, 0x6E, 0xC8,
1546 0xA6, 0x68, 0x6A, 0xD5, 0xE6, 0xAC, 0x09, 0xBE,
1547 0x3F, 0xF1, 0xF3, 0x4C, 0x7F, 0x35, 0x90, 0x27,
1548 0xF2, 0x64, 0x69, 0x03, 0x83, 0x37, 0x42, 0x91,
1549 0x21, 0xB7, 0xBA, 0xD0, 0x50, 0xE4, 0x91, 0x42,
1550 0xE4, 0x0D, 0x64, 0x19, 0x70, 0x84, 0xA5, 0xB7,
1551 0x86, 0x6F, 0x06, 0x7B, 0x12, 0xE6, 0xC7, 0xD5,
1552 0xAB, 0x10, 0xDB, 0x03, 0x4F, 0xF6, 0x8A, 0xFE,
1553 0x17, 0xAC, 0x67, 0xBF, 0xF3, 0x4A, 0x36, 0x42,
1554 0x04, 0xAE, 0x85, 0xB3, 0xB6, 0x47, 0xCE, 0xC4,
1555 0x0F, 0xA5, 0x8E, 0xB8, 0xBD, 0x4C, 0xC5, 0xCF,
1556 ];
1557 assert_eq!(&codeword[128..], &expected_parity[..]);
1558 }
1559
1560 #[test]
1563 fn decode_valid_codeword() {
1564 let code = &CODE_TM2048;
1567 let mut info = [0u8; 128];
1568 info[5] = 0x42;
1569 let mut codeword = [0u8; 256];
1570 encode(code, &info, &mut codeword).unwrap();
1571
1572 let mut decoded = [0u8; 128];
1573 decode_hard(code, &codeword, &mut decoded, 50).unwrap();
1574 assert_eq!(&decoded[..], &info[..]);
1575 }
1576
1577 #[test]
1578 fn decode_corrects_1_error_tm2048() {
1579 let code = &CODE_TM2048;
1580 let mut info = [0u8; 128];
1581 info[5] = 0x42;
1582 let mut codeword = [0u8; 256];
1583 encode(code, &info, &mut codeword).unwrap();
1584
1585 codeword[0] ^= 0x80; let mut decoded = [0u8; 128];
1588 let iters =
1589 decode_hard(code, &codeword, &mut decoded, 50)
1590 .unwrap();
1591 assert!(iters > 0);
1592 assert_eq!(&decoded[..], &info[..]);
1593 }
1594
1595 #[test]
1596 fn decode_corrects_errors_tm1536() {
1597 let code = &CODE_TM1536;
1598 let mut info = [0u8; 128];
1599 for i in 0..128 {
1600 info[i] = i as u8;
1601 }
1602 let mut codeword = [0u8; 192];
1603 encode(code, &info, &mut codeword).unwrap();
1604
1605 codeword[0] ^= 0x80;
1606 codeword[10] ^= 0x01;
1607
1608 let mut decoded = [0u8; 128];
1609 decode_hard(code, &codeword, &mut decoded, 50).unwrap();
1610 assert_eq!(&decoded[..], &info[..]);
1611 }
1612
1613 #[test]
1614 fn decode_corrects_errors_tm1280() {
1615 let code = &CODE_TM1280;
1616 let mut info = [0u8; 128];
1617 for i in 0..128 {
1618 info[i] = i as u8;
1619 }
1620 let mut codeword = [0u8; 160];
1621 encode(code, &info, &mut codeword).unwrap();
1622
1623 codeword[3] ^= 0x04;
1624
1625 let mut decoded = [0u8; 128];
1626 decode_hard(code, &codeword, &mut decoded, 50).unwrap();
1627 assert_eq!(&decoded[..], &info[..]);
1628 }
1629
1630 #[test]
1631 fn decode_hard_roundtrip_all_rates() {
1632 for code in
1633 [&CODE_TM2048, &CODE_TM1536, &CODE_TM1280]
1634 {
1635 let mut info = [0u8; 128];
1636 for i in 0..128 {
1637 info[i] = (i ^ 0xAA) as u8;
1638 }
1639 let n_bytes = code.codeword_bytes();
1640 let mut codeword = [0u8; 256];
1641 encode(code, &info, &mut codeword[..n_bytes])
1642 .unwrap();
1643
1644 codeword[7] ^= 0x10;
1646
1647 let mut decoded = [0u8; 128];
1648 decode_hard(
1649 code,
1650 &codeword[..n_bytes],
1651 &mut decoded,
1652 50,
1653 )
1654 .unwrap();
1655 assert_eq!(
1656 &decoded[..],
1657 &info[..],
1658 "failed for n={}",
1659 code.n
1660 );
1661 }
1662 }
1663
1664 const K4096_CW: usize = 1024; #[test]
1670 fn encode_all_zeros_k4096() {
1671 for code in
1672 [&CODE_TM8192, &CODE_TM6144, &CODE_TM5120]
1673 {
1674 let info = [0u8; 512];
1675 let nb = code.codeword_bytes();
1676 let mut cw = [0u8; K4096_CW];
1677 encode(code, &info, &mut cw[..nb]).unwrap();
1678 assert!(
1679 cw[..nb].iter().all(|&b| b == 0),
1680 "all-zeros failed for n={}",
1681 code.n
1682 );
1683 }
1684 }
1685
1686 #[test]
1687 fn encode_systematic_k4096() {
1688 for code in
1689 [&CODE_TM8192, &CODE_TM6144, &CODE_TM5120]
1690 {
1691 let mut info = [0u8; 512];
1692 info[0] = 0xA5;
1693 info[511] = 0x01;
1694 let nb = code.codeword_bytes();
1695 let mut cw = [0u8; K4096_CW];
1696 encode(code, &info, &mut cw[..nb]).unwrap();
1697 assert_eq!(&cw[..512], &info[..]);
1698 assert!(cw[512..nb].iter().any(|&b| b != 0));
1699 }
1700 }
1701
1702 #[test]
1703 fn syndrome_check_valid_k4096() {
1704 for code in
1705 [&CODE_TM8192, &CODE_TM6144, &CODE_TM5120]
1706 {
1707 let mut info = [0u8; 512];
1708 for i in 0..512 {
1709 info[i] = (i & 0xFF) as u8;
1710 }
1711 let nb = code.codeword_bytes();
1712 let mut cw = [0u8; K4096_CW];
1713 encode(code, &info, &mut cw[..nb]).unwrap();
1714 assert!(
1715 syndrome_check(code, &cw[..nb]),
1716 "syndrome failed for n={}",
1717 code.n
1718 );
1719 }
1720 }
1721
1722 #[test]
1723 fn decode_corrects_error_tm8192() {
1724 let code = &CODE_TM8192;
1725 let mut info = [0u8; 512];
1726 for i in 0..512 {
1727 info[i] = (i & 0xFF) as u8;
1728 }
1729 let mut cw = [0u8; K4096_CW];
1730 encode(code, &info, &mut cw).unwrap();
1731 cw[0] ^= 0x80;
1732
1733 let total = code.n + code.punctured;
1734 let mut llr = [0i16; 10240];
1735 bytes_to_llr(&cw, &mut llr, code.n);
1736 let iters = decode(code, &mut llr[..total], 50)
1737 .unwrap();
1738 assert!(iters > 0);
1739 let mut decoded = [0u8; 512];
1740 llr_to_bytes(&llr, &mut decoded, code.k);
1741 assert_eq!(&decoded[..], &info[..]);
1742 }
1743
1744 #[test]
1745 fn decode_corrects_error_tm6144() {
1746 let code = &CODE_TM6144;
1747 let mut info = [0u8; 512];
1748 for i in 0..512 {
1749 info[i] = (i & 0xFF) as u8;
1750 }
1751 let nb = code.codeword_bytes();
1752 let mut cw = [0u8; K4096_CW];
1753 encode(code, &info, &mut cw[..nb]).unwrap();
1754 cw[10] ^= 0x01;
1755
1756 let total = code.n + code.punctured;
1757 let mut llr = [0i16; 10240];
1758 bytes_to_llr(&cw[..nb], &mut llr, code.n);
1759 decode(code, &mut llr[..total], 50).unwrap();
1760 let mut decoded = [0u8; 512];
1761 llr_to_bytes(&llr, &mut decoded, code.k);
1762 assert_eq!(&decoded[..], &info[..]);
1763 }
1764
1765 #[test]
1766 fn decode_corrects_error_tm5120() {
1767 let code = &CODE_TM5120;
1768 let mut info = [0u8; 512];
1769 for i in 0..512 {
1770 info[i] = (i & 0xFF) as u8;
1771 }
1772 let nb = code.codeword_bytes();
1773 let mut cw = [0u8; K4096_CW];
1774 encode(code, &info, &mut cw[..nb]).unwrap();
1775 cw[3] ^= 0x04;
1776
1777 let total = code.n + code.punctured;
1778 let mut llr = [0i16; 10240];
1779 bytes_to_llr(&cw[..nb], &mut llr, code.n);
1780 decode(code, &mut llr[..total], 50).unwrap();
1781 let mut decoded = [0u8; 512];
1782 llr_to_bytes(&llr, &mut decoded, code.k);
1783 assert_eq!(&decoded[..], &info[..]);
1784 }
1785}