Skip to content

Commit

Permalink
shuffle transaction inputs and outputs
Browse files Browse the repository at this point in the history
Change strategy regarding transaction inputs/outputs ordering. The node shuffles inputs and outputs, while Electrum was sorting them in a deterministic order. Both strategies are viable ways of improving user privacy, but the randomization helps also users of other wallets. If most wallets apply randomization, then the few wallets that don't will stand out less. It will be difficult to guess if a simple transaction (one or two inputs, two outputs) that matches some sorting rules did it intentionnaly or by random luck.
  • Loading branch information
PiRK committed Jan 30, 2023
1 parent 8a2d53c commit 7853985
Show file tree
Hide file tree
Showing 2 changed files with 7 additions and 8 deletions.
8 changes: 4 additions & 4 deletions electrumabc/transaction.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
# SOFTWARE.
import hashlib
import random
import struct
import warnings
from typing import Optional, Tuple, Union
Expand Down Expand Up @@ -780,10 +781,9 @@ def serialize_input(self, txin, script, estimate_size=False):
s += bitcoin.int_to_hex(txin["value"], 8)
return s

def BIP_LI01_sort(self):
# See https://github.com/kristovatlas/rfc/blob/master/bips/bip-li01.mediawiki
self._inputs.sort(key=lambda i: (i["prevout_hash"], i["prevout_n"]))
self._outputs.sort(key=lambda o: (o[2], self.pay_script(o[1])))
def shuffle_inputs_outputs(self):
random.shuffle(self._inputs)
random.shuffle(self._outputs)

def serialize_output(self, output):
output_type, addr, amount = output
Expand Down
7 changes: 3 additions & 4 deletions electrumabc/wallet.py
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@ def sweep(
tx = Transaction.from_io(
inputs, outputs, locktime=locktime, sign_schnorr=sign_schnorr
)
tx.BIP_LI01_sort()
tx.shuffle_inputs_outputs()
tx.sign(keypairs)
return tx

Expand Down Expand Up @@ -2160,8 +2160,7 @@ def fee_estimator(size):
if sats_per_byte > 100:
raise ExcessiveFee()

# Sort the inputs and outputs deterministically
tx.BIP_LI01_sort()
tx.shuffle_inputs_outputs()
# Timelock tx to current height.
locktime = 0
if config.is_current_block_locktime_enabled():
Expand Down Expand Up @@ -2440,7 +2439,7 @@ def cpfp(self, tx, fee, sign_schnorr=None, enable_current_block_locktime=True):
locktime = 0
if enable_current_block_locktime:
locktime = self.get_local_height()
# note: no need to call tx.BIP_LI01_sort() here - single input/output
# note: no need to call tx.shuffle_inputs_outputs here - single input/output
return Transaction.from_io(
inputs, outputs, locktime=locktime, sign_schnorr=sign_schnorr
)
Expand Down

0 comments on commit 7853985

Please sign in to comment.