Namesome 如何抽选
简短版:在转盘开始转动之前,你的浏览器就已经用加密随机数生成器抽出了结果。下面是详细版,以及怎么核对它。
随机性从哪里来
每一次抽选都从 crypto.getRandomValues 开始,它是浏览器内置、由操作系统提供种子的随机数生成器。这和保护网络连接用的是同一个来源,而不是多数动画凑合用的那种算术捷径。结果在你按下「转动」的那一刻就定了;动画只是把一个已经做出的决定演给你看,所以手势里的任何东西 —— 甩得多用力、按住多久 —— 都改变不了它。
权重本来就是有意改变机会的,扇形的宽度也随之改变,所以大家看到的和抽签实际做的一致。
有一个例外,直说出来:当一场礼物抽签带的「不能抽到谁」的规则太多,随机取样找不到同时满足所有规则的结果时,Namesome 会退回到一个由这些规则本身构造、再打乱得到的解。那个结果是一次有效的抽签,但不是等概率的抽签——这是全站唯一一处两者不一致的地方。
自己核对
在这个浏览器里跑 5 万次转动,再用卡方检验比对结果。均等的转盘落在预期范围内;带权重的转盘落在各自的权重旁边。什么都不会发送到任何地方 —— 检验在你自己的机器上运行。
分布检验
测试 2 给三个参与项分别设为权重 1、2、3:扇形大三倍,出现的次数也就多三倍,这正是它那组数字所测量的。
检验是怎么做的
每一次抽选都从 crypto.getRandomValues 取 64 个新的随机比特 —— 浏览器生成密钥用的就是它 —— 把它们变成 [0, 1) 区间里的一个数,再沿着各参与项的权重走,走到哪里就是哪里。手势、时机和动画都碰不到结果:名字在转盘开始转动之前就已经定了。
两项测试都是皮尔逊卡方拟合优度检验。统计量把各参与项的 (实测 − 期望)² ÷ 期望加起来,数值小就说明计数落在均等抽选该有的位置上。测试 1 用八个等权重的参与项:7 个自由度,临界值 24.322。测试 2 用权重 1、2、3,所以三者的份额应当是六分之一、三分之一和二分之一:2 个自由度,临界值 13.816。两个临界值都取自 p = 0.001。
在这个阈值下,完全正常的抽选器每跑约一千轮仍会有一轮不通过。一次不通过就再跑一次 —— 连续两次不通过才是真的有问题。
谁都能验证的抽签
当人们需要证据时 —— 谁先发言、谁在值班表上、哪个名字被抽了出来 —— 抽签记录会把这次抽选变成陌生人也能重现的东西。记录里有参与项、设置、种子和指纹,还有一个当着你的面把整件事重算一遍的按钮。
先承诺,后揭晓
在结果存在之前,我们先公布一个指纹:保密种子、参与项和抽签编号的 SHA-256。结果之后才从那个种子推导出来,种子也随结果一起公布。因为指纹先公开了,我们不可能一遍遍重抽直到自己满意 —— 那样指纹就对不上了。
承诺值
46cc3578fe29c825a7134c9ba9b5b43d346147d11f2e5264f806f92b943b8b17种子
49114b046bdfc2b0b62c1366dfc097dbb5d2aba0fe251e2c6c8516c4d44696f4ns-draw-v1,十行代码
参与项先规范化并排序,然后用 SHA-256 哈希。顺序是一次 Fisher-Yates 洗牌,由以种子为密钥的 HMAC-SHA256 流驱动,抽中的就是这个顺序里最前面的名字。同样的输入,同样的输出,在任何机器上、任何语言下都一样。
// Excerpt of ns-draw-v1. sha256Hex, unhex and next32 are on the record page.
const entries = [...record.entries].map(s=>s.normalize('NFC')).sort();
const entriesHash = await sha256Hex(te.encode(JSON.stringify(entries)));
const commitment = await sha256Hex(te.encode(
record.seed + '|' + entriesHash + '|' + record.id));
const key = await crypto.subtle.importKey('raw', unhex(record.seed),
{name:'HMAC', hash:'SHA-256'}, false, ['sign']);
const arr = [...entries];
for (let i = arr.length-1; i > 0; i--){
const bound = i+1, lim = Math.floor(0x100000000/bound)*bound;
let r; do { r = await next32(); } while (r >= lim);
const j = r % bound; [arr[i],arr[j]] = [arr[j],arr[i]];
}
return { entriesHash, commitment, order: arr, winners: arr.slice(0, record.winners) };这是节选 —— 它调用的辅助函数,以及当着你的面把整件事重跑一遍的按钮,都在抽签记录页面上。
我们绝不做的事
我们绝不为任何抽签收钱。Namesome 里没有门票、没有报名费、没有奖品,也没有赔率,条款同样禁止把它用于赌博。它只挑名字,这就是它的全部工作。
从设计上就与金钱无关 —— 这里没有任何东西指向钱。
给智能体和程序
API 和 MCP 服务器返回同样的记录、同样的指纹,所以一个助手可以核对另一个助手的抽签。每一个响应都带着一条人能读的页面链接。