Intro
In this document, I’ll describe a protocol for a provably fair Bitcoin lottery in which players can pay into the jackpot using Lightning. If everyone cooperates, the winner can even receive their prize using Lightning too. This enables large scale federated lotteries with very low barriers to entry, and highly flexible ticketing systems, where 1 satoshi paid into the jackpot is literally equivalent to one ticket in the lottery. Players maintain total anonymity from one-another.
The lottery’s jackpot capital is backed on-chain by a market maker. The market maker is trusted, but verifiable: While the market maker could choose to award the jackpot to the wrong player (collusion is possible), any other honest player can immediately recognize this misbehavior, and publish a non-interactive fraud proof to warn others.
The market maker can publish irrefutable proofs demonstrating they picked winners fairly, and can commit himself to a deadline, where he must award the jackpot by a given block height, or else be financially punished.
Given more advancements in BitVM, it could even be possible for the market maker to commit himself to honest winner selection, allowing players to financially punish the market maker for choosing a winner dishonestly.
Prerequisite Knowledge
- Elliptic curve math basics
- Merkle trees
- MuSig
- Adaptor signatures
- Point-time lock contracts
- Hash-time lock contracts
How?
Paying a Lightning Network invoice is essentially an exchange of money for a secret. Exposing one secret can do a lot if we set things up carefully.
My approach will be to construct a scenario where a prospective player - someone who wants to buy into the lottery - need only pay a Lightning invoice in exchange for the market maker revealing a secret, called a ticket. The buyer can verify that, upon receiving the ticket, she can always claim jackpot (if she also wins). If a player wins but cannot present a valid ticket, the jackpot is returned to the market maker.
The winner is chosen based on a value which nobody can predict, but everyone can (eventually) agree on: A verifiable hash of a Bitcoin block at a pre-defined block-height in the future. For additional randomness, the winner hash is salted with the various parameters of the lottery, such as public keys and tickets.
By consulting the Bitcoin blockchain, players can verify who the correct winner is, and whether they were paid. If the market maker misbehaved and awarded money to the wrong player, then honest players can publish an irrefutable fraud proof, proving the market maker acted dishonestly.
Lottery Registration
The market maker has a long-lived static public key
To initiate a lottery, the market maker generates a random nonce
, and publishes the public nonce , with which he will later sign the lottery outcome. Alongside
the market maker publishes lottery metadata, such as: - the settlement block height
- the block whose hash will be used to compute the winner. - the locktime delta,
, which is some block delay during which a transaction can confidently confirm, e.g. 144 blocks (~24 hours). - the price per ticket (or price range, if applicable).
- minimum/maximum number of players.
- assorted implementation-dependent context info about the lottery.
- the settlement block height
A player who wishes to join a lottery pays a small deposit using a lightning invoice.
- The deposit covers the cost of on-chain transaction fees by the market maker, and prevents DoS attacks.
- Its value will be factored into the cost of the ticket, and depends on various factors like the on-chain fee market conditions, the size of the jackpot, the price of the ticket, and the minimum number of players in the lottery.
- It should be as small as possible, because paying the deposit does not assure the player they can participate in the lottery.
The set of players in a lottery are identified by their public keys
, where is the number of players. - Players’ pubkeys should be ephemeral, used only once per lottery (for privacy).
- Each player
specifies some satoshi value which they want to pay into the lottery. Each satoshi paid is one chance of winning. More sats = more chance of winning. - Under this protocol, the set of players and their ticket values must be fixed before the lottery can officially begin.
- Players’ public key keys should be arranged in some canonical sorting order, such as lexicographical order, so that each player is assigned a unique integer index.
Each player
generates a random salt , which they provide to the market maker. The salt ensures a player’s ticket value cannot be guessed and analyzed by outside observers. The market maker generates a fairness secret key
, and computes its public key . This will be used to derive a provably fair lottery winner later. The market maker generates a random set of secret tickets, one for each player:
. The market maker publishes to all players in the lottery:
- The set of public keys
- The public tickets
- The ticket prices
- All player salt values
- The fairness pubkey
.
- The set of public keys
Players verify that the salt value, pubkey, and ticket price they requested were not changed by the market maker.
Everyone uses the ordered set of ticket prices to compute the win-windows
. - Win-windows are used for weighted winner selection (the more you pay, the better your chances of winning).
- Each player’s win-window
is a tuple of two numbers, , where is simply the sum of all preceding ticket values, i.e. , and . - In other words, a win-window describe an interval which is as wide as the value
of the lottery ticket that the player intends to purchase. Win-windows do not overlap. Specifically, they describe the range . - Win-windows must be committed to explicitly, to allow fair-winner verification without revealing the ticket prices of any other players.
The total jackpot value can be computed as the sum:
- Players and the market maker independently compute a special merkle tree unique to this lottery, which is used for post-lottery fraud proofs and audits. The structure of this merkle tree allows for independent verification of almost any facet of a lottery, while exposing only a minimum of information.
First they compute the ticket node hashes
- Each ticket node hash
is the root of a special merkle tree built from player-specific parameters: - Pubkey
- Ticket
- Ticket price
- Win-window
- Salt
- Pubkey
- The ticket node hash supports membership checks for any one or more of these parameters, without revealing (or allowing guessing of) the remaining parameters.
The salt
The ticket node hashes are combined to form the ticket merkle tree root
- This is the root of a merkle tree committing to all the ticket node hashes
. - Each ticket node hash
is a leaf in the tree at index .
Using merkle tree membership proofs within
- The pubkey
was a participant in this lottery. - The ticket
was issued for this lottery. - A ticket with a given price
was issued for this lottery. - A ticket with win-window
was issued for this lottery.
Any such statement can be proven independently, or in tandem with one-another. This will be crucial for proving misbehavior later.
Finally, parties can compute the lottery root hash
. is the hash where: is the fairness pubkey. is the nonce which will be used to sign a winner. is the settlement block height.
will be unique for any given lottery.
All parties compute a set of
outcome points, , one for each possible winner:
- Each
represents a public key which the market maker promises to unlock if player wins this lottery, by revealing its discrete log . Only the market maker has the power to do this. - The idea is similar to Discreet Log Contracts. It discourages equivocation: If the market maker signs two different players as the winners with the same nonce
and key , he reveals his long-lived secret key , which discredits the market maker completely. - Every outcome point
will be used in concert with the ticket to guard the outcome where player wins the lottery.
- All parties compute their joint pubkey,
using MuSig’s key aggregation algorithm on . This creates a multisignature pubkey which is jointly controlled by all players and the market maker.
At this point, all participants have what they need to start signing transactions for the on-chain lottery contract.
Lottery Signing
The market maker creates the lottery init transaction
which pays the whole jackpot value (fronted by the market maker) to a Taproot address of , tweaked with the lottery root hash . - Specifically,
pays satoshis to the tweaked pubkey . This output is called the jackpot output. - The tweak with
allows the participants to later prove that this jackpot output was associated with a particular lottery.
- Specifically,
The market maker constructs a set of mutually exclusive transactions which spend from the jackpot output. There are different spending paths for every possible outcome.
- A set of
outcome transactions, . - Each outcome transaction
spends the full balance of the jackpot output, paying to a 2-of-2 multisig address, owned by the market maker and a player . - Each must have an absolute locktime of at most height
.
- Each outcome transaction
- A set of
reclaim transactions, . - One of these transactions will be used if a player registers, but fails to pay for a winning ticket. Unpurchased tickets will be treated as being owned by the market maker. If a player
wins the lottery but can’t claim their prize because they didn’t buy their ticket secret , then the market maker will use to reclaim the jackpot. - Each must have a relative locktime of at least
blocks.
- One of these transactions will be used if a player registers, but fails to pay for a winning ticket. Unpurchased tickets will be treated as being owned by the market maker. If a player
- A set of
winner transactions, . - One of these transactions will be used by an authentic winner to claim their jackpot on-chain using a ticket purchased from the market maker.
- A set of
The market maker sends the following unsigned transactions each player
in the lottery: - The init transaction
- All outcome transactions
- The reclaim transaction
- The winner transaction
- The init transaction
Every player verifies:
: - pays at least
satoshis to the correct taproot address , and - has a locktime which is less than or equal to the current block height.
- pays at least
- Every
: - spends the jackpot output from
, - pays the entire balance to a 2-of-2 address owned by
and the market maker’s key , - has a reasonable fee rate, and
- has a locktime which is at most
.
- spends the jackpot output from
: - spends the output of
, and - has a relative locktime of at least
.
- spends the output of
: - spends the output of
, - pays the entire balance to
, and - has a relative locktime of at most
.
- spends the output of
If any of the above conditions fail, the player aborts.
- In response, each player
provides the market maker with a set of MuSig partial signatures: - on all outcome transactions
- on their specific reclaim transaction
- on their specific winner transaction
- on all outcome transactions
MuSig nonces can be pre-shared after the registration stage, for greater efficiency.
- The market maker aggregates MuSig signatures on all transactions:
…but he does NOT publish any transaction or its plaintext signature.
At this stage, the market maker is holding all the the signatures on all transactions. He could broadcast
Here is a diagram of the structure of the pre-signed transactions now held by the market maker.
Let’s see how he can convince players to start paying into the lottery.
How to Make Tickets Valuable
- The market maker uses an adaptor signature scheme to encrypt the final aggregated signatures on all of the outcome and winner transactions.
- Each
signature is encrypted under the point . - Each
signature is encrypted under the ticket point . - If using hash-locks instead of point-locks, then the output of
must instead be encumbered by an HTLC, which requires knowledge of the ticket preimage .
- If using hash-locks instead of point-locks, then the output of
- The market maker computes a fairness hint
. - This means:
- If you have the adaptor-signed
: - if you learn
, then: - you can use the hint
to compute , and - you can decrypt the signature and broadcast
.
- you can use the hint
- if someone publishes a valid
, then you immediately learn , and can use the hint to compute .
- if you learn
- If you have the adaptor-signed
and you learn the ticket , then you can decrypt the signature and broadcast the transaction. - If using hash-locks, you can claim the output of
once you learn the preimage .
- If using hash-locks, you can claim the output of
- If you have the adaptor-signed
- Each
The core idea is, in order to claim the jackpot on-chain, a player needs to know their corresponding outcome secret
The market maker distributes all of these adaptor signatures and hints to every player.
- It is important that every player receives a full set of all outcome transactions
, and their adaptor signatures, not just the signature for their own preferred outcome transaction. This is necessary for players to be able to build fraud proofs later. - Along with each adaptor signature on
, the market maker sends the fairness hint . The hint is essential because it enables players to learn from the decrypted adaptor signature, which is also crucial for fraud proofs.
- It is important that every player receives a full set of all outcome transactions
Players verify the adaptor signatures given by the market maker, and abort if any are not vaild. A hint
can be verified by confirming . Once all players have confirmed their adaptor signatures are correct, the market maker can sign and publish
. The on-chain lottery contract is now live.
If a player stops cooperating at any time before the
Ticket Sales
At this stage, each player has valid adaptor signatures for every possible outcome transaction
Each player also has verified that the money locked into the escrow contract by
If the market maker decides to sign the player’s index and publish
That is, unless the player can learn the ticket secret
By publishing
Players should not buy tickets after height
Counterparty Risk
Any tickets which have not been purchased by a player by block height
By fronting the jackpot value himself, the market maker takes on counterparty risk. A player who puts down a deposit but doesn’t pay for a ticket is effectively forcing the market maker to buy into the lottery, even though he may not wish to participate himself. For a market maker who runs many lotteries, this risk will balance out over time, especially since each player who forfeits their deposit is paying for it each time.
A market maker who does not wish to bear this risk or would prefer not to timelock their liquidity could use HODL invoices to refund players’ tickets and deposits automatically if not enough players buy in.
Future research could also seek out a robust protocol variant which allows the lottery to continue (with a smaller jackpot) even if some players refuse to purchase their tickets.
Winner Choice
Once block
Remember our fairness secret key
A naive design might use a hash of
The core problem is that nobody, not even the market maker, should be able to predict the outcome in advance. However, everyone (including passive observers) should be able to verify the outcome was fair. Does anyone know of a random number generator whose output everyone can agree on, but nobody can predict in advance?
Block Hashes
The hashes of Bitcoin blocks are determined by miners, but miners cannot easily pick and choose block hashes without enormous physical energy expenditure. Most miners will publish the first block they can mine successfully. After the first nbits
of leading zeros in the block hash, the remaining bits are effectively random, since they’re the output of SHA256.
Because nobody can effectively predict block hashes more than one block in the future, we can use block hashes to salt the outcome which determines the winner of the lottery. Let
The market maker should wait for block height
The distribution of
This diagram illustrates the various data points which go into selecting
The only agent able to predict or influence
The fairness secret
The actual winner’s index
Settlement
The winning player
Alternatively, if the player prefers to receive their jackpot with an on-chain transaction (or if the jackpot is too large for a lightning payment), then they can cooperate with the market maker to sign a new winner transaction
If the market maker does not cooperate, the winner can simply wait for the relative locktime on the original
Incentivizing an Unresponsive Market Maker
There is still one gap in the protocol: Handling a market maker who goes completely offline after everyone purchases their tickets.
The market maker is the only agent who can unlock the outcome transactions. If he goes dark once block
To prove his intent to cooperate, the market maker can commit extra collateral to the lottery, forcing himself to reveal one of the outcome secrets shortly after the settlement height
This collateral output should be added as a second output to
Except, unlike the jackpot output which is solely a multisig address, the collateral output address encodes a spending condition in a tapscript leaf which allows anyone to take the collateral at block height
From the collateral output, players sign an acceptance transaction,
The market maker must not provide different encryptions of the same signature on
Fees
As an alternative or auxillary inducement to publish an outcome, the market maker could charge a fee to the winner of the lottery, splitting the jackpot output at the winner transaction stage
Succinct Fairness/Fraud Proof
This lottery protocol is not entirely trustless, as the market maker has the sole ability to determine which of the players receives the jackpot money. However, all the complexity described above is designed to assure players that, in the event of cheating by the market maker, they can construct an irrefutable proof that the market maker cheated. The market maker can similarly prove irrefutably that a lottery was executed honestly and fairly.
A succinct fairness/fraud proof consists of the following pieces of data:
- The settlement block height
- The fairness secret key
- The expected winner’s index
- The index of the actual winner
(the one signed by the market maker) - If
, then the proof asserts fairness. - If
, the proof asserts fraud.
- If
- The TXID of the published outcome transaction
- The expected winner’s win-window
- The actual winner’s win-window
- The actual winner’s pubkey
- The expected winner’s ticket node hash
- The actual winner’s ticket node hash
- The ticket merkle root hash
- A proof that the expected winner’s win-window
is a member of - A proof that the actual winner’s win-window
is a member of - A proof that both ticket node hashes
and are members of the ticket merkle root - The outcome signature pair
attesting to player as the winner
Verifying A Fairness/Fraud Proof
A verifier who already knows the market maker’s signing key
- Verify the proof the win-window
is a member of - Verify the proof the win-window
is a member of - Verify the proof the ticket nodes
and are members of - Verify that
and are indeed at their expected indexes and among the merkle tree leaves of - Compute the fairness pubkey
- Look up the outcome transaction
on the blockchain to learn the jackpot output value . - Compute the lottery root hash
- Verify the outcome signature
: - Look up the block hash
of the block at height - Compute the winning satoshi index
- Verify that
is within in the win-window - Verify that
pays the jackpot to the MuSig aggregated pubkey
If any of the above verification steps fail, then the proof is invalid. Whether it was trying to assert fraud or fairness, its claim cannot proven true or false based on this proof.
If all of the above verification steps pass, then the proof is authentic. It confirms:
- the market maker chose the player at index
as the winner and awarded the jackpot to them. - the player at index
should have won this lottery
Whether the proof demonstrates fairness or fraud depends on whether
- If
, then the proof irrefutably demonstrates the market maker awarded the jackpot to the correct winner. - If
, then the proof irrefutably demonstrates the market maker cheated by awarding the jackpot to the wrong winner.
Keep in mind that although a fairness proof demonstrates a lottery was conducted fairly, this proof cannot demonstrate that the players involved in the lottery were independent agents. The entire proof could be staged quite easily by the market maker to create the illusion of lottery volume. The lottery could have been the market maker buying tickets from himself, paying himself, playing around with his own money in a sandbox. It does not prove money actually changed hands.
Privacy
Let’s assume the best case scenario: The entire lottery went smoothly, a valid ticket-holding winner was chosen, and the jackpot was paid off-chain through a lightning invoice. We’ll examine what can be seen or verified by passive observers. What does the lottery’s audit trail look like?
If you don’t know anything about a specific lottery and are just dragnet-scanning transactions on the blockchain, you won’t be able to distinguish a successful lottery transaction from a normal payment transaction, except for the fact that taproot addresses are used.
You might be able to identify that a lottery occurred and its jackpot value, provided you can identify the UTXOs controlled by a market maker. But you won’t be able to tell how many players there were, nor how much each player paid into the jackpot.
As the winner used a cooperative off-chain withdrawal, then you also won’t be able to identify the ultimate destination of funds.
On-chain, all you see is:
which creates the jackpot at a taproot address, followed by which key-spends the jackpot to another taproot address, followed by which key-spends the jackpot to someone, possibly the market maker or possibly the winner.
In cases where a forceful resolution was required, you might be able to identify (based on the nSequence numbers in
If presented with a valid fairness/fraud proof, you will be able to see how much the correct winning player paid for their ticket, but you won’t learn exactly how much the other players paid. You might gain a slight idea of how many players there were overall (by noting the depth of the merkle tree used for the ticket root hash
Generalizing for DLCs
This off-chain ticketing protocol could be generalized to work with any Discreet Log Contract, not just random lotteries. A single untrusted market maker could provide on-chain capital for a DLC funded off-chain by many independent players. The market maker could even be one of the players themselves.
To generalize this principle to any DLC, the market maker sets up an
The market maker deposits the DLC capital into escrow. Each player pays for a ticket to the DLC, without which they would be unable to claim their share of the winnings (whatever the outcome might be).
The outcome and payout transactions can be constructed with timelocks such that if players cooperate with the market maker, they can receive their payouts privately off-chain, or via CoinSwap.
Throughout this process, the market maker would be fully untrusted, with trust only needed for the DLC oracle itself. All of it would be verifiable off-chain by the participants.
Future Work
- To reduce counterparty risk, the market maker could require that all players buy tickets, utilizing lightning HODL invoices to refund ticket payments in cases where not all players cooperate. The DLC or lottery could then proceed excluding the players who didn’t pay their invoices.
- Market makers could use CoinSwap to make on-chain withdrawals more private, breaking the link between the jackpot output and the actual prize payment.
- A market maker could set up a zero-knowledge lottery where players never learn each others’ ticket prices. In such a setup, only the correct winner could prove fraud if the market maker misbehaves.
- Could the need for an initial deposit be removed? Could the deposit be used to buy some secret that contractually assures a player the right to participate in a lottery?
- The market maker who provides the capital could be fully decoupled from an oracle who signs bits of the latest block hash. This would turn the market maker into a fully untrusted entity who simply provides capital, while the actual outcome of the lottery would be decided by an blind oracle, who isn’t privy to the details of every lottery.
More research is needed to solidify these ideas.
Notation Reference
Variable | Meaning |
---|---|
The secp256k1 curve generator point | |
Market maker’s secret key | |
Market maker’s public key | |
The market maker’s secret signing nonce for a lottery | |
The market maker’s public signing nonce for a lottery | |
The pubkey for player index |
|
The ticket secret (or preimage) for player |
|
The public ticket point (or hash) for player |
|
The ticket salt for player |
|
The price of the ticket for player |
|
The win-window for player |
|
The total jackpot output value | |
The ticket node hash for player |
|
The ticket root hash for all players; The merkle tree root of all |
|
The lottery root hash; Identifies the whole lottery and all players therein | |
A reasonable block delay to allow a transaction to confirm (e.g 144 blocks) | |
The initialization transaction, which creates the escrowed jackpot output | |
The outcome transaction for the outcome where player |
|
The reclaim transaction for outcome |
|
The winner transaction for outcome |
|
The final block hash of the block at height |
|
The index of the winning satoshi; Used to select the winner among the win-windows | |
The outcome secret needed for player |
|
The public outcome adaptor point for player |