Jump to content
Main menu
Main menu
move to sidebar
hide
Navigation
Main page
Recent changes
Random page
Help about MediaWiki
Matthews Lab
Search
Search
Appearance
Log in
Personal tools
Log in
Pages for logged out editors
learn more
Contributions
Talk
Editing
Timechain
(section)
Page
Discussion
British English
Read
Edit
Edit source
View history
Tools
Tools
move to sidebar
hide
Actions
Read
Edit
Edit source
View history
General
What links here
Related changes
Special pages
Page information
Appearance
move to sidebar
hide
Warning:
You are not logged in. Your IP address will be publicly visible if you make any edits. If you
log in
or
create an account
, your edits will be attributed to your username, along with other benefits.
Anti-spam check. Do
not
fill this in!
= The timechain DAC = The timechain DAC adapts the basic idea behind the timechain but adds financial incentive so that participants not only want to decrypt the timechain but that doing so simultaneously forces individuals to release the RSA private key of the current link plus the IV to the next key. [http://www.gwern.net/Self-decrypting%20files Gwern Branwen] and [https://github.com/petertodd/timelock Peter Todd] have already done work on using Bitcoin to incentivize the release of time-lock encryption keys but where my work differs from their own is in the way I’ve used the concept to create a general purpose, decentralized, time-lock encryption service that pays its participants to decrypts itself and forces them to provide the service. '''How it works is … complicated''' The DAC needs to be able to pay participants for their time so we’re going to need to insert [https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm ECDSA key pairs] into the chain links. The ECDSA key pairs can be used to pay participants to break the timechain by allowing cryptocurrencies to be redeemed by signing with a particular key pair so the first person to break a link will get the coins. Before we go into the full details its important to understand the [https://en.wikipedia.org/wiki/Game_theory game theory] taking place here: because the first person who breaks a link is racing against countless other participants they must broadcast a redeeming transaction as early as possible or risk losing their reward. Thus, the timechain forces participants to redeem coins as early as possible. Using these basic properties together with a special hash-locked contract it is possible to force participants to simultaneously release the details to decrypt the time-lock encrypted … AES encrypted … RSA private key ''and'' provide participants with the next IV in the chain. This is done by using the ''public'' key of a time-lock encrypted ECDSA key pair as an IV. The public key is also used as a symmetric AES key to encrypt the RSA key pair. Finally, a ''hash'' of the public key along with the AES ciphertext for the RSA key is publicly released. The hash allows participants to pay fees to the DAC and requires providing the public key to redeem those coins (which simultaneously releases the secret key needed to decrypt the RSA key ''and'' gives participants the next IV in the chain.) I think we’re going to need some code and diagrams over here … <syntaxhighlight lang="python3"> import time from Crypto.Cipher import AES from Crypto import Random from Crypto.Cipher import PKCS1_OAEP from Crypto.PublicKey import RSA import ecdsa import hashlib import bitcoin.base58 from bitcoin import SelectParams from bitcoin.core import b2x, lx, x, COIN, COutPoint, CTxOut from bitcoin.core import CTxIn, CTransaction, Hash160, Serializable, str_money_value import binascii def compress_public_key(public_key): #https://bitcointalk.org/index.php?topic=644919.0 public_key = binascii.hexlify(public_key).decode("utf-8") #Is there a prefix byte? if len(public_key) == 128: offset = 0 else: offset = 2 #Extract X from X, Y public key. x = int(public_key[offset:64 + offset], 16) y = int(public_key[65 + offset:], 16) if y % 2: prefix = "03" else: prefix = "02" #Return compressed public key. ret = prefix + "{0:0{1}x}".format(x, 64) return binascii.unhexlify(ret) def make_aes_cipher(key): return AES.new(key, AES.MODE_CFB) def encrypt(plaintext, cipher): return cipher.encrypt(plaintext) def timelock(duration, iv): #Starting time. last_run = time.time() #Generate time-lock encryption key. elapsed = int(time.time() - last_run) key = hashlib.sha256(iv).digest() while elapsed < duration: key = hashlib.sha256(key).digest() elapsed = int(time.time() - last_run) #Time-lock encrypted key. return key #For demonstration only. def publish_timechain(genesis, timechain, genesis_time): return None """ Generate starting IVs for parallel keys. These need to be distributed to individual processors. """ ivs = [] key_no = 2 for i in range(0, key_no): iv = ecdsa.SigningKey.generate(curve=ecdsa.SECP256k1) ivs.append(iv) """ Generate individual time-locked keys. (Image this is done in parallel because I'm lazy.) """ keys = [] duration = 10 for i in range(0, key_no): verify_key = ivs[i].get_verifying_key() ecdsa_pub_key = compress_public_key(verify_key.to_string()) key = timelock(duration, ecdsa_pub_key) keys.append(key) """ This is where the magic happens: stitch the keys together into one long chain of serial keys. time lock -> ecdsa priv key -> btc tx -> ecdsa pub key -> (rsa priv + IV) time lock -> ... -> timechain """ pub_key_hashes = [] en_rsa_priv_keys = [] rsa_public_keys = [] en_ecdsa_priv_keys = [] for i in range(1, key_no): #Generate pub key hash - this is where we pay. verify_key = ivs[i].get_verifying_key() ecdsa_pub_key = verify_key.to_string() pub_key_hash = hashlib.sha256(ecdsa_pub_key).digest() pub_key_hash = hashlib.new('ripemd160', pub_key_hash).hexdigest() pub_key_hashes.append(pub_key_hash) #Build asymmetric, time-locked RSA key. random_generator = Random.new().read rsa_key = RSA.generate(1024 * 2, random_generator) rsa_priv_key = rsa_key.exportKey('DER') rsa_public_key = rsa_key.publickey().exportKey('DER') rsa_public_keys.append(rsa_public_key) #Encrypt RSA key with hash-locked AES key. ecdsa_32_bytes = compress_public_key(ecdsa_pub_key) ecdsa_32_bytes = hashlib.sha512(ecdsa_32_bytes).digest() ecdsa_32_bytes = hashlib.sha256(ecdsa_32_bytes).digest() hash_locked_aes = make_aes_cipher(ecdsa_32_bytes) en_rsa_priv_key = encrypt(rsa_priv_key, hash_locked_aes) en_rsa_priv_keys.append(en_rsa_priv_key) #Stitch keys together with time-lock encryption. ecdsa_priv_key = ivs[i].to_string() time_locked_aes = make_aes_cipher(keys[i]) en_ecdsa_priv = encrypt(ecdsa_priv_key, time_locked_aes) en_ecdsa_priv_keys.append(en_ecdsa_priv) #When should the timechain be released? genesis_time = time.time() + (10 * 60) #Generate timechain. timechain = [] for i in range(0, key_no - 1): link = { "en_ecdsa_priv_keys": en_ecdsa_priv_keys[i], "pub_key_hashes": pub_key_hashes[i], "en_rsa_priv_key": en_rsa_priv_keys[i], "rsa_public_key": rsa_public_keys[i], "expiry": genesis_time + ((i + 1) * duration) } timechain.append(link) #Timechain starts here. genesis = compress_public_key(ivs[0].get_verifying_key().to_string()) #Publish timechain - not coded - for example only. publish_timechain(genesis, timechain, genesis_time) </syntaxhighlight> If you read the code very closely you will notice that I’m using [http://bitcoin.stackexchange.com/questions/3059/what-is-a-compressed-bitcoin-key compressed ECDSA public keys] as IVs. The reason for that is that Bitcoin-style ECDSA public key hashes are released publicly to everyone in the form ''ripemd160(sha256(uncompressed_ecdsa_pub_key))''. If a vulnerability were to be found in [https://en.wikipedia.org/wiki/RIPEMD ripemd160] that could lead to inverted hashes and I was using the same input data (uncompressed ECDSA public keys for the IVs), then [https://en.wikipedia.org/wiki/Secure_Hash_Algorithm sha256] hashing the inverted ripemd160 hash would essentially yield arbitrary points on the timechain: '''extremely bad'''. By using compressed keys for the IVs we rely on the [https://en.wikipedia.org/wiki/Avalanche_effect avalanche effect] of cryptographic hash functions which states that any small changes to the input data produce profoundly different hashes (so even if ripemd160 was completely invertible it would not effect the security of the timechain.) For the same reason, different hashes of compressed ECDSA pub keys are used as symmetric AES keys to encrypt the time-locked RSA key. [[File:Timechain 2.png|thumb]] The dotted lines in the diagram mean that the input is being used directly as the key to the cipher (''not'' that the cipher is being applied to the input.) Green boxes denote publicly available information. Another way to conceptualize the Timechain DAC is listed bellow. <blockquote>Genesis IV -> sha256 -> … -> sha256 -> AES1 -> (next ECDSA priv key, AES2(new RSA priv key)) compressed ECDSA pub key -> iv - > sha256 -> … -> sha256 -> AES1 -> (next ECDSA priv key, AES2(new RSA priv key)) compressed ECDSA pub key -> iv -> sha256 -> … -> sha256 -> AES1 -> (next ECDSA priv key, AES2(new RSA priv key)) … Timechain DAC. </blockquote><span id="redeeming-funds-from-the-timechain-dac"></span> == Redeeming funds from the timechain DAC == After winning the race to generate a new time-lock encrypted AES key and gaining access to an ECDSA private key with funds inside it - you want to spend them as early as possible. This can be accomplished with a standard Bitcoin transaction type called a “[https://en.bitcoin.it/wiki/Transaction#Pay-to-PubkeyHash pay to public key hash]”. P2PKH was invented as a way to have shorter Bitcoin addresses and to conceal the owner of a public key in the event that a flaw was found in ECDSA but for our purposes it allows us to create complex contracts that tie directly into the timechain. The Bitcoin transaction Script to fund a P2PKH transaction looks like this: <pre>OP_DUP, OP_HASH160, ripemd160(sha256(ecdsa_public key))</pre> … which is the same public key hash generated previously. To redeem the transaction simply provide the original public key and a valid signature.<span id="solving-complex-trust-problems-with-the-timechain"></span>
Summary:
Please note that all contributions to Matthews Lab may be edited, altered, or removed by other contributors. If you do not want your writing to be edited mercilessly, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource (see
Matthews Lab:Copyrights
for details).
Do not submit copyrighted work without permission!
Cancel
Editing help
(opens in new window)