@@ -30,6 +30,33 @@ const int8_t CHARSET_REV[128] = {
30
30
1 , 0 , 3 , 16 , 11 , 28 , 12 , 14 , 6 , 4 , 2 , -1 , -1 , -1 , -1 , -1
31
31
};
32
32
33
+ // We work with the finite field GF(1024) defined as a degree 2 extension of the base field GF(32)
34
+ // The defining polynomial of the extension is x^2 + 9x + 23
35
+ // Let (e) be a primitive element of GF(1024), that is, a generator of the field.
36
+ // Every non-zero element of the field can then be represented as (e)^k for some power k.
37
+ // The array GF1024_EXP contains all these powers of (e) - GF1024_EXP[k] = (e)^k in GF(1024).
38
+ // Conversely, GF1024_LOG contains the discrete logarithms of these powers, so
39
+ // GF1024_LOG[GF1024_EXP[k]] == k
40
+ // Each element v of GF(1024) is encoded as a 10 bit integer in the following way:
41
+ // v = v1 || v0 where v0, v1 are 5-bit integers (elements of GF(32)).
42
+ //
43
+ // The element (e) is encoded as 9 || 15. Given (v), we compute (e)*(v) by multiplying in the following way:
44
+ // v0' = 27*v1 + 15*v0
45
+ // v1' = 6*v1 + 9*v0
46
+ // e*v = v1' || v0'
47
+ //
48
+ // The following sage code can be used to reproduce both _EXP and _LOG arrays
49
+ // GF1024_LOG = [-1] + [0] * 1023
50
+ // GF1024_EXP = [1] * 1024
51
+ // v = 1
52
+ // for i in range(1, 1023):
53
+ // v0 = v & 31
54
+ // v1 = v >> 5
55
+ // v0n = F.fetch_int(27)*F.fetch_int(v1) + F.fetch_int(15)*F.fetch_int(v0)
56
+ // v1n = F.fetch_int(6)*F.fetch_int(v1) + F.fetch_int(9)*F.fetch_int(v0)
57
+ // v = v1n.integer_representation() << 5 | v0n.integer_representation()
58
+ // GF1024_EXP[i] = v
59
+ // GF1024_LOG[v] = i
33
60
34
61
const int16_t GF1024_EXP[] = {
35
62
1 , 303 , 635 , 446 , 997 , 640 , 121 , 142 , 959 , 420 , 350 , 438 , 166 , 39 , 543 ,
@@ -103,6 +130,7 @@ const int16_t GF1024_EXP[] = {
103
130
433 , 610 , 116 , 855 , 180 , 479 , 910 , 1014 , 599 , 915 , 905 , 306 , 516 , 731 ,
104
131
626 , 978 , 825 , 344 , 605 , 654 , 209
105
132
};
133
+ // As above, GF1024_EXP contains all elements of GF(1024) except 0
106
134
static_assert (std::size(GF1024_EXP) == 1023 , " GF1024_EXP length should be 1023" );
107
135
108
136
const int16_t GF1024_LOG[] = {
@@ -276,8 +304,51 @@ uint32_t PolyMod(const data& v)
276
304
return c;
277
305
}
278
306
307
+ /* * Syndrome computes the values s_j = R(e^j) for j in [997, 998, 999]. As described above, the
308
+ * generator polynomial G is the LCM of the minimal polynomials of (e)^997, (e)^998, and (e)^999.
309
+ *
310
+ * Consider a codeword with errors, of the form R(x) = C(x) + E(x). The residue is the bit-packed
311
+ * result of computing R(x) mod G(X), where G is the generator of the code. Because C(x) is a valid
312
+ * codeword, it is a multiple of G(X), so the residue is in fact just E(x) mod G(x). Note that all
313
+ * of the (e)^j are roots of G(x) by definition, so R((e)^j) = E((e)^j).
314
+ *
315
+ * Syndrome returns the three values packed into a 30-bit integer, where each 10 bits is one value.
316
+ */
279
317
uint32_t Syndrome (const uint32_t residue) {
318
+ // Let R(x) = r1*x^5 + r2*x^4 + r3*x^3 + r4*x^2 + r5*x + r6
319
+ // low is the first 5 bits, corresponding to the r6 in the residue
320
+ // (the constant term of the polynomial).
321
+
280
322
uint32_t low = residue & 0x1f ;
323
+
324
+ // Recall that XOR corresponds to addition in a characteristic 2 field.
325
+ //
326
+ // To compute R((e)^j), we are really computing:
327
+ // r1*(e)^(j*5) + r2*(e)^(j*4) + r3*(e)^(j*3) + r4*(e)^(j*2) + r5*(e)^j + r6
328
+ // Now note that all of the (e)^(j*i) for i in [5..0] are constants and can be precomputed
329
+ // for efficiency. But even more than that, we can consider each coefficient as a bit-string.
330
+ // For example, take r5 = (b_5, b_4, b_3, b_2, b_1) written out as 5 bits. Then:
331
+ // r5*(e)^j = b_1*(e)^j + b_2*(2*(e)^j) + b_3*(4*(e)^j) + b_4*(8*(e)^j) + b_5*(16*(e)^j)
332
+ // where all the (2^i*(e)^j) are constants and can be precomputed. Then we just add each
333
+ // of these corresponding constants to our final value based on the bit values b_i.
334
+ // This is exactly what is done below. Note that all three values of s_j for j in (997, 998,
335
+ // 999) are computed simultaneously.
336
+ //
337
+ // We begin by setting s_j = low = r6 for all three values of j, because these are unconditional.
338
+ // Then for each following bit, we add the corresponding precomputed constant if the bit is 1.
339
+ // For example, 0x31edd3c4 is 1100011110 1101110100 1111000100 when unpacked in groups of 10
340
+ // bits, corresponding exactly to a^999 || a^998 || a^997 (matching the corresponding values in
341
+ // GF1024_EXP above).
342
+ //
343
+ // The following sage code reproduces these constants:
344
+ // for k in range(1, 6):
345
+ // for b in [1,2,4,8,16]:
346
+ // c0 = GF1024_EXP[(997*k + GF1024_LOG[b]) % 1023]
347
+ // c1 = GF1024_EXP[(998*k + GF1024_LOG[b]) % 1023]
348
+ // c2 = GF1024_EXP[(999*k + GF1024_LOG[b]) % 1023]
349
+ // c = c2 << 20 | c1 << 10 | c0
350
+ // print("0x%x" % c)
351
+
281
352
return low ^ (low << 10 ) ^ (low << 20 ) ^
282
353
((residue >> 5 ) & 1 ? 0x31edd3c4 : 0 ) ^
283
354
((residue >> 6 ) & 1 ? 0x335f86a8 : 0 ) ^
@@ -469,44 +540,104 @@ std::string LocateErrors(const std::string& str, std::vector<int>& error_locatio
469
540
// We can't simply use the segwit version, because that may be one of the errors
470
541
for (Encoding encoding : {Encoding::BECH32, Encoding::BECH32M}) {
471
542
std::vector<int > possible_errors;
543
+ // Recall that (ExpandHRP(hrp) ++ values) is interpreted as a list of coefficients of a polynomial
544
+ // over GF(32). PolyMod computes the "remainder" of this polynomial modulo the generator G(x).
472
545
uint32_t residue = PolyMod (Cat (ExpandHRP (hrp), values)) ^ EncodingConstant (encoding);
546
+
547
+ // All valid codewords should be multiples of G(x), so this remainder (after XORing with the encoding
548
+ // constant) should be 0 - hence 0 indicates there are no errors present.
473
549
if (residue != 0 ) {
550
+ // If errors are present, our polynomial must be of the form C(x) + E(x) where C is the valid
551
+ // codeword (a multiple of G(x)), and E encodes the errors.
474
552
uint32_t syn = Syndrome (residue);
553
+
554
+ // Unpack the three 10-bit syndrome values
475
555
int s0 = syn & 0x3FF ;
476
556
int s1 = (syn >> 10 ) & 0x3FF ;
477
557
int s2 = syn >> 20 ;
558
+
559
+ // Get the discrete logs of these values in GF1024 for more efficient computation
478
560
int l_s0 = GF1024_LOG[s0];
479
561
int l_s1 = GF1024_LOG[s1];
480
562
int l_s2 = GF1024_LOG[s2];
481
563
564
+ // First, suppose there is only a single error. Then E(x) = e1*x^p1 for some position p1
565
+ // Then s0 = E((e)^997) = e1*(e)^(997*p1) and s1 = E((e)^998) = e1*(e)^(998*p1)
566
+ // Therefore s1/s0 = (e)^p1, and by the same logic, s2/s1 = (e)^p1 too.
567
+ // Hence, s1^2 == s0*s2, which is exactly the condition we check first:
482
568
if (l_s0 != -1 && l_s1 != -1 && l_s2 != -1 && (2 * l_s1 - l_s2 - l_s0 + 2046 ) % 1023 == 0 ) {
483
- size_t p1 = (l_s1 - l_s0 + 1023 ) % 1023 ;
569
+ // Compute the error position p1 as l_s1 - l_s0 = p1 (mod 1023)
570
+ size_t p1 = (l_s1 - l_s0 + 1023 ) % 1023 ; // the +1023 ensures it is positive
571
+ // Now because s0 = e1*(e)^(997*p1), we get e1 = s0/((e)^(997*p1)). Remember that (e)^1023 = 1,
572
+ // so 1/((e)^997) = (e)^(1023-997).
484
573
int l_e1 = l_s0 + (1023 - 997 ) * p1;
574
+ // Finally, some sanity checks on the result:
575
+ // - The error position should be within the length of the data
576
+ // - e1 should be in GF(32), which implies that e1 = (e)^(33k) for some k (the 31 non-zero elements
577
+ // of GF(32) form an index 33 subgroup of the 1023 non-zero elements of GF(1024)).
485
578
if (p1 < length && !(l_e1 % 33 )) {
579
+ // Polynomials run from highest power to lowest, so the index p1 is from the right.
580
+ // We don't return e1 because it is dangerous to suggest corrections to the user,
581
+ // the user should check the address themselves.
486
582
possible_errors.push_back (str.size () - p1 - 1 );
487
583
}
584
+ // Otherwise, suppose there are two errors. Then E(x) = e1*x^p1 + e2*x^p2.
488
585
} else {
586
+ // For all possible first error positions p1
489
587
for (size_t p1 = 0 ; p1 < length; ++p1) {
588
+ // We have guessed p1, and want to solve for p2. Recall that E(x) = e1*x^p1 + e2*x^p2, so
589
+ // s0 = E((e)^997) = e1*(e)^(997^p1) + e2*(e)^(997*p2), and similar for s1 and s2.
590
+ //
591
+ // Consider s2 + s1*(e)^p1
592
+ // = 2e1*(e)^(999^p1) + e2*(e)^(999*p2) + e2*(e)^(998*p2)*(e)^p1
593
+ // = e2*(e)^(999*p2) + e2*(e)^(998*p2)*(e)^p1
594
+ // (Because we are working in characteristic 2.)
595
+ // = e2*(e)^(998*p2) ((e)^p2 + (e)^p1)
596
+ //
490
597
int s2_s1p1 = s2 ^ (s1 == 0 ? 0 : GF1024_EXP[(l_s1 + p1) % 1023 ]);
491
598
if (s2_s1p1 == 0 ) continue ;
599
+ int l_s2_s1p1 = GF1024_LOG[s2_s1p1];
492
600
601
+ // Similarly, s1 + s0*(e)^p1
602
+ // = e2*(e)^(997*p2) ((e)^p2 + (e)^p1)
493
603
int s1_s0p1 = s1 ^ (s0 == 0 ? 0 : GF1024_EXP[(l_s0 + p1) % 1023 ]);
494
604
if (s1_s0p1 == 0 ) continue ;
495
-
496
605
int l_s1_s0p1 = GF1024_LOG[s1_s0p1];
497
- size_t p2 = (GF1024_LOG[s2_s1p1] - l_s1_s0p1 + 1023 ) % 1023 ;
606
+
607
+ // So, putting these together, we can compute the second error position as
608
+ // (e)^p2 = (s2 + s1^p1)/(s1 + s0^p1)
609
+ // p2 = log((e)^p2)
610
+ size_t p2 = (l_s2_s1p1 - l_s1_s0p1 + 1023 ) % 1023 ;
611
+
612
+ // Sanity checks that p2 is a valid position and not the same as p1
498
613
if (p2 >= length || p1 == p2) continue ;
499
614
615
+ // Now we want to compute the error values e1 and e2.
616
+ // Similar to above, we compute s1 + s0*(e)^p2
617
+ // = e1*(e)^(997*p1) ((e)^p1 + (e)^p2)
500
618
int s1_s0p2 = s1 ^ (s0 == 0 ? 0 : GF1024_EXP[(l_s0 + p2) % 1023 ]);
501
619
if (s1_s0p2 == 0 ) continue ;
620
+ int l_s1_s0p2 = GF1024_LOG[s1_s0p2];
502
621
622
+ // And compute (the log of) 1/((e)^p1 + (e)^p2))
503
623
int inv_p1_p2 = 1023 - GF1024_LOG[GF1024_EXP[p1] ^ GF1024_EXP[p2]];
624
+
625
+ // Then (s1 + s0*(e)^p1) * (1/((e)^p1 + (e)^p2)))
626
+ // = e2*(e)^(997*p2)
627
+ // Then recover e2 by dividing by (e)^(997*p2)
504
628
int l_e2 = l_s1_s0p1 + inv_p1_p2 + (1023 - 997 ) * p2;
629
+ // Check that e2 is in GF(32)
505
630
if (l_e2 % 33 ) continue ;
506
631
507
- int l_e1 = GF1024_LOG[s1_s0p2] + inv_p1_p2 + (1023 - 997 ) * p1;
632
+ // In the same way, (s1 + s0*(e)^p2) * (1/((e)^p1 + (e)^p2)))
633
+ // = e1*(e)^(997*p1)
634
+ // So recover e1 by dividing by (e)^(997*p1)
635
+ int l_e1 = l_s1_s0p2 + inv_p1_p2 + (1023 - 997 ) * p1;
636
+ // Check that e1 is in GF(32)
508
637
if (l_e1 % 33 ) continue ;
509
638
639
+ // Again, we do not return e1 or e2 for safety.
640
+ // Order the error positions from the left of the string and return them
510
641
if (p1 > p2) {
511
642
possible_errors.push_back (str.size () - p1 - 1 );
512
643
possible_errors.push_back (str.size () - p2 - 1 );
0 commit comments