Proof, without the theatre

What you can verify

Rugpull is a middleman. Here is the clean line between public fact and a promise you still have to trust.

Public fact

The draw is verifiable.

Your deposit, ticket, round commitment, and result are public Bitcoin facts. Anyone can replay the draw.

Review the Luckotto proof ↗
Private promise

The payout requires trust.

Rugpull signs the voucher before payment. That proves the terms, but it cannot force us to pay or prove we are solvent.

Signing key

ed25519 public key (hex)

bcaa31caecca78f07f547e437d19da3b3139b8776749c90003ccca23ccd6aad3

also served as json at /api/claim-key. save it somewhere we cannot edit.

Canonical message

every voucher signs exactly this shape, joined with newlines, utf-8:

RUGPULL VOUCHER v9
claim-hash: <sha-256 of your secret, 64 hex>
deposit-address: <your bitcoin deposit address>
tiles: <your 6 tiles, space-separated, ascending>
credit-factor: 0.9
issued-at: <utc timestamp>
terms: rugpull.com promises to pay this voucher's Luckotto winnings to whoever proves knowledge of the secret whose SHA-256 equals claim-hash.

Verify a voucher file

The file is checked entirely in this browser and is not uploaded. The check covers the signature and consistency of every signed voucher field.

Verify offline

from the folder holding your downloaded voucher file (fix the filename), with node installed. no network, no rugpull:

node -e 'const v=require("./rugpull-voucher-XXXXXXXX.json");const {createHash,createPublicKey,verify}=require("node:crypto");const issued=v.message.match(/^issued-at: ([^\r\n]+)$/m)?.[1];const message=["RUGPULL VOUCHER v9","claim-hash: "+createHash("sha256").update(v.secret).digest("hex"),"deposit-address: "+v.depositAddress,"tiles: "+v.tiles.join(" "),"credit-factor: 0.9","issued-at: "+issued,"terms: rugpull.com promises to pay this voucher\u0027s Luckotto winnings to whoever proves knowledge of the secret whose SHA-256 equals claim-hash."].join("\n");const pub=createPublicKey({key:Buffer.from("302a300506032b6570032100"+"bcaa31caecca78f07f547e437d19da3b3139b8776749c90003ccca23ccd6aad3","hex"),format:"der",type:"spki"});const genuine=v.v===9&&issued&&v.message===message&&verify(null,Buffer.from(v.message,"utf8"),pub,Buffer.from(v.signature,"base64"));console.log(genuine?"genuine":"forged or damaged")'

the hex prefix is the der/spki header for ed25519; the rest is the public key above. this checks the signature and all voucher fields, then prints genuine only when both agree.

What “genuine” means

A genuine result proves Rugpull signed the exact canonical message and that the voucher file's secret, address, tiles, claim hash, and issue time agree with it. Nobody — including us — can quietly swap those fields without the verifier rejecting the file.

it does not prove rugpull is solvent, honest, or alive. no coins are locked behind it, and no contract enforces the payout. if we vanish, the signature is evidence for shaming us, not a key for paying you. size your deposits accordingly.