initializeGaloisField(); } private function initializeGaloisField(): void { $this->gfLog = array_fill(0, 256, 0); $this->gfExp = array_fill(0, 512, 0); $x = 1; for ($i = 0; $i < 255; $i++) { $this->gfExp[$i] = $x; $this->gfLog[$x] = $i; $x <<= 1; if ($x & 0x100) { $x ^= 0x11d; } } for ($i = 255; $i < 512; $i++) { $this->gfExp[$i] = $this->gfExp[$i - 255]; } } private function gfMultiply(int $a, int $b): int { if ($a === 0 || $b === 0) { return 0; } return $this->gfExp[$this->gfLog[$a] + $this->gfLog[$b]]; } /** * Calculate syndromes for the received codeword * For a valid codeword, all syndromes should be zero * * Standard Reed-Solomon: c(x) = c[0] + c[1]*x + c[2]*x^2 + ... + c[n-1]*x^(n-1) * Evaluate at generator roots: S[i] = c(α^i) */ public function calculateSyndromes(array $codeword, int $ecCodewords): array { $syndromes = array_fill(0, $ecCodewords, 0); // Evaluate at generator roots (α^0, α^1, ..., α^(t-1)) for ($i = 0; $i < $ecCodewords; $i++) { $syndrome = 0; $alphaPower = $this->gfExp[$i]; // α^i // Evaluate polynomial at α^i: sum(codeword[j] * (α^i)^j) $power = 1; // (α^i)^0 = 1 for ($j = 0; $j < count($codeword); $j++) { $syndrome ^= $this->gfMultiply($codeword[$j], $power); $power = $this->gfMultiply($power, $alphaPower); } $syndromes[$i] = $syndrome; } return $syndromes; } /** * Check if codeword is valid (all syndromes are zero) */ public function isValid(array $codeword, int $ecCodewords): bool { $syndromes = $this->calculateSyndromes($codeword, $ecCodewords); foreach ($syndromes as $syndrome) { if ($syndrome !== 0) { return false; } } return true; } } // Test with our QR code data echo "Test with QR Code Data:\n\n"; $dataCodewords = [64, 180, 132, 84, 196, 196, 242, 5, 116, 245, 36, 196, 64, 236, 17, 236]; $rs = new ReedSolomonEncoder(); $ecCodewords = $rs->encode($dataCodewords, 10); echo "Data codewords (16): " . implode(', ', $dataCodewords) . "\n"; echo "EC codewords (10): " . implode(', ', $ecCodewords) . "\n\n"; // Create full codeword $fullCodeword = array_merge($dataCodewords, $ecCodewords); echo "Full codeword (26): " . implode(', ', $fullCodeword) . "\n\n"; // Decode and verify $decoder = new SimpleRSDecoder(); $syndromes = $decoder->calculateSyndromes($fullCodeword, 10); echo "Syndromes (should all be 0 for valid codeword):\n"; $allZero = true; for ($i = 0; $i < count($syndromes); $i++) { $status = $syndromes[$i] === 0 ? '✅' : '❌'; if ($syndromes[$i] !== 0) { $allZero = false; } echo " S[{$i}] = {$syndromes[$i]} {$status}\n"; } echo "\n"; if ($allZero) { echo "✅ All syndromes are zero - Reed-Solomon codeword is VALID!\n"; echo "\nThis means the EC codewords are correct.\n"; echo "If the QR code still doesn't scan, the issue is NOT in Reed-Solomon.\n"; } else { echo "❌ Some syndromes are non-zero - Reed-Solomon codeword is INVALID!\n"; echo "\nThis means the EC codewords are incorrect.\n"; echo "The Reed-Solomon implementation has a bug.\n"; } // Test with corrupted data echo "\n=== Test with Corrupted Data ===\n"; $corruptedCodeword = $fullCodeword; $corruptedCodeword[0] ^= 1; // Flip one bit $corruptedSyndromes = $decoder->calculateSyndromes($corruptedCodeword, 10); echo "Corrupted codeword (bit 0 flipped):\n"; $corruptedAllZero = true; for ($i = 0; $i < count($corruptedSyndromes); $i++) { if ($corruptedSyndromes[$i] !== 0) { $corruptedAllZero = false; } echo " S[{$i}] = {$corruptedSyndromes[$i]}\n"; } if ($corruptedAllZero) { echo "❌ Corrupted codeword appears valid (decoder bug)\n"; } else { echo "✅ Corrupted codeword correctly detected as invalid\n"; }