Showing posts with label bitcoin protocol. Show all posts
Showing posts with label bitcoin protocol. Show all posts

Friday, 23 October 2015

Blockchain proof of existence, part 2

This is the second part of a series on developing a Bitcoin application able to record document checksums in the Blockchain. The first part covered development of the software needed to take control over some addresses and create valid transactions, which itself was built on top of software handling discovering and connecting to the Bitcoin peer-to-peer network (covered in this post).

The actual additions needed to the Bitcoin wallet in order to write arbitrary data to the Blockchain turned out to be quite trivial; replacing the pay-to-pubkey-hash script with OP_RETURN followed by the data payload and broadcast it as normal:

Transaction: e4a325b4b54ca05bd58655a1c535c86fb7648e5392e83c72b428aee07ed19547

Input: tx aa37ea6c35e6688b52f71908bd3fb7700b83d6e88e32349914a7be964e5d69a8 (output index 1) => 1LivLKSyh9hU9enjptHveRqxp1uJ8NfDYd
Signature: 3046022100c22c7f8b3e49718fa8cb6db530c4d0607feb5cabe649a4070713e922d523058a022100d08292daabf847e6968572a9c6ec0a723b49ee85f11104de24e43510ce1e623f01

Output: 0 satoshis (0.000000 mBTC) to script: OP_RETURN 636861696e206f662074686f75676874
Output: 30000 satoshis (0.300000 mBTC) to script: OP_DUP OP_HASH160 1dhBEoKc1soKqVLfrgs8SPAn3hyVBRoWC OP_EQUALVERIFY OP_CHECKSIG

Where the payload 636861696e206f662074686f75676874 is, narcissistically, the hex encoded "chain of though". How well Blockchain trackers displays the payload data varies, but at least one (coinsecrets.org) does a good job at it.

From here the next step will be to expose this functionality online, giving everyone the power to record checksums, or other data, on the blockchain.



Monday, 19 October 2015

Transaction malleability

Transaction malleability is an artifact of how Bitcoin transactions are signed. As I mentioned in my last post, the input signatures are there to, in part, protect your transaction from being modified by third parties. Without access to the private key used to sign a transaction, there's no way for an attacker to change where that transaction sends its satoshis without invalidating the signature. However, the signature itself is not protected from change, and herein lies the rub; changing the signature will change the hash of a transaction, essentially creating a new equivalent transaction, that is still valid. This has a number of issues, and due to, apparently, a bored Russian hacker, malleability has recently gone from a theoretical problem to something pretty much all Bitcoin software has to deal with all the time, my wallet software being no exception.

What does it look like?

I recently broadcast a simple transaction that can serve as an example of what exactly malleability looks like. The transaction sends two unspent outputs to a new address and hashes to 3d9ae35ec8e5b4c9b9cdad8c1fe7bd9afc465646485a9d5932fb71cbff586294. It has already gotten a few confirmations and can be viewed in detail on blockchain.info.

 This is how it looked on my wallet just before I broadcast it, let call this transaction A:

Transaction: 3d9ae35ec8e5b4c9b9cdad8c1fe7bd9afc465646485a9d5932fb71cbff586294, version 1

Input: tx 389a80eaccc69ce8504de8f60cbbb5ecb0c975be6197e77d91326417ab8166ff (output index 1) => 17pZuDHfXNLKxyA7hsd1cGrSSPtUrhnxTq
Signature: 3044022035e0595694e040591bd9ca90015a889318ce1e5eb247c547672ea3974eecd7fb02205004cd171a1b282cb75ab7e285d840a6ec1facffbc50aa6e651e969e6103bc6201

Input: tx e4231428afe4a2fd1574a2e7d9eaec392db6c6b75ee53c99e34ed1c141b01aa0 (output index 0) => 18WPbS5dxLUjE16DymRpv1q7W9JmPz8u9u
Signature: 30460221008a162fbaf43f2f10db622d9443f89a50574f83d9c57b66dd14ec276130dafeec022100a013b18159b5737f0d7dec9f0e95815cd3cfd82e461baad6c42d37e93d55bb4001

Output: 30000 satoshis (0.300000 mBTC) to script: OP_DUP OP_HASH160 13ZsFbiWrDeyyBwwtFpmssA47Tv7v7tZNX OP_EQUALVERIFY OP_CHECKSIG 


Within seconds, the connected nodes indicated that transaction A had been added to their mempools and regarded as a valid transaction. Then, roughly 8 seconds after the broadcast, one node notifies my wallet that it has a transaction with hash b4f3c62159a222ea9eccf5d0f9057c555d0d519cfe580412c4c185c244d8bb30 paying one of its addresses. The wallet software promptly fetches the transaction, and this is how it looks (lets call this transaction B):

Transaction: b4f3c62159a222ea9eccf5d0f9057c555d0d519cfe580412c4c185c244d8bb30, version 1

Input: tx 389a80eaccc69ce8504de8f60cbbb5ecb0c975be6197e77d91326417ab8166ff (output index 1) => 17pZuDHfXNLKxyA7hsd1cGrSSPtUrhnxTq
Signature: 3044022035e0595694e040591bd9ca90015a889318ce1e5eb247c547672ea3974eecd7fb02205004cd171a1b282cb75ab7e285d840a6ec1facffbc50aa6e651e969e6103bc6201

Input: tx e4231428afe4a2fd1574a2e7d9eaec392db6c6b75ee53c99e34ed1c141b01aa0 (output index 0) => 18WPbS5dxLUjE16DymRpv1q7W9JmPz8u9u
Signature: 30450221008a162fbaf43f2f10db622d9443f89a50574f83d9c57b66dd14ec276130dafeec02205fec4e7ea64a8c80f2821360f16a7ea1e6df04b8692cf564fba526a392e0860101
The 
Output: 30000 satoshis (0.300000 mBTC) to script: OP_DUP OP_HASH160 13ZsFbiWrDeyyBwwtFpmssA47Tv7v7tZNX OP_EQUALVERIFY OP_CHECKSIG 

At first glance it looks like the same transaction. In fact, transaction A and B both uses the same inputs to pay the same output the same amount. The only reason they have different hashes, and thus show up as two unique transactions, is a change to the signature on the second input.

Input signatures

Every transaction input has a signature field, and for standard transactions it contains two objects; a DER-encoded signature of the transaction, and the unhashed version of the public key the consumed output was originally sent to (only the actual signature is shown in the transactions above).

So what has changed between transaction A and transaction B.
  • Second input to A:
    30460221008a162fbaf43f2f10db622d9443f89a50574f83d9c57b66dd14ec276130dafeec022100a013b18159b5737f0d7dec9f0e95815cd3cfd82e461baad6c42d37e93d55bb4001
  • Second input to B:30450221008a162fbaf43f2f10db622d9443f89a50574f83d9c57b66dd14ec276130dafeec02205fec4e7ea64a8c80f2821360f16a7ea1e6df04b8692cf564fba526a392e0860101
The signature actually consists of two numbers, R and S, and they are encode as follows
  • Signature: 0x30 <total length (one byte)> R(encoded) S(encoded) 0x01
    • where the last byte is a signature hash code that isn't really part of the signature.
  • R and S (encoded): 0x02 <length (one byte)> <actual number>
As we can see, R is unchanged whereas S has changed. Although there's a large number of valid ECDSA signatures for any given data (this helps avoid leaking information if you were to, say, sign the same data twice), you'd think creating a new signature required knowing the private key. There is however a quirk in how an ECDSA signature works allowing for two valid values of S in any signature, and crucially for this attack, the relationship between the two Ses is really simple. It turns out that for any valid ECDSA signature (with the particular parameters used in Bitcoin), the signature will still be valid if S is replaced with S' = 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 - S.

In our case transaction A has Sa = 00a013b18159b5737f0d7dec9f0e95815cd3cfd82e461baad6c42d37e93d55bb40 and transaction B has Sb = fffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141 - Sa = 5fec4e7ea64a8c80f2821360f16a7ea1e6df04b8692cf564fba526a392e08601.

This is simple math, and basically something anyone can do. In fact, the way the signature is encoded is loosely enough defined to open up for countless modification that don't involve any math at all. For this particular transaction, it would for instance be possible to just strip the leading 0x00 from Sa, yielding the signature 30450221008a162fbaf43f2f10db622d9443f89a50574f83d9c57b66dd14ec276130dafeec0220..a013b18159b5737f0d7dec9f0e95815cd3cfd82e461baad6c42d37e93d55bb4001 and the transaction hash b5514b39d578be2c0889382930780ac33997571b4bb1611990f8e897380dcefb; a third unique but equivalent transaction. For a list all known ways to modify signatures without invalidating them, as well as the proposed fixes to the Bitcoin protocol, see BIP-0062.

Consequences and short term solutions

Even though transaction malleability doesn't change the essence of a transaction, and once one is confirmed by a miner, the other one(s) will be clearly invalid, the period of uncertainty before that happens can be quite a nuisance (essentially all versions of a transaction must be treated as equally valid/invalid as there's no way to tell which one was the original one, or which one will end up sticking). Naively implemented wallets (including mine at this point) can double count incoming transfers, messing up the account balance. Worse though, transactions made using the change output from a recent, not-yet-confirmed transaction, may turn out to be invalid if a miner confirms the modified transaction rather than the original.

Take for instance the following transaction proposed my wallet before the malleability issue above was settled (let's call this transaction C):

Transaction: 3e90b646873675f6728f7878484dda5f7693f66ccc0b0b30a0145f02d9d4797a, version 1

Input: tx b4f3c62159a222ea9eccf5d0f9057c555d0d519cfe580412c4c185c244d8bb30 (output index 0) => 13ZsFbiWrDeyyBwwtFpmssA47Tv7v7tZNX
Signature: 3046022100f5622225b11cd4ecc35625f9ebedfb4b10059941d41ab20f68b1bc60bd9a7c91022100ad99b6e367e830916abc20e71eb4dbfbe25251d6dd5c0724099c4db0f1a453f201

Output: 20000 satoshis (0.200000 mBTC) to script: OP_DUP OP_HASH160 1L9SmY5i3bQ17RJreX4CoJJJBrWK6oN5HF OP_EQUALVERIFY OP_CHECKSIG 
 

It's trying to use an output from transaction B to form a new transaction, something that would be considered valid by a significant fraction of the network (any node that saw transaction B before A), before eventually ending up being an invalid transaction once transaction A was mined, rendering transaction B invalid.

I could program the wallet to disregard outputs from transaction B, after all it knows which one was the original one, but that wouldn't stop miners from confirming transaction B if they happened to see that before A.

A better solution would probably be to keep track of all the modified versions of the original transaction, and create corresponding versions of any new transaction spending the outputs. Ideally these should then be forwarded to miners with compatible views of the world for inclusion in their next block, so miners who believe transaction B is the valid one are sent C as it stand above, while miners who think transaction A is the valid one are sent C(a), where the corresponding output of A is used instead of the one from B. This process might be hard to get accurate, but sending C(a) back to nodes that sent us A, while sending C(b) back to nodes that sent us B, will probably not be too far off. In any case, putting both versions of C out there will ensure that one is still valid once the network has decided on the A vs B situation.

With this solution implemented, the wallet should be able to function as normal even during malleability attacks like the one that's currently ongoing, without having to wait for protocol level improvements (like those proposed in BIP-0062). I'll write a new post on this topic once I have this functionality implemented and ready for testing.

Thursday, 17 September 2015

Bitcoin peer to peer network

Bitcoin is based on a peer to peer network, where each peer, or node, verifies, stores and forwards the transactions taking place on the network. Some nodes, the miners, collect valid transactions into blocks and publish these. Each block references the previous block, thus creating a chain of them, the Blockchain. Although creating blocks is hard work and requires specialized hardware, anyone can subscribe to these blocks, then inspect and verify them.

By connecting to a node on the network, we can receive a stream of real-time transactions as well as the blocks being published as miners create them. For robustness and security, we should probably connect to several independent nodes, thus reducing the chance that transactions are being censored by malicious nodes, or dropped by a faulty one. Ensuring that we're well connected is far from trivial, so in this first pass we'll just connect to a handful of nodes and hope that they're not all colluding against us. Unresponsive or otherwise broken connections will be dropped and new ones created to replace them.

Implementation

I've written a simple implementation of this network layer based on the protocol documentation (refer to this for details on the various messages mentioned below, or terms that are unfamiliar). I chose Go as the implementation language, and as an experiment the code relies solely on channels for synchronization, which is elegant at times, but far from perfect. I'll write a separate blog post about interesting problems arising from these choices.

The code consist of two layers, the connection and the network. The former focuses on a setting up and maintaining a single connection, including sending and responding to pings. The latter will acquire the addresses of as many peers as possible, score the quality of them by various metrics and create and set up connections to a number of the best scoring ones. New peers' addresses are found by performing DNS look-ups, asking already connected peers by sending a getaddr message, or loading previously known peers from local storage. Usually this will quickly result in a pretty good overview of the network, with hundreds of nodes to chose between for connections.

Users of the library will get a channel to send messages on (either addressed messages or broadcasts) and the ability to subscribe to received messages by type. They don't have to worry about managing the connections and won't even be aware of the low level messages, with the exception of received version messages, that can be subscribed to by users who need to be aware of new peers being connected to (eg. because they want to address messages to them -- the example application included with the library will listen for version messages and send a mempool message to each new peer, thus initiating one or more inv messages containing transactions in the respective peer's mempool to be sent our way). This is a good starting point for beginning to write software interacting with the Bitcoin network.

Inspecting current connectivity

The example application contains a simple web server that can be used to see current connections as well as the applications view of the network. The page /peers on localhost:8080 list all known peers, with their connection status, address, time of last activity and a quality score.

Example peer list as seen on http://localhost:8080/peers:
(connected) 75.189.201.141:8333   2015-09-17 13:10:48.073832944 -0500 CDT Q(1000)
(connected) 73.162.143.196:8333   2015-09-17 13:10:42.964351941 -0500 CDT Q(1000)
(connected) 79.98.137.63:8333   2015-09-17 13:10:47.438899944 -0500 CDT Q(1000)
(spare)     52.11.33.24:8333   2015-09-17 13:10:32.825600001 -0500 CDT Q(800)
(pending)   50.147.76.86:8333   2015-09-17 13:10:32.825595045 -0500 CDT Q(800)
(spare)     69.143.149.38:8333   2015-09-17 13:10:32.825507889 -0500 CDT Q(800)
(pending)   24.52.35.44:8333   2015-09-17 13:10:32.695354838 -0500 CDT Q(800)
(spare)     54.153.97.109:8333   2015-09-17 13:10:32.825616717 -0500 CDT Q(800)
(spare)     25.96.107.191:8333   2015-09-17 11:08:03 -0500 CDT Q(678)
[...]
(spare)     71.93.135.167:8333   2015-09-17 05:02:53 -0500 CDT Q(313)
(spare)     155.133.19.109:8333   2015-09-17 05:00:28 -0500 CDT Q(310)
(failed)    50.177.196.160:8333, failed at 2015-09-17 13:10:43.100961354 -0500 CDT Q(300)
(failed)    173.69.49.106:8333, failed at 2015-09-17 13:10:42.699932334 -0500 CDT Q(300)
(failed)    198.38.93.227:8333, failed at 2015-09-17 13:10:42.700074666 -0500 CDT Q(300)
(spare)     68.238.62.169:8333   2015-09-17 04:49:01 -0500 CDT Q(299)
(spare)     72.241.129.31:8333   2015-09-15 16:09:59 -0500 CDT Q(0)
(spare)     84.104.142.12:8333   2015-09-09 23:23:42 -0500 CDT Q(0)
(spare)     87.220.72.124:8333   2015-08-20 08:24:59 -0500 CDT Q(0)

The application contains a simple In the example above there are 3 established connections, with 2 more pending. 3 nodes have had recent failures and are ranked lower because of this, while the rest are spares, ranked by the time of the last known activity from them (as seen by us, or as communicated by a peer in an addr message).