Minh bạch trong trò chơi
Hoạt động như thế nào
Giao thức tách cam kết công khai ra khỏi việc tiết lộ hạt giống. Điều này ngăn kết quả được chọn sau khi đã tham gia.
1. Cam kết
Một hàm băm được công bố trước kết quả. Nó hoạt động như một phong bì kỹ thuật số bị niêm phong.
2. Rút thăm
Kết quả được suy ra từ dữ liệu đã được cam kết bởi một hàm xác định.
3. Tiết lộ
Sau khi có kết quả, hạt giống và các tham số cần thiết được cung cấp để kiểm tra.
4. Tái tạo
Trình duyệt lặp lại các hàm băm và lượt rút thăm. Bằng chứng chỉ được chấp nhận khi mọi thứ khớp với bản ghi.
Bằng chứng Vòng quay
Kết quả được tính toán như thế nào
Vòng quay kết hợp một chuỗi hạt giống với danh mục và trọng số được bảo tồn tại thời điểm quay.
- Các mục được sắp xếp theo khóa. Mỗi khóa và trọng số đi vào danh mục chuẩn được sử dụng trong tính toán.
- Cam kết của lượt quay là sha-256 của miền giao thức, hạt giống của máy chủ và danh mục chuẩn.
- Cam kết của chuỗi liên kết băm ban đầu, danh mục và kích thước; vị trí chứng minh rằng hạt giống thuộc về chuỗi đã công bố.
- Băm của kết quả trở thành một số modulo tổng trọng số. Vé này xác định mục được chọn.
Mã xác minh
Dán vào console của trình duyệt hoặc lưu dưới dạng tệp .mjs và chạy với Node. Mã sẽ tái tạo các hash và bốc thăm với dữ liệu bằng chứng và hiển thị liệu từng phần có khớp hay không.
Kiểm tra một cam kết ở trên để điền mã với dữ liệu bằng chứng.
const proof = {
"serverSeed": "SERVER_SEED",
"commitmentHash": "COMMITMENT_HASH",
"chainCommitment": "CHAIN_COMMITMENT",
"headHash": "HEAD_HASH",
"index": 0,
"size": 1,
"items": [
{
"key": "ITEM_KEY",
"weight": 1
}
]
}
async function sha256(text) {
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text))
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('')
}
async function verifyReward(proof) {
const items = [...proof.items]
.sort((left, right) => (left.key < right.key ? -1 : left.key > right.key ? 1 : 0))
.map(({ key, weight }) => ({ key, weight }))
const commitment = await sha256(
JSON.stringify(['tgrtslj:reward:commitment:v1', proof.serverSeed, items]),
)
const chain = await sha256(
JSON.stringify(['tgrtslj:reward:commitment-chain:v1', proof.headHash, items, proof.size]),
)
let link = proof.serverSeed
for (let step = 0; step <= proof.index; step += 1) link = await sha256(link)
const resultHash = await sha256(
JSON.stringify(['tgrtslj:reward:weighted-draw:v1', proof.serverSeed, items]),
)
const totalWeight = items.reduce((sum, item) => sum + item.weight, 0)
const ticket = Number(BigInt('0x' + resultHash) % BigInt(totalWeight))
let upperBound = 0
const selected = items.find((item) => ticket < (upperBound += item.weight))
return {
commitmentMatches: commitment === proof.commitmentHash,
chainMatches: chain === proof.chainCommitment,
positionMatches: proof.index < proof.size && link === proof.headHash,
resultHash,
ticket,
item: selected.key,
}
}
console.log(await verifyReward(proof))
Bằng chứng Trò cào
Kết quả được tính toán như thế nào
Bằng chứng chỉ có sẵn sau khi tiết lộ, khi seed đã có thể được hiển thị một cách an toàn.
- Danh mục và trọng số được đóng băng khi trò cào được cấp, ngay cả khi cài đặt thay đổi sau đó.
- Cam kết sử dụng cùng miền mật mã và cùng bốc thăm có trọng số của Roulette.
- Vị trí của hạt giống được xác minh so với băm ban đầu và cam kết chuỗi đã được công bố trước đó.
- Mục, băm kết quả và hạt giống được tiết lộ cần phải tái tạo chính xác phần thưởng đã được ghi nhận.
Mã xác minh
Dán vào console của trình duyệt hoặc lưu dưới dạng tệp .mjs và chạy với Node. Mã sẽ tái tạo các hash và bốc thăm với dữ liệu bằng chứng và hiển thị liệu từng phần có khớp hay không.
Kiểm tra một cam kết ở trên để điền mã với dữ liệu bằng chứng.
const proof = {
"serverSeed": "SERVER_SEED",
"commitmentHash": "COMMITMENT_HASH",
"chainCommitment": "CHAIN_COMMITMENT",
"headHash": "HEAD_HASH",
"index": 0,
"size": 1,
"items": [
{
"key": "ITEM_KEY",
"weight": 1
}
]
}
async function sha256(text) {
const digest = await crypto.subtle.digest('SHA-256', new TextEncoder().encode(text))
return [...new Uint8Array(digest)].map((byte) => byte.toString(16).padStart(2, '0')).join('')
}
async function verifyReward(proof) {
const items = [...proof.items]
.sort((left, right) => (left.key < right.key ? -1 : left.key > right.key ? 1 : 0))
.map(({ key, weight }) => ({ key, weight }))
const commitment = await sha256(
JSON.stringify(['tgrtslj:reward:commitment:v1', proof.serverSeed, items]),
)
const chain = await sha256(
JSON.stringify(['tgrtslj:reward:commitment-chain:v1', proof.headHash, items, proof.size]),
)
let link = proof.serverSeed
for (let step = 0; step <= proof.index; step += 1) link = await sha256(link)
const resultHash = await sha256(
JSON.stringify(['tgrtslj:reward:weighted-draw:v1', proof.serverSeed, items]),
)
const totalWeight = items.reduce((sum, item) => sum + item.weight, 0)
const ticket = Number(BigInt('0x' + resultHash) % BigInt(totalWeight))
let upperBound = 0
const selected = items.find((item) => ticket < (upperBound += item.weight))
return {
commitmentMatches: commitment === proof.commitmentHash,
chainMatches: chain === proof.chainCommitment,
positionMatches: proof.index < proof.size && link === proof.headHash,
resultHash,
ticket,
item: selected.key,
}
}
console.log(await verifyReward(proof))

