In Bitcoin this is really damn complicated for a number of reasons. The first reason is that transaction IDs in Bitcoin can be randomly mutated so that chains of unconfirmed transactions can be invalided [0]. And the second reason is that all of the OP_CODES you need to create complex contracts in Bitcoin are either disabled or too limited to use.

That meant that the only way I could figure out how to get this contract to work on Bitcoin was to:

Rely on a theoretical segwit existing (it’s not deployed yet) and

Build a chain of transactions in such a way that Bitcoin itself is used to validate signatures so that if a person provides incorrect secrets to try claim payments they only end up scamming themselves out of a future payment.

Number 2 was done with complex zero-knowledge proofs and the code never managed to get anywhere beyond a shitty research-grade POC. I think its still sitting on some dark VM somewhere… So it’s not exactly very useful.

Now enter Ethereum.

Pay for private key contracts in Ethereum

Believe it or not - it’s not exactly easy to do this in Ethereum either because Ethereum doesn’t allow you to directly generate and verify ECDSA key-pairs from within a contract [0]. The solution is to use a function called ecrecover that we can exploit to implement pay for private key contracts in Solidity.

Here’s how it works. ECDSA signatures have a few components that matter, s and r. The r value is generated either from a deterministic look at the message to sign OR from a random number, where the s value is uniquely determined by the message that is signed.

The idea is that the r value created for a signature should always be unique with respect to the same public key. Or to put this another way, if you can get 2 valid signatures for the same public key that contain the same r value but with different s values then you can effectively recover the priv key.

To implement this in Solidity requires that you:

Generate two signatures for unique messages with duplicate r values.

Call ecrecover on both signatures and check that the public key returned matches the public key whose private key we’re paying for.

Check that the r values are the same; That s in both sigs are unique; And to make things less complex for recovery - check that v is the same for both signatures [1][2].

I have implemented the first step as a Python program that generates an ECDSA key pair using the Bitcoin curve and then generates provably insecure signatures. This is what the output looks like:

Create a new instance of the PayForPrivKey contract and specify the Ethereum address for the public key whose private key you want to find. The Python program converts the ECDSA pub key to an Ethereum address for you automatically :) So copy-paste.

Create a commitment. This means you’re just hashing all the solution values for the backdoored signatures along with the address that you want to receive an Ether reward at. When you run the Python script it asks for a destination address (there is a default Ethereum address there for testing already.)

Copy paste the solution_hash into the CommitSolutionHash function. It will return an index number that you should save.

Wait for the min_block number so you don’t get h4x0red by blockchain devs.

Prove that you know the solution by revealing the commitment. There is a function in the Solidity contract call ProvePrivKey that takes most of the data above to prove you know the private key. I have made things easier – just copy and paste the Ethereum input string directly into this function and replace the index number at the end with the result from step 3.

Enjoy your new Ether.

Note: I haven’t deployed this to testnet or mainnet yet because my Internet is currently terrible, but if anyone wants to deploy this to either network hit me up over email with a contract address.

Atomic storage contracts

Pay for private key contracts can be used as the basis for a large number of contracts. In fact, some of the original discussion around these concepts took place in the context of the Lightning Network where people were discussing how to get someone to release a private key.

You can also use this contract for gambling and for Peter Todd’s dark release scheme, but my original motivation for trying to get this to work was to implement my idea for atomic storage contracts.

…

Now image that you want to pay someone to store content on their hard drive. Traditionally, you could pay them after they store the content but you could easily scam them afterwards by not sending payment. The other solution is for you to send the money first but now the host can scam you.

What I wanted to design was a contract that could atomically bind content to money so that neither side can scam the other…

Thus, it is completely possible to implement an atomic payment system for a decentralized cloud storage system on top of Ethereum without the need for a custom blockchain [3] like Sia or Filecoin for trustless payments.

Anyway, that’s it for now. Fin.

Notes

[0] Ethereum could benefit from adding more support for crypto primitives to contracts.
[1] https://bitcoin.stackexchange.com/questions/38351/ecdsa-v-r-s-what-is-v
[2] You don’t need to freak out at me dropping yet another constant. The value of v is almost always 27 or 28.
[3] Auditing protocols for proof-of-retrievability are also trivial on Ethereum. You can use a server to implement audits with a Merkle tree (credits Storj) or a version that doesn’t require a server could utilize a Timechain to do public audits over-time without the need for a party to be trusted for audits.
[4] Both sides need to commit to their public keys as hashes that are exchanged before they exchange keys otherwise one of them can use ECC addition to create a public key that results in a private key they already have. I left that step out for simplicity but its not too difficult.