Browse Source

Privacy improvements for direct_send()

* Shuffle order of tx inputs and outputs
* Set locktime for best anonset (Core, Electrum)
master
Kristaps Kaupe 6 years ago
parent
commit
c23808f054
No known key found for this signature in database
GPG Key ID: D47B1B4232B55437
  1. 2
      jmclient/jmclient/__init__.py
  2. 4
      jmclient/jmclient/blockchaininterface.py
  3. 8
      jmclient/jmclient/maker.py
  4. 8
      jmclient/jmclient/taker.py
  5. 8
      jmclient/jmclient/taker_utils.py
  6. 11
      jmclient/jmclient/wallet.py

2
jmclient/jmclient/__init__.py

@ -17,7 +17,7 @@ from .taker import Taker, P2EPTaker
from .wallet import (Mnemonic, estimate_tx_fee, WalletError, BaseWallet, ImportWalletMixin,
BIP39WalletMixin, BIP32Wallet, BIP49Wallet, LegacyWallet,
SegwitWallet, SegwitLegacyWallet, UTXOManager,
WALLET_IMPLEMENTATIONS)
WALLET_IMPLEMENTATIONS, compute_tx_locktime)
from .storage import (Argon2Hash, Storage, StorageError, RetryableStorageError,
StoragePasswordError, VolatileStorage)
from .cryptoengine import BTCEngine, BTC_P2PKH, BTC_P2SH_P2WPKH, EngineError

4
jmclient/jmclient/blockchaininterface.py

@ -388,6 +388,10 @@ class BitcoinCoreInterface(BlockchainInterface):
return 10000
return int(Decimal(1e8) * Decimal(estimate))
def get_current_block_height(self):
return self.rpc("getblockchaininfo", [])["blocks"]
class RegtestBitcoinCoreMixin():
"""
This Mixin provides helper functions that are used in Interface classes

8
jmclient/jmclient/maker.py

@ -13,7 +13,7 @@ from binascii import unhexlify
from jmbitcoin import SerializationError, SerializationTruncationError
import jmbitcoin as btc
from jmclient.wallet import estimate_tx_fee
from jmclient.wallet import estimate_tx_fee, compute_tx_locktime
from jmclient.wallet_service import WalletService
from jmclient.configure import jm_single
from jmbase.support import get_log, EXIT_SUCCESS, EXIT_FAILURE
@ -605,11 +605,7 @@ class P2EPMaker(Maker):
"value": new_change_amount})
new_ins = [x[1] for x in utxo.values()]
new_ins.extend(my_utxos.keys())
# set locktime for best anonset (Core, Electrum) - most recent block.
# this call should never fail so no catch here.
currentblock = jm_single().bc_interface.rpc(
"getblockchaininfo", [])["blocks"]
new_tx = btc.make_shuffled_tx(new_ins, new_outs, False, 2, currentblock)
new_tx = btc.make_shuffled_tx(new_ins, new_outs, False, 2, compute_tx_locktime())
new_tx_deser = btc.deserialize(new_tx)
# sign our inputs before transfer

8
jmclient/jmclient/taker.py

@ -16,7 +16,7 @@ from jmclient.configure import jm_single, validate_address
from jmbase.support import get_log
from jmclient.support import (calc_cj_fee, weighted_order_choose, choose_orders,
choose_sweep_orders)
from jmclient.wallet import estimate_tx_fee
from jmclient.wallet import estimate_tx_fee, compute_tx_locktime
from jmclient.podle import generate_podle, get_podle_commitments, PoDLE
from jmclient.wallet_service import WalletService
from .output import generate_podle_error_string
@ -1007,14 +1007,10 @@ class P2EPTaker(Taker):
if self.my_change_addr is not None:
self.outputs.append({'address': self.my_change_addr,
'value': my_change_value})
# set locktime for best anonset (Core, Electrum) - most recent block.
# this call should never fail so no catch here.
currentblock = jm_single().bc_interface.rpc(
"getblockchaininfo", [])["blocks"]
# As for JM coinjoins, the `None` key is used for our own inputs
# to the transaction; this preparatory version contains only those.
tx = btc.make_shuffled_tx(self.utxos[None], self.outputs,
False, 2, currentblock)
False, 2, compute_tx_locktime())
jlog.info('Created proposed fallback tx\n' + pprint.pformat(
btc.deserialize(tx)))
# We now sign as a courtesy, because if we disappear the recipient

8
jmclient/jmclient/taker_utils.py

@ -11,8 +11,9 @@ from jmbase import get_log, jmprint
from .configure import jm_single, validate_address
from .schedule import human_readable_schedule_entry, tweak_tumble_schedule,\
schedule_to_text
from .wallet import BaseWallet, estimate_tx_fee
from jmbitcoin import deserialize, mktx, serialize, txhash, amount_to_str
from .wallet import BaseWallet, estimate_tx_fee, compute_tx_locktime
from jmbitcoin import deserialize, make_shuffled_tx, serialize, txhash,\
amount_to_str
from jmbase.support import EXIT_SUCCESS
log = get_log()
@ -78,7 +79,8 @@ def direct_send(wallet_service, amount, mixdepth, destaddr, answeryes=False,
log.info("Using a fee of : " + amount_to_str(fee_est) + ".")
if amount != 0:
log.info("Using a change value of: " + amount_to_str(changeval) + ".")
txsigned = sign_tx(wallet_service, mktx(list(utxos.keys()), outs), utxos)
txsigned = sign_tx(wallet_service, make_shuffled_tx(
list(utxos.keys()), outs, False, 2, compute_tx_locktime()), utxos)
log.info("Got signed transaction:\n")
log.info(pformat(txsigned))
tx = serialize(txsigned)

11
jmclient/jmclient/wallet.py

@ -7,6 +7,7 @@ import warnings
import functools
import collections
import numbers
import random
from binascii import hexlify, unhexlify
from datetime import datetime
from copy import deepcopy
@ -92,6 +93,16 @@ def estimate_tx_fee(ins, outs, txtype='p2pkh'):
raise NotImplementedError("Txtype: " + txtype + " not implemented.")
def compute_tx_locktime():
# set locktime for best anonset (Core, Electrum)
# most recent block or some time back in random cases
locktime = jm_single().bc_interface.get_current_block_height()
if random.randint(0, 9) == 0:
# P2EP requires locktime > 0
locktime = max(1, locktime - random.randint(0, 99))
return locktime
#FIXME: move this to a utilities file?
def deprecated(func):
@functools.wraps(func)

Loading…
Cancel
Save