bindbox-game/抽奖算法.md
邹方成 00452cba59 feat: 添加用户统计功能及相关API接口
feat(admin): 新增管理后台前端资源文件

feat(api): 实现获取用户统计数据的API接口
- 添加获取用户道具卡数量、优惠券数量和积分余额的接口
- 实现设置默认地址和删除地址的接口

feat(service): 新增用户统计服务方法
- 实现GetUserStats方法查询用户统计数据
- 添加地址管理相关服务方法

fix(core): 修复静态资源路由问题
- 调整静态资源路由配置
- 优化404路由处理逻辑

chore: 更新前端构建配置
- 添加Windows平台构建命令
- 更新README构建说明
2025-11-15 03:08:53 +08:00

7.5 KiB
Raw Blame History

/Users/win/code2025/bindbox_game/docs/抽奖一致性方案/TECH_DESIGN_抽奖一致性.md

抽奖一致性与离线验证技术方案

1. 背景与目标

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

2. 总体方案

  • 方案AMVPCommit-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: 期IDissue_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,仅保留 itemsRootweightsTotal;本地需提供 pool.json,其哈希必须等于 itemsRoot

4. 消息编码与随机选取规范

  • 编码规则(用于 HMAC 消息)
    • 固定顺序:algoVersion | roundId | drawId | clientId | clientSeed | nonce | itemsRoot | weightsTotal
    • 字符串:uint32(大端)长度 + UTF-8 字节
    • 整数:uint64(大端)
    • 哈希:原始 32 字节
  • 随机选取(拒绝采样)
    • R = uint64(entropy[0:8])
    • W = weightsTotalM = 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:查看承诺
  • 现有点位复用
    • 奖励配置与权重:ListIssueRewardsinternal/service/activity/rewards_list.go
    • 抽奖日志查询:ListDrawLogsinternal/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;并校验子种子派生规则
    • 验奖池:重算 itemsRootweightsTotal
    • 重算随机:按编码规范 HMAC 与拒绝采样
    • 映射比对:selectedIndex/selectedItemId 是否一致
  • 构建(参考已有命令)
    • WindowsCGO_ENABLED=0 GOOS=windows GOARCH=amd64 go build -ldflags "-s -w" -trimpath -o build/bindbox_verify.exe ./cmd/verify
    • macOSamd64/arm64同上构建现有参考命令见 README.md:17

9. 安全与公平

  • 不可预测
    • 每次抽奖一次一密(serverSubSeed),不提前揭示
    • drawId/nonce 单调递增并纳入消息编码
  • 不可操控
    • 抽前公开承诺:serverSeedHashitemsRoot
    • 回执签名覆盖所有字段;日志保留顺序与上下文
  • 无偏性
    • 严格使用拒绝采样;权重与数量为非负整数;总和与整型范围校验

10. 实施步骤与时间节点

  • 第1周协议固化与承诺表设计管理端承诺接口服务层 ExecuteDraw 实现(无库存/有库存)
  • 第2周APP路由与处理器接入离线验证 CLI 首版;测试向量与集成测试
  • 第3周文档与用户指引压测极端权重/库存可选VRF调研与二期规划

11. 验收标准

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

12. 参考与代码位置

  • 构建命令WindowsREADME.md:17
  • 奖励配置查询:internal/service/activity/rewards_list.go:7
  • 抽奖日志查询:internal/api/activity/draw_logs_app.go:35internal/service/activity/draw_logs_list.go:7
  • 用户资产发放参考:internal/service/user/reward_grant.go:136