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.
In the timed commitment below, Alice commits a secret of hash b472a266d0bd89c13706a4132ccfb16f7c3b9fcb
,
and has until block 1550000 to reveal it. After block 1550000 is appended to the blockchain,
Bob can redeem Alice’s deposit.
#lang bitml
(participant "A" "0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1")
(participant "B" "034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809")
(define (txA) "tx:0200000001c75e1b501f7a1691b16d06398b4235ab35e11ccda3c3f9160d68739c84d435ed00000000e4483045022100ad5f0022e6ae8e789a97ca9497b8d307690b96ddbfcdf822711b1983b328d26702204f276374584292322c1ad33dc7b67600673ace464e9c60990de7a0123933803c014730440220055c42ae93321b4061055c782be11d3392c84ff34b1d4fbbe3a9e208f63518170220231d7712a4d36e5397264bfc8db89fd1d13d64937ee886fb9872f260bf979760014c516b6b006c766c766b7c6b5221034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809210339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe152aeffffffff01d5ea0600000000001976a914ded135b86a7ff97aece531c8b97dc8a3cb3ddc7488ac00000000@0")
(define (txFee) "tx:02000000013ea7dd4d036b9a3048992e9c7e4b8c054e7949d08d233005aa79c50ee92ff0a800000000e3483045022100f956e4b07562a209662b42ab0b6d26784de59470d992a542c207e74bf03776d5022071a5089744aa25316d29cb9d1e9bd28f5f50eba6c2c5b57177bf0a17c35308a601463043021f26ce5a6c343fcb5edf3a06dbb95006cbf063393ec7b5beebd16e2c8120c059022015c4afec46a1c04d1dcfbf8e414d9f83d0a008c91b1a96f6b499edec2b8d1d48014c516b6b006c766c766b7c6b5221034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809210339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe152aeffffffff01d5ea0600000000001976a914ded135b86a7ff97aece531c8b97dc8a3cb3ddc7488ac00000000@0")
(debug-mode)
(contract
(pre (deposit "A" 0.00453333 (ref (txA)))
(fee "A" 0.00453333 (ref (txFee)))
(secret "A" a "b472a266d0bd89c13706a4132ccfb16f7c3b9fcb"))
(choice (reveal (a) (withdraw "A"))
(after 1550000 (withdraw "B")))
(check-liquid))
Alice’s view¶
Alice opens the Balzac Online Editor,
and pastes the output of the compiler.
She starts computing her signatures, by first defining her public key privA
,
then putting sig(privA)
where the compiler requires her signatures.
She also puts the value of her secret 00000000...001
.
Then, she evaluates her signatures, using eval sig(privA) of Tinit@0, ...
at the bottom of the file, and sends them to Bob.
Bob does the same, so Alice receives his signatures and puts them
in the constant declarations sigBT1
, sigBT3
, sigBT3
.
Now all the transactions are completed and Alice can evaluate them,
and send to the Bitcoin network Tinit
to start the contract,
T1
to reveal the secret, and T2
to redeem her deposit.
After T1
added to the blockchain, is not possible to publish
T3
(the transaction that send Alice’s deposit to Bob) anymore,
because they spend the same output Tinit@0
.
This is coherent with the specification of the contract,
because if Alice reveals her secret, Bob shouldn’t be able to take her deposit.
const privA = _ removed
const sec_a:string = "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001"
const pubkeyA6 = pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1
const pubkeyB1 = pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809
const pubkeyB3 = pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809
const pubkeyB5 = pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809
const pubkeyA2 = pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1
const pubkeyA4 = pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1
const pubkeyB = pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809
const pubkeyA = pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1
transaction Tinit {
input = [ tx:0200000001c75e1b501f7a1691b16d06398b4235ab35e11ccda3c3f9160d68739c84d435ed00000000e4483045022100ad5f0022e6ae8e789a97ca9497b8d307690b96ddbfcdf822711b1983b328d26702204f276374584292322c1ad33dc7b67600673ace464e9c60990de7a0123933803c014730440220055c42ae93321b4061055c782be11d3392c84ff34b1d4fbbe3a9e208f63518170220231d7712a4d36e5397264bfc8db89fd1d13d64937ee886fb9872f260bf979760014c516b6b006c766c766b7c6b5221034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809210339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe152aeffffffff01d5ea0600000000001976a914ded135b86a7ff97aece531c8b97dc8a3cb3ddc7488ac00000000@0:sig(privA);
tx:02000000013ea7dd4d036b9a3048992e9c7e4b8c054e7949d08d233005aa79c50ee92ff0a800000000e3483045022100f956e4b07562a209662b42ab0b6d26784de59470d992a542c207e74bf03776d5022071a5089744aa25316d29cb9d1e9bd28f5f50eba6c2c5b57177bf0a17c35308a601463043021f26ce5a6c343fcb5edf3a06dbb95006cbf063393ec7b5beebd16e2c8120c059022015c4afec46a1c04d1dcfbf8e414d9f83d0a008c91b1a96f6b499edec2b8d1d48014c516b6b006c766c766b7c6b5221034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809210339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe152aeffffffff01d5ea0600000000001976a914ded135b86a7ff97aece531c8b97dc8a3cb3ddc7488ac00000000@0:sig(privA) ]
output = 0.00876666 BTC : fun(a:string, sB, sA) . (( (hash160(a) == hash:9f3df038eeadc0c240fb7f82e31fdfe46804fc7c && size(a) >= 128 && versig(pubkeyB1, pubkeyA2; sB, sA)) ||
versig(pubkeyB3, pubkeyA4; sB, sA) ))
}
const sigBT1 : signature = sig:30450221008e8cf2da8535b488dab5234a8a6cc942d4f3dbbf0993a0be77aa5d80f520c1fa02203e407d58fe6dc8eeca8478c9c0c0e43e5cc2b25567716489f8358b157aa9dacc01[pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809]
//received from Bob
transaction T1 {
input = [ Tinit@0:sec_a sigBT1 sig(privA) ]
output = 0.00846666 BTC : fun(sB, sA) . versig(pubkeyB5, pubkeyA6; sB, sA)
}
const sigBT2 : signature = sig:3045022100fff909e25bcc800deebce554eb24b68080f2b02290b41076ad5cfb8b026453740220725b65455de27a643d74ac2deeccc3cb2bb3ba5c486bd19a2fc7c9034228e0f801[pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809]
//received from Bob
transaction T2 {
input = [ T1@0: sigBT2 sig(privA) ]
output = 0.00816666 BTC : fun(x) . versig(pubkeyA; x)
}
const sigBT3 : signature = sig:3045022100c58572e8e1818ebbef2111da049a27f93cac791fc9d881acc48e43075382f8fb022032b2ff112f414463f884ccfcf427b4c952826e338779de63c3055d57b6ab89a501[pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809]
//received from Bob
const sigAT3 : signature = _
transaction T3 {
input = [ Tinit@0: "0" sigBT3 sig(privA) ]
output = 0.00846666 BTC : fun(x) . versig(pubkeyB; x)
absLock = block 1550000
}
eval sig(privA) of Tinit@0, sig(privA) of Tinit@1,
sig(privA) of T1, sig(privA) of T2, sig(privA) of T3,
Tinit, T1, T2
Bob’s view¶
The steps executed by Bob are the dual of the Alice’s ones.
Differently from Alice, he cannot publish T1
right away, because he doesn’t know the secret.
He wait for Alice to reveal her secret, or until block 155000,
when the timelock on T3
will unlock, and publish it to take Alice’s deposit.
const privB = _ //removed
const sec_a:string = ""
const pubkeyA6 = pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1
const pubkeyB1 = pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809
const pubkeyB3 = pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809
const pubkeyB5 = pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809
const pubkeyA2 = pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1
const pubkeyA4 = pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1
const pubkeyB = pubkey:034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809
const pubkeyA = pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1
const sigA0 : signature = sig:304402204adabfd7e29232148e3fa6a4bd8d3d3dd8fe6d5a9db8c77eec79fb556addb82b0220230c05987f38db659f9d1168ed7083a4ed602d44ba789c5ef903241e4577f6d501[pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1]
//received from Alice
const sigAFee : signature = sig:3045022100a81265cba65ad2fd793d241210ab194629efe41126673130cc40297c9d177c250220161c6087dcbb5957c21c2b415312eded883ed80964e6976e2559976e5cf21d6101[pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1]
//received from Alice
transaction Tinit {
input = [ tx:0200000001c75e1b501f7a1691b16d06398b4235ab35e11ccda3c3f9160d68739c84d435ed00000000e4483045022100ad5f0022e6ae8e789a97ca9497b8d307690b96ddbfcdf822711b1983b328d26702204f276374584292322c1ad33dc7b67600673ace464e9c60990de7a0123933803c014730440220055c42ae93321b4061055c782be11d3392c84ff34b1d4fbbe3a9e208f63518170220231d7712a4d36e5397264bfc8db89fd1d13d64937ee886fb9872f260bf979760014c516b6b006c766c766b7c6b5221034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809210339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe152aeffffffff01d5ea0600000000001976a914ded135b86a7ff97aece531c8b97dc8a3cb3ddc7488ac00000000@0:sigA0;
tx:02000000013ea7dd4d036b9a3048992e9c7e4b8c054e7949d08d233005aa79c50ee92ff0a800000000e3483045022100f956e4b07562a209662b42ab0b6d26784de59470d992a542c207e74bf03776d5022071a5089744aa25316d29cb9d1e9bd28f5f50eba6c2c5b57177bf0a17c35308a601463043021f26ce5a6c343fcb5edf3a06dbb95006cbf063393ec7b5beebd16e2c8120c059022015c4afec46a1c04d1dcfbf8e414d9f83d0a008c91b1a96f6b499edec2b8d1d48014c516b6b006c766c766b7c6b5221034a7192e922118173906555a39f28fa1e0b65657fc7f403094da4f85701a5f809210339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe152aeffffffff01d5ea0600000000001976a914ded135b86a7ff97aece531c8b97dc8a3cb3ddc7488ac00000000@0:sigAFee ]
output = 0.00876666 BTC : fun(a:string, sB, sA) . (( (hash160(a) == hash:9f3df038eeadc0c240fb7f82e31fdfe46804fc7c && size(a) >= 128 && versig(pubkeyB1, pubkeyA2; sB, sA)) ||
versig(pubkeyB3, pubkeyA4; sB, sA) ))
}
const sigAT1 : signature = sig:304402205f97481078e6b4579798a0233d0451cda9c905ae37adab483229d3034089e08302207ce6d7207a913aab50247f5961347e87802c28eb11a6aa9f45e0f9c92664e8ba01[pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1]
//received from Alice
transaction T1 {
input = [ Tinit@0:sec_a sig(privB) sigAT1 ]
output = 0.00846666 BTC : fun(sB, sA) . versig(pubkeyB5, pubkeyA6; sB, sA)
}
const sigAT2 : signature = sig:3045022100bcd87e903813a49e9c598c561a952ee26ceec4ac010644c6dd0055a518058c0d02201e35953d7f7c50244a8eeb0b289c387167f2fd9096e7f7f16dcb2501de8e658b01[pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1]
//received from Alice
transaction T2 {
input = [ T1@0: sig(privB) sigAT2 ]
output = 0.00816666 BTC : fun(x) . versig(pubkeyA; x)
}
const sigAT3 : signature = sig:304402202c47c0fb3d196074541d30e3d3680e1206f50d7abbf4431436f34423297729ba022022d7f5e5864eee01b721a2db695a58c1b586929f750d299b2a41122d62b247c001[pubkey:0339bd7fade9167e09681d68c5fc80b72166fe55bbb84211fd12bde1d57247fbe1]
//received from Alice
transaction T3 {
input = [ Tinit@0: "0" sig(privB) sigAT3 ]
output = 0.00846666 BTC : fun(x) . versig(pubkeyB; x)
absLock = block 1550000
}
eval sig(privB) of T1, sig(privB) of T2, sig(privB) of T3,
Tinit, T3
We have executed the compiled contract on the Bitcoin testnet. The hash of the transactions are the following:
Phase |
Tx name |
Tx id |
---|---|---|
Init |
Tinit |
139a7b529cb5b91ab54257abf22797b25700430f0cc49bf69324fc1d07827ad2 |
reveal a |
T1 |
46ceb75f2261c9879fac0192547dceb35123ee5188158fe7cbb1ca6200e7cefb |
withdraw “A” |
T2 |
6e1fd285cab75985de9b52a6068e67bc074d80e81baac72bb741004333df1f8e |