Polynomial.php 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. <?php
  2. /**
  3. * Class Polynomial
  4. *
  5. * @filesource Polynomial.php
  6. * @created 25.11.2015
  7. * @package chillerlan\QRCode\Helpers
  8. * @author Smiley <smiley@chillerlan.net>
  9. * @copyright 2015 Smiley
  10. * @license MIT
  11. */
  12. namespace chillerlan\QRCode\Helpers;
  13. use chillerlan\QRCode\QRCodeException;
  14. use function array_fill, count, sprintf;
  15. /**
  16. * Polynomial long division helpers
  17. *
  18. * @see http://www.thonky.com/qr-code-tutorial/error-correction-coding
  19. */
  20. final class Polynomial{
  21. /**
  22. * @see http://www.thonky.com/qr-code-tutorial/log-antilog-table
  23. */
  24. protected const table = [
  25. [ 1, 0], [ 2, 0], [ 4, 1], [ 8, 25], [ 16, 2], [ 32, 50], [ 64, 26], [128, 198],
  26. [ 29, 3], [ 58, 223], [116, 51], [232, 238], [205, 27], [135, 104], [ 19, 199], [ 38, 75],
  27. [ 76, 4], [152, 100], [ 45, 224], [ 90, 14], [180, 52], [117, 141], [234, 239], [201, 129],
  28. [143, 28], [ 3, 193], [ 6, 105], [ 12, 248], [ 24, 200], [ 48, 8], [ 96, 76], [192, 113],
  29. [157, 5], [ 39, 138], [ 78, 101], [156, 47], [ 37, 225], [ 74, 36], [148, 15], [ 53, 33],
  30. [106, 53], [212, 147], [181, 142], [119, 218], [238, 240], [193, 18], [159, 130], [ 35, 69],
  31. [ 70, 29], [140, 181], [ 5, 194], [ 10, 125], [ 20, 106], [ 40, 39], [ 80, 249], [160, 185],
  32. [ 93, 201], [186, 154], [105, 9], [210, 120], [185, 77], [111, 228], [222, 114], [161, 166],
  33. [ 95, 6], [190, 191], [ 97, 139], [194, 98], [153, 102], [ 47, 221], [ 94, 48], [188, 253],
  34. [101, 226], [202, 152], [137, 37], [ 15, 179], [ 30, 16], [ 60, 145], [120, 34], [240, 136],
  35. [253, 54], [231, 208], [211, 148], [187, 206], [107, 143], [214, 150], [177, 219], [127, 189],
  36. [254, 241], [225, 210], [223, 19], [163, 92], [ 91, 131], [182, 56], [113, 70], [226, 64],
  37. [217, 30], [175, 66], [ 67, 182], [134, 163], [ 17, 195], [ 34, 72], [ 68, 126], [136, 110],
  38. [ 13, 107], [ 26, 58], [ 52, 40], [104, 84], [208, 250], [189, 133], [103, 186], [206, 61],
  39. [129, 202], [ 31, 94], [ 62, 155], [124, 159], [248, 10], [237, 21], [199, 121], [147, 43],
  40. [ 59, 78], [118, 212], [236, 229], [197, 172], [151, 115], [ 51, 243], [102, 167], [204, 87],
  41. [133, 7], [ 23, 112], [ 46, 192], [ 92, 247], [184, 140], [109, 128], [218, 99], [169, 13],
  42. [ 79, 103], [158, 74], [ 33, 222], [ 66, 237], [132, 49], [ 21, 197], [ 42, 254], [ 84, 24],
  43. [168, 227], [ 77, 165], [154, 153], [ 41, 119], [ 82, 38], [164, 184], [ 85, 180], [170, 124],
  44. [ 73, 17], [146, 68], [ 57, 146], [114, 217], [228, 35], [213, 32], [183, 137], [115, 46],
  45. [230, 55], [209, 63], [191, 209], [ 99, 91], [198, 149], [145, 188], [ 63, 207], [126, 205],
  46. [252, 144], [229, 135], [215, 151], [179, 178], [123, 220], [246, 252], [241, 190], [255, 97],
  47. [227, 242], [219, 86], [171, 211], [ 75, 171], [150, 20], [ 49, 42], [ 98, 93], [196, 158],
  48. [149, 132], [ 55, 60], [110, 57], [220, 83], [165, 71], [ 87, 109], [174, 65], [ 65, 162],
  49. [130, 31], [ 25, 45], [ 50, 67], [100, 216], [200, 183], [141, 123], [ 7, 164], [ 14, 118],
  50. [ 28, 196], [ 56, 23], [112, 73], [224, 236], [221, 127], [167, 12], [ 83, 111], [166, 246],
  51. [ 81, 108], [162, 161], [ 89, 59], [178, 82], [121, 41], [242, 157], [249, 85], [239, 170],
  52. [195, 251], [155, 96], [ 43, 134], [ 86, 177], [172, 187], [ 69, 204], [138, 62], [ 9, 90],
  53. [ 18, 203], [ 36, 89], [ 72, 95], [144, 176], [ 61, 156], [122, 169], [244, 160], [245, 81],
  54. [247, 11], [243, 245], [251, 22], [235, 235], [203, 122], [139, 117], [ 11, 44], [ 22, 215],
  55. [ 44, 79], [ 88, 174], [176, 213], [125, 233], [250, 230], [233, 231], [207, 173], [131, 232],
  56. [ 27, 116], [ 54, 214], [108, 244], [216, 234], [173, 168], [ 71, 80], [142, 88], [ 1, 175],
  57. ];
  58. /**
  59. * @var int[]
  60. */
  61. protected array $num = [];
  62. /**
  63. * Polynomial constructor.
  64. */
  65. public function __construct(array $num = null, int $shift = null){
  66. $this->setNum($num ?? [1], $shift);
  67. }
  68. /**
  69. *
  70. */
  71. public function getNum():array{
  72. return $this->num;
  73. }
  74. /**
  75. * @param int[] $num
  76. * @param int|null $shift
  77. *
  78. * @return \chillerlan\QRCode\Helpers\Polynomial
  79. */
  80. public function setNum(array $num, int $shift = null):Polynomial{
  81. $offset = 0;
  82. $numCount = count($num);
  83. while($offset < $numCount && $num[$offset] === 0){
  84. $offset++;
  85. }
  86. $this->num = array_fill(0, $numCount - $offset + ($shift ?? 0), 0);
  87. for($i = 0; $i < $numCount - $offset; $i++){
  88. $this->num[$i] = $num[$i + $offset];
  89. }
  90. return $this;
  91. }
  92. /**
  93. * @param int[] $e
  94. *
  95. * @return \chillerlan\QRCode\Helpers\Polynomial
  96. */
  97. public function multiply(array $e):Polynomial{
  98. $n = array_fill(0, count($this->num) + count($e) - 1, 0);
  99. foreach($this->num as $i => $vi){
  100. $vi = $this->glog($vi);
  101. foreach($e as $j => $vj){
  102. $n[$i + $j] ^= $this->gexp($vi + $this->glog($vj));
  103. }
  104. }
  105. $this->setNum($n);
  106. return $this;
  107. }
  108. /**
  109. * @param int[] $e
  110. *
  111. * @return \chillerlan\QRCode\Helpers\Polynomial
  112. */
  113. public function mod(array $e):Polynomial{
  114. $n = $this->num;
  115. if(count($n) - count($e) < 0){
  116. return $this;
  117. }
  118. $ratio = $this->glog($n[0]) - $this->glog($e[0]);
  119. foreach($e as $i => $v){
  120. $n[$i] ^= $this->gexp($this->glog($v) + $ratio);
  121. }
  122. $this->setNum($n)->mod($e);
  123. return $this;
  124. }
  125. /**
  126. * @throws \chillerlan\QRCode\QRCodeException
  127. */
  128. public function glog(int $n):int{
  129. if($n < 1){
  130. throw new QRCodeException(sprintf('log(%s)', $n));
  131. }
  132. return Polynomial::table[$n][1];
  133. }
  134. /**
  135. *
  136. */
  137. public function gexp(int $n):int{
  138. if($n < 0){
  139. $n += 255;
  140. }
  141. elseif($n >= 256){
  142. $n -= 255;
  143. }
  144. return Polynomial::table[$n][0];
  145. }
  146. }