Skip to content

VRF (Verifiable Random Function)

Our gacha machines use a Verifiable Random Function (VRF) to ensure every pull is provably fair and tamper-proof. Neither the server nor the user can manipulate the outcome - and anyone can verify this independently.

How it works

The VRF combines entropy from both the server and the client to generate a deterministic, verifiable random number. Here’s the complete flow:

sequenceDiagram
  participant User
  participant Client App
  participant Server
  participant Blockchain

  User->>Client App: Initiate gacha pull
  Client App->>Server: Request new pull session
  Server->>Server: Generate initialEntropy (nanoid)
  Server-->>Client App: Return pullId + initialEntropy
  Client App->>Client App: Generate clientEntropy (random)
  Client App->>Blockchain: Send payment with pullId|clientEntropy
  Blockchain-->>Server: Payment confirmed
  Server->>Server: Combine & sign entropy
  Server->>Server: Hash → finalEntropy
  Server->>Server: Convert to random number [1-10000]
  Server->>Server: Select prize based on tier ranges
  Server-->>Client App: Return prize + VRF proof data
  Client App->>Client App: Verify signature & hash integrity
  User->>User: Can independently verify result

The VRF process step-by-step

1. Initial entropy (server-side)

When you initiate a gacha pull, the server generates a random 10-character string using nanoid. This is committed to the database before you make your payment, preventing the server from changing it later.

2. Client entropy (your side)

Your device generates its own random data. This entropy is included in your payment transaction on the blockchain, creating an immutable record that the server cannot alter.

3. Combined entropy

The two entropy sources are concatenated:

combinedEntropy = initialEntropy + clientEntropy

4. Signed combined entropy

The server signs the combined entropy using Ed25519 (via TweetNaCl):

signedCombinedEntropy = Ed25519.sign(combinedEntropy, serverSecretKey)

This signature proves the server processed your specific entropy values.

5. Final entropy

The signature is hashed using SHA-256 to produce the final entropy:

finalEntropy = SHA256(signedCombinedEntropy)

6. Random number generation

The final entropy is converted to a number in the range [1, 10000]:

randomNumber = (BigInt(finalEntropy) % 10000) + 1

This gives us a uniformly distributed random number with 0.01% precision.

7. Prize tier selection

The random number maps to prize tiers based on configured probability ranges. Each gacha machine has its own tier configuration.

Why this is fair

flowchart TD
  subgraph ServerCantCheat ["Server Cannot Cheat"]
      A[Initial entropy committed<br/>before payment] --> B[Cannot change after<br/>seeing client entropy]
  end

  subgraph UserCantCheat ["User Cannot Cheat"]
      C[Client entropy in<br/>blockchain transaction] --> D[Cannot change after<br/>seeing initial entropy]
  end

  subgraph Deterministic ["Result is Deterministic"]
      E[Same inputs always<br/>produce same output] --> F[Anyone can verify<br/>the calculation]
  end

  B --> G[Fair Result]
  D --> G
  F --> G

Server cannot manipulate results because:

  • Initial entropy is committed to the database before you pay
  • The server doesn’t know your client entropy until after commitment
  • Changing anything would invalidate the cryptographic signature

Users cannot manipulate results because:

  • Client entropy is embedded in the blockchain transaction
  • Once submitted, it cannot be changed
  • The server’s initial entropy is already fixed

Results are verifiable because:

  • All entropy values are returned to you after the pull
  • The public key for signature verification is published
  • Anyone can reproduce the exact calculation

Verifying your results

After each gacha pull, you receive the complete VRF proof data:

  1. Initial Entropy - The server’s random string (committed before your payment)
  2. Client Entropy - Your random data (from the blockchain transaction)
  3. Signed Combined Entropy - Server’s Ed25519 signature
  4. Final Entropy - SHA-256 hash of the signature
  5. Random Number - The derived number [1-10000]
  6. Prize Tier - Which tier your roll landed in

The app automatically verifies:

  • ✓ The signature matches the public key
  • ✓ The hash of the signature equals the final entropy
  • ✓ The random number calculation is correct

You can also verify manually using any Ed25519 and SHA-256 implementation.

Technical specifications

ComponentImplementation
Initial entropynanoid(10) - 10-character random string
Signature algorithmEd25519 (TweetNaCl)
Hash functionSHA-256
Random range[1, 10000] inclusive
Precision0.01% (100 basis points)

Public key

The VRF public key for signature verification:

i5ScBBvmGh6my9B/X+NpcUIlvRSWz7+U8M7/GprNzYk=

This is a 32-byte Ed25519 public key encoded as base64. To use it for verification, decode from base64 to get the raw bytes, then use any Ed25519 implementation (such as TweetNaCl) to verify signatures against this key.