1. 바카라 넘버스
  2. 휠 공정성 검산

시험 벡터로 처음부터 끝까지 따라 하는 SNOW 휠 공정성 검산

SNOW의 공정성 검증 페이지는 휠 추첨 계산식과 원본 코드(draw.go)를 공개하고, 계산기에 ‘시험 예시’를 넣어 볼 수 있게 해 둡니다. 이 시트는 그 시험 예시 하나를 손으로 다시 계산합니다. 여기서 같은 값이 나오면, 실제 영수증의 검증 자료도 같은 방법으로 직접 확인할 수 있습니다.

84,923
추첨값 (0~9,999,999)
0번 칸
누적 가중치 100,000
0회
다시 뽑은 횟수
8.3×10⁻⁷¹
다시 뽑을 확률

검산으로 확인되는 것과 확인되지 않는 것

공정성 검증은 ‘기록된 결과가 당시 입력값으로 계산한 결과와 같은지’를 확인하는 방법입니다. ‘당첨이 잘 나오는지’를 알려 주는 도구는 아닙니다. SNOW 페이지도 계산이 같아도 공개 시점, 장부 연결, 재고, 실제 지급까지 증명하지는 않는다고 적고 있습니다.

휠 검산의 범위
질문검산으로 답할 수 있나필요한 것
서버 시드가 추첨 뒤에 바뀌지 않았나예추첨 전에 받아 둔 server_seed_hash
보상표 가중치가 바뀌지 않았나예추첨 전에 받아 둔 table_version_hash
내 시드⁠·커밋으로 같은 칸이 나오나예영수증의 calculation_proof
해시가 실제로 추첨 전에 공개됐나아니요별도 기록(내가 받아 둔 사본)
보상이 실제로 지급됐나아니요지급 내역
슬롯⁠·라이브 카지노 결과아니요게임사 별도 시스템

그래서 검산을 제대로 하려면 추첨 전에 시드 해시와 보상표 해시를 따로 저장해 두어야 합니다. 추첨 뒤에 한꺼번에 받은 자료만으로는 ‘계산이 맞다’까지만 확인됩니다.

필요한 값과 형식 규칙

휠 검증 자료의 항목
항목형식규칙
server_seed64자리 16진수 = 32바이트추첨 뒤 공개. 해시⁠·HMAC에는 글자가 아닌 32바이트를 씀
server_seed_hash64자리 16진수SHA-256(32바이트 시드). 추첨 전 공개
client_seedUTF-8 문자열NFC 정규화 뒤 1~128바이트. 제어 문자, |, @ 불가. 공백은 그대로
brand_env문자열비어 있으면 안 되고 |와 제어 문자 불가
commit_id소문자 UUID추첨마다 다름
canonical_documentJSON 원문받은 글자 그대로 해시. 칸 위치⁠·가중치⁠·기본 칸 표시

계산기 화면의 ‘대조할 브랜드 환경’ 칸이 brand_env입니다. 시험 예시의 brand_env는 test이고 실제 영수증은 영수증에 적힌 값을 씁니다.

시험 벡터를 한 단계씩 계산하기

계산기의 ‘시험 예시 넣기’에 들어 있는 값입니다. 서버 시드는 0을 62개 쓰고 끝에 62를 붙인 64자리 16진수이고 보상표는 0번 칸 100,000, 1번 칸 50,000, 2번 칸(기본 칸) 9,850,000 세 칸입니다. 당첨 확률로 바꾸면 1%, 0.5%, 98.5%입니다.

  1. 서버 시드 해시

    64자리 글자를 32바이트로 풀어 SHA-256을 구합니다.

    0010d2c57c2552b023f787cafcd6cd962d6faa04a7621fba14faa3a9f6de8910

  2. 보상표 해시

    canonical_document 원문을 UTF-8 바이트 그대로 SHA-256에 넣습니다.

    3e26d57e91ece2366848e3d9f4dc2eaf6288b24e405b12314a87555787b90110

  3. 메시지

    알고리즘 번호 1, brand_env, WHEEL, NFC로 정규화한 client_seed, commit_id를 |로 잇습니다.

    1|test|WHEEL|c98|aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa

  4. HMAC-SHA256

    키는 32바이트 서버 시드, 내용은 메시지의 UTF-8 바이트입니다.

    8a329eff3157fa17ca047ba0014fbe4c5e1fc27e2c4387e61b47d48b2ed4383b

  5. 256비트 정수

    32바이트를 앞자리부터 읽어 부호 없는 정수 H로 바꿉니다. H가 경계값 L보다 작으므로 첫 시도(접미사 없음)에서 통과합니다.

    H = 62508612813635367744208359319450530045745479443396350918367385282301090084923

  6. 추첨값

    H를 10,000,000으로 나눈 나머지입니다. H의 끝 일곱 자리가 그대로 추첨값이 됩니다.

    value = 84923

  7. 칸 선택

    위치 순서대로 가중치를 더하다가 누적값이 추첨값보다 처음 커지는 칸을 고릅니다. 0번 칸에서 누적 100,000이 84,923보다 크므로 0번 칸입니다.

쏠림을 없애는 경계값 L

2256은 10,000,000으로 나누어떨어지지 않습니다. 그냥 나머지를 쓰면 0부터 시작하는 일부 추첨값이 아주 조금 더 자주 나옵니다. 그래서 10,000,000의 배수 중 2256 이하에서 가장 큰 수를 경계값 L로 두고 H가 L 이상이면 메시지 뒤에 |1, |2…를 붙여 다시 계산합니다.

L = 115792089237316195423570985008687907853269984665640564039457584007913120000000

H가 L 이상일 확률은 약 8.3×10−71입니다. 실제로 다시 뽑는 일은 사실상 없지만 검산 코드에는 이 반복이 들어 있어야 원본과 같은 계산이 됩니다. 영수증의 attempt 값이 0이 아니면 메시지 끝에 그 번호가 붙었다는 뜻입니다.

클라이언트 시드 한 글자의 차이

서버 시드와 커밋은 그대로 두고 client_seed만 바꿔 다시 계산했습니다. 대소문자 하나, 끝의 공백 하나만 달라도 HMAC 전체가 바뀌어 전혀 다른 추첨값이 나옵니다.

같은 서버 시드에서 client_seed만 바꿨을 때
client_seedHMAC 앞 8자리추첨값칸
c988a329eff84,9230번
c991980c8c3286,1672번
C98af77648c4,399,1912번
c98␠ (끝 공백)73a66e657,553,3812번
baccaratnumbersddb636c4904,1492번

추첨값이 100,000 미만이면 0번, 100,000~149,999면 1번, 150,000 이상이면 2번 칸입니다.

검산이 안 맞을 때 먼저 볼 곳

  • 시드 글자를 해시했다. 64자리 16진수 글자를 그대로 SHA-256에 넣으면 1cd48b66…이 나옵니다. 32바이트로 풀어서 넣어야 0010d2c5…가 나옵니다.
  • 보상표 JSON을 다시 만들었다. 줄바꿈, 들여쓰기, 키 순서가 하나만 달라도 표 해시가 달라집니다. 받은 원문을 복사해 그대로 넣으세요.
  • NFC 정규화를 빠뜨렸다. é는 합친 형태로 2바이트, 나눈 형태로 3바이트입니다. 다른 곳에서 복사해 온 글자에는 나눈 형태가 섞여 있을 수 있습니다.
  • 끝 공백을 지웠다. 공백은 규칙상 그대로 남깁니다. 위 표처럼 결과가 달라집니다.
  • 지금 시드로 지난 결과를 확인했다. 계정의 현재 시드나 설정은 과거 추첨에 쓰인 값과 다를 수 있습니다. 그 추첨의 영수증에 저장된 값을 쓰세요.
  • 품절 칸을 빼고 더했다. 품절 칸도 가중치를 그대로 갖고 누적에 들어갑니다. 가중치가 0인 칸만 뽑히지 않습니다.

파이썬 검산 코드

Python 3 표준 라이브러리만 씁니다. proof 안의 값을 영수증의 calculation_proof 값으로 바꾸면 실제 추첨도 같은 방식으로 다시 계산할 수 있습니다. 이미 공개된 시드만 넣으세요.

import hashlib, hmac, json, unicodedata

proof = {
    "brand_env": "test",
    "commit_id": "aaaaaaaa-aaaa-4aaa-8aaa-aaaaaaaaaaaa",
    "client_seed": "c98",
    "server_seed": "62".zfill(64),
    "canonical_document": '{"alg":"1","feature":"WHEEL","slots":[{"position":0,"weight":100000,"is_default":false},{"position":1,"weight":50000,"is_default":false},{"position":2,"weight":9850000,"is_default":true}]}',
}

seed = bytes.fromhex(proof["server_seed"])   # 64자리 글자가 아니라 32바이트
print("seed hash :", hashlib.sha256(seed).hexdigest())
print("table hash:", hashlib.sha256(proof["canonical_document"].encode()).hexdigest())

client = unicodedata.normalize("NFC", proof["client_seed"])
base = "|".join(["1", proof["brand_env"], "WHEEL", client, proof["commit_id"]])
TOTAL = 10_000_000
L = (2**256 // TOTAL) * TOTAL
attempt = 0
while True:
    msg = base if attempt == 0 else f"{base}|{attempt}"
    digest = hmac.new(seed, msg.encode(), hashlib.sha256).digest()
    H = int.from_bytes(digest, "big")
    if H < L:
        break
    attempt += 1
value = H % TOTAL
print("hmac      :", digest.hex())
print("attempt   :", attempt, " value:", value)

cumulative = 0
for slot in sorted(json.loads(proof["canonical_document"])["slots"], key=lambda s: s["position"]):
    cumulative += slot["weight"]
    if cumulative > value:
        print("selected  : position", slot["position"])
        break

실행하면 seed hash 0010d2c5…, table hash 3e26d57e…, hmac 8a329eff…, attempt 0, value 84923, position 0이 출력됩니다. SNOW 계산기는 같은 계산을 브라우저의 Web Crypto로만 다시 합니다.

확인 시점의 SNOW 휠⁠·검증 상태

2026-11-02~03 확인 상태
항목상태
스노우 휠‘곧 열려요’, 아직 돌릴 수 없음
루트박스진행 중인 보상표 없음. 외부 증명을 포함한 전체 검증은 완료되지 않았다고 표시
래플이 회차에 검증 가능한 증명이 아직 연결되지 않음
외부 검증 도구아직 연결되지 않음
영수증 불러오기PF 코드나 영수증 번호로 조회. 샘플 휠 코드는 조회되지 않음
슬롯⁠·라이브 카지노게임사 별도 시스템. 게임사 인증서는 추후 추가 예정으로 표시

검증 자료는 스노우 휠 결과 화면, ‘내 주문 내역’의 ‘검증’, 보너스 마켓 › ‘내 휠 내역’의 ‘공정성 확인’에서 열립니다. 휠이 열리기 전이라 이 시트는 공개 시험 벡터로만 계산했습니다.