JavaScript is optional. Read each open request and replay instruction below; they include the complete manual path.
Saved walkthrough progress is ready to resume in this tab.
Guided commit-reveal integration
Make the promise first.
A public fingerprint is made before the draw settings are chosen. Save the returned record; it makes later changes easy to spot.
- Commitment ID
- Created by POST /api/commit
- Server hash
- Published before client input
- Expires
- Reveal within the returned TTL
Developer example: create the commitment
curl -X POST "https://api.provable.io/api/commit"const response = await fetch("https://api.provable.io/api/commit", {
method: "POST"
});
const commitment = await response.json();
// Save this complete JSON record before choosing clientSeed, min, or max.
console.log(JSON.stringify(commitment, null, 2));Choose what everyone can see.
Your client seed is simply a phrase you choose. It appears in the proof alongside the inclusive range.
Count: 1 result. This walkthrough intentionally makes one draw.
Create a commitment first, then review these values.
Check, then reveal.
Review the request before sending it. A successful reveal uses this commitment once and cannot be repeated.
For the manual request, replace COMMIT_ID with the saved commitment’s commitId, and use your agreed clientSeed, min, and max. Send it before expiresAt. Save the entire response; a second successful reveal is not possible.
Client seed: summer-draw-24 · Count: 1 result · Range: 1–100 inclusive
This uses the commitment once. Do not reveal until everyone accepts these visible values. An unused expired commitment must be restarted.
One result from the locked inclusive range.
Developer example: reveal the result once
curl -X POST "https://api.provable.io/api/reveal" \
-H "Content-Type: application/json" \
-d '{"commitId":"COMMIT_ID","clientSeed":"summer-draw-24","endpoint":"ints","params":{"count":1,"min":1,"max":100}}'const response = await fetch("https://api.provable.io/api/reveal", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
commitId: "COMMIT_ID",
clientSeed: "summer-draw-24",
endpoint: "ints",
params: { count: 1, min: 1, max: 100 }
})
});
const proof = await response.json();
console.log(JSON.stringify(proof, null, 2));Open the complete proof JSON returned by /api/reveal
After /api/reveal, save the complete JSON response here. Use its exact values below; do not shorten or reconstruct the proof.Now check it yourself.
Your browser checks the original commitment and recalculates the number. A server lookup does not replace these local checks.
One result from the locked inclusive range.
Open the exact proof JSON used for verification
After /api/reveal, save the complete JSON response here. Use its exact values below; do not shorten or reconstruct the proof.Replay this exact proof in Node.js
Save the complete commitment response as commitment.json before choosing inputs, and the full reveal response as proof.json. Save the script below as replay-proof.mjs, set its three locked inputs to the values you recorded before reveal, then run:
npm install @provableio/provable-core
node replay-proof.mjsimport assert from "node:assert/strict";
import crypto from "node:crypto";
import { readFileSync } from "node:fs";
import { Provable } from "@provableio/provable-core";
const commitment = JSON.parse(readFileSync("commitment.json", "utf8"));
const proof = JSON.parse(readFileSync("proof.json", "utf8"));
// Insert the inputs you independently recorded before reveal.
const lockedClientSeed = "summer-draw-24";
const lockedMin = 1;
const lockedMax = 100;
assert.equal(proof.commitId, commitment.commitId);
assert.equal(proof.serverHash, commitment.serverHash);
assert.equal(proof.endpoint, "ints");
assert.equal(Number(proof.count), 1);
assert.equal(proof.clientSeed, lockedClientSeed);
assert.equal(proof.min, lockedMin);
assert.equal(proof.max, lockedMax);
assert.equal(
crypto.createHash("sha256").update(proof.serverSeed).digest("hex"),
commitment.serverHash
);
const replayed = Provable(() => {})({
serverSeed: proof.serverSeed,
clientSeed: proof.clientSeed,
cursor: proof.cursor,
nonce: proof.nonce
}).ints(1, proof.max - proof.min + 1, proof.min);
assert.deepEqual(replayed, proof.outcome);Optional record lookups
Lookup confirms server records; it is not a local check.