Remove WireGuard integration from production deployment to simplify infrastructure: - Remove docker-compose-direct-access.yml (VPN-bound services) - Remove VPN-only middlewares from Grafana, Prometheus, Portainer - Remove WireGuard middleware definitions from Traefik - Remove WireGuard IPs (10.8.0.0/24) from Traefik forwarded headers All monitoring services now publicly accessible via subdomains: - grafana.michaelschiemer.de (with Grafana native auth) - prometheus.michaelschiemer.de (with Basic Auth) - portainer.michaelschiemer.de (with Portainer native auth) All services use Let's Encrypt SSL certificates via Traefik.
159 lines
4.5 KiB
PHP
159 lines
4.5 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||
|
||
use App\Framework\QrCode\ErrorCorrection\ReedSolomonEncoder;
|
||
|
||
echo "=== Reed-Solomon Decoder Test ===\n\n";
|
||
|
||
// Simple Reed-Solomon decoder for verification
|
||
// This implements a basic syndrome calculation
|
||
|
||
class SimpleRSDecoder
|
||
{
|
||
private array $gfLog;
|
||
private array $gfExp;
|
||
|
||
public function __construct()
|
||
{
|
||
$this->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";
|
||
}
|
||
|