From 61a9711deb1947f8bd3d05987e4c4f1d104849ab Mon Sep 17 00:00:00 2001 From: Kristov Atlas Date: Fri, 12 Jun 2015 17:31:23 -0400 Subject: Added BIP 79 Lexicographical Indexing of Transaction Inputs and Outputs --- README.mediawiki | 6 ++ bip-0079.mediawiki | 129 ++++++++++++++++++++++++++++++++++++++++++ bip-0079/bip-0079_examples.py | 112 ++++++++++++++++++++++++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 bip-0079.mediawiki create mode 100644 bip-0079/bip-0079_examples.py diff --git a/README.mediawiki b/README.mediawiki index 56f15d5..a758f1a 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -277,6 +277,12 @@ Those proposing changes should consider that ultimately consent may rest with th | Stephen Pair | Standard | Draft +|- +| [[bip-0079.mediawiki|79]] +| Lexicographical Indexing of Transaction Inputs and Outputs +| Kristov Atlas +| Standard +| Draft |} diff --git a/bip-0079.mediawiki b/bip-0079.mediawiki new file mode 100644 index 0000000..65e35e6 --- /dev/null +++ b/bip-0079.mediawiki @@ -0,0 +1,129 @@ +
+  BIP:     BIP: 79
+  Title:   Lexicographical Indexing of Transaction Inputs and Outputs
+  Authors: Kristov Atlas 
+  Status:  Draft
+  Type:    Informational
+  Created: 2015-06-12
+
+ +==Abstract== + +Currently there is no standard for bitcoin wallet clients when ordering transaction inputs and outputs. As a result, wallet clients often have a discernible blockchain fingerprint, and can leak private information about their users. By contrast, a standard for non-deterministic sorting could be difficult to audit. This document proposes deterministic lexicographical sorting, using hashes of previous transactions and output indices to sort transaction inputs, as well as values and scriptPubKeys to sort transaction outputs. + +==Copyright== + +This BIP is in the public domain. + +==Motivation== + +Currently, there is no clear standard for how wallet clients ought to order transaction inputs and outputs. Since wallet clients are left to their own devices to determine this ordering, they often leak information about their users’ finances. For example, a wallet client might naively order inputs based on when addresses were added to a wallet by the user through importing or random generation. Many wallets will place spending outputs first and change outputs second, leaking information about both the sender and receiver’s finances to passive blockchain observers. Such information should remain private not only for the benefit of consumers, but in higher order financial systems must be kept secret to prevent fraud. A researcher recently demonstrated this principle when he detected that Bitstamp leaked information when creating exchange transactions, enabling potential espionage among traders. [1] + +One way to address these privacy weaknesses is by randomly ordering inputs and outputs. [2] After all, the order of inputs and outputs does not impact the function of the transaction they belong to, making random sorting viable. Unfortunately, it can be difficult to prove that this sorting process is genuinely randomly sorted based on code or run-time analysis, especially if the software is closed source. A malicious software developer can abuse the ordering of inputs and outputs as a side channel of leaking information. For example, if an attacker can patch a victim’s HD wallet client to order inputs and outputs based on the bits of a master private key, then the attacker can eventually steal all of the victim’s funds by monitoring the blockchain. Non-deterministic methods of sorting are difficult to audit because they are not repeatable. + +The lack of standardization between wallet clients when ordering inputs and outputs can yield predictable quirks that characterize particular wallet clients or services. Such quirks create unique fingerprints that a privacy attacker can employ through simple passive blockchain observation. + +The solution is to create an algorithm for sorting transaction inputs and outputs that is deterministic. Since it is deterministic, it should also be unambiguous — that is, given a particular transaction, the proper order of inputs and outputs should be obvious. To make this standard as widely applicable as possible, it should rely on information that is downloaded by both full nodes (with or without typical efficiency techniques such as pruning) and SPV nodes. In order to ensure that it does not leak confidential data, it must rely on information that is publicly accessible through the blockchain. The use of public blockchain information also allows a transaction to be sorted even when it is a multi-party transaction, such as in the example of a CoinJoin. + +==Specification== + +===Applicability=== + +This BIP applies to any transaction for which the order of its inputs and outputs does not impact the transaction’s function. Currently, this refers to any transaction that employs the SIGHASH_ALL signature hash type, in which signatures commit to the exact order of inputs and outputs. Transactions that use SIGHASH_ANYONECANPAY and/or SIGHASH_NONE may include inputs and/or outputs that are not signed; however, compliant software should still emit transactions with lexicographically sorted inputs and outputs, even though they may later be modified by others. + +In the event that future protocol upgrades introduce new signature hash types, compliant software should apply the lexicographical ordering principle analogously. + +While out of scope of this BIP, protocols that do require a specified order of inputs/outputs (e.g. due to use of SIGHASH_SINGLE) should consider the goals of this BIP and how best to adapt them to the specific needs of those protocols. + +===Lexicographical Sorting=== + +Ordering of inputs and outputs will rely on the output of sorting functions. These functions can be defined as taking two inputs or two outputs as parameters and returning their appropriate ordering with respect to each other. + +Byte arrays must be sorted with an algorithm that produces the same output as the following comparison algorithm: + + #returns -1 if barr1 is lesser, 1 if barr1 is greater, and 0 if equal + def bytearr_cmp(barr1, barr2): + pos = 0 + while (pos < len(barr1) and pos < len(barr2)): + if (barr1[pos] < barr2[pos]): + return -1; + elif (barr1[pos] > barr2[pos]): + return 1; + pos = pos + 1 + #the shorter array will be ordered first + if (len(barr1) < len(barr2)): + return -1 + elif (len(barr1) > len(barr2)): + return 1 + else: + return 0 + +N.B. These comparisons do not need to operate in constant time since they are not processing secret information. + +===Transaction Inputs=== + +104 Transaction inputs are defined by the hash of a previous transaction, the output index of of a UTXO from that previous transaction, the size of an unlocking script, the unlocking script, and a sequence number. [3] For sorting inputs, the hash of the previous transaction and the output index within that transaction are sufficient for sorting purposes; each transaction hash has an extremely high probability of being unique in the blockchain — this is enforced for coinbase transactions by BIP30 — and output indices within a transaction are unique. For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables. + +Hashes of previous transactions are considered for the purposes of this BIP in their little-endian, byte array format in order to match the traditional, human-readable string representation of the hashes. They must be sorted in accordance with the output of the bytearr_cmp() function above: the hash with the earliest lesser byte is ordered first, and shorter hashes are ordered before longer ones as a tie-breaker. In the event of two matching transaction hashes, output indices will be compared based on their integer value, with the smaller value ordered first. A further tie is extremely improbable for the aforementioned reasons. + +Because the hash of previous transactions and output indices must be included in a signed transaction, wallet clients capable of signing transactions will necessarily have access to this data. + +Transaction malleability will not negatively impact the correctness of this process. Even if a wallet client follows this process using unconfirmed UTXOs as inputs and an attacker changes modifies the blockchain’s record of the hash of the previous transaction, the wallet client will include the invalidated previous transaction hash in its input data, and will still correctly sort with respect to that invalidated hash. + +===Transaction Outputs=== + +A transaction output is defined by its scriptPubKey and amount. [3] For sorting purposes, we will consider a scriptPubKey in its byte array representation, and a bitcoin amount in terms of their integer number of satoshis (smallest amount ordered first). + +For the sake of efficiency, amounts will be considered first for sorting, since they contain fewer bytes of information (8 bytes) compared to a standard P2PKH scriptPubKey (25 bytes). [4] When the values are tied, the scriptPubKey is then considered. In the event of a tie between scriptPubKeys, sorting is irrelevant since the outputs are exactly equivalent. + +===Examples=== + +Transaction 0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3: + +Inputs: + + 0: 0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57[0] + 1: 26aa6e6d8b9e49bb0630aac301db6757c02e3619feb4ee0eea81eb1672947024[1] + 2: 28e0fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2[0] + 3: 381de9b9ae1a94d9c17f6a08ef9d341a5ce29e2e60c36a52d333ff6203e58d5d[1] + 4: 3b8b2f8efceb60ba78ca8bba206a137f14cb5ea4035e761ee204302d46b98de2[0] + 5: 402b2c02411720bf409eff60d05adad684f135838962823f3614cc657dd7bc0a[1] + 6: 54ffff182965ed0957dba1239c27164ace5a73c9b62a660c74b7b7f15ff61e7a[1] + 7: 643e5f4e66373a57251fb173151e838ccd27d279aca882997e005016bb53d5aa[0] + 8: 6c1d56f31b2de4bfc6aaea28396b333102b1f600da9c6d6149e96ca43f1102b1[1] + 9: 7a1de137cbafb5c70405455c49c5104ca3057a1f1243e6563bb9245c9c88c191[0] + 10: 7d037ceb2ee0dc03e82f17be7935d238b35d1deabf953a892a4507bfbeeb3ba4[1] + 11: a5e899dddb28776ea9ddac0a502316d53a4a3fca607c72f66c470e0412e34086[0] + 12: b4112b8f900a7ca0c8b0e7c4dfad35c6be5f6be46b3458974988e1cdb2fa61b8[0] + 13: bafd65e3c7f3f9fdfdc1ddb026131b278c3be1af90a4a6ffa78c4658f9ec0c85[0] + 14: de0411a1e97484a2804ff1dbde260ac19de841bebad1880c782941aca883b4e9[1] + 15: f0a130a84912d03c1d284974f563c5949ac13f8342b8112edff52971599e6a45[0] + 16: f320832a9d2e2452af63154bc687493484a0e7745ebd3aaf9ca19eb80834ad60[0] + +Outputs: + + 0: 400057456 76a9144a5fba237213a062f6f57978f796390bdcf8d01588ac + 1: 40000000000 76a9145be32612930b8323add2212a4ec03c1562084f8488ac + +Transaction 28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f + +Inputs: + + 0: 35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055[0] + 1: 35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055[1] + +Outputs: + + 0: 100000000 41046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac + 1: 2400000000 41044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac + +==References== + +* [[https://bitcoinmagazine.com/20273/bitstamp-exchange-activity-trackable-due-multisig-wallet-implementation/|1: Bitstamp Info Leak]] +* [[https://github.com/OpenBitcoinPrivacyProject/wallet-ratings/blob/master/2015-1/criteria.md|2: OBPP Random Indexing as Countermeasure]] +* [[https://github.com/aantonop/bitcoinbook/blob/develop/ch05.asciidoc|3: Mastering Bitcoin]] +* [[https://en.bitcoin.it/wiki/Script|4: Bitcoin Wiki on Script]] + +==Acknowledgements== + +Danno Ferrin <danno@numisight.com>, Sergio Demian Lerner <sergiolerner@certimix.com>, Justus Ranvier <justus@openbitcoinprivacyproject.org>, and Peter Todd <pete@petertodd.org> contributed to the design and motivations for this BIP. \ No newline at end of file diff --git a/bip-0079/bip-0079_examples.py b/bip-0079/bip-0079_examples.py new file mode 100644 index 0000000..7622cfe --- /dev/null +++ b/bip-0079/bip-0079_examples.py @@ -0,0 +1,112 @@ +import binascii + +#returns -1 if barr1 is less, 1 if barr1 is greater, and 0 if equal +def bytearr_cmp(barr1, barr2): + pos = 0 + while (pos < len(barr1) and pos < len(barr2)): + if (barr1[pos] < barr2[pos]): + return -1; + elif (barr1[pos] > barr2[pos]): + return 1; + pos = pos + 1 + #the shorter array will be ordered first + if (len(barr1) < len(barr2)): + return -1 + elif (len(barr1) > len(barr2)): + return 1 + else: + return 0 + +#tuples: (prev_tx_hash_byte_arr_little_endian, prev_tx_output_index) +def input_cmp(input_tuple1, input_tuple2): + #test prev_tx_hash_byte_arr_little_endian first + prev_tx_hash_cmp = bytearr_cmp(input_tuple1[0], input_tuple2[0]) + if (prev_tx_hash_cmp != 0): + return prev_tx_hash_cmp + #tie-breaker: prev_tx_output_index + if (input_tuple1[1] < input_tuple2[1]): + return -1 + elif (input_tuple1[1] > input_tuple2[1]): + return 1 + else: + raise ValueError('Matching previous transaction hash and previous transaction output index for two disinct inputs. Invalid!') + +def sort_inputs(input_tuples): + return sorted(input_tuples, cmp=input_cmp) + +def print_inputs(ordered_input_tuples): + index = 0 + for prev_tx_hash_byte_arr_little_endian, prev_tx_output_index in ordered_input_tuples: + prev_tx_hash_hex = binascii.hexlify(bytearray(prev_tx_hash_byte_arr_little_endian)) + print("%d: %s[%d]" % (index, prev_tx_hash_hex, prev_tx_output_index)) + index = index + 1 + +#tuples: (amount, scriptPubKey_byte_arr) +def output_cmp(output_tuple1, output_tuple2): + #test amount first + if (output_tuple1[0] < output_tuple2[0]): + return -1 + elif (output_tuple1[0] > output_tuple2[0]): + return 1 + #tie-breaker: scriptPubKey_byte_arr + return bytearray_cmp(output_tuple1[1], output_tuple2[1]) + +def sort_outputs(output_tuples): + return sorted(output_tuples, cmp=output_cmp) + +def print_outputs(ordered_output_tuples): + index = 0 + for amount, scriptPubKey_byte_arr in ordered_output_tuples: + scriptPubKey_hex = binascii.hexlify(bytearray(scriptPubKey_byte_arr)) + print("%d:\t%d\t%s" % (index, amount, scriptPubKey_hex)) + index = index + 1 + +def main(): + #reference data: https://blockchain.info/rawtx/0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3 + tx_0a6a_input_tuples = [ + # (prev_tx_hash_byte_arr_little_endian, prev_tx_output_index) + ([0x64, 0x3e, 0x5f, 0x4e, 0x66, 0x37, 0x3a, 0x57, 0x25, 0x1f, 0xb1, 0x73, 0x15, 0x1e, 0x83, 0x8c, 0xcd, 0x27, 0xd2, 0x79, 0xac, 0xa8, 0x82, 0x99, 0x7e, 0x00, 0x50, 0x16, 0xbb, 0x53, 0xd5, 0xaa], 0), + ([0x28, 0xe0, 0xfd, 0xd1, 0x85, 0x54, 0x2f, 0x2c, 0x6e, 0xa1, 0x90, 0x30, 0xb0, 0x79, 0x60, 0x51, 0xe7, 0x77, 0x2b, 0x60, 0x26, 0xdd, 0x5d, 0xdc, 0xcd, 0x7a, 0x2f, 0x93, 0xb7, 0x3e, 0x6f, 0xc2], 0), + ([0xf0, 0xa1, 0x30, 0xa8, 0x49, 0x12, 0xd0, 0x3c, 0x1d, 0x28, 0x49, 0x74, 0xf5, 0x63, 0xc5, 0x94, 0x9a, 0xc1, 0x3f, 0x83, 0x42, 0xb8, 0x11, 0x2e, 0xdf, 0xf5, 0x29, 0x71, 0x59, 0x9e, 0x6a, 0x45], 0), + ([0x0e, 0x53, 0xec, 0x5d, 0xfb, 0x2c, 0xb8, 0xa7, 0x1f, 0xec, 0x32, 0xdc, 0x9a, 0x63, 0x4a, 0x35, 0xb7, 0xe2, 0x47, 0x99, 0x29, 0x5d, 0xdd, 0x52, 0x78, 0x21, 0x78, 0x22, 0xe0, 0xb3, 0x1f, 0x57], 0), + ([0x38, 0x1d, 0xe9, 0xb9, 0xae, 0x1a, 0x94, 0xd9, 0xc1, 0x7f, 0x6a, 0x08, 0xef, 0x9d, 0x34, 0x1a, 0x5c, 0xe2, 0x9e, 0x2e, 0x60, 0xc3, 0x6a, 0x52, 0xd3, 0x33, 0xff, 0x62, 0x03, 0xe5, 0x8d, 0x5d], 1), + ([0xf3, 0x20, 0x83, 0x2a, 0x9d, 0x2e, 0x24, 0x52, 0xaf, 0x63, 0x15, 0x4b, 0xc6, 0x87, 0x49, 0x34, 0x84, 0xa0, 0xe7, 0x74, 0x5e, 0xbd, 0x3a, 0xaf, 0x9c, 0xa1, 0x9e, 0xb8, 0x08, 0x34, 0xad, 0x60], 0), + ([0xde, 0x04, 0x11, 0xa1, 0xe9, 0x74, 0x84, 0xa2, 0x80, 0x4f, 0xf1, 0xdb, 0xde, 0x26, 0x0a, 0xc1, 0x9d, 0xe8, 0x41, 0xbe, 0xba, 0xd1, 0x88, 0x0c, 0x78, 0x29, 0x41, 0xac, 0xa8, 0x83, 0xb4, 0xe9], 1), + ([0x3b, 0x8b, 0x2f, 0x8e, 0xfc, 0xeb, 0x60, 0xba, 0x78, 0xca, 0x8b, 0xba, 0x20, 0x6a, 0x13, 0x7f, 0x14, 0xcb, 0x5e, 0xa4, 0x03, 0x5e, 0x76, 0x1e, 0xe2, 0x04, 0x30, 0x2d, 0x46, 0xb9, 0x8d, 0xe2], 0), + ([0x54, 0xff, 0xff, 0x18, 0x29, 0x65, 0xed, 0x09, 0x57, 0xdb, 0xa1, 0x23, 0x9c, 0x27, 0x16, 0x4a, 0xce, 0x5a, 0x73, 0xc9, 0xb6, 0x2a, 0x66, 0x0c, 0x74, 0xb7, 0xb7, 0xf1, 0x5f, 0xf6, 0x1e, 0x7a], 1), + ([0xba, 0xfd, 0x65, 0xe3, 0xc7, 0xf3, 0xf9, 0xfd, 0xfd, 0xc1, 0xdd, 0xb0, 0x26, 0x13, 0x1b, 0x27, 0x8c, 0x3b, 0xe1, 0xaf, 0x90, 0xa4, 0xa6, 0xff, 0xa7, 0x8c, 0x46, 0x58, 0xf9, 0xec, 0x0c, 0x85], 0), + ([0xa5, 0xe8, 0x99, 0xdd, 0xdb, 0x28, 0x77, 0x6e, 0xa9, 0xdd, 0xac, 0x0a, 0x50, 0x23, 0x16, 0xd5, 0x3a, 0x4a, 0x3f, 0xca, 0x60, 0x7c, 0x72, 0xf6, 0x6c, 0x47, 0x0e, 0x04, 0x12, 0xe3, 0x40, 0x86], 0), + ([0x7a, 0x1d, 0xe1, 0x37, 0xcb, 0xaf, 0xb5, 0xc7, 0x04, 0x05, 0x45, 0x5c, 0x49, 0xc5, 0x10, 0x4c, 0xa3, 0x05, 0x7a, 0x1f, 0x12, 0x43, 0xe6, 0x56, 0x3b, 0xb9, 0x24, 0x5c, 0x9c, 0x88, 0xc1, 0x91], 0), + ([0x26, 0xaa, 0x6e, 0x6d, 0x8b, 0x9e, 0x49, 0xbb, 0x06, 0x30, 0xaa, 0xc3, 0x01, 0xdb, 0x67, 0x57, 0xc0, 0x2e, 0x36, 0x19, 0xfe, 0xb4, 0xee, 0x0e, 0xea, 0x81, 0xeb, 0x16, 0x72, 0x94, 0x70, 0x24], 1), + ([0x40, 0x2b, 0x2c, 0x02, 0x41, 0x17, 0x20, 0xbf, 0x40, 0x9e, 0xff, 0x60, 0xd0, 0x5a, 0xda, 0xd6, 0x84, 0xf1, 0x35, 0x83, 0x89, 0x62, 0x82, 0x3f, 0x36, 0x14, 0xcc, 0x65, 0x7d, 0xd7, 0xbc, 0x0a], 1), + ([0x7d, 0x03, 0x7c, 0xeb, 0x2e, 0xe0, 0xdc, 0x03, 0xe8, 0x2f, 0x17, 0xbe, 0x79, 0x35, 0xd2, 0x38, 0xb3, 0x5d, 0x1d, 0xea, 0xbf, 0x95, 0x3a, 0x89, 0x2a, 0x45, 0x07, 0xbf, 0xbe, 0xeb, 0x3b, 0xa4], 1), + ([0x6c, 0x1d, 0x56, 0xf3, 0x1b, 0x2d, 0xe4, 0xbf, 0xc6, 0xaa, 0xea, 0x28, 0x39, 0x6b, 0x33, 0x31, 0x02, 0xb1, 0xf6, 0x00, 0xda, 0x9c, 0x6d, 0x61, 0x49, 0xe9, 0x6c, 0xa4, 0x3f, 0x11, 0x02, 0xb1], 1), + ([0xb4, 0x11, 0x2b, 0x8f, 0x90, 0x0a, 0x7c, 0xa0, 0xc8, 0xb0, 0xe7, 0xc4, 0xdf, 0xad, 0x35, 0xc6, 0xbe, 0x5f, 0x6b, 0xe4, 0x6b, 0x34, 0x58, 0x97, 0x49, 0x88, 0xe1, 0xcd, 0xb2, 0xfa, 0x61, 0xb8], 0)] + tx_0a6a_sorted_input_tuples = sort_inputs(tx_0a6a_input_tuples) + print_inputs(tx_0a6a_sorted_input_tuples) + + tx_0a6a_output_tuples = [ + # (amount, scriptPubKey_byte_arr) + (400057456, [0x76, 0xa9, 0x14, 0x4a, 0x5f, 0xba, 0x23, 0x72, 0x13, 0xa0, 0x62, 0xf6, 0xf5, 0x79, 0x78, 0xf7, 0x96, 0x39, 0x0b, 0xdc, 0xf8, 0xd0, 0x15, 0x88, 0xac]), + (40000000000, [0x76, 0xa9, 0x14, 0x5b, 0xe3, 0x26, 0x12, 0x93, 0x0b, 0x83, 0x23, 0xad, 0xd2, 0x21, 0x2a, 0x4e, 0xc0, 0x3c, 0x15, 0x62, 0x08, 0x4f, 0x84, 0x88, 0xac])] + tx_0a6a_sorted_output_tuples = sort_outputs(tx_0a6a_output_tuples) + print_outputs(tx_0a6a_sorted_output_tuples) + + #reference data: https://blockchain.info/rawtx/28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f thanks @quantabytes! + tx_2820_input_tuples = [ + # (prev_tx_hash, prev_tx_output_index) + ("35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", 0), + ("35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", 1)] #duplicate prev_tx_hash + + tx_2820_sorted_input_tuples = sort_inputs(tx_2820_input_tuples) + print_inputs(tx_2820_sorted_input_tuples) + + tx_2820_output_tuples = [ + # (amount, scriptPubKey_byte_arr) + (100000000, [0x41, 0x04, 0x6a, 0x07, 0x65, 0xb5, 0x86, 0x56, 0x41, 0xce, 0x08, 0xdd, 0x39, 0x69, 0x0a, 0xad, 0xe2, 0x6d, 0xfb, 0xf5, 0x51, 0x14, 0x30, 0xca, 0x42, 0x8a, 0x30, 0x89, 0x26, 0x13, 0x61, 0xce, 0xf1, 0x70, 0xe3, 0x92, 0x9a, 0x68, 0xae, 0xe3, 0xd8, 0xd4, 0x84, 0x8b, 0x0c, 0x51, 0x11, 0xb0, 0xa3, 0x7b, 0x82, 0xb8, 0x6a, 0xd5, 0x59, 0xfd, 0x2a, 0x74, 0x5b, 0x44, 0xd8, 0xe8, 0xd9, 0xdf, 0xdc, 0x0c, 0xac]), + (2400000000, [0x41, 0x04, 0x4a, 0x65, 0x6f, 0x06, 0x58, 0x71, 0xa3, 0x53, 0xf2, 0x16, 0xca, 0x26, 0xce, 0xf8, 0xdd, 0xe2, 0xf0, 0x3e, 0x8c, 0x16, 0x20, 0x2d, 0x2e, 0x8a, 0xd7, 0x69, 0xf0, 0x20, 0x32, 0xcb, 0x86, 0xa5, 0xeb, 0x5e, 0x56, 0x84, 0x2e, 0x92, 0xe1, 0x91, 0x41, 0xd6, 0x0a, 0x01, 0x92, 0x8f, 0x8d, 0xd2, 0xc8, 0x75, 0xa3, 0x90, 0xf6, 0x7c, 0x1f, 0x6c, 0x94, 0xcf, 0xc6, 0x17, 0xc0, 0xea, 0x45, 0xaf, 0xac])] + tx_2820_sorted_output_tuples = sort_outputs(tx_2820_output_tuples) + print_outputs(tx_2820_output_tuples) + +if __name__ == "__main__": + main() \ No newline at end of file -- cgit v1.2.3 From 469e7e7f12b1e1da05f91e2f9c485a8be3a28fd3 Mon Sep 17 00:00:00 2001 From: Kristov Atlas Date: Wed, 24 Jun 2015 17:02:43 -0400 Subject: BIP #69 assigned by gmaxwell --- README.mediawiki | 12 ++-- bip-0069.mediawiki | 129 ++++++++++++++++++++++++++++++++++++++++++ bip-0069/bip-0079_examples.py | 112 ++++++++++++++++++++++++++++++++++++ bip-0079.mediawiki | 129 ------------------------------------------ bip-0079/bip-0079_examples.py | 112 ------------------------------------ 5 files changed, 247 insertions(+), 247 deletions(-) create mode 100644 bip-0069.mediawiki create mode 100644 bip-0069/bip-0079_examples.py delete mode 100644 bip-0079.mediawiki delete mode 100644 bip-0079/bip-0079_examples.py diff --git a/README.mediawiki b/README.mediawiki index a758f1a..56c8bd1 100644 --- a/README.mediawiki +++ b/README.mediawiki @@ -254,6 +254,12 @@ Those proposing changes should consider that ultimately consent may rest with th | Standard | Draft |- +| [[bip-0069.mediawiki|69]] +| Lexicographical Indexing of Transaction Inputs and Outputs +| Kristov Atlas +| Standard +| Draft +|- | [[bip-0070.mediawiki|70]] | Payment protocol | Gavin Andresen @@ -277,12 +283,6 @@ Those proposing changes should consider that ultimately consent may rest with th | Stephen Pair | Standard | Draft -|- -| [[bip-0079.mediawiki|79]] -| Lexicographical Indexing of Transaction Inputs and Outputs -| Kristov Atlas -| Standard -| Draft |} diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki new file mode 100644 index 0000000..65e35e6 --- /dev/null +++ b/bip-0069.mediawiki @@ -0,0 +1,129 @@ +
+  BIP:     BIP: 79
+  Title:   Lexicographical Indexing of Transaction Inputs and Outputs
+  Authors: Kristov Atlas 
+  Status:  Draft
+  Type:    Informational
+  Created: 2015-06-12
+
+ +==Abstract== + +Currently there is no standard for bitcoin wallet clients when ordering transaction inputs and outputs. As a result, wallet clients often have a discernible blockchain fingerprint, and can leak private information about their users. By contrast, a standard for non-deterministic sorting could be difficult to audit. This document proposes deterministic lexicographical sorting, using hashes of previous transactions and output indices to sort transaction inputs, as well as values and scriptPubKeys to sort transaction outputs. + +==Copyright== + +This BIP is in the public domain. + +==Motivation== + +Currently, there is no clear standard for how wallet clients ought to order transaction inputs and outputs. Since wallet clients are left to their own devices to determine this ordering, they often leak information about their users’ finances. For example, a wallet client might naively order inputs based on when addresses were added to a wallet by the user through importing or random generation. Many wallets will place spending outputs first and change outputs second, leaking information about both the sender and receiver’s finances to passive blockchain observers. Such information should remain private not only for the benefit of consumers, but in higher order financial systems must be kept secret to prevent fraud. A researcher recently demonstrated this principle when he detected that Bitstamp leaked information when creating exchange transactions, enabling potential espionage among traders. [1] + +One way to address these privacy weaknesses is by randomly ordering inputs and outputs. [2] After all, the order of inputs and outputs does not impact the function of the transaction they belong to, making random sorting viable. Unfortunately, it can be difficult to prove that this sorting process is genuinely randomly sorted based on code or run-time analysis, especially if the software is closed source. A malicious software developer can abuse the ordering of inputs and outputs as a side channel of leaking information. For example, if an attacker can patch a victim’s HD wallet client to order inputs and outputs based on the bits of a master private key, then the attacker can eventually steal all of the victim’s funds by monitoring the blockchain. Non-deterministic methods of sorting are difficult to audit because they are not repeatable. + +The lack of standardization between wallet clients when ordering inputs and outputs can yield predictable quirks that characterize particular wallet clients or services. Such quirks create unique fingerprints that a privacy attacker can employ through simple passive blockchain observation. + +The solution is to create an algorithm for sorting transaction inputs and outputs that is deterministic. Since it is deterministic, it should also be unambiguous — that is, given a particular transaction, the proper order of inputs and outputs should be obvious. To make this standard as widely applicable as possible, it should rely on information that is downloaded by both full nodes (with or without typical efficiency techniques such as pruning) and SPV nodes. In order to ensure that it does not leak confidential data, it must rely on information that is publicly accessible through the blockchain. The use of public blockchain information also allows a transaction to be sorted even when it is a multi-party transaction, such as in the example of a CoinJoin. + +==Specification== + +===Applicability=== + +This BIP applies to any transaction for which the order of its inputs and outputs does not impact the transaction’s function. Currently, this refers to any transaction that employs the SIGHASH_ALL signature hash type, in which signatures commit to the exact order of inputs and outputs. Transactions that use SIGHASH_ANYONECANPAY and/or SIGHASH_NONE may include inputs and/or outputs that are not signed; however, compliant software should still emit transactions with lexicographically sorted inputs and outputs, even though they may later be modified by others. + +In the event that future protocol upgrades introduce new signature hash types, compliant software should apply the lexicographical ordering principle analogously. + +While out of scope of this BIP, protocols that do require a specified order of inputs/outputs (e.g. due to use of SIGHASH_SINGLE) should consider the goals of this BIP and how best to adapt them to the specific needs of those protocols. + +===Lexicographical Sorting=== + +Ordering of inputs and outputs will rely on the output of sorting functions. These functions can be defined as taking two inputs or two outputs as parameters and returning their appropriate ordering with respect to each other. + +Byte arrays must be sorted with an algorithm that produces the same output as the following comparison algorithm: + + #returns -1 if barr1 is lesser, 1 if barr1 is greater, and 0 if equal + def bytearr_cmp(barr1, barr2): + pos = 0 + while (pos < len(barr1) and pos < len(barr2)): + if (barr1[pos] < barr2[pos]): + return -1; + elif (barr1[pos] > barr2[pos]): + return 1; + pos = pos + 1 + #the shorter array will be ordered first + if (len(barr1) < len(barr2)): + return -1 + elif (len(barr1) > len(barr2)): + return 1 + else: + return 0 + +N.B. These comparisons do not need to operate in constant time since they are not processing secret information. + +===Transaction Inputs=== + +104 Transaction inputs are defined by the hash of a previous transaction, the output index of of a UTXO from that previous transaction, the size of an unlocking script, the unlocking script, and a sequence number. [3] For sorting inputs, the hash of the previous transaction and the output index within that transaction are sufficient for sorting purposes; each transaction hash has an extremely high probability of being unique in the blockchain — this is enforced for coinbase transactions by BIP30 — and output indices within a transaction are unique. For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables. + +Hashes of previous transactions are considered for the purposes of this BIP in their little-endian, byte array format in order to match the traditional, human-readable string representation of the hashes. They must be sorted in accordance with the output of the bytearr_cmp() function above: the hash with the earliest lesser byte is ordered first, and shorter hashes are ordered before longer ones as a tie-breaker. In the event of two matching transaction hashes, output indices will be compared based on their integer value, with the smaller value ordered first. A further tie is extremely improbable for the aforementioned reasons. + +Because the hash of previous transactions and output indices must be included in a signed transaction, wallet clients capable of signing transactions will necessarily have access to this data. + +Transaction malleability will not negatively impact the correctness of this process. Even if a wallet client follows this process using unconfirmed UTXOs as inputs and an attacker changes modifies the blockchain’s record of the hash of the previous transaction, the wallet client will include the invalidated previous transaction hash in its input data, and will still correctly sort with respect to that invalidated hash. + +===Transaction Outputs=== + +A transaction output is defined by its scriptPubKey and amount. [3] For sorting purposes, we will consider a scriptPubKey in its byte array representation, and a bitcoin amount in terms of their integer number of satoshis (smallest amount ordered first). + +For the sake of efficiency, amounts will be considered first for sorting, since they contain fewer bytes of information (8 bytes) compared to a standard P2PKH scriptPubKey (25 bytes). [4] When the values are tied, the scriptPubKey is then considered. In the event of a tie between scriptPubKeys, sorting is irrelevant since the outputs are exactly equivalent. + +===Examples=== + +Transaction 0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3: + +Inputs: + + 0: 0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57[0] + 1: 26aa6e6d8b9e49bb0630aac301db6757c02e3619feb4ee0eea81eb1672947024[1] + 2: 28e0fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2[0] + 3: 381de9b9ae1a94d9c17f6a08ef9d341a5ce29e2e60c36a52d333ff6203e58d5d[1] + 4: 3b8b2f8efceb60ba78ca8bba206a137f14cb5ea4035e761ee204302d46b98de2[0] + 5: 402b2c02411720bf409eff60d05adad684f135838962823f3614cc657dd7bc0a[1] + 6: 54ffff182965ed0957dba1239c27164ace5a73c9b62a660c74b7b7f15ff61e7a[1] + 7: 643e5f4e66373a57251fb173151e838ccd27d279aca882997e005016bb53d5aa[0] + 8: 6c1d56f31b2de4bfc6aaea28396b333102b1f600da9c6d6149e96ca43f1102b1[1] + 9: 7a1de137cbafb5c70405455c49c5104ca3057a1f1243e6563bb9245c9c88c191[0] + 10: 7d037ceb2ee0dc03e82f17be7935d238b35d1deabf953a892a4507bfbeeb3ba4[1] + 11: a5e899dddb28776ea9ddac0a502316d53a4a3fca607c72f66c470e0412e34086[0] + 12: b4112b8f900a7ca0c8b0e7c4dfad35c6be5f6be46b3458974988e1cdb2fa61b8[0] + 13: bafd65e3c7f3f9fdfdc1ddb026131b278c3be1af90a4a6ffa78c4658f9ec0c85[0] + 14: de0411a1e97484a2804ff1dbde260ac19de841bebad1880c782941aca883b4e9[1] + 15: f0a130a84912d03c1d284974f563c5949ac13f8342b8112edff52971599e6a45[0] + 16: f320832a9d2e2452af63154bc687493484a0e7745ebd3aaf9ca19eb80834ad60[0] + +Outputs: + + 0: 400057456 76a9144a5fba237213a062f6f57978f796390bdcf8d01588ac + 1: 40000000000 76a9145be32612930b8323add2212a4ec03c1562084f8488ac + +Transaction 28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f + +Inputs: + + 0: 35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055[0] + 1: 35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055[1] + +Outputs: + + 0: 100000000 41046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac + 1: 2400000000 41044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac + +==References== + +* [[https://bitcoinmagazine.com/20273/bitstamp-exchange-activity-trackable-due-multisig-wallet-implementation/|1: Bitstamp Info Leak]] +* [[https://github.com/OpenBitcoinPrivacyProject/wallet-ratings/blob/master/2015-1/criteria.md|2: OBPP Random Indexing as Countermeasure]] +* [[https://github.com/aantonop/bitcoinbook/blob/develop/ch05.asciidoc|3: Mastering Bitcoin]] +* [[https://en.bitcoin.it/wiki/Script|4: Bitcoin Wiki on Script]] + +==Acknowledgements== + +Danno Ferrin <danno@numisight.com>, Sergio Demian Lerner <sergiolerner@certimix.com>, Justus Ranvier <justus@openbitcoinprivacyproject.org>, and Peter Todd <pete@petertodd.org> contributed to the design and motivations for this BIP. \ No newline at end of file diff --git a/bip-0069/bip-0079_examples.py b/bip-0069/bip-0079_examples.py new file mode 100644 index 0000000..7622cfe --- /dev/null +++ b/bip-0069/bip-0079_examples.py @@ -0,0 +1,112 @@ +import binascii + +#returns -1 if barr1 is less, 1 if barr1 is greater, and 0 if equal +def bytearr_cmp(barr1, barr2): + pos = 0 + while (pos < len(barr1) and pos < len(barr2)): + if (barr1[pos] < barr2[pos]): + return -1; + elif (barr1[pos] > barr2[pos]): + return 1; + pos = pos + 1 + #the shorter array will be ordered first + if (len(barr1) < len(barr2)): + return -1 + elif (len(barr1) > len(barr2)): + return 1 + else: + return 0 + +#tuples: (prev_tx_hash_byte_arr_little_endian, prev_tx_output_index) +def input_cmp(input_tuple1, input_tuple2): + #test prev_tx_hash_byte_arr_little_endian first + prev_tx_hash_cmp = bytearr_cmp(input_tuple1[0], input_tuple2[0]) + if (prev_tx_hash_cmp != 0): + return prev_tx_hash_cmp + #tie-breaker: prev_tx_output_index + if (input_tuple1[1] < input_tuple2[1]): + return -1 + elif (input_tuple1[1] > input_tuple2[1]): + return 1 + else: + raise ValueError('Matching previous transaction hash and previous transaction output index for two disinct inputs. Invalid!') + +def sort_inputs(input_tuples): + return sorted(input_tuples, cmp=input_cmp) + +def print_inputs(ordered_input_tuples): + index = 0 + for prev_tx_hash_byte_arr_little_endian, prev_tx_output_index in ordered_input_tuples: + prev_tx_hash_hex = binascii.hexlify(bytearray(prev_tx_hash_byte_arr_little_endian)) + print("%d: %s[%d]" % (index, prev_tx_hash_hex, prev_tx_output_index)) + index = index + 1 + +#tuples: (amount, scriptPubKey_byte_arr) +def output_cmp(output_tuple1, output_tuple2): + #test amount first + if (output_tuple1[0] < output_tuple2[0]): + return -1 + elif (output_tuple1[0] > output_tuple2[0]): + return 1 + #tie-breaker: scriptPubKey_byte_arr + return bytearray_cmp(output_tuple1[1], output_tuple2[1]) + +def sort_outputs(output_tuples): + return sorted(output_tuples, cmp=output_cmp) + +def print_outputs(ordered_output_tuples): + index = 0 + for amount, scriptPubKey_byte_arr in ordered_output_tuples: + scriptPubKey_hex = binascii.hexlify(bytearray(scriptPubKey_byte_arr)) + print("%d:\t%d\t%s" % (index, amount, scriptPubKey_hex)) + index = index + 1 + +def main(): + #reference data: https://blockchain.info/rawtx/0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3 + tx_0a6a_input_tuples = [ + # (prev_tx_hash_byte_arr_little_endian, prev_tx_output_index) + ([0x64, 0x3e, 0x5f, 0x4e, 0x66, 0x37, 0x3a, 0x57, 0x25, 0x1f, 0xb1, 0x73, 0x15, 0x1e, 0x83, 0x8c, 0xcd, 0x27, 0xd2, 0x79, 0xac, 0xa8, 0x82, 0x99, 0x7e, 0x00, 0x50, 0x16, 0xbb, 0x53, 0xd5, 0xaa], 0), + ([0x28, 0xe0, 0xfd, 0xd1, 0x85, 0x54, 0x2f, 0x2c, 0x6e, 0xa1, 0x90, 0x30, 0xb0, 0x79, 0x60, 0x51, 0xe7, 0x77, 0x2b, 0x60, 0x26, 0xdd, 0x5d, 0xdc, 0xcd, 0x7a, 0x2f, 0x93, 0xb7, 0x3e, 0x6f, 0xc2], 0), + ([0xf0, 0xa1, 0x30, 0xa8, 0x49, 0x12, 0xd0, 0x3c, 0x1d, 0x28, 0x49, 0x74, 0xf5, 0x63, 0xc5, 0x94, 0x9a, 0xc1, 0x3f, 0x83, 0x42, 0xb8, 0x11, 0x2e, 0xdf, 0xf5, 0x29, 0x71, 0x59, 0x9e, 0x6a, 0x45], 0), + ([0x0e, 0x53, 0xec, 0x5d, 0xfb, 0x2c, 0xb8, 0xa7, 0x1f, 0xec, 0x32, 0xdc, 0x9a, 0x63, 0x4a, 0x35, 0xb7, 0xe2, 0x47, 0x99, 0x29, 0x5d, 0xdd, 0x52, 0x78, 0x21, 0x78, 0x22, 0xe0, 0xb3, 0x1f, 0x57], 0), + ([0x38, 0x1d, 0xe9, 0xb9, 0xae, 0x1a, 0x94, 0xd9, 0xc1, 0x7f, 0x6a, 0x08, 0xef, 0x9d, 0x34, 0x1a, 0x5c, 0xe2, 0x9e, 0x2e, 0x60, 0xc3, 0x6a, 0x52, 0xd3, 0x33, 0xff, 0x62, 0x03, 0xe5, 0x8d, 0x5d], 1), + ([0xf3, 0x20, 0x83, 0x2a, 0x9d, 0x2e, 0x24, 0x52, 0xaf, 0x63, 0x15, 0x4b, 0xc6, 0x87, 0x49, 0x34, 0x84, 0xa0, 0xe7, 0x74, 0x5e, 0xbd, 0x3a, 0xaf, 0x9c, 0xa1, 0x9e, 0xb8, 0x08, 0x34, 0xad, 0x60], 0), + ([0xde, 0x04, 0x11, 0xa1, 0xe9, 0x74, 0x84, 0xa2, 0x80, 0x4f, 0xf1, 0xdb, 0xde, 0x26, 0x0a, 0xc1, 0x9d, 0xe8, 0x41, 0xbe, 0xba, 0xd1, 0x88, 0x0c, 0x78, 0x29, 0x41, 0xac, 0xa8, 0x83, 0xb4, 0xe9], 1), + ([0x3b, 0x8b, 0x2f, 0x8e, 0xfc, 0xeb, 0x60, 0xba, 0x78, 0xca, 0x8b, 0xba, 0x20, 0x6a, 0x13, 0x7f, 0x14, 0xcb, 0x5e, 0xa4, 0x03, 0x5e, 0x76, 0x1e, 0xe2, 0x04, 0x30, 0x2d, 0x46, 0xb9, 0x8d, 0xe2], 0), + ([0x54, 0xff, 0xff, 0x18, 0x29, 0x65, 0xed, 0x09, 0x57, 0xdb, 0xa1, 0x23, 0x9c, 0x27, 0x16, 0x4a, 0xce, 0x5a, 0x73, 0xc9, 0xb6, 0x2a, 0x66, 0x0c, 0x74, 0xb7, 0xb7, 0xf1, 0x5f, 0xf6, 0x1e, 0x7a], 1), + ([0xba, 0xfd, 0x65, 0xe3, 0xc7, 0xf3, 0xf9, 0xfd, 0xfd, 0xc1, 0xdd, 0xb0, 0x26, 0x13, 0x1b, 0x27, 0x8c, 0x3b, 0xe1, 0xaf, 0x90, 0xa4, 0xa6, 0xff, 0xa7, 0x8c, 0x46, 0x58, 0xf9, 0xec, 0x0c, 0x85], 0), + ([0xa5, 0xe8, 0x99, 0xdd, 0xdb, 0x28, 0x77, 0x6e, 0xa9, 0xdd, 0xac, 0x0a, 0x50, 0x23, 0x16, 0xd5, 0x3a, 0x4a, 0x3f, 0xca, 0x60, 0x7c, 0x72, 0xf6, 0x6c, 0x47, 0x0e, 0x04, 0x12, 0xe3, 0x40, 0x86], 0), + ([0x7a, 0x1d, 0xe1, 0x37, 0xcb, 0xaf, 0xb5, 0xc7, 0x04, 0x05, 0x45, 0x5c, 0x49, 0xc5, 0x10, 0x4c, 0xa3, 0x05, 0x7a, 0x1f, 0x12, 0x43, 0xe6, 0x56, 0x3b, 0xb9, 0x24, 0x5c, 0x9c, 0x88, 0xc1, 0x91], 0), + ([0x26, 0xaa, 0x6e, 0x6d, 0x8b, 0x9e, 0x49, 0xbb, 0x06, 0x30, 0xaa, 0xc3, 0x01, 0xdb, 0x67, 0x57, 0xc0, 0x2e, 0x36, 0x19, 0xfe, 0xb4, 0xee, 0x0e, 0xea, 0x81, 0xeb, 0x16, 0x72, 0x94, 0x70, 0x24], 1), + ([0x40, 0x2b, 0x2c, 0x02, 0x41, 0x17, 0x20, 0xbf, 0x40, 0x9e, 0xff, 0x60, 0xd0, 0x5a, 0xda, 0xd6, 0x84, 0xf1, 0x35, 0x83, 0x89, 0x62, 0x82, 0x3f, 0x36, 0x14, 0xcc, 0x65, 0x7d, 0xd7, 0xbc, 0x0a], 1), + ([0x7d, 0x03, 0x7c, 0xeb, 0x2e, 0xe0, 0xdc, 0x03, 0xe8, 0x2f, 0x17, 0xbe, 0x79, 0x35, 0xd2, 0x38, 0xb3, 0x5d, 0x1d, 0xea, 0xbf, 0x95, 0x3a, 0x89, 0x2a, 0x45, 0x07, 0xbf, 0xbe, 0xeb, 0x3b, 0xa4], 1), + ([0x6c, 0x1d, 0x56, 0xf3, 0x1b, 0x2d, 0xe4, 0xbf, 0xc6, 0xaa, 0xea, 0x28, 0x39, 0x6b, 0x33, 0x31, 0x02, 0xb1, 0xf6, 0x00, 0xda, 0x9c, 0x6d, 0x61, 0x49, 0xe9, 0x6c, 0xa4, 0x3f, 0x11, 0x02, 0xb1], 1), + ([0xb4, 0x11, 0x2b, 0x8f, 0x90, 0x0a, 0x7c, 0xa0, 0xc8, 0xb0, 0xe7, 0xc4, 0xdf, 0xad, 0x35, 0xc6, 0xbe, 0x5f, 0x6b, 0xe4, 0x6b, 0x34, 0x58, 0x97, 0x49, 0x88, 0xe1, 0xcd, 0xb2, 0xfa, 0x61, 0xb8], 0)] + tx_0a6a_sorted_input_tuples = sort_inputs(tx_0a6a_input_tuples) + print_inputs(tx_0a6a_sorted_input_tuples) + + tx_0a6a_output_tuples = [ + # (amount, scriptPubKey_byte_arr) + (400057456, [0x76, 0xa9, 0x14, 0x4a, 0x5f, 0xba, 0x23, 0x72, 0x13, 0xa0, 0x62, 0xf6, 0xf5, 0x79, 0x78, 0xf7, 0x96, 0x39, 0x0b, 0xdc, 0xf8, 0xd0, 0x15, 0x88, 0xac]), + (40000000000, [0x76, 0xa9, 0x14, 0x5b, 0xe3, 0x26, 0x12, 0x93, 0x0b, 0x83, 0x23, 0xad, 0xd2, 0x21, 0x2a, 0x4e, 0xc0, 0x3c, 0x15, 0x62, 0x08, 0x4f, 0x84, 0x88, 0xac])] + tx_0a6a_sorted_output_tuples = sort_outputs(tx_0a6a_output_tuples) + print_outputs(tx_0a6a_sorted_output_tuples) + + #reference data: https://blockchain.info/rawtx/28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f thanks @quantabytes! + tx_2820_input_tuples = [ + # (prev_tx_hash, prev_tx_output_index) + ("35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", 0), + ("35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", 1)] #duplicate prev_tx_hash + + tx_2820_sorted_input_tuples = sort_inputs(tx_2820_input_tuples) + print_inputs(tx_2820_sorted_input_tuples) + + tx_2820_output_tuples = [ + # (amount, scriptPubKey_byte_arr) + (100000000, [0x41, 0x04, 0x6a, 0x07, 0x65, 0xb5, 0x86, 0x56, 0x41, 0xce, 0x08, 0xdd, 0x39, 0x69, 0x0a, 0xad, 0xe2, 0x6d, 0xfb, 0xf5, 0x51, 0x14, 0x30, 0xca, 0x42, 0x8a, 0x30, 0x89, 0x26, 0x13, 0x61, 0xce, 0xf1, 0x70, 0xe3, 0x92, 0x9a, 0x68, 0xae, 0xe3, 0xd8, 0xd4, 0x84, 0x8b, 0x0c, 0x51, 0x11, 0xb0, 0xa3, 0x7b, 0x82, 0xb8, 0x6a, 0xd5, 0x59, 0xfd, 0x2a, 0x74, 0x5b, 0x44, 0xd8, 0xe8, 0xd9, 0xdf, 0xdc, 0x0c, 0xac]), + (2400000000, [0x41, 0x04, 0x4a, 0x65, 0x6f, 0x06, 0x58, 0x71, 0xa3, 0x53, 0xf2, 0x16, 0xca, 0x26, 0xce, 0xf8, 0xdd, 0xe2, 0xf0, 0x3e, 0x8c, 0x16, 0x20, 0x2d, 0x2e, 0x8a, 0xd7, 0x69, 0xf0, 0x20, 0x32, 0xcb, 0x86, 0xa5, 0xeb, 0x5e, 0x56, 0x84, 0x2e, 0x92, 0xe1, 0x91, 0x41, 0xd6, 0x0a, 0x01, 0x92, 0x8f, 0x8d, 0xd2, 0xc8, 0x75, 0xa3, 0x90, 0xf6, 0x7c, 0x1f, 0x6c, 0x94, 0xcf, 0xc6, 0x17, 0xc0, 0xea, 0x45, 0xaf, 0xac])] + tx_2820_sorted_output_tuples = sort_outputs(tx_2820_output_tuples) + print_outputs(tx_2820_output_tuples) + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/bip-0079.mediawiki b/bip-0079.mediawiki deleted file mode 100644 index 65e35e6..0000000 --- a/bip-0079.mediawiki +++ /dev/null @@ -1,129 +0,0 @@ -
-  BIP:     BIP: 79
-  Title:   Lexicographical Indexing of Transaction Inputs and Outputs
-  Authors: Kristov Atlas 
-  Status:  Draft
-  Type:    Informational
-  Created: 2015-06-12
-
- -==Abstract== - -Currently there is no standard for bitcoin wallet clients when ordering transaction inputs and outputs. As a result, wallet clients often have a discernible blockchain fingerprint, and can leak private information about their users. By contrast, a standard for non-deterministic sorting could be difficult to audit. This document proposes deterministic lexicographical sorting, using hashes of previous transactions and output indices to sort transaction inputs, as well as values and scriptPubKeys to sort transaction outputs. - -==Copyright== - -This BIP is in the public domain. - -==Motivation== - -Currently, there is no clear standard for how wallet clients ought to order transaction inputs and outputs. Since wallet clients are left to their own devices to determine this ordering, they often leak information about their users’ finances. For example, a wallet client might naively order inputs based on when addresses were added to a wallet by the user through importing or random generation. Many wallets will place spending outputs first and change outputs second, leaking information about both the sender and receiver’s finances to passive blockchain observers. Such information should remain private not only for the benefit of consumers, but in higher order financial systems must be kept secret to prevent fraud. A researcher recently demonstrated this principle when he detected that Bitstamp leaked information when creating exchange transactions, enabling potential espionage among traders. [1] - -One way to address these privacy weaknesses is by randomly ordering inputs and outputs. [2] After all, the order of inputs and outputs does not impact the function of the transaction they belong to, making random sorting viable. Unfortunately, it can be difficult to prove that this sorting process is genuinely randomly sorted based on code or run-time analysis, especially if the software is closed source. A malicious software developer can abuse the ordering of inputs and outputs as a side channel of leaking information. For example, if an attacker can patch a victim’s HD wallet client to order inputs and outputs based on the bits of a master private key, then the attacker can eventually steal all of the victim’s funds by monitoring the blockchain. Non-deterministic methods of sorting are difficult to audit because they are not repeatable. - -The lack of standardization between wallet clients when ordering inputs and outputs can yield predictable quirks that characterize particular wallet clients or services. Such quirks create unique fingerprints that a privacy attacker can employ through simple passive blockchain observation. - -The solution is to create an algorithm for sorting transaction inputs and outputs that is deterministic. Since it is deterministic, it should also be unambiguous — that is, given a particular transaction, the proper order of inputs and outputs should be obvious. To make this standard as widely applicable as possible, it should rely on information that is downloaded by both full nodes (with or without typical efficiency techniques such as pruning) and SPV nodes. In order to ensure that it does not leak confidential data, it must rely on information that is publicly accessible through the blockchain. The use of public blockchain information also allows a transaction to be sorted even when it is a multi-party transaction, such as in the example of a CoinJoin. - -==Specification== - -===Applicability=== - -This BIP applies to any transaction for which the order of its inputs and outputs does not impact the transaction’s function. Currently, this refers to any transaction that employs the SIGHASH_ALL signature hash type, in which signatures commit to the exact order of inputs and outputs. Transactions that use SIGHASH_ANYONECANPAY and/or SIGHASH_NONE may include inputs and/or outputs that are not signed; however, compliant software should still emit transactions with lexicographically sorted inputs and outputs, even though they may later be modified by others. - -In the event that future protocol upgrades introduce new signature hash types, compliant software should apply the lexicographical ordering principle analogously. - -While out of scope of this BIP, protocols that do require a specified order of inputs/outputs (e.g. due to use of SIGHASH_SINGLE) should consider the goals of this BIP and how best to adapt them to the specific needs of those protocols. - -===Lexicographical Sorting=== - -Ordering of inputs and outputs will rely on the output of sorting functions. These functions can be defined as taking two inputs or two outputs as parameters and returning their appropriate ordering with respect to each other. - -Byte arrays must be sorted with an algorithm that produces the same output as the following comparison algorithm: - - #returns -1 if barr1 is lesser, 1 if barr1 is greater, and 0 if equal - def bytearr_cmp(barr1, barr2): - pos = 0 - while (pos < len(barr1) and pos < len(barr2)): - if (barr1[pos] < barr2[pos]): - return -1; - elif (barr1[pos] > barr2[pos]): - return 1; - pos = pos + 1 - #the shorter array will be ordered first - if (len(barr1) < len(barr2)): - return -1 - elif (len(barr1) > len(barr2)): - return 1 - else: - return 0 - -N.B. These comparisons do not need to operate in constant time since they are not processing secret information. - -===Transaction Inputs=== - -104 Transaction inputs are defined by the hash of a previous transaction, the output index of of a UTXO from that previous transaction, the size of an unlocking script, the unlocking script, and a sequence number. [3] For sorting inputs, the hash of the previous transaction and the output index within that transaction are sufficient for sorting purposes; each transaction hash has an extremely high probability of being unique in the blockchain — this is enforced for coinbase transactions by BIP30 — and output indices within a transaction are unique. For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables. - -Hashes of previous transactions are considered for the purposes of this BIP in their little-endian, byte array format in order to match the traditional, human-readable string representation of the hashes. They must be sorted in accordance with the output of the bytearr_cmp() function above: the hash with the earliest lesser byte is ordered first, and shorter hashes are ordered before longer ones as a tie-breaker. In the event of two matching transaction hashes, output indices will be compared based on their integer value, with the smaller value ordered first. A further tie is extremely improbable for the aforementioned reasons. - -Because the hash of previous transactions and output indices must be included in a signed transaction, wallet clients capable of signing transactions will necessarily have access to this data. - -Transaction malleability will not negatively impact the correctness of this process. Even if a wallet client follows this process using unconfirmed UTXOs as inputs and an attacker changes modifies the blockchain’s record of the hash of the previous transaction, the wallet client will include the invalidated previous transaction hash in its input data, and will still correctly sort with respect to that invalidated hash. - -===Transaction Outputs=== - -A transaction output is defined by its scriptPubKey and amount. [3] For sorting purposes, we will consider a scriptPubKey in its byte array representation, and a bitcoin amount in terms of their integer number of satoshis (smallest amount ordered first). - -For the sake of efficiency, amounts will be considered first for sorting, since they contain fewer bytes of information (8 bytes) compared to a standard P2PKH scriptPubKey (25 bytes). [4] When the values are tied, the scriptPubKey is then considered. In the event of a tie between scriptPubKeys, sorting is irrelevant since the outputs are exactly equivalent. - -===Examples=== - -Transaction 0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3: - -Inputs: - - 0: 0e53ec5dfb2cb8a71fec32dc9a634a35b7e24799295ddd5278217822e0b31f57[0] - 1: 26aa6e6d8b9e49bb0630aac301db6757c02e3619feb4ee0eea81eb1672947024[1] - 2: 28e0fdd185542f2c6ea19030b0796051e7772b6026dd5ddccd7a2f93b73e6fc2[0] - 3: 381de9b9ae1a94d9c17f6a08ef9d341a5ce29e2e60c36a52d333ff6203e58d5d[1] - 4: 3b8b2f8efceb60ba78ca8bba206a137f14cb5ea4035e761ee204302d46b98de2[0] - 5: 402b2c02411720bf409eff60d05adad684f135838962823f3614cc657dd7bc0a[1] - 6: 54ffff182965ed0957dba1239c27164ace5a73c9b62a660c74b7b7f15ff61e7a[1] - 7: 643e5f4e66373a57251fb173151e838ccd27d279aca882997e005016bb53d5aa[0] - 8: 6c1d56f31b2de4bfc6aaea28396b333102b1f600da9c6d6149e96ca43f1102b1[1] - 9: 7a1de137cbafb5c70405455c49c5104ca3057a1f1243e6563bb9245c9c88c191[0] - 10: 7d037ceb2ee0dc03e82f17be7935d238b35d1deabf953a892a4507bfbeeb3ba4[1] - 11: a5e899dddb28776ea9ddac0a502316d53a4a3fca607c72f66c470e0412e34086[0] - 12: b4112b8f900a7ca0c8b0e7c4dfad35c6be5f6be46b3458974988e1cdb2fa61b8[0] - 13: bafd65e3c7f3f9fdfdc1ddb026131b278c3be1af90a4a6ffa78c4658f9ec0c85[0] - 14: de0411a1e97484a2804ff1dbde260ac19de841bebad1880c782941aca883b4e9[1] - 15: f0a130a84912d03c1d284974f563c5949ac13f8342b8112edff52971599e6a45[0] - 16: f320832a9d2e2452af63154bc687493484a0e7745ebd3aaf9ca19eb80834ad60[0] - -Outputs: - - 0: 400057456 76a9144a5fba237213a062f6f57978f796390bdcf8d01588ac - 1: 40000000000 76a9145be32612930b8323add2212a4ec03c1562084f8488ac - -Transaction 28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f - -Inputs: - - 0: 35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055[0] - 1: 35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055[1] - -Outputs: - - 0: 100000000 41046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac - 1: 2400000000 41044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac - -==References== - -* [[https://bitcoinmagazine.com/20273/bitstamp-exchange-activity-trackable-due-multisig-wallet-implementation/|1: Bitstamp Info Leak]] -* [[https://github.com/OpenBitcoinPrivacyProject/wallet-ratings/blob/master/2015-1/criteria.md|2: OBPP Random Indexing as Countermeasure]] -* [[https://github.com/aantonop/bitcoinbook/blob/develop/ch05.asciidoc|3: Mastering Bitcoin]] -* [[https://en.bitcoin.it/wiki/Script|4: Bitcoin Wiki on Script]] - -==Acknowledgements== - -Danno Ferrin <danno@numisight.com>, Sergio Demian Lerner <sergiolerner@certimix.com>, Justus Ranvier <justus@openbitcoinprivacyproject.org>, and Peter Todd <pete@petertodd.org> contributed to the design and motivations for this BIP. \ No newline at end of file diff --git a/bip-0079/bip-0079_examples.py b/bip-0079/bip-0079_examples.py deleted file mode 100644 index 7622cfe..0000000 --- a/bip-0079/bip-0079_examples.py +++ /dev/null @@ -1,112 +0,0 @@ -import binascii - -#returns -1 if barr1 is less, 1 if barr1 is greater, and 0 if equal -def bytearr_cmp(barr1, barr2): - pos = 0 - while (pos < len(barr1) and pos < len(barr2)): - if (barr1[pos] < barr2[pos]): - return -1; - elif (barr1[pos] > barr2[pos]): - return 1; - pos = pos + 1 - #the shorter array will be ordered first - if (len(barr1) < len(barr2)): - return -1 - elif (len(barr1) > len(barr2)): - return 1 - else: - return 0 - -#tuples: (prev_tx_hash_byte_arr_little_endian, prev_tx_output_index) -def input_cmp(input_tuple1, input_tuple2): - #test prev_tx_hash_byte_arr_little_endian first - prev_tx_hash_cmp = bytearr_cmp(input_tuple1[0], input_tuple2[0]) - if (prev_tx_hash_cmp != 0): - return prev_tx_hash_cmp - #tie-breaker: prev_tx_output_index - if (input_tuple1[1] < input_tuple2[1]): - return -1 - elif (input_tuple1[1] > input_tuple2[1]): - return 1 - else: - raise ValueError('Matching previous transaction hash and previous transaction output index for two disinct inputs. Invalid!') - -def sort_inputs(input_tuples): - return sorted(input_tuples, cmp=input_cmp) - -def print_inputs(ordered_input_tuples): - index = 0 - for prev_tx_hash_byte_arr_little_endian, prev_tx_output_index in ordered_input_tuples: - prev_tx_hash_hex = binascii.hexlify(bytearray(prev_tx_hash_byte_arr_little_endian)) - print("%d: %s[%d]" % (index, prev_tx_hash_hex, prev_tx_output_index)) - index = index + 1 - -#tuples: (amount, scriptPubKey_byte_arr) -def output_cmp(output_tuple1, output_tuple2): - #test amount first - if (output_tuple1[0] < output_tuple2[0]): - return -1 - elif (output_tuple1[0] > output_tuple2[0]): - return 1 - #tie-breaker: scriptPubKey_byte_arr - return bytearray_cmp(output_tuple1[1], output_tuple2[1]) - -def sort_outputs(output_tuples): - return sorted(output_tuples, cmp=output_cmp) - -def print_outputs(ordered_output_tuples): - index = 0 - for amount, scriptPubKey_byte_arr in ordered_output_tuples: - scriptPubKey_hex = binascii.hexlify(bytearray(scriptPubKey_byte_arr)) - print("%d:\t%d\t%s" % (index, amount, scriptPubKey_hex)) - index = index + 1 - -def main(): - #reference data: https://blockchain.info/rawtx/0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3 - tx_0a6a_input_tuples = [ - # (prev_tx_hash_byte_arr_little_endian, prev_tx_output_index) - ([0x64, 0x3e, 0x5f, 0x4e, 0x66, 0x37, 0x3a, 0x57, 0x25, 0x1f, 0xb1, 0x73, 0x15, 0x1e, 0x83, 0x8c, 0xcd, 0x27, 0xd2, 0x79, 0xac, 0xa8, 0x82, 0x99, 0x7e, 0x00, 0x50, 0x16, 0xbb, 0x53, 0xd5, 0xaa], 0), - ([0x28, 0xe0, 0xfd, 0xd1, 0x85, 0x54, 0x2f, 0x2c, 0x6e, 0xa1, 0x90, 0x30, 0xb0, 0x79, 0x60, 0x51, 0xe7, 0x77, 0x2b, 0x60, 0x26, 0xdd, 0x5d, 0xdc, 0xcd, 0x7a, 0x2f, 0x93, 0xb7, 0x3e, 0x6f, 0xc2], 0), - ([0xf0, 0xa1, 0x30, 0xa8, 0x49, 0x12, 0xd0, 0x3c, 0x1d, 0x28, 0x49, 0x74, 0xf5, 0x63, 0xc5, 0x94, 0x9a, 0xc1, 0x3f, 0x83, 0x42, 0xb8, 0x11, 0x2e, 0xdf, 0xf5, 0x29, 0x71, 0x59, 0x9e, 0x6a, 0x45], 0), - ([0x0e, 0x53, 0xec, 0x5d, 0xfb, 0x2c, 0xb8, 0xa7, 0x1f, 0xec, 0x32, 0xdc, 0x9a, 0x63, 0x4a, 0x35, 0xb7, 0xe2, 0x47, 0x99, 0x29, 0x5d, 0xdd, 0x52, 0x78, 0x21, 0x78, 0x22, 0xe0, 0xb3, 0x1f, 0x57], 0), - ([0x38, 0x1d, 0xe9, 0xb9, 0xae, 0x1a, 0x94, 0xd9, 0xc1, 0x7f, 0x6a, 0x08, 0xef, 0x9d, 0x34, 0x1a, 0x5c, 0xe2, 0x9e, 0x2e, 0x60, 0xc3, 0x6a, 0x52, 0xd3, 0x33, 0xff, 0x62, 0x03, 0xe5, 0x8d, 0x5d], 1), - ([0xf3, 0x20, 0x83, 0x2a, 0x9d, 0x2e, 0x24, 0x52, 0xaf, 0x63, 0x15, 0x4b, 0xc6, 0x87, 0x49, 0x34, 0x84, 0xa0, 0xe7, 0x74, 0x5e, 0xbd, 0x3a, 0xaf, 0x9c, 0xa1, 0x9e, 0xb8, 0x08, 0x34, 0xad, 0x60], 0), - ([0xde, 0x04, 0x11, 0xa1, 0xe9, 0x74, 0x84, 0xa2, 0x80, 0x4f, 0xf1, 0xdb, 0xde, 0x26, 0x0a, 0xc1, 0x9d, 0xe8, 0x41, 0xbe, 0xba, 0xd1, 0x88, 0x0c, 0x78, 0x29, 0x41, 0xac, 0xa8, 0x83, 0xb4, 0xe9], 1), - ([0x3b, 0x8b, 0x2f, 0x8e, 0xfc, 0xeb, 0x60, 0xba, 0x78, 0xca, 0x8b, 0xba, 0x20, 0x6a, 0x13, 0x7f, 0x14, 0xcb, 0x5e, 0xa4, 0x03, 0x5e, 0x76, 0x1e, 0xe2, 0x04, 0x30, 0x2d, 0x46, 0xb9, 0x8d, 0xe2], 0), - ([0x54, 0xff, 0xff, 0x18, 0x29, 0x65, 0xed, 0x09, 0x57, 0xdb, 0xa1, 0x23, 0x9c, 0x27, 0x16, 0x4a, 0xce, 0x5a, 0x73, 0xc9, 0xb6, 0x2a, 0x66, 0x0c, 0x74, 0xb7, 0xb7, 0xf1, 0x5f, 0xf6, 0x1e, 0x7a], 1), - ([0xba, 0xfd, 0x65, 0xe3, 0xc7, 0xf3, 0xf9, 0xfd, 0xfd, 0xc1, 0xdd, 0xb0, 0x26, 0x13, 0x1b, 0x27, 0x8c, 0x3b, 0xe1, 0xaf, 0x90, 0xa4, 0xa6, 0xff, 0xa7, 0x8c, 0x46, 0x58, 0xf9, 0xec, 0x0c, 0x85], 0), - ([0xa5, 0xe8, 0x99, 0xdd, 0xdb, 0x28, 0x77, 0x6e, 0xa9, 0xdd, 0xac, 0x0a, 0x50, 0x23, 0x16, 0xd5, 0x3a, 0x4a, 0x3f, 0xca, 0x60, 0x7c, 0x72, 0xf6, 0x6c, 0x47, 0x0e, 0x04, 0x12, 0xe3, 0x40, 0x86], 0), - ([0x7a, 0x1d, 0xe1, 0x37, 0xcb, 0xaf, 0xb5, 0xc7, 0x04, 0x05, 0x45, 0x5c, 0x49, 0xc5, 0x10, 0x4c, 0xa3, 0x05, 0x7a, 0x1f, 0x12, 0x43, 0xe6, 0x56, 0x3b, 0xb9, 0x24, 0x5c, 0x9c, 0x88, 0xc1, 0x91], 0), - ([0x26, 0xaa, 0x6e, 0x6d, 0x8b, 0x9e, 0x49, 0xbb, 0x06, 0x30, 0xaa, 0xc3, 0x01, 0xdb, 0x67, 0x57, 0xc0, 0x2e, 0x36, 0x19, 0xfe, 0xb4, 0xee, 0x0e, 0xea, 0x81, 0xeb, 0x16, 0x72, 0x94, 0x70, 0x24], 1), - ([0x40, 0x2b, 0x2c, 0x02, 0x41, 0x17, 0x20, 0xbf, 0x40, 0x9e, 0xff, 0x60, 0xd0, 0x5a, 0xda, 0xd6, 0x84, 0xf1, 0x35, 0x83, 0x89, 0x62, 0x82, 0x3f, 0x36, 0x14, 0xcc, 0x65, 0x7d, 0xd7, 0xbc, 0x0a], 1), - ([0x7d, 0x03, 0x7c, 0xeb, 0x2e, 0xe0, 0xdc, 0x03, 0xe8, 0x2f, 0x17, 0xbe, 0x79, 0x35, 0xd2, 0x38, 0xb3, 0x5d, 0x1d, 0xea, 0xbf, 0x95, 0x3a, 0x89, 0x2a, 0x45, 0x07, 0xbf, 0xbe, 0xeb, 0x3b, 0xa4], 1), - ([0x6c, 0x1d, 0x56, 0xf3, 0x1b, 0x2d, 0xe4, 0xbf, 0xc6, 0xaa, 0xea, 0x28, 0x39, 0x6b, 0x33, 0x31, 0x02, 0xb1, 0xf6, 0x00, 0xda, 0x9c, 0x6d, 0x61, 0x49, 0xe9, 0x6c, 0xa4, 0x3f, 0x11, 0x02, 0xb1], 1), - ([0xb4, 0x11, 0x2b, 0x8f, 0x90, 0x0a, 0x7c, 0xa0, 0xc8, 0xb0, 0xe7, 0xc4, 0xdf, 0xad, 0x35, 0xc6, 0xbe, 0x5f, 0x6b, 0xe4, 0x6b, 0x34, 0x58, 0x97, 0x49, 0x88, 0xe1, 0xcd, 0xb2, 0xfa, 0x61, 0xb8], 0)] - tx_0a6a_sorted_input_tuples = sort_inputs(tx_0a6a_input_tuples) - print_inputs(tx_0a6a_sorted_input_tuples) - - tx_0a6a_output_tuples = [ - # (amount, scriptPubKey_byte_arr) - (400057456, [0x76, 0xa9, 0x14, 0x4a, 0x5f, 0xba, 0x23, 0x72, 0x13, 0xa0, 0x62, 0xf6, 0xf5, 0x79, 0x78, 0xf7, 0x96, 0x39, 0x0b, 0xdc, 0xf8, 0xd0, 0x15, 0x88, 0xac]), - (40000000000, [0x76, 0xa9, 0x14, 0x5b, 0xe3, 0x26, 0x12, 0x93, 0x0b, 0x83, 0x23, 0xad, 0xd2, 0x21, 0x2a, 0x4e, 0xc0, 0x3c, 0x15, 0x62, 0x08, 0x4f, 0x84, 0x88, 0xac])] - tx_0a6a_sorted_output_tuples = sort_outputs(tx_0a6a_output_tuples) - print_outputs(tx_0a6a_sorted_output_tuples) - - #reference data: https://blockchain.info/rawtx/28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f thanks @quantabytes! - tx_2820_input_tuples = [ - # (prev_tx_hash, prev_tx_output_index) - ("35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", 0), - ("35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", 1)] #duplicate prev_tx_hash - - tx_2820_sorted_input_tuples = sort_inputs(tx_2820_input_tuples) - print_inputs(tx_2820_sorted_input_tuples) - - tx_2820_output_tuples = [ - # (amount, scriptPubKey_byte_arr) - (100000000, [0x41, 0x04, 0x6a, 0x07, 0x65, 0xb5, 0x86, 0x56, 0x41, 0xce, 0x08, 0xdd, 0x39, 0x69, 0x0a, 0xad, 0xe2, 0x6d, 0xfb, 0xf5, 0x51, 0x14, 0x30, 0xca, 0x42, 0x8a, 0x30, 0x89, 0x26, 0x13, 0x61, 0xce, 0xf1, 0x70, 0xe3, 0x92, 0x9a, 0x68, 0xae, 0xe3, 0xd8, 0xd4, 0x84, 0x8b, 0x0c, 0x51, 0x11, 0xb0, 0xa3, 0x7b, 0x82, 0xb8, 0x6a, 0xd5, 0x59, 0xfd, 0x2a, 0x74, 0x5b, 0x44, 0xd8, 0xe8, 0xd9, 0xdf, 0xdc, 0x0c, 0xac]), - (2400000000, [0x41, 0x04, 0x4a, 0x65, 0x6f, 0x06, 0x58, 0x71, 0xa3, 0x53, 0xf2, 0x16, 0xca, 0x26, 0xce, 0xf8, 0xdd, 0xe2, 0xf0, 0x3e, 0x8c, 0x16, 0x20, 0x2d, 0x2e, 0x8a, 0xd7, 0x69, 0xf0, 0x20, 0x32, 0xcb, 0x86, 0xa5, 0xeb, 0x5e, 0x56, 0x84, 0x2e, 0x92, 0xe1, 0x91, 0x41, 0xd6, 0x0a, 0x01, 0x92, 0x8f, 0x8d, 0xd2, 0xc8, 0x75, 0xa3, 0x90, 0xf6, 0x7c, 0x1f, 0x6c, 0x94, 0xcf, 0xc6, 0x17, 0xc0, 0xea, 0x45, 0xaf, 0xac])] - tx_2820_sorted_output_tuples = sort_outputs(tx_2820_output_tuples) - print_outputs(tx_2820_output_tuples) - -if __name__ == "__main__": - main() \ No newline at end of file -- cgit v1.2.3 From f5b652d6ba8b4c939380630e8e738e91e6c26d67 Mon Sep 17 00:00:00 2001 From: Kristov Atlas Date: Wed, 24 Jun 2015 17:04:36 -0400 Subject: BIP 69 not 79 --- bip-0069.mediawiki | 2 +- bip-0069/bip-0069_examples.py | 112 ++++++++++++++++++++++++++++++++++++++++++ bip-0069/bip-0079_examples.py | 112 ------------------------------------------ 3 files changed, 113 insertions(+), 113 deletions(-) create mode 100644 bip-0069/bip-0069_examples.py delete mode 100644 bip-0069/bip-0079_examples.py diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki index 65e35e6..8b66550 100644 --- a/bip-0069.mediawiki +++ b/bip-0069.mediawiki @@ -1,5 +1,5 @@
-  BIP:     BIP: 79
+  BIP:     BIP: 69
   Title:   Lexicographical Indexing of Transaction Inputs and Outputs
   Authors: Kristov Atlas 
   Status:  Draft
diff --git a/bip-0069/bip-0069_examples.py b/bip-0069/bip-0069_examples.py
new file mode 100644
index 0000000..7622cfe
--- /dev/null
+++ b/bip-0069/bip-0069_examples.py
@@ -0,0 +1,112 @@
+import binascii
+
+#returns -1 if barr1 is less, 1 if barr1 is greater, and 0 if equal
+def bytearr_cmp(barr1, barr2):
+	pos = 0
+	while (pos < len(barr1) and pos < len(barr2)):
+		if (barr1[pos] < barr2[pos]):
+			return -1;
+		elif (barr1[pos] > barr2[pos]):
+			return 1;
+		pos = pos + 1
+	#the shorter array will be ordered first
+	if (len(barr1) < len(barr2)):
+		return -1
+	elif (len(barr1) > len(barr2)):
+		return 1
+	else:
+		return 0
+
+#tuples: (prev_tx_hash_byte_arr_little_endian, prev_tx_output_index)
+def input_cmp(input_tuple1, input_tuple2):
+	#test prev_tx_hash_byte_arr_little_endian first
+	prev_tx_hash_cmp = bytearr_cmp(input_tuple1[0], input_tuple2[0])
+	if (prev_tx_hash_cmp != 0):
+		return prev_tx_hash_cmp
+	#tie-breaker: prev_tx_output_index
+	if (input_tuple1[1] < input_tuple2[1]):
+		return -1
+	elif (input_tuple1[1] > input_tuple2[1]):
+		return 1
+	else:
+		raise ValueError('Matching previous transaction hash and previous transaction output index for two disinct inputs. Invalid!')
+
+def sort_inputs(input_tuples):
+	return sorted(input_tuples, cmp=input_cmp)
+
+def print_inputs(ordered_input_tuples):
+	index = 0
+	for prev_tx_hash_byte_arr_little_endian, prev_tx_output_index in ordered_input_tuples:
+		prev_tx_hash_hex = binascii.hexlify(bytearray(prev_tx_hash_byte_arr_little_endian))
+		print("%d: %s[%d]" % (index, prev_tx_hash_hex, prev_tx_output_index))
+		index = index + 1
+
+#tuples: (amount, scriptPubKey_byte_arr)
+def output_cmp(output_tuple1, output_tuple2):
+	#test amount first
+	if (output_tuple1[0] < output_tuple2[0]):
+		return -1
+	elif (output_tuple1[0] > output_tuple2[0]):
+		return 1
+	#tie-breaker: scriptPubKey_byte_arr
+	return bytearray_cmp(output_tuple1[1], output_tuple2[1])
+
+def sort_outputs(output_tuples):
+	return sorted(output_tuples, cmp=output_cmp)
+
+def print_outputs(ordered_output_tuples):
+	index = 0
+	for amount, scriptPubKey_byte_arr in ordered_output_tuples:
+		scriptPubKey_hex = binascii.hexlify(bytearray(scriptPubKey_byte_arr))
+		print("%d:\t%d\t%s" % (index, amount, scriptPubKey_hex))
+		index = index + 1
+
+def main():
+	#reference data: https://blockchain.info/rawtx/0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3
+	tx_0a6a_input_tuples = [
+		# (prev_tx_hash_byte_arr_little_endian, prev_tx_output_index)
+		([0x64, 0x3e, 0x5f, 0x4e, 0x66, 0x37, 0x3a, 0x57, 0x25, 0x1f, 0xb1, 0x73, 0x15, 0x1e, 0x83, 0x8c, 0xcd, 0x27, 0xd2, 0x79, 0xac, 0xa8, 0x82, 0x99, 0x7e, 0x00, 0x50, 0x16, 0xbb, 0x53, 0xd5, 0xaa], 0),
+		([0x28, 0xe0, 0xfd, 0xd1, 0x85, 0x54, 0x2f, 0x2c, 0x6e, 0xa1, 0x90, 0x30, 0xb0, 0x79, 0x60, 0x51, 0xe7, 0x77, 0x2b, 0x60, 0x26, 0xdd, 0x5d, 0xdc, 0xcd, 0x7a, 0x2f, 0x93, 0xb7, 0x3e, 0x6f, 0xc2], 0),
+		([0xf0, 0xa1, 0x30, 0xa8, 0x49, 0x12, 0xd0, 0x3c, 0x1d, 0x28, 0x49, 0x74, 0xf5, 0x63, 0xc5, 0x94, 0x9a, 0xc1, 0x3f, 0x83, 0x42, 0xb8, 0x11, 0x2e, 0xdf, 0xf5, 0x29, 0x71, 0x59, 0x9e, 0x6a, 0x45], 0),
+		([0x0e, 0x53, 0xec, 0x5d, 0xfb, 0x2c, 0xb8, 0xa7, 0x1f, 0xec, 0x32, 0xdc, 0x9a, 0x63, 0x4a, 0x35, 0xb7, 0xe2, 0x47, 0x99, 0x29, 0x5d, 0xdd, 0x52, 0x78, 0x21, 0x78, 0x22, 0xe0, 0xb3, 0x1f, 0x57], 0),
+		([0x38, 0x1d, 0xe9, 0xb9, 0xae, 0x1a, 0x94, 0xd9, 0xc1, 0x7f, 0x6a, 0x08, 0xef, 0x9d, 0x34, 0x1a, 0x5c, 0xe2, 0x9e, 0x2e, 0x60, 0xc3, 0x6a, 0x52, 0xd3, 0x33, 0xff, 0x62, 0x03, 0xe5, 0x8d, 0x5d], 1),
+		([0xf3, 0x20, 0x83, 0x2a, 0x9d, 0x2e, 0x24, 0x52, 0xaf, 0x63, 0x15, 0x4b, 0xc6, 0x87, 0x49, 0x34, 0x84, 0xa0, 0xe7, 0x74, 0x5e, 0xbd, 0x3a, 0xaf, 0x9c, 0xa1, 0x9e, 0xb8, 0x08, 0x34, 0xad, 0x60], 0),
+		([0xde, 0x04, 0x11, 0xa1, 0xe9, 0x74, 0x84, 0xa2, 0x80, 0x4f, 0xf1, 0xdb, 0xde, 0x26, 0x0a, 0xc1, 0x9d, 0xe8, 0x41, 0xbe, 0xba, 0xd1, 0x88, 0x0c, 0x78, 0x29, 0x41, 0xac, 0xa8, 0x83, 0xb4, 0xe9], 1),
+		([0x3b, 0x8b, 0x2f, 0x8e, 0xfc, 0xeb, 0x60, 0xba, 0x78, 0xca, 0x8b, 0xba, 0x20, 0x6a, 0x13, 0x7f, 0x14, 0xcb, 0x5e, 0xa4, 0x03, 0x5e, 0x76, 0x1e, 0xe2, 0x04, 0x30, 0x2d, 0x46, 0xb9, 0x8d, 0xe2], 0),
+		([0x54, 0xff, 0xff, 0x18, 0x29, 0x65, 0xed, 0x09, 0x57, 0xdb, 0xa1, 0x23, 0x9c, 0x27, 0x16, 0x4a, 0xce, 0x5a, 0x73, 0xc9, 0xb6, 0x2a, 0x66, 0x0c, 0x74, 0xb7, 0xb7, 0xf1, 0x5f, 0xf6, 0x1e, 0x7a], 1),
+		([0xba, 0xfd, 0x65, 0xe3, 0xc7, 0xf3, 0xf9, 0xfd, 0xfd, 0xc1, 0xdd, 0xb0, 0x26, 0x13, 0x1b, 0x27, 0x8c, 0x3b, 0xe1, 0xaf, 0x90, 0xa4, 0xa6, 0xff, 0xa7, 0x8c, 0x46, 0x58, 0xf9, 0xec, 0x0c, 0x85], 0),
+		([0xa5, 0xe8, 0x99, 0xdd, 0xdb, 0x28, 0x77, 0x6e, 0xa9, 0xdd, 0xac, 0x0a, 0x50, 0x23, 0x16, 0xd5, 0x3a, 0x4a, 0x3f, 0xca, 0x60, 0x7c, 0x72, 0xf6, 0x6c, 0x47, 0x0e, 0x04, 0x12, 0xe3, 0x40, 0x86], 0),
+		([0x7a, 0x1d, 0xe1, 0x37, 0xcb, 0xaf, 0xb5, 0xc7, 0x04, 0x05, 0x45, 0x5c, 0x49, 0xc5, 0x10, 0x4c, 0xa3, 0x05, 0x7a, 0x1f, 0x12, 0x43, 0xe6, 0x56, 0x3b, 0xb9, 0x24, 0x5c, 0x9c, 0x88, 0xc1, 0x91], 0),
+		([0x26, 0xaa, 0x6e, 0x6d, 0x8b, 0x9e, 0x49, 0xbb, 0x06, 0x30, 0xaa, 0xc3, 0x01, 0xdb, 0x67, 0x57, 0xc0, 0x2e, 0x36, 0x19, 0xfe, 0xb4, 0xee, 0x0e, 0xea, 0x81, 0xeb, 0x16, 0x72, 0x94, 0x70, 0x24], 1),
+		([0x40, 0x2b, 0x2c, 0x02, 0x41, 0x17, 0x20, 0xbf, 0x40, 0x9e, 0xff, 0x60, 0xd0, 0x5a, 0xda, 0xd6, 0x84, 0xf1, 0x35, 0x83, 0x89, 0x62, 0x82, 0x3f, 0x36, 0x14, 0xcc, 0x65, 0x7d, 0xd7, 0xbc, 0x0a], 1),
+		([0x7d, 0x03, 0x7c, 0xeb, 0x2e, 0xe0, 0xdc, 0x03, 0xe8, 0x2f, 0x17, 0xbe, 0x79, 0x35, 0xd2, 0x38, 0xb3, 0x5d, 0x1d, 0xea, 0xbf, 0x95, 0x3a, 0x89, 0x2a, 0x45, 0x07, 0xbf, 0xbe, 0xeb, 0x3b, 0xa4], 1),
+		([0x6c, 0x1d, 0x56, 0xf3, 0x1b, 0x2d, 0xe4, 0xbf, 0xc6, 0xaa, 0xea, 0x28, 0x39, 0x6b, 0x33, 0x31, 0x02, 0xb1, 0xf6, 0x00, 0xda, 0x9c, 0x6d, 0x61, 0x49, 0xe9, 0x6c, 0xa4, 0x3f, 0x11, 0x02, 0xb1], 1),
+		([0xb4, 0x11, 0x2b, 0x8f, 0x90, 0x0a, 0x7c, 0xa0, 0xc8, 0xb0, 0xe7, 0xc4, 0xdf, 0xad, 0x35, 0xc6, 0xbe, 0x5f, 0x6b, 0xe4, 0x6b, 0x34, 0x58, 0x97, 0x49, 0x88, 0xe1, 0xcd, 0xb2, 0xfa, 0x61, 0xb8], 0)]
+	tx_0a6a_sorted_input_tuples = sort_inputs(tx_0a6a_input_tuples)
+	print_inputs(tx_0a6a_sorted_input_tuples)
+
+	tx_0a6a_output_tuples = [
+		# (amount, scriptPubKey_byte_arr)
+		(400057456, [0x76, 0xa9, 0x14, 0x4a, 0x5f, 0xba, 0x23, 0x72, 0x13, 0xa0, 0x62, 0xf6, 0xf5, 0x79, 0x78, 0xf7, 0x96, 0x39, 0x0b, 0xdc, 0xf8, 0xd0, 0x15, 0x88, 0xac]),
+		(40000000000, [0x76, 0xa9, 0x14, 0x5b, 0xe3, 0x26, 0x12, 0x93, 0x0b, 0x83, 0x23, 0xad, 0xd2, 0x21, 0x2a, 0x4e, 0xc0, 0x3c, 0x15, 0x62, 0x08, 0x4f, 0x84, 0x88, 0xac])]
+	tx_0a6a_sorted_output_tuples = sort_outputs(tx_0a6a_output_tuples)
+	print_outputs(tx_0a6a_sorted_output_tuples)
+
+	#reference data: https://blockchain.info/rawtx/28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f thanks @quantabytes!
+	tx_2820_input_tuples = [
+		# (prev_tx_hash, prev_tx_output_index)
+		("35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", 0),
+		("35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", 1)] #duplicate prev_tx_hash
+
+	tx_2820_sorted_input_tuples = sort_inputs(tx_2820_input_tuples)
+	print_inputs(tx_2820_sorted_input_tuples)
+
+	tx_2820_output_tuples = [
+		# (amount, scriptPubKey_byte_arr)
+		(100000000, [0x41, 0x04, 0x6a, 0x07, 0x65, 0xb5, 0x86, 0x56, 0x41, 0xce, 0x08, 0xdd, 0x39, 0x69, 0x0a, 0xad, 0xe2, 0x6d, 0xfb, 0xf5, 0x51, 0x14, 0x30, 0xca, 0x42, 0x8a, 0x30, 0x89, 0x26, 0x13, 0x61, 0xce, 0xf1, 0x70, 0xe3, 0x92, 0x9a, 0x68, 0xae, 0xe3, 0xd8, 0xd4, 0x84, 0x8b, 0x0c, 0x51, 0x11, 0xb0, 0xa3, 0x7b, 0x82, 0xb8, 0x6a, 0xd5, 0x59, 0xfd, 0x2a, 0x74, 0x5b, 0x44, 0xd8, 0xe8, 0xd9, 0xdf, 0xdc, 0x0c, 0xac]),
+		(2400000000, [0x41, 0x04, 0x4a, 0x65, 0x6f, 0x06, 0x58, 0x71, 0xa3, 0x53, 0xf2, 0x16, 0xca, 0x26, 0xce, 0xf8, 0xdd, 0xe2, 0xf0, 0x3e, 0x8c, 0x16, 0x20, 0x2d, 0x2e, 0x8a, 0xd7, 0x69, 0xf0, 0x20, 0x32, 0xcb, 0x86, 0xa5, 0xeb, 0x5e, 0x56, 0x84, 0x2e, 0x92, 0xe1, 0x91, 0x41, 0xd6, 0x0a, 0x01, 0x92, 0x8f, 0x8d, 0xd2, 0xc8, 0x75, 0xa3, 0x90, 0xf6, 0x7c, 0x1f, 0x6c, 0x94, 0xcf, 0xc6, 0x17, 0xc0, 0xea, 0x45, 0xaf, 0xac])]
+	tx_2820_sorted_output_tuples = sort_outputs(tx_2820_output_tuples)
+	print_outputs(tx_2820_output_tuples)
+
+if __name__ == "__main__":
+	main()
\ No newline at end of file
diff --git a/bip-0069/bip-0079_examples.py b/bip-0069/bip-0079_examples.py
deleted file mode 100644
index 7622cfe..0000000
--- a/bip-0069/bip-0079_examples.py
+++ /dev/null
@@ -1,112 +0,0 @@
-import binascii
-
-#returns -1 if barr1 is less, 1 if barr1 is greater, and 0 if equal
-def bytearr_cmp(barr1, barr2):
-	pos = 0
-	while (pos < len(barr1) and pos < len(barr2)):
-		if (barr1[pos] < barr2[pos]):
-			return -1;
-		elif (barr1[pos] > barr2[pos]):
-			return 1;
-		pos = pos + 1
-	#the shorter array will be ordered first
-	if (len(barr1) < len(barr2)):
-		return -1
-	elif (len(barr1) > len(barr2)):
-		return 1
-	else:
-		return 0
-
-#tuples: (prev_tx_hash_byte_arr_little_endian, prev_tx_output_index)
-def input_cmp(input_tuple1, input_tuple2):
-	#test prev_tx_hash_byte_arr_little_endian first
-	prev_tx_hash_cmp = bytearr_cmp(input_tuple1[0], input_tuple2[0])
-	if (prev_tx_hash_cmp != 0):
-		return prev_tx_hash_cmp
-	#tie-breaker: prev_tx_output_index
-	if (input_tuple1[1] < input_tuple2[1]):
-		return -1
-	elif (input_tuple1[1] > input_tuple2[1]):
-		return 1
-	else:
-		raise ValueError('Matching previous transaction hash and previous transaction output index for two disinct inputs. Invalid!')
-
-def sort_inputs(input_tuples):
-	return sorted(input_tuples, cmp=input_cmp)
-
-def print_inputs(ordered_input_tuples):
-	index = 0
-	for prev_tx_hash_byte_arr_little_endian, prev_tx_output_index in ordered_input_tuples:
-		prev_tx_hash_hex = binascii.hexlify(bytearray(prev_tx_hash_byte_arr_little_endian))
-		print("%d: %s[%d]" % (index, prev_tx_hash_hex, prev_tx_output_index))
-		index = index + 1
-
-#tuples: (amount, scriptPubKey_byte_arr)
-def output_cmp(output_tuple1, output_tuple2):
-	#test amount first
-	if (output_tuple1[0] < output_tuple2[0]):
-		return -1
-	elif (output_tuple1[0] > output_tuple2[0]):
-		return 1
-	#tie-breaker: scriptPubKey_byte_arr
-	return bytearray_cmp(output_tuple1[1], output_tuple2[1])
-
-def sort_outputs(output_tuples):
-	return sorted(output_tuples, cmp=output_cmp)
-
-def print_outputs(ordered_output_tuples):
-	index = 0
-	for amount, scriptPubKey_byte_arr in ordered_output_tuples:
-		scriptPubKey_hex = binascii.hexlify(bytearray(scriptPubKey_byte_arr))
-		print("%d:\t%d\t%s" % (index, amount, scriptPubKey_hex))
-		index = index + 1
-
-def main():
-	#reference data: https://blockchain.info/rawtx/0a6a357e2f7796444e02638749d9611c008b253fb55f5dc88b739b230ed0c4c3
-	tx_0a6a_input_tuples = [
-		# (prev_tx_hash_byte_arr_little_endian, prev_tx_output_index)
-		([0x64, 0x3e, 0x5f, 0x4e, 0x66, 0x37, 0x3a, 0x57, 0x25, 0x1f, 0xb1, 0x73, 0x15, 0x1e, 0x83, 0x8c, 0xcd, 0x27, 0xd2, 0x79, 0xac, 0xa8, 0x82, 0x99, 0x7e, 0x00, 0x50, 0x16, 0xbb, 0x53, 0xd5, 0xaa], 0),
-		([0x28, 0xe0, 0xfd, 0xd1, 0x85, 0x54, 0x2f, 0x2c, 0x6e, 0xa1, 0x90, 0x30, 0xb0, 0x79, 0x60, 0x51, 0xe7, 0x77, 0x2b, 0x60, 0x26, 0xdd, 0x5d, 0xdc, 0xcd, 0x7a, 0x2f, 0x93, 0xb7, 0x3e, 0x6f, 0xc2], 0),
-		([0xf0, 0xa1, 0x30, 0xa8, 0x49, 0x12, 0xd0, 0x3c, 0x1d, 0x28, 0x49, 0x74, 0xf5, 0x63, 0xc5, 0x94, 0x9a, 0xc1, 0x3f, 0x83, 0x42, 0xb8, 0x11, 0x2e, 0xdf, 0xf5, 0x29, 0x71, 0x59, 0x9e, 0x6a, 0x45], 0),
-		([0x0e, 0x53, 0xec, 0x5d, 0xfb, 0x2c, 0xb8, 0xa7, 0x1f, 0xec, 0x32, 0xdc, 0x9a, 0x63, 0x4a, 0x35, 0xb7, 0xe2, 0x47, 0x99, 0x29, 0x5d, 0xdd, 0x52, 0x78, 0x21, 0x78, 0x22, 0xe0, 0xb3, 0x1f, 0x57], 0),
-		([0x38, 0x1d, 0xe9, 0xb9, 0xae, 0x1a, 0x94, 0xd9, 0xc1, 0x7f, 0x6a, 0x08, 0xef, 0x9d, 0x34, 0x1a, 0x5c, 0xe2, 0x9e, 0x2e, 0x60, 0xc3, 0x6a, 0x52, 0xd3, 0x33, 0xff, 0x62, 0x03, 0xe5, 0x8d, 0x5d], 1),
-		([0xf3, 0x20, 0x83, 0x2a, 0x9d, 0x2e, 0x24, 0x52, 0xaf, 0x63, 0x15, 0x4b, 0xc6, 0x87, 0x49, 0x34, 0x84, 0xa0, 0xe7, 0x74, 0x5e, 0xbd, 0x3a, 0xaf, 0x9c, 0xa1, 0x9e, 0xb8, 0x08, 0x34, 0xad, 0x60], 0),
-		([0xde, 0x04, 0x11, 0xa1, 0xe9, 0x74, 0x84, 0xa2, 0x80, 0x4f, 0xf1, 0xdb, 0xde, 0x26, 0x0a, 0xc1, 0x9d, 0xe8, 0x41, 0xbe, 0xba, 0xd1, 0x88, 0x0c, 0x78, 0x29, 0x41, 0xac, 0xa8, 0x83, 0xb4, 0xe9], 1),
-		([0x3b, 0x8b, 0x2f, 0x8e, 0xfc, 0xeb, 0x60, 0xba, 0x78, 0xca, 0x8b, 0xba, 0x20, 0x6a, 0x13, 0x7f, 0x14, 0xcb, 0x5e, 0xa4, 0x03, 0x5e, 0x76, 0x1e, 0xe2, 0x04, 0x30, 0x2d, 0x46, 0xb9, 0x8d, 0xe2], 0),
-		([0x54, 0xff, 0xff, 0x18, 0x29, 0x65, 0xed, 0x09, 0x57, 0xdb, 0xa1, 0x23, 0x9c, 0x27, 0x16, 0x4a, 0xce, 0x5a, 0x73, 0xc9, 0xb6, 0x2a, 0x66, 0x0c, 0x74, 0xb7, 0xb7, 0xf1, 0x5f, 0xf6, 0x1e, 0x7a], 1),
-		([0xba, 0xfd, 0x65, 0xe3, 0xc7, 0xf3, 0xf9, 0xfd, 0xfd, 0xc1, 0xdd, 0xb0, 0x26, 0x13, 0x1b, 0x27, 0x8c, 0x3b, 0xe1, 0xaf, 0x90, 0xa4, 0xa6, 0xff, 0xa7, 0x8c, 0x46, 0x58, 0xf9, 0xec, 0x0c, 0x85], 0),
-		([0xa5, 0xe8, 0x99, 0xdd, 0xdb, 0x28, 0x77, 0x6e, 0xa9, 0xdd, 0xac, 0x0a, 0x50, 0x23, 0x16, 0xd5, 0x3a, 0x4a, 0x3f, 0xca, 0x60, 0x7c, 0x72, 0xf6, 0x6c, 0x47, 0x0e, 0x04, 0x12, 0xe3, 0x40, 0x86], 0),
-		([0x7a, 0x1d, 0xe1, 0x37, 0xcb, 0xaf, 0xb5, 0xc7, 0x04, 0x05, 0x45, 0x5c, 0x49, 0xc5, 0x10, 0x4c, 0xa3, 0x05, 0x7a, 0x1f, 0x12, 0x43, 0xe6, 0x56, 0x3b, 0xb9, 0x24, 0x5c, 0x9c, 0x88, 0xc1, 0x91], 0),
-		([0x26, 0xaa, 0x6e, 0x6d, 0x8b, 0x9e, 0x49, 0xbb, 0x06, 0x30, 0xaa, 0xc3, 0x01, 0xdb, 0x67, 0x57, 0xc0, 0x2e, 0x36, 0x19, 0xfe, 0xb4, 0xee, 0x0e, 0xea, 0x81, 0xeb, 0x16, 0x72, 0x94, 0x70, 0x24], 1),
-		([0x40, 0x2b, 0x2c, 0x02, 0x41, 0x17, 0x20, 0xbf, 0x40, 0x9e, 0xff, 0x60, 0xd0, 0x5a, 0xda, 0xd6, 0x84, 0xf1, 0x35, 0x83, 0x89, 0x62, 0x82, 0x3f, 0x36, 0x14, 0xcc, 0x65, 0x7d, 0xd7, 0xbc, 0x0a], 1),
-		([0x7d, 0x03, 0x7c, 0xeb, 0x2e, 0xe0, 0xdc, 0x03, 0xe8, 0x2f, 0x17, 0xbe, 0x79, 0x35, 0xd2, 0x38, 0xb3, 0x5d, 0x1d, 0xea, 0xbf, 0x95, 0x3a, 0x89, 0x2a, 0x45, 0x07, 0xbf, 0xbe, 0xeb, 0x3b, 0xa4], 1),
-		([0x6c, 0x1d, 0x56, 0xf3, 0x1b, 0x2d, 0xe4, 0xbf, 0xc6, 0xaa, 0xea, 0x28, 0x39, 0x6b, 0x33, 0x31, 0x02, 0xb1, 0xf6, 0x00, 0xda, 0x9c, 0x6d, 0x61, 0x49, 0xe9, 0x6c, 0xa4, 0x3f, 0x11, 0x02, 0xb1], 1),
-		([0xb4, 0x11, 0x2b, 0x8f, 0x90, 0x0a, 0x7c, 0xa0, 0xc8, 0xb0, 0xe7, 0xc4, 0xdf, 0xad, 0x35, 0xc6, 0xbe, 0x5f, 0x6b, 0xe4, 0x6b, 0x34, 0x58, 0x97, 0x49, 0x88, 0xe1, 0xcd, 0xb2, 0xfa, 0x61, 0xb8], 0)]
-	tx_0a6a_sorted_input_tuples = sort_inputs(tx_0a6a_input_tuples)
-	print_inputs(tx_0a6a_sorted_input_tuples)
-
-	tx_0a6a_output_tuples = [
-		# (amount, scriptPubKey_byte_arr)
-		(400057456, [0x76, 0xa9, 0x14, 0x4a, 0x5f, 0xba, 0x23, 0x72, 0x13, 0xa0, 0x62, 0xf6, 0xf5, 0x79, 0x78, 0xf7, 0x96, 0x39, 0x0b, 0xdc, 0xf8, 0xd0, 0x15, 0x88, 0xac]),
-		(40000000000, [0x76, 0xa9, 0x14, 0x5b, 0xe3, 0x26, 0x12, 0x93, 0x0b, 0x83, 0x23, 0xad, 0xd2, 0x21, 0x2a, 0x4e, 0xc0, 0x3c, 0x15, 0x62, 0x08, 0x4f, 0x84, 0x88, 0xac])]
-	tx_0a6a_sorted_output_tuples = sort_outputs(tx_0a6a_output_tuples)
-	print_outputs(tx_0a6a_sorted_output_tuples)
-
-	#reference data: https://blockchain.info/rawtx/28204cad1d7fc1d199e8ef4fa22f182de6258a3eaafe1bbe56ebdcacd3069a5f thanks @quantabytes!
-	tx_2820_input_tuples = [
-		# (prev_tx_hash, prev_tx_output_index)
-		("35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", 0),
-		("35288d269cee1941eaebb2ea85e32b42cdb2b04284a56d8b14dcc3f5c65d6055", 1)] #duplicate prev_tx_hash
-
-	tx_2820_sorted_input_tuples = sort_inputs(tx_2820_input_tuples)
-	print_inputs(tx_2820_sorted_input_tuples)
-
-	tx_2820_output_tuples = [
-		# (amount, scriptPubKey_byte_arr)
-		(100000000, [0x41, 0x04, 0x6a, 0x07, 0x65, 0xb5, 0x86, 0x56, 0x41, 0xce, 0x08, 0xdd, 0x39, 0x69, 0x0a, 0xad, 0xe2, 0x6d, 0xfb, 0xf5, 0x51, 0x14, 0x30, 0xca, 0x42, 0x8a, 0x30, 0x89, 0x26, 0x13, 0x61, 0xce, 0xf1, 0x70, 0xe3, 0x92, 0x9a, 0x68, 0xae, 0xe3, 0xd8, 0xd4, 0x84, 0x8b, 0x0c, 0x51, 0x11, 0xb0, 0xa3, 0x7b, 0x82, 0xb8, 0x6a, 0xd5, 0x59, 0xfd, 0x2a, 0x74, 0x5b, 0x44, 0xd8, 0xe8, 0xd9, 0xdf, 0xdc, 0x0c, 0xac]),
-		(2400000000, [0x41, 0x04, 0x4a, 0x65, 0x6f, 0x06, 0x58, 0x71, 0xa3, 0x53, 0xf2, 0x16, 0xca, 0x26, 0xce, 0xf8, 0xdd, 0xe2, 0xf0, 0x3e, 0x8c, 0x16, 0x20, 0x2d, 0x2e, 0x8a, 0xd7, 0x69, 0xf0, 0x20, 0x32, 0xcb, 0x86, 0xa5, 0xeb, 0x5e, 0x56, 0x84, 0x2e, 0x92, 0xe1, 0x91, 0x41, 0xd6, 0x0a, 0x01, 0x92, 0x8f, 0x8d, 0xd2, 0xc8, 0x75, 0xa3, 0x90, 0xf6, 0x7c, 0x1f, 0x6c, 0x94, 0xcf, 0xc6, 0x17, 0xc0, 0xea, 0x45, 0xaf, 0xac])]
-	tx_2820_sorted_output_tuples = sort_outputs(tx_2820_output_tuples)
-	print_outputs(tx_2820_output_tuples)
-
-if __name__ == "__main__":
-	main()
\ No newline at end of file
-- 
cgit v1.2.3


From 9a0d3bb69e97f6bb3721ff23ee06f0402e2181d0 Mon Sep 17 00:00:00 2001
From: Kristov Atlas 
Date: Wed, 24 Jun 2015 17:12:19 -0400
Subject: Links to discussion, changed Acknowledgements

Added links to discussion per request from laanwj.
---
 bip-0069.mediawiki | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index 8b66550..7123488 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -117,6 +117,11 @@ Outputs:
  0:    100000000    41046a0765b5865641ce08dd39690aade26dfbf5511430ca428a3089261361cef170e3929a68aee3d8d4848b0c5111b0a37b82b86ad559fd2a745b44d8e8d9dfdc0cac
  1:    2400000000    41044a656f065871a353f216ca26cef8dde2f03e8c16202d2e8ad769f02032cb86a5eb5e56842e92e19141d60a01928f8dd2c875a390f67c1f6c94cfc617c0ea45afac
 
+==Discussion==
+
+* [[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-June/008484.html|[Bitcoin-development] Lexicographical Indexing of Transaction Inputs and Outputs]]
+* [[https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2015-June/008487.html|[Bitcoin-development] [RFC] Canonical input and output ordering in transactions]]
+
 ==References==
 
 * [[https://bitcoinmagazine.com/20273/bitstamp-exchange-activity-trackable-due-multisig-wallet-implementation/|1: Bitstamp Info Leak]]
@@ -126,4 +131,4 @@ Outputs:
 
 ==Acknowledgements==
 
-Danno Ferrin <danno@numisight.com>, Sergio Demian Lerner <sergiolerner@certimix.com>, Justus Ranvier <justus@openbitcoinprivacyproject.org>, and Peter Todd <pete@petertodd.org> contributed to the design and motivations for this BIP.
\ No newline at end of file
+Danno Ferrin <danno@numisight.com>, Sergio Demian Lerner <sergiolerner@certimix.com>, Justus Ranvier <justus@openbitcoinprivacyproject.org>, and Peter Todd <pete@petertodd.org> contributed to the design and motivations for this BIP. A similar proposal was submitted to the Bitcoin-dev mailing list independently by Rusty Russell <rusty@rustcorp.com.au>
\ No newline at end of file
-- 
cgit v1.2.3


From 5f07cd0d18428b32174f352f9bb525dc9807bacf Mon Sep 17 00:00:00 2001
From: Kristov Atlas 
Date: Tue, 18 Aug 2015 17:43:46 -0400
Subject: trying to fix git mixup with bip68

---
 README.mediawiki | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/README.mediawiki b/README.mediawiki
index 1f8ef4d..6949512 100644
--- a/README.mediawiki
+++ b/README.mediawiki
@@ -254,15 +254,15 @@ Those proposing changes should consider that ultimately consent may rest with th
 | Standard
 | Draft
 |-
-<<<<<<< HEAD
-| [[bip-0069.mediawiki|69]]
-| Lexicographical Indexing of Transaction Inputs and Outputs
-| Kristov Atlas
-=======
 | [[bip-0068.mediawiki|68]]
 | Consensus-enforced transaction replacement signalled via sequence numbers
 | Mark Friedenbach
->>>>>>> bitcoin/master
+| Standard
+| Draft
+|-
+| [[bip-0069.mediawiki|69]]
+| Lexicographical Indexing of Transaction Inputs and Outputs
+| Kristov Atlas
 | Standard
 | Draft
 |-
@@ -297,4 +297,4 @@ Those proposing changes should consider that ultimately consent may rest with th
 | Draft
 |}
 
-
+
\ No newline at end of file
-- 
cgit v1.2.3


From 831a003f36652a3465fe0ff4e46090ad12c5a9e8 Mon Sep 17 00:00:00 2001
From: Kristov Atlas 
Date: Tue, 18 Aug 2015 17:50:31 -0400
Subject: added list of open source implementations

H/T @dcousens
---
 bip-0069.mediawiki | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index 7123488..77c1fb9 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -129,6 +129,13 @@ Outputs:
 * [[https://github.com/aantonop/bitcoinbook/blob/develop/ch05.asciidoc|3: Mastering Bitcoin]]
 * [[https://en.bitcoin.it/wiki/Script|4: Bitcoin Wiki on Script]]
 
+==Implementations==
+
+* [[https://github.com/spesmilo/electrum/blob/2af670ea2b92e835919b745d94afcb8b4ec32fda/lib/transaction.py#L648|Electrum]]
+* [[https://github.com/bitcoinjs/bip69/blob/master/index.js|BitcoinJS]]
+* [[https://github.com/bitcoinjs/bip69/blob/master/test/fixtures.json|BitcoinJS Test Fixtures]]
+* [[https://www.npmjs.com/package/bip69|NodeJS]]
+
 ==Acknowledgements==
 
 Danno Ferrin <danno@numisight.com>, Sergio Demian Lerner <sergiolerner@certimix.com>, Justus Ranvier <justus@openbitcoinprivacyproject.org>, and Peter Todd <pete@petertodd.org> contributed to the design and motivations for this BIP. A similar proposal was submitted to the Bitcoin-dev mailing list independently by Rusty Russell <rusty@rustcorp.com.au>
\ No newline at end of file
-- 
cgit v1.2.3


From d9acdcb6b12cd52424e8fec7cae89eef6bafcad9 Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 21 Aug 2015 08:44:55 +1000
Subject: split sentences over lines for smaller diffs

---
 bip-0069.mediawiki | 68 +++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 52 insertions(+), 16 deletions(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index 77c1fb9..d4a9a23 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -9,7 +9,10 @@
 
 ==Abstract==
 
-Currently there is no standard for bitcoin wallet clients when ordering transaction inputs and outputs. As a result, wallet clients often have a discernible blockchain fingerprint, and can leak private information about their users. By contrast, a standard for non-deterministic sorting could be difficult to audit. This document proposes deterministic lexicographical sorting, using hashes of previous transactions and output indices to sort transaction inputs, as well as values and scriptPubKeys to sort transaction outputs.
+Currently there is no standard for bitcoin wallet clients when ordering transaction inputs and outputs.
+As a result, wallet clients often have a discernible blockchain fingerprint, and can leak private information about their users.
+By contrast, a standard for non-deterministic sorting could be difficult to audit.
+This document proposes deterministic lexicographical sorting, using hashes of previous transactions and output indices to sort transaction inputs, as well as values and scriptPubKeys to sort transaction outputs.
 
 ==Copyright==
 
@@ -17,19 +20,41 @@ This BIP is in the public domain.
 
 ==Motivation==
 
-Currently, there is no clear standard for how wallet clients ought to order transaction inputs and outputs. Since wallet clients are left to their own devices to determine this ordering, they often leak information about their users’ finances. For example, a wallet client might naively order inputs based on when addresses were added to a wallet by the user through importing or random generation. Many wallets will place spending outputs first and change outputs second, leaking information about both the sender and receiver’s finances to passive blockchain observers. Such information should remain private not only for the benefit of consumers, but in higher order financial systems must be kept secret to prevent fraud. A researcher recently demonstrated this principle when he detected that Bitstamp leaked information when creating exchange transactions, enabling potential espionage among traders. [1]
-
-One way to address these privacy weaknesses is by randomly ordering inputs and outputs. [2] After all, the order of inputs and outputs does not impact the function of the transaction they belong to, making random sorting viable. Unfortunately, it can be difficult to prove that this sorting process is genuinely randomly sorted based on code or run-time analysis, especially if the software is closed source. A malicious software developer can abuse the ordering of inputs and outputs as a side channel of leaking information. For example, if an attacker can patch a victim’s HD wallet client to order inputs and outputs based on the bits of a master private key, then the attacker can eventually steal all of the victim’s funds by monitoring the blockchain. Non-deterministic methods of sorting are difficult to audit because they are not repeatable.
-
-The lack of standardization between wallet clients when ordering inputs and outputs can yield predictable quirks that characterize particular wallet clients or services. Such quirks create unique fingerprints that a privacy attacker can employ through simple passive blockchain observation.
-
-The solution is to create an algorithm for sorting transaction inputs and outputs that is deterministic. Since it is deterministic, it should also be unambiguous — that is, given a particular transaction, the proper order of inputs and outputs should be obvious. To make this standard as widely applicable as possible, it should rely on information that is downloaded by both full nodes (with or without typical efficiency techniques such as pruning) and SPV nodes. In order to ensure that it does not leak confidential data, it must rely on information that is publicly accessible through the blockchain. The use of public blockchain information also allows a transaction to be sorted even when it is a multi-party transaction, such as in the example of a CoinJoin.
+Currently, there is no clear standard for how wallet clients ought to order transaction inputs and outputs.
+Since wallet clients are left to their own devices to determine this ordering, they often leak information about their users’ finances.
+For example, a wallet client might naively order inputs based on when addresses were added to a wallet by the user through importing or random generation.
+Many wallets will place spending outputs first and change outputs second, leaking information about both the sender and receiver’s finances to passive blockchain observers.
+Such information should remain private not only for the benefit of consumers, but in higher order financial systems must be kept secret to prevent fraud.
+Currently, there is no clear standard for how wallet clients ought to order transaction inputs and outputs.
+Since wallet clients are left to their own devices to determine this ordering, they often leak information about their users’ finances.
+For example, a wallet client might naively order inputs based on when addresses were added to a wallet by the user through importing or random generation.
+Many wallets will place spending outputs first and change outputs second, leaking information about both the sender and receiver’s finances to passive blockchain observers.
+Such information should remain private not only for the benefit of consumers, but in higher order financial systems must be kept secret to prevent fraud.
+A researcher recently demonstrated this principle when he detected that Bitstamp leaked information when creating exchange transactions, enabling potential espionage among traders. [1]
+
+One way to address these privacy weaknesses is by randomly ordering inputs and outputs. [2]
+After all, the order of inputs and outputs does not impact the function of the transaction they belong to, making random sorting viable.
+Unfortunately, it can be difficult to prove that this sorting process is genuinely randomly sorted based on code or run-time analysis, especially if the software is closed source.
+A malicious software developer can abuse the ordering of inputs and outputs as a side channel of leaking information.
+For example, if an attacker can patch a victim’s HD wallet client to order inputs and outputs based on the bits of a master private key, then the attacker can eventually steal all of the victim’s funds by monitoring the blockchain.
+Non-deterministic methods of sorting are difficult to audit because they are not repeatable.
+
+The lack of standardization between wallet clients when ordering inputs and outputs can yield predictable quirks that characterize particular wallet clients or services.
+Such quirks create unique fingerprints that a privacy attacker can employ through simple passive blockchain observation.
+
+The solution is to create an algorithm for sorting transaction inputs and outputs that is deterministic.
+Since it is deterministic, it should also be unambiguous — that is, given a particular transaction, the proper order of inputs and outputs should be obvious.
+To make this standard as widely applicable as possible, it should rely on information that is downloaded by both full nodes (with or without typical efficiency techniques such as pruning) and SPV nodes.
+In order to ensure that it does not leak confidential data, it must rely on information that is publicly accessible through the blockchain.
+The use of public blockchain information also allows a transaction to be sorted even when it is a multi-party transaction, such as in the example of a CoinJoin.
 
 ==Specification==
 
 ===Applicability===
 
-This BIP applies to any transaction for which the order of its inputs and outputs does not impact the transaction’s function. Currently, this refers to any transaction that employs the SIGHASH_ALL signature hash type, in which signatures commit to the exact order of inputs and outputs. Transactions that use SIGHASH_ANYONECANPAY and/or SIGHASH_NONE may include inputs and/or outputs that are not signed; however, compliant software should still emit transactions with lexicographically sorted inputs and outputs, even though they may later be modified by others.
+This BIP applies to any transaction for which the order of its inputs and outputs does not impact the transaction’s function.
+Currently, this refers to any transaction that employs the SIGHASH_ALL signature hash type, in which signatures commit to the exact order of inputs and outputs.
+Transactions that use SIGHASH_ANYONECANPAY and/or SIGHASH_NONE may include inputs and/or outputs that are not signed; however, compliant software should still emit transactions with lexicographically sorted inputs and outputs, even though they may later be modified by others.
 
 In the event that future protocol upgrades introduce new signature hash types, compliant software should apply the lexicographical ordering principle analogously.
 
@@ -37,7 +62,8 @@ While out of scope of this BIP, protocols that do require a specified order of i
 
 ===Lexicographical Sorting===
 
-Ordering of inputs and outputs will rely on the output of sorting functions. These functions can be defined as taking two inputs or two outputs as parameters and returning their appropriate ordering with respect to each other.
+Ordering of inputs and outputs will rely on the output of sorting functions.
+These functions can be defined as taking two inputs or two outputs as parameters and returning their appropriate ordering with respect to each other.
 
 Byte arrays must be sorted with an algorithm that produces the same output as the following comparison algorithm:
 
@@ -62,19 +88,28 @@ N.B. These comparisons do not need to operate in constant time since they are no
 
 ===Transaction Inputs===
 
-104	Transaction inputs are defined by the hash of a previous transaction, the output index of of a UTXO from that previous transaction, the size of an unlocking script, the unlocking script, and a sequence number. [3] For sorting inputs, the hash of the previous transaction and the output index within that transaction are sufficient for sorting purposes; each transaction hash has an extremely high probability of being unique in the blockchain — this is enforced for coinbase transactions by BIP30 — and output indices within a transaction are unique. For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables.
+104 Transaction inputs are defined by the hash of a previous transaction, the output index of of a UTXO from that previous transaction, the size of an unlocking script, the unlocking script, and a sequence number. [3]
+For sorting inputs, the hash of the previous transaction and the output index within that transaction are sufficient for sorting purposes; each transaction hash has an extremely high probability of being unique in the blockchain — this is enforced for coinbase transactions by BIP30 — and output indices within a transaction are unique.
+For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables.
 
-Hashes of previous transactions are considered for the purposes of this BIP in their little-endian, byte array format in order to match the traditional, human-readable string representation of the hashes. They must be sorted in accordance with the output of the bytearr_cmp() function above: the hash with the earliest lesser byte is ordered first, and shorter hashes are ordered before longer ones as a tie-breaker. In the event of two matching transaction hashes, output indices will be compared based on their integer value, with the smaller value ordered first. A further tie is extremely improbable for the aforementioned reasons.
+Hashes of previous transactions are considered for the purposes of this BIP in their little-endian, byte array format in order to match the traditional, human-readable string representation of the hashes.
+They must be sorted in accordance with the output of the bytearr_cmp() function above: the hash with the earliest lesser byte is ordered first, and shorter hashes are ordered before longer ones as a tie-breaker.
+In the event of two matching transaction hashes, output indices will be compared based on their integer value, with the smaller value ordered first.
+A further tie is extremely improbable for the aforementioned reasons.
 
 Because the hash of previous transactions and output indices must be included in a signed transaction, wallet clients capable of signing transactions will necessarily have access to this data.
 
-Transaction malleability will not negatively impact the correctness of this process. Even if a wallet client follows this process using unconfirmed UTXOs as inputs and an attacker changes modifies the blockchain’s record of the hash of the previous transaction, the wallet client will include the invalidated previous transaction hash in its input data, and will still correctly sort with respect to that invalidated hash.
+Transaction malleability will not negatively impact the correctness of this process.
+Even if a wallet client follows this process using unconfirmed UTXOs as inputs and an attacker changes modifies the blockchain’s record of the hash of the previous transaction, the wallet client will include the invalidated previous transaction hash in its input data, and will still correctly sort with respect to that invalidated hash.
 
 ===Transaction Outputs===
 
-A transaction output is defined by its scriptPubKey and amount. [3] For sorting purposes, we will consider a scriptPubKey in its byte array representation, and a bitcoin amount in terms of their integer number of satoshis (smallest amount ordered first).
+A transaction output is defined by its scriptPubKey and amount. [3]
+For sorting purposes, we will consider a scriptPubKey in its byte array representation, and a bitcoin amount in terms of their integer number of satoshis (smallest amount ordered first).
 
-For the sake of efficiency, amounts will be considered first for sorting, since they contain fewer bytes of information (8 bytes) compared to a standard P2PKH scriptPubKey (25 bytes). [4] When the values are tied, the scriptPubKey is then considered. In the event of a tie between scriptPubKeys, sorting is irrelevant since the outputs are exactly equivalent.
+For the sake of efficiency, amounts will be considered first for sorting, since they contain fewer bytes of information (8 bytes) compared to a standard P2PKH scriptPubKey (25 bytes). [4]
+When the values are tied, the scriptPubKey is then considered.
+In the event of a tie between scriptPubKeys, sorting is irrelevant since the outputs are exactly equivalent.
 
 ===Examples===
 
@@ -138,4 +173,5 @@ Outputs:
 
 ==Acknowledgements==
 
-Danno Ferrin <danno@numisight.com>, Sergio Demian Lerner <sergiolerner@certimix.com>, Justus Ranvier <justus@openbitcoinprivacyproject.org>, and Peter Todd <pete@petertodd.org> contributed to the design and motivations for this BIP. A similar proposal was submitted to the Bitcoin-dev mailing list independently by Rusty Russell <rusty@rustcorp.com.au>
\ No newline at end of file
+Danno Ferrin <danno@numisight.com>, Sergio Demian Lerner <sergiolerner@certimix.com>, Justus Ranvier <justus@openbitcoinprivacyproject.org>, and Peter Todd <pete@petertodd.org> contributed to the design and motivations for this BIP.
+A similar proposal was submitted to the Bitcoin-dev mailing list independently by Rusty Russell <rusty@rustcorp.com.au>
-- 
cgit v1.2.3


From 66cb8346fed16c407b84416923130422bb9c5036 Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 21 Aug 2015 08:47:06 +1000
Subject: human-readable string representation is big-endian

---
 bip-0069.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index d4a9a23..250787c 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -92,7 +92,7 @@ N.B. These comparisons do not need to operate in constant time since they are no
 For sorting inputs, the hash of the previous transaction and the output index within that transaction are sufficient for sorting purposes; each transaction hash has an extremely high probability of being unique in the blockchain — this is enforced for coinbase transactions by BIP30 — and output indices within a transaction are unique.
 For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables.
 
-Hashes of previous transactions are considered for the purposes of this BIP in their little-endian, byte array format in order to match the traditional, human-readable string representation of the hashes.
+Previous transaction hashes are considered for the purposes of this BIP in their big-endian, byte array format in order to match the human-readable string representation of the hashes.
 They must be sorted in accordance with the output of the bytearr_cmp() function above: the hash with the earliest lesser byte is ordered first, and shorter hashes are ordered before longer ones as a tie-breaker.
 In the event of two matching transaction hashes, output indices will be compared based on their integer value, with the smaller value ordered first.
 A further tie is extremely improbable for the aforementioned reasons.
-- 
cgit v1.2.3


From 8d2a159496b8b1518a66abb29a28a68e70e0209c Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 21 Aug 2015 08:50:11 +1000
Subject: sort by prevTxHash in little-endian, descending order,
 lexicographically

---
 bip-0069.mediawiki | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index 250787c..85e3fdd 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -92,9 +92,8 @@ N.B. These comparisons do not need to operate in constant time since they are no
 For sorting inputs, the hash of the previous transaction and the output index within that transaction are sufficient for sorting purposes; each transaction hash has an extremely high probability of being unique in the blockchain — this is enforced for coinbase transactions by BIP30 — and output indices within a transaction are unique.
 For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables.
 
-Previous transaction hashes are considered for the purposes of this BIP in their big-endian, byte array format in order to match the human-readable string representation of the hashes.
-They must be sorted in accordance with the output of the bytearr_cmp() function above: the hash with the earliest lesser byte is ordered first, and shorter hashes are ordered before longer ones as a tie-breaker.
-In the event of two matching transaction hashes, output indices will be compared based on their integer value, with the smaller value ordered first.
+Previous transaction hashes (in their little-endian, byte-array form) are to be sorted in descending order, lexicographically.
+In the event of two matching transaction hashes, the respective output indices will be compared by their integer value, in ascending order.
 A further tie is extremely improbable for the aforementioned reasons.
 
 Because the hash of previous transactions and output indices must be included in a signed transaction, wallet clients capable of signing transactions will necessarily have access to this data.
-- 
cgit v1.2.3


From 342058602eb7737ceeb098d07eb9237d5e5fc65a Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 21 Aug 2015 08:51:18 +1000
Subject: remove probability, specify behaviour for matching prevOut indices

---
 bip-0069.mediawiki | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index 85e3fdd..43d25ee 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -93,8 +93,8 @@ For sorting inputs, the hash of the previous transaction and the output index wi
 For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables.
 
 Previous transaction hashes (in their little-endian, byte-array form) are to be sorted in descending order, lexicographically.
-In the event of two matching transaction hashes, the respective output indices will be compared by their integer value, in ascending order.
-A further tie is extremely improbable for the aforementioned reasons.
+In the event of two matching transaction hashes, the respective previous output indices will be compared by their integer value, in ascending order.
+If the previous output indices match, the inputs are considered equal.
 
 Because the hash of previous transactions and output indices must be included in a signed transaction, wallet clients capable of signing transactions will necessarily have access to this data.
 
-- 
cgit v1.2.3


From c351ae0b9f518709fdd540573c30206696078f0b Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 21 Aug 2015 08:52:18 +1000
Subject: remove mention of information typically found in wallets

---
 bip-0069.mediawiki | 2 --
 1 file changed, 2 deletions(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index 43d25ee..5a20389 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -96,8 +96,6 @@ Previous transaction hashes (in their little-endian, byte-array form) are to be
 In the event of two matching transaction hashes, the respective previous output indices will be compared by their integer value, in ascending order.
 If the previous output indices match, the inputs are considered equal.
 
-Because the hash of previous transactions and output indices must be included in a signed transaction, wallet clients capable of signing transactions will necessarily have access to this data.
-
 Transaction malleability will not negatively impact the correctness of this process.
 Even if a wallet client follows this process using unconfirmed UTXOs as inputs and an attacker changes modifies the blockchain’s record of the hash of the previous transaction, the wallet client will include the invalidated previous transaction hash in its input data, and will still correctly sort with respect to that invalidated hash.
 
-- 
cgit v1.2.3


From c6ed18d8b27be10b5f0c5f357969e1b0dbf963db Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 21 Aug 2015 08:54:12 +1000
Subject: remove malleability foot note

---
 bip-0069.mediawiki | 2 --
 1 file changed, 2 deletions(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index 5a20389..d600825 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -96,8 +96,6 @@ Previous transaction hashes (in their little-endian, byte-array form) are to be
 In the event of two matching transaction hashes, the respective previous output indices will be compared by their integer value, in ascending order.
 If the previous output indices match, the inputs are considered equal.
 
-Transaction malleability will not negatively impact the correctness of this process.
-Even if a wallet client follows this process using unconfirmed UTXOs as inputs and an attacker changes modifies the blockchain’s record of the hash of the previous transaction, the wallet client will include the invalidated previous transaction hash in its input data, and will still correctly sort with respect to that invalidated hash.
 
 ===Transaction Outputs===
 
-- 
cgit v1.2.3


From c60771d2299a08299a7734a697587dde2378d489 Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 21 Aug 2015 09:07:31 +1000
Subject: reword transaction outputs in-line with transaction inputs format

---
 bip-0069.mediawiki | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index d600825..f3dff42 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -100,11 +100,11 @@ If the previous output indices match, the inputs are considered equal.
 ===Transaction Outputs===
 
 A transaction output is defined by its scriptPubKey and amount. [3]
-For sorting purposes, we will consider a scriptPubKey in its byte array representation, and a bitcoin amount in terms of their integer number of satoshis (smallest amount ordered first).
+For the sake of efficiency, amounts should be compared first for sorting, since they contain fewer bytes of information (8 bytes) compared to a standard P2PKH scriptPubKey (25 bytes). [4]
 
-For the sake of efficiency, amounts will be considered first for sorting, since they contain fewer bytes of information (8 bytes) compared to a standard P2PKH scriptPubKey (25 bytes). [4]
-When the values are tied, the scriptPubKey is then considered.
-In the event of a tie between scriptPubKeys, sorting is irrelevant since the outputs are exactly equivalent.
+Transaction output amounts (as 64-bit unsigned integers) are to be sorted in ascending order.
+In the event of two matching output amounts, the respective output scriptPubKeys (in their little-endian, byte-array form) will be compared lexicographically, in ascending order.
+If the scriptPubKeys match, the outputs are considered equal.
 
 ===Examples===
 
-- 
cgit v1.2.3


From 64a44180b87ceb6101f4b62c5dd6c2b4bba33669 Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 21 Aug 2015 09:08:50 +1000
Subject: remove random 104

---
 bip-0069.mediawiki | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index f3dff42..e4d273c 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -88,7 +88,7 @@ N.B. These comparisons do not need to operate in constant time since they are no
 
 ===Transaction Inputs===
 
-104 Transaction inputs are defined by the hash of a previous transaction, the output index of of a UTXO from that previous transaction, the size of an unlocking script, the unlocking script, and a sequence number. [3]
+Transaction inputs are defined by the hash of a previous transaction, the output index of of a UTXO from that previous transaction, the size of an unlocking script, the unlocking script, and a sequence number. [3]
 For sorting inputs, the hash of the previous transaction and the output index within that transaction are sufficient for sorting purposes; each transaction hash has an extremely high probability of being unique in the blockchain — this is enforced for coinbase transactions by BIP30 — and output indices within a transaction are unique.
 For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables.
 
-- 
cgit v1.2.3


From 5f75c82dc47423e026461dc228eebed76fde89b0 Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 21 Aug 2015 09:10:49 +1000
Subject: add editor note

---
 bip-0069.mediawiki | 1 +
 1 file changed, 1 insertion(+)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index e4d273c..d265aae 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -2,6 +2,7 @@
   BIP:     BIP: 69
   Title:   Lexicographical Indexing of Transaction Inputs and Outputs
   Authors: Kristov Atlas 
+  Editors: Daniel Cousens 
   Status:  Draft
   Type:    Informational
   Created: 2015-06-12
-- 
cgit v1.2.3


From 64f321e2c9919ffc2b6bfb7999d5986c1cb7cf34 Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 21 Aug 2015 09:22:50 +1000
Subject: dont include pseudo-code for lexicographical sorting

---
 bip-0069.mediawiki | 44 +++++++++++++++++++-------------------------
 1 file changed, 19 insertions(+), 25 deletions(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index d265aae..e01a792 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -61,31 +61,21 @@ In the event that future protocol upgrades introduce new signature hash types, c
 
 While out of scope of this BIP, protocols that do require a specified order of inputs/outputs (e.g. due to use of SIGHASH_SINGLE) should consider the goals of this BIP and how best to adapt them to the specific needs of those protocols.
 
-===Lexicographical Sorting===
-
-Ordering of inputs and outputs will rely on the output of sorting functions.
-These functions can be defined as taking two inputs or two outputs as parameters and returning their appropriate ordering with respect to each other.
-
-Byte arrays must be sorted with an algorithm that produces the same output as the following comparison algorithm:
-
- #returns -1 if barr1 is lesser, 1 if barr1 is greater, and 0 if equal
- def bytearr_cmp(barr1, barr2):
-    pos = 0
-    while (pos < len(barr1) and pos < len(barr2)):
-        if (barr1[pos] < barr2[pos]):
-            return -1;
-        elif (barr1[pos] > barr2[pos]):
-            return 1;
-        pos = pos + 1
-    #the shorter array will be ordered first
-    if (len(barr1) < len(barr2)):
-        return -1
-    elif (len(barr1) > len(barr2)):
-        return 1
-    else:
-        return 0
-
-N.B. These comparisons do not need to operate in constant time since they are not processing secret information.
+===Lexicographical Ordering===
+
+Lexicographical ordering is an algorithm for comparison used to sort two sets based on their cartesian order within their common superset.
+Lexicographic order is also often known as alphabetical order, or dictionary order.
+
+Common implementations include:
+
+* `std::lexicographical_compare` in C++ [5]
+* `cmp` in Python 2.7
+* `memcmp` in C [6]
+* `Buffer.compare` in Node.js [7]
+
+For more information, see the wikipedia entry on Lexicographical order. [8]
+
+N.B. All comparisons do not need to operate in constant time since they are not processing secret information.
 
 ===Transaction Inputs===
 
@@ -159,6 +149,10 @@ Outputs:
 * [[https://github.com/OpenBitcoinPrivacyProject/wallet-ratings/blob/master/2015-1/criteria.md|2: OBPP Random Indexing as Countermeasure]]
 * [[https://github.com/aantonop/bitcoinbook/blob/develop/ch05.asciidoc|3: Mastering Bitcoin]]
 * [[https://en.bitcoin.it/wiki/Script|4: Bitcoin Wiki on Script]]
+* [[http://www.cplusplus.com/reference/algorithm/lexicographical_compare|5: std::lexicographical_compare]]
+* [[http://www.cplusplus.com/reference/cstring/memcmp|6: memcmp]]
+* [[https://nodejs.org/api/buffer.html#buffer_class_method_buffer_compare_buf1_buf2|7: Buffer.compare]]
+* [[https://en.wikipedia.org/wiki/Lexicographical_order|8: Lexicographical order]]
 
 ==Implementations==
 
-- 
cgit v1.2.3


From 1d74463fd97f81d9612214420f44978991cd3ca6 Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Fri, 28 Aug 2015 10:50:23 +1000
Subject: Revert "remove malleability foot note"

This reverts commit c6ed18d8b27be10b5f0c5f357969e1b0dbf963db.
---
 bip-0069.mediawiki | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index e01a792..56400cb 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -87,6 +87,8 @@ Previous transaction hashes (in their little-endian, byte-array form) are to be
 In the event of two matching transaction hashes, the respective previous output indices will be compared by their integer value, in ascending order.
 If the previous output indices match, the inputs are considered equal.
 
+Transaction malleability will not negatively impact the correctness of this process.
+Even if a wallet client follows this process using unconfirmed UTXOs as inputs and an attacker changes modifies the blockchain’s record of the hash of the previous transaction, the wallet client will include the invalidated previous transaction hash in its input data, and will still correctly sort with respect to that invalidated hash.
 
 ===Transaction Outputs===
 
-- 
cgit v1.2.3


From 8368e7553ca073ff887bf8d22cde21bec545b56d Mon Sep 17 00:00:00 2001
From: Daniel Cousens 
Date: Thu, 10 Sep 2015 07:43:00 +1000
Subject: endianness not relevant, use byte order

---
 bip-0069.mediawiki | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/bip-0069.mediawiki b/bip-0069.mediawiki
index 56400cb..e868df3 100644
--- a/bip-0069.mediawiki
+++ b/bip-0069.mediawiki
@@ -83,7 +83,7 @@ Transaction inputs are defined by the hash of a previous transaction, the output
 For sorting inputs, the hash of the previous transaction and the output index within that transaction are sufficient for sorting purposes; each transaction hash has an extremely high probability of being unique in the blockchain — this is enforced for coinbase transactions by BIP30 — and output indices within a transaction are unique.
 For the sake of efficiency, transaction hashes should be compared first before output indices, since output indices from different transactions are often equivalent, while all bytes of the transaction hash are effectively random variables.
 
-Previous transaction hashes (in their little-endian, byte-array form) are to be sorted in descending order, lexicographically.
+Previous transaction hashes (in reversed byte-order) are to be sorted in ascending order, lexicographically.
 In the event of two matching transaction hashes, the respective previous output indices will be compared by their integer value, in ascending order.
 If the previous output indices match, the inputs are considered equal.
 
@@ -96,7 +96,7 @@ A transaction output is defined by its scriptPubKey and amount. [3]
 For the sake of efficiency, amounts should be compared first for sorting, since they contain fewer bytes of information (8 bytes) compared to a standard P2PKH scriptPubKey (25 bytes). [4]
 
 Transaction output amounts (as 64-bit unsigned integers) are to be sorted in ascending order.
-In the event of two matching output amounts, the respective output scriptPubKeys (in their little-endian, byte-array form) will be compared lexicographically, in ascending order.
+In the event of two matching output amounts, the respective output scriptPubKeys (as a byte-array) will be compared lexicographically, in ascending order.
 If the scriptPubKeys match, the outputs are considered equal.
 
 ===Examples===
-- 
cgit v1.2.3


From 42c0650ccb2d6483f44e71c04d8c982a5e9208fe Mon Sep 17 00:00:00 2001
From: Kristov Atlas 
Date: Sat, 19 Sep 2015 17:22:41 -0400
Subject: add EOF newlines per @luke-jr
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

“README.mediawiki and bip-0069/bip-0069_examples.py are missing EOF
newlines. Anything else needed before merging this draft?” — @luke-jr
---
 README.mediawiki              | 2 +-
 bip-0069/bip-0069_examples.py | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/README.mediawiki b/README.mediawiki
index 6949512..13e38e8 100644
--- a/README.mediawiki
+++ b/README.mediawiki
@@ -297,4 +297,4 @@ Those proposing changes should consider that ultimately consent may rest with th
 | Draft
 |}
 
-
\ No newline at end of file
+
diff --git a/bip-0069/bip-0069_examples.py b/bip-0069/bip-0069_examples.py
index 7622cfe..e2f52ed 100644
--- a/bip-0069/bip-0069_examples.py
+++ b/bip-0069/bip-0069_examples.py
@@ -109,4 +109,4 @@ def main():
 	print_outputs(tx_2820_output_tuples)
 
 if __name__ == "__main__":
-	main()
\ No newline at end of file
+	main()
-- 
cgit v1.2.3