From 1cbc2f44b0f3c6106d3c97e822bbaa44a37e60e6 Mon Sep 17 00:00:00 2001 From: tecnovert Date: Mon, 25 Mar 2024 13:37:35 +0200 Subject: [PATCH] Allow multiple base58 prefix bytes. --- basicswap/chainparams.py | 3 +++ basicswap/interface/xmr.py | 16 +++++++++------- basicswap/util/__init__.py | 2 ++ basicswap/util/integer.py | 23 +++++++++++++++++++++++ basicswap/util_xmr.py | 6 ++++-- tests/basicswap/test_other.py | 31 +++++++++++++++++++++++++++++++ 6 files changed, 72 insertions(+), 9 deletions(-) create mode 100644 basicswap/util/integer.py diff --git a/basicswap/chainparams.py b/basicswap/chainparams.py index 59be4c8..9a3065c 100644 --- a/basicswap/chainparams.py +++ b/basicswap/chainparams.py @@ -200,18 +200,21 @@ chainparams = { 'walletrpcport': 18082, 'min_amount': 100000, 'max_amount': 10000 * XMR_COIN, + 'address_prefix': 18, }, 'testnet': { 'rpcport': 28081, 'walletrpcport': 28082, 'min_amount': 100000, 'max_amount': 10000 * XMR_COIN, + 'address_prefix': 18, }, 'regtest': { 'rpcport': 18081, 'walletrpcport': 18082, 'min_amount': 100000, 'max_amount': 10000 * XMR_COIN, + 'address_prefix': 18, } }, Coins.PIVX: { diff --git a/basicswap/interface/xmr.py b/basicswap/interface/xmr.py index 4840640..47992a6 100644 --- a/basicswap/interface/xmr.py +++ b/basicswap/interface/xmr.py @@ -81,6 +81,8 @@ class XMRInterface(CoinInterface): def __init__(self, coin_settings, network, swap_client=None): super().__init__(network) + self._addr_prefix = self.chainparams_network()['address_prefix'] + self.blocks_confirmed = coin_settings['blocks_confirmed'] self._restore_height = coin_settings.get('restore_height', 0) self.setFeePriority(coin_settings.get('fee_priority', 2)) @@ -165,7 +167,7 @@ class XMRInterface(CoinInterface): Kbv = self.getPubkey(key_view) Kbs = self.getPubkey(key_spend) - address_b58 = xmr_util.encode_address(Kbv, Kbs) + address_b58 = xmr_util.encode_address(Kbv, Kbs, self._addr_prefix) params = { 'filename': self._wallet_filename, @@ -289,7 +291,7 @@ class XMRInterface(CoinInterface): def getAddressFromKeys(self, key_view: bytes, key_spend: bytes) -> str: pk_view = self.getPubkey(key_view) pk_spend = self.getPubkey(key_spend) - return xmr_util.encode_address(pk_view, pk_spend) + return xmr_util.encode_address(pk_view, pk_spend, self._addr_prefix) def verifyKey(self, k: int) -> bool: i = b2i(k) @@ -317,7 +319,7 @@ class XMRInterface(CoinInterface): return ed25519_add(Ka, Kb) def encodeSharedAddress(self, Kbv: bytes, Kbs: bytes) -> str: - return xmr_util.encode_address(Kbv, Kbs) + return xmr_util.encode_address(Kbv, Kbs, self._addr_prefix) def publishBLockTx(self, kbv: bytes, Kbs: bytes, output_amount: int, feerate: int, unlock_time: int = 0) -> bytes: with self._mx_wallet: @@ -325,7 +327,7 @@ class XMRInterface(CoinInterface): self.rpc_wallet('refresh') Kbv = self.getPubkey(kbv) - shared_addr = xmr_util.encode_address(Kbv, Kbs) + shared_addr = xmr_util.encode_address(Kbv, Kbs, self._addr_prefix) params = {'destinations': [{'amount': output_amount, 'address': shared_addr}], 'unlock_time': unlock_time} if self._fee_priority > 0: @@ -339,7 +341,7 @@ class XMRInterface(CoinInterface): def findTxB(self, kbv, Kbs, cb_swap_value, cb_block_confirmed, restore_height, bid_sender): with self._mx_wallet: Kbv = self.getPubkey(kbv) - address_b58 = xmr_util.encode_address(Kbv, Kbs) + address_b58 = xmr_util.encode_address(Kbv, Kbs, self._addr_prefix) kbv_le = kbv[::-1] params = { @@ -417,7 +419,7 @@ class XMRInterface(CoinInterface): with self._mx_wallet: Kbv = self.getPubkey(kbv) Kbs = self.getPubkey(kbs) - address_b58 = xmr_util.encode_address(Kbv, Kbs) + address_b58 = xmr_util.encode_address(Kbv, Kbs, self._addr_prefix) wallet_filename = address_b58 + '_spend' @@ -504,7 +506,7 @@ class XMRInterface(CoinInterface): with self._mx_wallet: try: Kbv = self.getPubkey(kbv) - address_b58 = xmr_util.encode_address(Kbv, Kbs) + address_b58 = xmr_util.encode_address(Kbv, Kbs, self._addr_prefix) wallet_file = address_b58 + '_spend' try: self.openWallet(wallet_file) diff --git a/basicswap/util/__init__.py b/basicswap/util/__init__.py index 542c8bd..8efcfa0 100644 --- a/basicswap/util/__init__.py +++ b/basicswap/util/__init__.py @@ -67,6 +67,7 @@ def dumpje(jin): def SerialiseNum(n: int) -> bytes: + # For script if n == 0: return bytes((0x00,)) if n > 0 and n <= 16: @@ -85,6 +86,7 @@ def SerialiseNum(n: int) -> bytes: def DeserialiseNum(b: bytes, o: int = 0) -> int: + # For script if b[o] == 0: return 0 if b[o] > 0x50 and b[o] <= 0x50 + 16: diff --git a/basicswap/util/integer.py b/basicswap/util/integer.py new file mode 100644 index 0000000..7b001a7 --- /dev/null +++ b/basicswap/util/integer.py @@ -0,0 +1,23 @@ +# -*- coding: utf-8 -*- + +# Copyright (c) 2024 tecnovert +# Distributed under the MIT software license, see the accompanying +# file LICENSE or http://www.opensource.org/licenses/mit-license.php. + + +def decode_varint(b: bytes) -> int: + i = 0 + shift = 0 + for c in b: + i += (c & 0x7F) << shift + shift += 7 + return i + + +def encode_varint(i: int) -> bytes: + b = bytearray() + while i > 0x7F: + b += bytes(((i & 0x7F) | 0x80,)) + i = (i >> 7) + b += bytes((i,)) + return b diff --git a/basicswap/util_xmr.py b/basicswap/util_xmr.py index a3d93d3..8671d81 100644 --- a/basicswap/util_xmr.py +++ b/basicswap/util_xmr.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- import basicswap.contrib.Keccak as Keccak +from basicswap.util.integer import encode_varint from .contrib.MoneroPy.base58 import encode as xmr_b58encode @@ -9,8 +10,9 @@ def cn_fast_hash(s): return k.Keccak((len(s) * 8, s.hex()), 1088, 512, 32 * 8, False).lower() # r = bitrate = 1088, c = capacity, n = output length in bits -def encode_address(view_point, spend_point, version=18): - buf = bytes((version,)) + spend_point + view_point +def encode_address(view_point: bytes, spend_point: bytes, version=18) -> str: + prefix_bytes = version if isinstance(version, bytes) else encode_varint(version) + buf = prefix_bytes + spend_point + view_point h = cn_fast_hash(buf) buf = buf + bytes.fromhex(h[0: 8]) diff --git a/tests/basicswap/test_other.py b/tests/basicswap/test_other.py index 3d8508d..a0ccdeb 100644 --- a/tests/basicswap/test_other.py +++ b/tests/basicswap/test_other.py @@ -22,9 +22,11 @@ from coincurve.keys import ( PrivateKey) from basicswap.util import i2b, h2b +from basicswap.util.integer import encode_varint, decode_varint from basicswap.util.crypto import ripemd160, hash160 from basicswap.util.network import is_private_ip_address from basicswap.util.rfc2440 import rfc2440_hash_password +from basicswap.util_xmr import encode_address as xmr_encode_address from basicswap.interface.btc import BTCInterface from basicswap.interface.xmr import XMRInterface @@ -347,6 +349,35 @@ class Test(unittest.TestCase): assert (is_private_ip_address('20.87.245.0') is False) assert (is_private_ip_address('particl.io') is False) + def test_varint(self): + def test_case(i, expect_length): + b = encode_varint(i) + assert (len(b) == expect_length) + assert (decode_varint(b) == i) + + test_case(0, 1) + test_case(1, 1) + test_case(127, 1) + test_case(128, 2) + test_case(253, 2) + test_case(8321, 2) + test_case(16383, 2) + test_case(16384, 3) + test_case(2097151, 3) + test_case(2097152, 4) + + def test_base58(self): + kv = edu.get_secret() + Kv = edu.encodepoint(edf.scalarmult_B(kv)) + ks = edu.get_secret() + Ks = edu.encodepoint(edf.scalarmult_B(ks)) + + addr = xmr_encode_address(Kv, Ks) + assert (addr.startswith('4')) + + addr = xmr_encode_address(Kv, Ks, 4146) + assert (addr.startswith('Wo')) + if __name__ == '__main__': unittest.main()