Exponential ElGamal
Each stake is encrypted before it ever reaches the chain. The scheme is ElGamal on the BabyJubJub curve, in its exponential form:m is your stake, r is fresh randomness you pick per bet, G is the curve’s generator
and H is the committee’s public key.
The ciphertext is two curve points. Nothing about m is recoverable from them without the
committee’s secret.
Fresh randomness per bet matters. Two bets of the same size encrypted with the same
r would
produce identical ciphertexts, and identical ciphertexts on-chain would say “these two stakes
are equal” — a leak with no cryptography involved. The circuit refuses r = 0 and the client
draws a new one each time.Why it adds
The useful property is that ciphertexts add:Enc(total) — having never seen
a single stake.
The accumulator contract holds ciphertext and has no decryption capability whatsoever. It is
not that it declines to decrypt — it does not possess the key, and the key is not on the chain.
The proof that ties it together
A ciphertext on its own proves nothing. You could encrypt 1,000,000 while spending a note worth 10. So the bet proof establishes, in zero knowledge, that:- you own an unspent note in the tree, and
- the ciphertext you published is an encryption of exactly that note’s value
This is the step where privacy would quietly break in an obvious implementation. Making the
amount private removes it from every check the contract used to perform, so each of those
checks has to move into the circuit. A guard that silently stops applying is worse than one
that was never written.
Recovering the number
Decryption gives back[m]G — the message multiplied by the generator — not m itself.
Recovering m from [m]G is the discrete logarithm problem, which is hard in general.
It is tractable here only because stakes are bounded. The publisher uses baby-step
giant-step, which costs about √bound operations: a pool of tens of millions is recovered in a
few thousand steps, in milliseconds.
That bound is not an accident. Every circuit range-checks values to 40 bits precisely so that
decryption stays feasible. An unbounded plaintext would be encrypted perfectly well and then be
unrecoverable forever.