Timed Commitment
Assume that Alice wants to choose a secret s
, and reveal it after some time –
while guaranteeing that the revealed value corresponds to the chosen secret (or paying
a penalty otherwise). This can be obtained through a timed commitment, a
protocol with applications e.g. in gambling games, where the secret
contains the player move, and the delay in the revelation of the secret is intended
to prevent other players from altering the outcome of the game.
Intuitively, Alice starts by exposing the hash of the secret, i.e. h = H(s)
, and at
the same time depositing some amount deposit
in a transaction. The participant Bob
has the guarantee that after a date deadline
,
either he will know the secret s
, or he will be able to redeem the deposit
.
Firstly, we present this protocol from Alice’s point of view, that creates two transactions:
T_commit
commits the hash of her secret; T_reveal
is a transaction that spends it
revealing the secret.
Then we present Bob’s point of view. Bob wants to read the secret (no transaction is needed)
or he will publish a new transaction T_timeout
that spends T_commit
.
Alice’s view
Alice starts defining some constants:
fee
is the miner’s fee, i.e. the amount of bitcoins earned by the node that will mine the transaction;secret
andh
are the Alice’s secret and its hashed value respectively;deposit
is the amount of bitcoins that Alice will lose if she will not reveal her secret;deadline
is the deadline for revealing her secret.
// some constants
const fee = 0.00113 BTC // miner's fee
const secret = "42" // Alice's secret
const h = hash:73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049 // hash of the secret - sha256(secret)
const deposit = 10 BTC // Alice's deposit
const deadline = 2018-06-11 // deadline to reveal the secret
Funds
The timed commitment requires Alice to own an amount of money to use as a deposit. In Balzac, one can use real funds or simulate them via fake coinbase transactions.
For example, assume that there exists a transaction A_funds
on the blockchain and that
it has exactly one output script, which is a simple P2PKH (Pay to Public Key Hash)
for the public key kApub
of Alice.
// Alice's public key
const kApub = pubkey:03ff41f23b70b1c83b01914eb223d7a97a6c2b24e9a9ef2762bf25ed1c1b83c9c3
It is possible to refer the real transaction A_funds
declaring const A_funds = tx:TRANSACTION-HEX
.
However, if we don’t have a real transaction, we can create a fake coinbase transaction that behaves in the same way. This transaction cannot be really published on the blockchain, but it is useful to check if the transactions we are building are correct.
// tx with Alice's funds, redeemable with kA
transaction A_funds { input = _ output = deposit: fun(sigma) . versig(kApub; sigma)}
Now Alice owns a deposit
, stored in A_funds
, that she can pawn for the timed commitment protocol.
Commit and reveal
Once the transaction A_funds
is defined, either real or not,
Alice can create the transaction T_commit
that spends her deposit.
To do so, Alice use the private key kA
(from which kApub
is
derived) to create a valid signature sig(kA)
. This signature
is set as witness in T_commit
.
The transaction T_commit
looks like:
// Alice's private key
const kA = key:cSthBXr8YQAexpKeh22LB9PdextVE1UJeahmyns5LzcmMDSy59L4
// Bob's public key
const kBpub = pubkey:03a5aded4cfa04cb4b49d4b19fe8fac0b58802983018cdd895a28b643e7510c1fb
transaction T_commit {
input = A_funds: sig(kA)
output = input.value - fee:
fun(x,s:string) . sha256(s) == h && versig(kApub;x)
|| after date deadline : versig(kBpub;x)
}
Within this transaction Alice is committing the hash of the chosen secret:
indeed, h
is encoded within the output script of the transaction.
This transaction can be redeemed either by Alice by revealing her secret,
or by Bob, but only after the deadline
has passed.
This constraint is encoded in the script with the expression after date deadline : ...
.
Once the transaction T_commit
is on the blockchain,
Alice chooses whether to reveal the secret, or do nothing.
In the first case, she can create the transaction T_reveal
and put it on the blockchain.
Since it redeems T_commit
, she needs to provide the secret
and her signature,
so making the former public.
transaction T_reveal {
input = T_commit: sig(kA) secret
output = deposit - fee*2: fun(x) . versig(kA;x)
}
We can evaluate Alice’s transactions as follows.
eval T_commit, T_reveal
To sum up, the whole file is:
// some constants
const fee = 0.00113 BTC // miner's fee
const secret = "42" // Alice's secret
const h = hash:73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049 // hash of the secret - sha256(secret)
const deposit = 10 BTC // Alice's deposit
const deadline = 2018-06-11 // deadline to reveal the secret
// Alice's private key
const kA = key:cSthBXr8YQAexpKeh22LB9PdextVE1UJeahmyns5LzcmMDSy59L4
// Alice's public key
const kApub = pubkey:03ff41f23b70b1c83b01914eb223d7a97a6c2b24e9a9ef2762bf25ed1c1b83c9c3
// Bob's public key
const kBpub = pubkey:03a5aded4cfa04cb4b49d4b19fe8fac0b58802983018cdd895a28b643e7510c1fb
// tx with Alice's funds, redeemable with kA
transaction A_funds { input = _ output = deposit: fun(sigma) . versig(kApub; sigma)}
transaction T_commit {
input = A_funds: sig(kA)
output = deposit - fee:
fun(x,s:string) . sha256(s) == h && versig(kApub;x)
|| checkDate deadline : versig(kBpub;x)
}
transaction T_reveal {
input = T_commit: sig(kA) secret
output = deposit - fee*2: fun(x) . versig(kA;x)
}
eval T_commit, T_reveal
Bob’s view
Bob waits that T_reveal
is appended to the blockchain: if this happen within the deadline,
he can learn Alice’s secret
by inspecting the witness of T_reveal
.
Otherwise, he redeems Alice’s deposit by appending the transaction T_timeout
, specified below.
Once Alice publishes T_commit
, Bob can construct T_timeout
in the event she does not reveal her secret.
Bob needs:
the serialized transaction
T_commit
;the output script of the transaction
T_commit
.
The first condition is quite obvious, since we need to specify which transaction is T_timeout
spending.
One can specify T_commit
as follows:
const T_commit = tx:02000000010bb... // specify the transaction body
Note that T_commit
is public on the blockchain.
The second condition is more sneaky.
The output script of the transaction T_commit
is encoded as a P2SH (Pay to Script Hash)
since it contains complex expressions. It means that T_commit
stores
only the hash of the script and, in order to spend it,
the redeeming transaction must pass the corresponding script as witness.
In Balzac it is possible to specify the script enclosed within square brackets,
e.g. [fun(x) . x == 42]
, alongside the witnesses.
The example below shows how to create Bob’s T_timeout
transaction.
// some constants
const fee = 0.00113 BTC // miner's fee
const deposit = 10 BTC // Alice's deposit
const deadline = 2018-06-11 // deadline to reveal the secret
const h = hash:73475cb40a568e8da8a045ced110137e159f890ac4da883b6b17dc651b3a8049 // hash of Alice's secret
// Alice's commit transaction
const T_commit = tx:02000000010bbd1756430fdd65b55f02f135a1d657ef5742f4b0ae3f1aed10baedd53c5b20000000006b483045022100ef81428e14f58cf6bcf34bd169b2ebcfc90611aac00c900ec30ad9eea9792051022029870f1cc257e08b52db93339423451d2a2288e8aa4376137ff7f5795d75a3f9012103ff41f23b70b1c83b01914eb223d7a97a6c2b24e9a9ef2762bf25ed1c1b83c9c3ffffffff019810993b0000000017a914904be77bfb6521b19e7d7712a5214c61c951f1668700000000
// Alice's public key
const kApub = pubkey:03ff41f23b70b1c83b01914eb223d7a97a6c2b24e9a9ef2762bf25ed1c1b83c9c3
// Bob's public key
const kBpub = pubkey:03a5aded4cfa04cb4b49d4b19fe8fac0b58802983018cdd895a28b643e7510c1fb
// Bob's private key
const kB = key:cQtkW1zgFCckRYvJ2Nm8rryV825GyDJ51qoJCw72rhHG4YmGfYgZ
transaction T_timeout {
input = T_commit: sig(kB) "" [fun(x,s:string) . sha256(s) == h && versig(kApub;x) || checkDate deadline : versig(kBpub;x)]
output = input.value - fee: fun(x) . versig(kB;x)
absLock = date deadline
}
eval T_timeout