From c3cff91fcadb240a82d2e5ae9789a89df299bdc7 Mon Sep 17 00:00:00 2001 From: tecnovert Date: Tue, 19 Jan 2021 15:10:42 +0200 Subject: [PATCH] Raise version. Verify message with coincurve. --- basicswap/__init__.py | 2 +- basicswap/basicswap.py | 2 +- basicswap/interface_btc.py | 24 +++++++++++++++++++++++- basicswap/util.py | 35 ++++++++++++++++++++++++----------- 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/basicswap/__init__.py b/basicswap/__init__.py index 338d8c4..cd29f0e 100644 --- a/basicswap/__init__.py +++ b/basicswap/__init__.py @@ -1,3 +1,3 @@ name = "basicswap" -__version__ = "0.0.11" +__version__ = "0.0.12" diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index d10409e..a4c8472 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -3523,7 +3523,7 @@ class BasicSwap(BaseApp): # Verify proof of funds bid_proof_address = replaceAddrPrefix(bid_data.proof_address, Coins.PART, self.chain) mm = chainparams[coin_to]['message_magic'] - passed = self.callcoinrpc(Coins.PART, 'verifymessage', [bid_proof_address, bid_data.proof_signature, bid_data.proof_address + '_swap_proof', mm]) + passed = self.ci(Coins.PART).verifyMessage(bid_proof_address, bid_data.proof_address + '_swap_proof', bid_data.proof_signature, mm) assert(passed is True), 'Proof of funds signature invalid' if self.coin_clients[coin_to]['use_segwit']: diff --git a/basicswap/interface_btc.py b/basicswap/interface_btc.py index 73db051..d601538 100644 --- a/basicswap/interface_btc.py +++ b/basicswap/interface_btc.py @@ -6,6 +6,7 @@ # file LICENSE or http://www.opensource.org/licenses/mit-license.php. import time +import base64 import hashlib import logging from io import BytesIO @@ -14,10 +15,12 @@ from basicswap.contrib.test_framework import segwit_addr from .util import ( decodeScriptNum, getCompactSizeLen, + SerialiseNumCompact, dumpj, format_amount, make_int, toWIF, + assert_cond, decodeAddress) from coincurve.keys import ( PrivateKey, @@ -61,7 +64,6 @@ from .contrib.test_framework.script import ( from .chainparams import CoinInterface, Coins, chainparams from .rpc import make_rpc_func -from .util import assert_cond def findOutput(tx, script_pk): @@ -859,6 +861,26 @@ class BTCInterface(CoinInterface): rv = pubkey.verify_compact(sig, message_hash, hasher=None) assert(rv is True) + def verifyMessage(self, address, message, signature, message_magic=None): + if message_magic is None: + message_magic = chainparams[self.coin_type()]['message_magic'] + + message_bytes = SerialiseNumCompact(len(message_magic)) + bytes(message_magic, 'utf-8') + SerialiseNumCompact(len(message)) + bytes(message, 'utf-8') + message_hash = hashlib.sha256(hashlib.sha256(message_bytes).digest()).digest() + signature_bytes = base64.b64decode(signature) + rec_id = (signature_bytes[0] - 27) & 3 + signature_bytes = signature_bytes[1:] + bytes((rec_id,)) + try: + pubkey = PublicKey.from_signature_and_message(signature_bytes, message_hash, hasher=None) + except Exception as e: + logging.info('verifyMessage failed: ' + str(e)) + return False + + address_hash = self.decodeAddress(address) + pubkey_hash = hash160(pubkey.format()) + + return True if address_hash == pubkey_hash else False + def testBTCInterface(): print('testBTCInterface') diff --git a/basicswap/util.py b/basicswap/util.py index 4572775..1cc653c 100644 --- a/basicswap/util.py +++ b/basicswap/util.py @@ -7,6 +7,7 @@ import json import time +import struct import decimal import hashlib @@ -113,9 +114,9 @@ def decodeWif(network_key): def toWIF(prefix_byte, b, compressed=True): - b = bytes((prefix_byte, )) + b + b = bytes((prefix_byte,)) + b if compressed: - b += bytes((0x01, )) + b += bytes((0x01,)) b += hashlib.sha256(hashlib.sha256(b).digest()).digest()[:4] return b58encode(b) @@ -163,9 +164,9 @@ def pubkeyToAddress(prefix, pubkey): def SerialiseNum(n): if n == 0: - return bytes([0x00]) + return bytes((0x00,)) if n > 0 and n <= 16: - return bytes([0x50 + n]) + return bytes((0x50 + n,)) rv = bytearray() neg = n < 0 absvalue = -n if neg else n @@ -176,7 +177,7 @@ def SerialiseNum(n): rv.append(0x80 if neg else 0) elif neg: rv[-1] |= 0x80 - return bytes([len(rv)]) + rv + return bytes((len(rv),)) + rv def DeserialiseNum(b, o=0): @@ -222,15 +223,27 @@ def getCompactSizeLen(v): # Compact Size if v < 253: return 1 - if v < 0xffff: # USHRT_MAX + if v <= 0xffff: # USHRT_MAX return 3 - if v < 0xffffffff: # UINT_MAX + if v <= 0xffffffff: # UINT_MAX return 5 - if v < 0xffffffffffffffff: # UINT_MAX + if v <= 0xffffffffffffffff: # UINT_MAX return 9 raise ValueError('Value too large') +def SerialiseNumCompact(v): + if v < 253: + return bytes((v,)) + if v <= 0xffff: # USHRT_MAX + return struct.pack("