How it works
1. Two quantum sources
Qentro fetches 32 bytes from the vacuum-fluctuation generator of the Australian National University and 32 bytes from the public LfD QRNG service. Both raw response bodies are kept exactly as received. If one source is down, the launch can continue only with an explicit “1 of 2 quantum sources” warning. Non-quantum randomness is never substituted.
2. Derivation
A browser-side salt keeps the seed secret until you reveal it. Everything below is pure and deterministic.
anuBytes = concat(hex data) // 4 × 8 bytes = 32 bytes lfdrBytes = hex qrn // 32 bytes salt = crypto.getRandomValues(32 bytes) // keeps the seed secret until reveal seedBase = SHA-256(anuBytes || lfdrBytes || salt) seed_n = SHA-256(seedBase || uint32BE(n)) // n = 0, 1, 2, ... mint = Keypair.fromSeed(seed_n).publicKey // first n whose base58 ends with the chosen suffix commit = "qentro:v1 commit=<SHA-256(seedBase)> anu=<SHA-256(raw ANU body)> lfdr=<SHA-256(raw LfD body)> n=<n>" reveal = "qentro:v1 reveal mint=<mint> seedBase=<hex> salt=<hex>"
Suffix options are none, “q”, “Qu” and “Qnt” (case-sensitive). The expected number of tries is 58 to the power of the suffix length, ground in parallel Web Workers.
3. Commit before launch
The commit string is written as an SPL Memo inside the same transaction that creates the coin on pumpfun. The entropy is therefore fixed on-chain before anything is revealed.
4. Reveal
After the launch confirms, you sign a second tiny transaction that publishes the seed base and salt. The mint keypair has no authority over the coin after a pumpfun launch, so revealing its seed is safe.
Verify it yourself
import { Keypair } from '@solana/web3.js'
const hex = (b: Uint8Array) => [...b].map((x) => x.toString(16).padStart(2, '0')).join('')
const fromHex = (h: string) => Uint8Array.from(h.match(/../g)!.map((x) => parseInt(x, 16)))
const sha = async (d: Uint8Array | string) =>
new Uint8Array(await crypto.subtle.digest('SHA-256', typeof d === 'string' ? new TextEncoder().encode(d) : d))
const cat = (...p: Uint8Array[]) => Uint8Array.from(p.flatMap((x) => [...x]))
export async function verify(proof: any) {
const anu = fromHex(JSON.parse(proof.anuRaw).data.join(''))
const lfdr = fromHex(JSON.parse(proof.lfdrRaw).qrn)
const seedBase = await sha(cat(anu, lfdr, fromHex(proof.salt)))
const n = new Uint8Array(4)
new DataView(n.buffer).setUint32(0, proof.counter, false)
const kp = Keypair.fromSeed(await sha(cat(seedBase, n)))
return {
seedBaseOk: hex(seedBase) === proof.seedBase,
commitOk: hex(await sha(seedBase)) === proof.commitHash,
mintOk: kp.publicKey.toBase58() === proof.mint,
}
}