Cách một lần quay thưởng hoạt động — ví dụ thực tế
Đi qua một lần quay thưởng thực tế từ đầu đến cuối: 1.000 bình luận đủ điều kiện, 3 người thắng, 9 dự bị. Không thuật ngữ khó hiểu.
Tình huống
Hãy tưởng tượng cuộc thi đã kết thúc. Bình luận đã được tải về, các bộ lọc của cuộc thi đã chạy, và 1.000 lượt tham gia đủ điều kiện. Giải thưởng trao cho 3 người thắng với 9 dự bị, phòng trường hợp không liên hệ được người thắng. Đây là xác suất cho mỗi lượt tham gia — giống hệt nhau cho mỗi một trong 1.000 bình luận đủ điều kiện, bất kể khi nào được đăng hoặc tên người bình luận dài bao nhiêu.
| Kết quả | Xác suất cho mỗi lượt tham gia |
|---|---|
| Được chọn là người thắng chính (vị trí 1–3) | 3 trong 1.000 — 0,30% |
| Được chọn là dự bị (vị trí 4–12) | 9 trong 1.000 — 0,90% |
| Được chọn vào bất kỳ vị trí thắng | 12 trong 1.000 — 1,20% |
Không có gì thay đổi nếu cuộc thi có 444 bình luận hay 444.444. Thuật toán giống nhau. Chỉ có mẫu số thay đổi.
Bước 1 — Thu thập và lọc các lượt tham gia
Ứng dụng tải mỗi bình luận trên bài đăng Facebook hoặc Instagram bạn đã kết nối, sau đó áp dụng các bộ lọc của cuộc thi — trùng lặp, từ bị chặn, quy tắc tuổi tài khoản, bất cứ điều gì đã được cấu hình. Những gì còn lại là tập hợp đủ điều kiện. Trong tình huống của chúng ta là 1.000 bình luận. Mỗi bình luận có một hàng cơ sở dữ liệu với ID số duy nhất; 1.000 ID đó là những gì phần còn lại của lần quay thưởng hoạt động trên.
Bước 2 — Sắp xếp chúng theo thứ tự chuẩn
Trước khi có bất cứ điều gì ngẫu nhiên xảy ra, ứng dụng sắp xếp 1.000 ID theo thứ tự tăng dần nghiêm ngặt — 17, 142, 203, 1058, 9941, … — và loại bỏ thứ tự chúng đến. Tại sao? Vì Facebook có thể trả về bình luận theo các thứ tự khác nhau tùy thuộc vào phân trang, thời gian trong ngày, hoặc thay đổi back-end. Nếu lần quay thưởng sử dụng thứ tự của Facebook, hai lần tải lại có thể tạo ra người thắng khác nhau từ cùng một hạt giống ngẫu nhiên. Sắp xếp trước ghim đầu vào vào một danh sách chuẩn, vì vậy hạt giống một mình xác định kết quả.
Bước 3 — Khóa danh sách đầu vào bằng hash SHA-256
Danh sách đã sắp xếp được đưa vào SHA-256 — một hàm hash mã hóa — tạo ra một dấu vân tay 64 ký tự. Dấu vân tay, cùng với toàn bộ danh sách, được lưu trên bản ghi cuộc thi. Từ thời điểm này, bất kỳ ai kiểm tra cuộc thi đều có thể xác nhận danh sách đủ điều kiện chưa bị thay đổi: hash lại danh sách đã công bố, so sánh với dấu vân tay đã lưu, và một ID duy nhất bị thay đổi sẽ cho ra hash hoàn toàn khác. Không có cách nào để lặng lẽ thêm hoặc xóa bình luận sau bước này mà không bị phát hiện.
Bước 4 — Tạo hạt giống ngẫu nhiên 256-bit
Ứng dụng yêu cầu nguồn ngẫu nhiên mã hóa của hệ điều hành (SecureRandom.hex(32)) cho 32 byte ngẫu nhiên không thể đoán trước, và lưu kết quả dưới dạng chuỗi thập lục phân 64 ký tự — ví dụ a3f1…ce. 256 bit có nghĩa là 2²⁵⁶ ≈ 10⁷⁷ hạt giống có thể. Để so sánh, vũ trụ quan sát được chứa khoảng 10⁸⁰ nguyên tử. Không ai — không phải người tạo cuộc thi, không phải người vận hành, không phải kẻ tấn công theo dõi từ bên ngoài — có thể dự đoán hoặc đoán hạt giống này trước khi nó được tạo ra.
Bước 5 — Xáo trộn 1.000 ID, sau đó lấy 12 cái đầu tiên
Hạt giống khởi tạo một công cụ xáo trộn xác định, sau đó thực hiện xáo trộn Fisher–Yates trên 1.000 ID đã sắp xếp. Fisher–Yates là thuật toán xáo trộn công bằng tiêu chuẩn — mỗi một trong 1.000 lượt tham gia có cơ hội bằng nhau để kết thúc ở mọi vị trí. Sau khi xáo trộn, ứng dụng lấy 12 lượt tham gia đầu tiên từ trên. Đó là toàn bộ bước chọn: xáo trộn, cắt 12.
Bước 6 — Phân công vị trí
12 lượt tham gia được chọn được đi theo thứ tự. Ba lượt đầu tiên trở thành người thắng 1, 2 và 3, và chín lượt tiếp theo trở thành dự bị 1 đến 9. 988 lượt tham gia đủ điều kiện còn lại được ghi lại là không được chọn. Bình luận bị lọc ra trước đó được đánh dấu là bị loại với lý do cụ thể họ không đủ điều kiện.
Bước 7 — Công bố mọi thứ
Cuối cùng, ứng dụng lưu năm bằng chứng trên bản ghi cuộc thi — tất cả đều có thể đọc công khai. Nếu không có chúng, kết quả sẽ là một hộp đen. Với chúng, bất kỳ ai cũng có thể tái tạo toàn bộ lần quay thưởng tại nhà và xác nhận người thắng đã công bố là người thắng duy nhất mà hạt giống có thể tạo ra.
Những gì được công bố với mỗi lần quay thưởng
Mỗi thông tin này được lưu trên cuộc thi và hiển thị qua các trang xác minh công khai. Cùng nhau chúng làm cho lần quay thưởng hoàn toàn có thể tái tạo — cùng đầu vào, cùng đầu ra, luôn luôn.
- Hạt giống ngẫu nhiên 256-bit — chuỗi hex 64 ký tự từ Bước 4.
- Danh sách ID đủ điều kiện đã sắp xếp — tất cả 1.000 ID từ Bước 2, theo thứ tự chuẩn.
- Dấu vân tay SHA-256 của các ID — hash 64 ký tự từ Bước 3. Xác nhận danh sách đã công bố chưa bị giả mạo.
- Phiên bản thuật toán — hiện tại là
v1. Ghim thuật toán chọn chính xác, vì vậy các cải tiến trong tương lai không bao giờ hồi tố thay đổi kết quả cũ. - Phiên bản Ruby — ghim môi trường chạy ngôn ngữ, vì thứ tự chính xác của việc xáo trộn phụ thuộc vào nó.
Tính lại toán học tự mình — trong năm dòng
Nếu bạn đã cài đặt Ruby (đi kèm với macOS và hầu hết các bản phân phối Linux), bạn có thể tái tạo chính xác lần quay thưởng tại nhà. Mỗi cuộc thi công bố eligible-ids.txt riêng của nó trên trang xác minh (mẫu URL: /results/<token>/verify) — hướng dẫn xác minh hướng dẫn từng bước tải xuống. Sao chép hạt giống đã công bố và dán vào irb:
require "digest"
seed = "PASTE_THE_PUBLISHED_SEED_HERE"
ids = File.read("eligible-ids.txt").split("\n").map(&:to_i).sort
# (1) Sanity check the input: must equal the published SHA-256.
Digest::SHA256.hexdigest(ids.join("\n"))
# (2) Re-run the shuffle. First 3 items are winners 1..3 (in order);
# the next 9 items are reserves 1..9.
ids.shuffle(random: Random.new(seed.to_i(16))).first(12)
12 ID xuất ra theo đúng thứ tự cuộc thi đã công bố. Ba người thắng, chín dự bị, giống hệt từng bit. Đó là điều làm cho một lần quay thưởng Pick a Winner có thể xác minh thay vì chỉ hứa hẹn — toán học làm việc, không phải lời của người vận hành.
Tại sao điều này khó gian lận
- Hạt giống không thể đoán được. 2²⁵⁶ khả năng, chỉ được tạo sau khi danh sách đủ điều kiện được cam kết. Không ai có thể tính trước ID nào mà hạt giống sẽ ưu tiên, vì hạt giống không tồn tại cho đến thời điểm quay thưởng.
- Đầu vào bị khóa. Dấu vân tay SHA-256 có nghĩa là bạn không thể lặng lẽ thêm bình luận của bạn bè sau khi nhìn thấy hạt giống — dấu vân tay sẽ thay đổi và lần quay thưởng sẽ không còn tái tạo được.
- Việc xáo trộn là cơ học. Một khi hạt giống và danh sách đã sắp xếp tồn tại, người thắng đã được xác định. Không có quyết định của con người nào ở giữa chúng. Bất kỳ sự điều chỉnh nào sau thực tế sẽ xuất hiện như một sự không khớp ngay khi ai đó tính lại toán học.
- Biên nhận là công khai. Hạt giống, danh sách, hash, phiên bản thuật toán, phiên bản Ruby — tất cả năm đều được công bố. Không có phần riêng tư nào của lần quay thưởng mà người vận hành có thể thay đổi mà không ai có thể thấy.