*/ public static function deriveAllSlotRows(string $seedHex, int $drawId): array { $rows = []; foreach (DrawPrizeLayout::slots() as $slotIndex => $slot) { $num = self::deriveNumber4d($seedHex, $drawId, $slotIndex); $rows[] = [ 'prize_type' => $slot['prize_type'], 'prize_index' => $slot['prize_index'], 'number_4d' => $num, 'suffix_3d' => substr($num, -3), 'suffix_2d' => substr($num, -2), 'head_digit' => $num !== '' ? (int) substr($num, 0, 1) : null, 'tail_digit' => $num !== '' ? (int) substr($num, 3, 1) : null, ]; } return $rows; } /** 审计:校验批次种子摘要、密文可解密且号码可由种子复算。 */ public static function verifyBatchAudit(DrawResultBatch $batch, Draw $draw): bool { if ($batch->source_type !== 'rng') { return false; } $encrypted = $batch->raw_seed_encrypted; $hash = $batch->rng_seed_hash; if (! is_string($encrypted) || $encrypted === '' || ! is_string($hash) || $hash === '') { return false; } try { $seedHex = self::decryptSeedHex($encrypted); } catch (\InvalidArgumentException) { return false; } if (self::hashSeedHex($seedHex) !== $hash) { return false; } $expected = self::deriveAllSlotRows($seedHex, (int) $draw->id); $items = $batch->items()->get(); if ($items->count() !== count($expected)) { return false; } foreach ($expected as $row) { $item = $items->first(fn (DrawResultItem $i) => $i->prize_type === $row['prize_type'] && (int) $i->prize_index === $row['prize_index']); if ($item === null || $item->number_4d !== $row['number_4d']) { return false; } } return true; } }