getMethod('getGeneratorPolynomial'); $getGeneratorMethod->setAccessible(true); $generator = $getGeneratorMethod->invoke($rs, $ecCodewords); echo "Data: " . implode(', ', $data) . "\n"; echo "EC codewords: {$ecCodewords}\n"; echo "Generator: " . implode(', ', $generator) . "\n\n"; // Manual trace $msg = array_merge($data, array_fill(0, $ecCodewords, 0)); echo "Initial message: " . implode(', ', $msg) . "\n\n"; $gfMultiplyMethod = $reflection->getMethod('gfMultiply'); $gfMultiplyMethod->setAccessible(true); echo "Step-by-step division:\n"; for ($i = 0; $i < count($data); $i++) { $coeff = $msg[$i]; echo "Iteration {$i}: coefficient = {$coeff}\n"; if ($coeff !== 0) { echo " Before: " . implode(', ', $msg) . "\n"; // Current implementation $msg[$i] = 0; for ($j = 1; $j < count($generator); $j++) { $index = $i + $j; if ($index < count($msg)) { $multiplied = $gfMultiplyMethod->invoke($rs, $generator[$j], $coeff); $old = $msg[$index]; $msg[$index] ^= $multiplied; echo " [{$index}]: {$old} XOR {$multiplied} = {$msg[$index]}\n"; } } echo " After: " . implode(', ', $msg) . "\n\n"; } } $ec = array_slice($msg, count($data)); echo "EC codewords: " . implode(', ', $ec) . "\n\n"; // Compare with actual $actualEC = $rs->encode($data, $ecCodewords); echo "Actual EC: " . implode(', ', $actualEC) . "\n\n"; if ($ec === $actualEC) { echo "✅ Manual trace matches implementation\n"; } else { echo "❌ Manual trace doesn't match\n"; } // Now test what the correct algorithm should be echo "\n=== Correct Algorithm (from qrcode.js) ===\n"; // The algorithm from qrcode.js: // for (var i = 0; i < data.length; i++) { // var lead = msg[i]; // if (lead !== 0) { // msg[i] = 0; // for (var j = 1; j < gen.length; j++) { // msg[i + j] ^= gfMult(gen[j], lead); // } // } // } // This is exactly what we're doing! So the algorithm should be correct. // The problem must be with the generator polynomial format or the GF multiplication.