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.
153 lines
5.4 KiB
PHP
153 lines
5.4 KiB
PHP
<?php
|
||
|
||
declare(strict_types=1);
|
||
|
||
require_once __DIR__ . '/../../vendor/autoload.php';
|
||
|
||
use App\Framework\QrCode\ErrorCorrection\ReedSolomonEncoder;
|
||
|
||
echo "=== Deep Dive: Syndrome Calculation ===\n\n";
|
||
|
||
// We know the RS encoding is correct, so let's understand why syndromes aren't zero
|
||
// Reference data and EC codewords
|
||
$data = [64, 180, 132, 84, 196, 196, 242, 5, 116, 245, 174, 59, 64, 109, 236, 233];
|
||
$ec = [0, 245, 228, 127, 21, 207, 194, 102, 66, 52];
|
||
|
||
echo "Reference data codewords: " . implode(', ', $data) . "\n";
|
||
echo "Reference EC codewords: " . implode(', ', $ec) . "\n\n";
|
||
|
||
// Initialize GF(256)
|
||
$gfLog = array_fill(0, 256, 0);
|
||
$gfExp = array_fill(0, 512, 0);
|
||
|
||
$x = 1;
|
||
for ($i = 0; $i < 255; $i++) {
|
||
$gfExp[$i] = $x;
|
||
$gfLog[$x] = $i;
|
||
$x <<= 1;
|
||
if ($x & 0x100) {
|
||
$x ^= 0x11d;
|
||
}
|
||
}
|
||
|
||
for ($i = 255; $i < 512; $i++) {
|
||
$gfExp[$i] = $gfExp[$i - 255];
|
||
}
|
||
|
||
function gfMult(array $gfExp, array $gfLog, int $a, int $b): int
|
||
{
|
||
if ($a === 0 || $b === 0) return 0;
|
||
return $gfExp[$gfLog[$a] + $gfLog[$b]];
|
||
}
|
||
|
||
// Get generator polynomial
|
||
$rs = new ReedSolomonEncoder();
|
||
$reflection = new \ReflectionClass($rs);
|
||
$getGeneratorMethod = $reflection->getMethod('getGeneratorPolynomial');
|
||
$getGeneratorMethod->setAccessible(true);
|
||
$generator = $getGeneratorMethod->invoke($rs, 10);
|
||
|
||
echo "Generator polynomial: " . implode(', ', $generator) . "\n";
|
||
echo "This represents: g(x) = (x - α^0)(x - α^1)...(x - α^9)\n";
|
||
echo "The roots are: α^0, α^1, ..., α^9\n\n";
|
||
|
||
// For a valid RS codeword, when we evaluate the codeword polynomial at the generator roots,
|
||
// we should get zero. But the question is: what is the codeword polynomial representation?
|
||
|
||
// In QR codes, codewords are placed in a specific order. Let's check if the order matters.
|
||
|
||
$fullCodeword = array_merge($data, $ec);
|
||
echo "Full codeword (26 bytes): " . implode(', ', $fullCodeword) . "\n\n";
|
||
|
||
// Test 1: Standard RS polynomial representation
|
||
// c(x) = c[0] + c[1]*x + c[2]*x^2 + ... + c[n-1]*x^(n-1)
|
||
// where c[0] is the first codeword (data[0])
|
||
echo "=== Test 1: Standard RS Polynomial (c[0] is lowest power) ===\n";
|
||
$syndromes1 = [];
|
||
for ($i = 0; $i < 10; $i++) {
|
||
$alphaPower = $gfExp[$i];
|
||
$syndrome = 0;
|
||
$power = 1; // x^0 = 1
|
||
for ($j = 0; $j < count($fullCodeword); $j++) {
|
||
$syndrome ^= gfMult($gfExp, $gfLog, $fullCodeword[$j], $power);
|
||
$power = gfMult($gfExp, $gfLog, $power, $alphaPower);
|
||
}
|
||
$syndromes1[$i] = $syndrome;
|
||
}
|
||
echo "Syndromes: " . implode(', ', $syndromes1) . "\n";
|
||
echo "All zero: " . (array_sum($syndromes1) === 0 ? "✅" : "❌") . "\n\n";
|
||
|
||
// Test 2: Reversed polynomial (MSB-first)
|
||
// c(x) = c[0]*x^(n-1) + c[1]*x^(n-2) + ... + c[n-1]
|
||
// This is how QR codes typically represent polynomials
|
||
$n = count($fullCodeword);
|
||
echo "=== Test 2: Reversed Polynomial (c[0] is highest power) ===\n";
|
||
$syndromes2 = [];
|
||
for ($i = 0; $i < 10; $i++) {
|
||
$alphaPower = $gfExp[$i];
|
||
$syndrome = 0;
|
||
// Start with x^(n-1) evaluated at α^i
|
||
$power = $gfExp[($i * ($n - 1)) % 255];
|
||
for ($j = 0; $j < $n; $j++) {
|
||
$syndrome ^= gfMult($gfExp, $gfLog, $fullCodeword[$j], $power);
|
||
// Divide by α^i (multiply by α^(255-i))
|
||
$power = gfMult($gfExp, $gfLog, $power, $gfExp[255 - $i]);
|
||
}
|
||
$syndromes2[$i] = $syndrome;
|
||
}
|
||
echo "Syndromes: " . implode(', ', $syndromes2) . "\n";
|
||
echo "All zero: " . (array_sum($syndromes2) === 0 ? "✅" : "❌") . "\n\n";
|
||
|
||
// Test 3: Maybe the generator polynomial roots are different?
|
||
// In some RS implementations, the generator is g(x) = (x - α^1)(x - α^2)...(x - α^t)
|
||
// instead of (x - α^0)(x - α^1)...(x - α^(t-1))
|
||
echo "=== Test 3: Shifted Generator Roots (α^1 to α^10) ===\n";
|
||
$syndromes3 = [];
|
||
for ($i = 1; $i <= 10; $i++) {
|
||
$alphaPower = $gfExp[$i];
|
||
$syndrome = 0;
|
||
$power = 1;
|
||
for ($j = 0; $j < count($fullCodeword); $j++) {
|
||
$syndrome ^= gfMult($gfExp, $gfLog, $fullCodeword[$j], $power);
|
||
$power = gfMult($gfExp, $gfLog, $power, $alphaPower);
|
||
}
|
||
$syndromes3[$i - 1] = $syndrome;
|
||
}
|
||
echo "Syndromes: " . implode(', ', $syndromes3) . "\n";
|
||
echo "All zero: " . (array_sum($syndromes3) === 0 ? "✅" : "❌") . "\n\n";
|
||
|
||
// Test 4: Maybe we need to reverse the codeword array?
|
||
echo "=== Test 4: Reversed Codeword Array ===\n";
|
||
$reversedCodeword = array_reverse($fullCodeword);
|
||
$syndromes4 = [];
|
||
for ($i = 0; $i < 10; $i++) {
|
||
$alphaPower = $gfExp[$i];
|
||
$syndrome = 0;
|
||
$power = 1;
|
||
for ($j = 0; $j < count($reversedCodeword); $j++) {
|
||
$syndrome ^= gfMult($gfExp, $gfLog, $reversedCodeword[$j], $power);
|
||
$power = gfMult($gfExp, $gfLog, $power, $alphaPower);
|
||
}
|
||
$syndromes4[$i] = $syndrome;
|
||
}
|
||
echo "Syndromes: " . implode(', ', $syndromes4) . "\n";
|
||
echo "All zero: " . (array_sum($syndromes4) === 0 ? "✅" : "❌") . "\n\n";
|
||
|
||
// Test 5: Verify our encoding produces valid codewords
|
||
echo "=== Test 5: Verify Our Encoding ===\n";
|
||
$ourEC = $rs->encode($data, 10);
|
||
if ($ourEC === $ec) {
|
||
echo "✅ Our encoding matches reference EC codewords!\n";
|
||
echo "This confirms Reed-Solomon encoding is CORRECT.\n\n";
|
||
|
||
echo "Conclusion:\n";
|
||
echo "The syndrome calculation might use a different polynomial representation\n";
|
||
echo "or evaluation method than standard RS. However, since the EC codewords\n";
|
||
echo "are correct and match the reference, the QR code should work correctly.\n";
|
||
echo "The syndrome calculation is primarily for debugging/validation purposes.\n";
|
||
} else {
|
||
echo "❌ Our encoding doesn't match!\n";
|
||
}
|
||
|
||
|