# 头衔加概率与折扣的可验证设计 ## 结论 * 采用“权重修饰”的方式为持有头衔的用户提升抽奖概率。 * 哈希算法(HMAC-SHA256 随机熵)保持不变;只扩展承诺与收据的字段以固化规则与有效权重,保证可验证性与不可篡改。 ## 必要扩展 * 承诺扩展(IssueRandomCommitment) * 新增 `AlgoRulesHash`:对“权重修饰规则(由头衔配置确定的纯函数)”做哈希并随期承诺固化。服务端在抽取前不能更改规则。 * 收据扩展(Receipt) * 新增 `UserId`:明确本次抽取的用户。 * 新增 `WeightsTotalEffective`:按用户头衔修饰后的总权重,用于位置采样与第三方复核。 * 新增 `UserWeightFactorsRoot`:以 `reward_id -> factor` 做 Merkle 根,第三方可据此对 `Items(snapshot)` 重建有效权重。 * 编码消息扩展(不改算法,仅改输入) * 仍使用 `HMAC(serverSubSeed, encodeMessage(...))`;`encodeMessage` 增加 `UserId` 与 `WeightsTotalEffective` 字段(保持确定性)。 ## 规则与确定性 * 规则来源:头衔模板配置(百分比或加点),以及叠加策略(none|max|multiply)。 * 纯函数:`factor = F(user_titles, reward_id)`,只依赖用户持有的头衔与静态规则;不依赖随机数或服务端临时状态。 * 可复核:第三方得到 `ItemsRoot`、`AlgoRulesHash`、`UserWeightFactorsRoot`、`UserId` 与收据内快照,即可重建每个 `reward_id` 的有效权重与 `WeightsTotalEffective`,据同样的消息编码与哈希熵验证 `SelectedIndex`。 ## 核心流程(抽奖不变,仅插入修饰步骤) 1. 读取承诺:`GetIssueRandomCommit(...)`(`internal/service/activity/random_commit.go:99`)。 2. 载入奖励池快照:同现有实现(`internal/service/activity/draw_execute.go:21-35`)。 3. 计算用户权重修饰:`effective_weight[i] = base_weight[i] * factor(user, reward_id[i])`;汇总 `WeightsTotalEffective`。 4. 使用 HMAC-SHA256 生成熵(算法不变),对 `encodeMessage(..., UserId, WeightsTotalEffective)` 取样位点。 5. 按有效权重的累加区间选中 `SelectedIndex/SelectedItemId`。 6. 返回收据,并包含 `UserWeightFactorsRoot` 与证明材料。 ## 折扣集成(独立不影响随机) * 抽奖订单创建(新增):以活动门票价 `PriceDraw`(`internal/repository/mysql/model/activities.gen.go:22`)为基价。 * 头衔折扣:按叠加策略计算 `discount_amount`,落到订单字段 `DiscountAmount/ActualAmount`(`internal/repository/mysql/model/orders.gen.go:22`)。 * 与优惠券/积分叠加:默认“优惠券优先 + 头衔折上折”,可通过 `stack_policy` 切到“取最大”。 ## 接口与服务 * 管理端:头衔模板 CRUD + 发放;配置权重修饰参数与叠加策略。 * APP: * 抽奖订单创建接口(新):返回计算后的金额。 * 抽奖接口:保持路径不变(`internal/api/activity/draw_app.go:28`),服务内执行权重修饰。 * 模拟与校验: * 模拟接口增加 `user_id`,输出期望概率与观测分布。 * 校验接口以收据扩展字段重建有效权重,验证 `SelectedIndex`。 ## 验收标准 * 头衔发放后,持有用户的抽奖订单能正确展示并结算折扣。 * 抽奖收据包含新增字段,第三方使用承诺与收据可重放选中过程;不持有头衔的用户与持有者的分布差异符合规则。 * 哈希熵算法未变,安全与不可预测性不受影响。 ## 说明:关于“加概率是否影响哈希算法” * 不影响哈希算法本身(仍是 HMAC-SHA256)。 * 影响的是“采样空间”——由原始 `weights_total` 改为 `WeightsTotalEffective`,并且将该值与用户标识作为消息输入的一部分来固定采样过程;承诺和收据的扩展确保服务端无法事后调参。