[expected_commitment] [winning_number] * * JSON array: [{"number":1,"ref":"..."}, ...] * [expected_commitment] the pool_commitment published at close (optional — compares) * [winning_number] the published winning number (optional — confirms it's in the pool) */ if ($argc < 2 || $argc > 4) { fwrite(STDERR, "Usage: php verify-pool.php [expected_commitment] [winning_number]\n"); exit(2); } $path = $argv[1]; if (! is_file($path)) { fwrite(STDERR, "Manifest file not found: {$path}\n"); exit(2); } $manifest = json_decode((string) file_get_contents($path), true); if (! is_array($manifest) || $manifest === []) { fwrite(STDERR, "Manifest is not a non-empty JSON array.\n"); exit(2); } // Canonical commitment: rows sorted by number asc, "number:ref" lines joined by \n. usort($manifest, static fn ($a, $b) => ((int) $a['number']) <=> ((int) $b['number'])); $lines = []; $numbers = []; foreach ($manifest as $row) { if (! isset($row['number'], $row['ref'])) { fwrite(STDERR, "Every manifest row must have 'number' and 'ref'.\n"); exit(2); } $n = (int) $row['number']; $lines[] = $n.':'.$row['ref']; $numbers[$n] = true; } $commitment = hash('sha256', implode("\n", $lines)); echo 'eligible_count: '.count($manifest)."\n"; echo 'pool_commitment (recomputed): '.$commitment."\n"; $exit = 0; if ($argc >= 3) { $expected = $argv[2]; $match = hash_equals($expected, $commitment); echo 'expected_commitment: '.$expected."\n"; echo 'COMMITMENT_MATCH: '.($match ? 'yes' : 'NO — pool has been altered')."\n"; if (! $match) { $exit = 1; } } if ($argc === 4) { $winning = (int) $argv[3]; $inPool = isset($numbers[$winning]); echo 'winning_number: '.$winning."\n"; echo 'WINNING_NUMBER_IN_POOL: '.($inPool ? 'yes' : 'NO')."\n"; if (! $inPool) { $exit = 1; } } exit($exit);