/Users/win/code2025/bindbox_game/docs/抽奖一致性方案/TECH_DESIGN_抽奖一致性.md
# 抽奖一致性与离线验证技术方案

## 1. 背景与目标
- 背景：当前系统具备活动/期/奖励配置与日志查询，但缺少“抽奖随机一致性与离线验证”的闭环
- 目标
  - 离线验证：用户拿一份回执单 (`receipt.json`) 在本地无网络环境重算并比对抽奖结果
  - 不可作假：平台在抽前预承诺随机源与奖池，抽后揭示并提供签名，用户可核验
  - 不可预测：一次一密、不提前泄露服务端随机，用户无法事前预测下一次结果
  - 便携性：单文件验证工具，零依赖、零配置，命令行运行即可

## 2. 总体方案
- 方案A（MVP）：Commit-Reveal + HMAC-SHA256
  - 服务端为每个期 `issue_id` 预承诺高熵主种子 `serverSeed_master`，公开 `SHA256(serverSeed_master)`（记为 `serverSeedHash`）
  - 每次抽奖派生一次性子种子：`serverSubSeed = HMAC_SHA256(serverSeed_master, encode(issueId|drawId))`；抽后在回执揭示 `serverSubSeed`，不泄露主种子
  - 抽奖随机：`entropy = HMAC_SHA256(serverSubSeed, encodedMessage)`；拒绝采样，映射到权重区间
  - 权重与奖池：抽奖前对奖励配置做规范化快照并哈希承诺 `itemsRoot`，确保各用户池一致
  - 优点：实现简单、使用标准库、双平台易构建；满足不可作假与便携校验
- 方案B（升级）：VRF（可验证随机函数）
  - 服务端用 VRF 私钥对消息生成随机与证明；用户用公钥离线验真，无需揭示任何种子
  - 优点：一次一密且天然不可预测；缺点：需引入并审计成熟库，跨平台打包复杂度更高
- 方案C（审计增强）：透明日志与库存状态证明
  - 使用追加型透明日志的 Merkle 根约束 `drawId` 顺序与库存变更；可提供单位级“包含/非包含证明”
  - 适合二期提升全局可追溯性与防“双花”

## 3. 核心数据与回执规范
- 回执字段（自包含模式）
  - `algoVersion`: 算法/编码版本
  - `roundId`: 期ID（`issue_id`）
  - `drawId`: 抽奖唯一ID（递增或全局唯一）
  - `clientId`: 用户ID
  - `timestamp`: 抽奖时间戳
  - `serverSeedHash`: `SHA256(serverSeed_master)` 的十六进制/Base64
  - `serverSubSeed`: 本次子种子（十六进制/Base64）
  - `clientSeed`: 用户种子（可系统生成）
  - `nonce`: 用户在该期内的递增计数（防重）
  - `items`: 奖池快照（按 `id` 排序）`[{id, name, weight, quantity_before}]`
  - `itemsRoot`: `SHA256(canonical_items_json)`
  - `weightsTotal`: 权重总和（整数）
  - `selectedIndex`: 选中项索引
  - `selectedItemId`: 选中奖励ID
  - `randProof`: 可选，记录一次性 `entropy` 的十六进制
  - `signature`: 平台签名（覆盖整份回执，推荐 ed25519）
- 双文件模式（大池可选）
  - 回执移除 `items`，仅保留 `itemsRoot` 与 `weightsTotal`；本地需提供 `pool.json`，其哈希必须等于 `itemsRoot`

## 4. 消息编码与随机选取规范
- 编码规则（用于 HMAC 消息）
  - 固定顺序：`algoVersion | roundId | drawId | clientId | clientSeed | nonce | itemsRoot | weightsTotal`
  - 字符串：`uint32`（大端）长度 + UTF-8 字节
  - 整数：`uint64`（大端）
  - 哈希：原始 32 字节
- 随机选取（拒绝采样）
  - 取 `R = uint64(entropy[0:8])`
  - 设 `W = weightsTotal`，`M = floor(2^64 / W) * W`
  - 若 `R >= M`：以计数器扩展重新计算 `entropy = HMAC_SHA256(serverSubSeed, encodedMessage || counter++)`，直到命中
  - 位置 `pos = R % W`；以权重累加区间定位 `selectedIndex`

## 5. 有库存的验证与扣减
- 抽奖前集合：仅在“`quantity_before > 0`”的奖励集合中参与权重抽取
- 两阶段（可选）：
  - 阶段1：类别选择（权重拒绝采样）
  - 阶段2：单位选择（该类别剩余单位内均匀或约定次序）
- 事务处理（服务端）
  - 扣减 `ActivityRewardSettings.Quantity`（乐观检查>0）
  - 写入 `ActivityDrawLogs`（抽奖记录）
  - 如需生成用户资产/订单，参考现有逻辑（`internal/service/user/reward_grant.go`）
- 二期增强（Merkle证明）
  - 维护稀疏 Merkle 树（键=`unitId`，值=状态位），回执包含“抽前包含证明 + 抽后非包含/状态更新证明”与版本号单调

## 6. 服务端接口与集成点
- APP端新增
  - `POST /api/app/activities/:activity_id/issues/:issue_id/draw`：执行抽奖，返回回执 JSON
  - 集成位置：`internal/router/router.go` 的 APP认证组（与用户接口相同组）
- 管理端新增
  - `POST /api/admin/activities/:activity_id/issues/:issue_id/commit_random`：生成/轮换期的随机承诺
  - `GET /api/admin/activities/:activity_id/issues/:issue_id/commit_random`：查看承诺
- 现有点位复用
  - 奖励配置与权重：`ListIssueRewards`（`internal/service/activity/rewards_list.go`）
  - 抽奖日志查询：`ListDrawLogs`（`internal/api/activity/draw_logs_app.go`）
  - 用户资产/订单：参考系统发放（`internal/service/user/reward_grant.go`）

## 7. 随机承诺存储设计
- 新增表：`issue_random_commitments`
  - 字段：`issue_id, algo_version, server_seed_master, server_seed_hash, items_root, weights_total, state_version, created_at`
  - 用途：管理期的随机承诺与池快照，支持版本化（`state_version` 递增）
- 过渡方案：若不立刻加表，可用配置存储（KV/配置表/文件），但建议最终落库便于审计

## 8. 离线验证工具（CLI）
- 用法：`bindbox_verify.exe receipt.json`（返回码 `0` 通过、`1` 失败）
- 验证步骤
  - 验签：用公钥验证 `signature`
  - 验承诺：`SHA256(serverSeed_master)` 是否等于 `serverSeedHash`；并校验子种子派生规则
  - 验奖池：重算 `itemsRoot` 与 `weightsTotal`
  - 重算随机：按编码规范 HMAC 与拒绝采样
  - 映射比对：`selectedIndex/selectedItemId` 是否一致
- 构建（参考已有命令）
  - Windows：`CGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o build/bindbox_verify.exe ./cmd/verify`
  - macOS（amd64/arm64）：同上构建；现有参考命令见 `README.md:17`

## 9. 安全与公平
- 不可预测
  - 每次抽奖一次一密（`serverSubSeed`），不提前揭示
  - `drawId/nonce` 单调递增并纳入消息编码
- 不可操控
  - 抽前公开承诺：`serverSeedHash` 与 `itemsRoot`
  - 回执签名覆盖所有字段；日志保留顺序与上下文
- 无偏性
  - 严格使用拒绝采样；权重与数量为非负整数；总和与整型范围校验

## 10. 实施步骤与时间节点
- 第1周：协议固化与承诺表设计；管理端承诺接口；服务层 `ExecuteDraw` 实现（无库存/有库存）
- 第2周：APP路由与处理器接入；离线验证 CLI 首版；测试向量与集成测试
- 第3周：文档与用户指引；压测极端权重/库存；可选VRF调研与二期规划

## 11. 验收标准
- 抽前承诺已公开且与回执一致
- 同一回执在 Windows/macOS 离线复验结果一致
- 有库存时仅在剩余>0集合中抽取；事务扣减与日志记录完整
- 随机输出在所有构建版本中一致；拒绝采样性能达标

## 12. 参考与代码位置
- 构建命令（Windows）：`README.md:17`
- 奖励配置查询：`internal/service/activity/rewards_list.go:7`
- 抽奖日志查询：`internal/api/activity/draw_logs_app.go:35`、`internal/service/activity/draw_logs_list.go:7`
- 用户资产发放参考：`internal/service/user/reward_grant.go:136`
