diff --git a/basicswap/basicswap.py b/basicswap/basicswap.py index 4721d31..813fd10 100644 --- a/basicswap/basicswap.py +++ b/basicswap/basicswap.py @@ -148,6 +148,12 @@ from .basicswap_util import ( ) +PROTOCOL_VERSION_SECRET_HASH = 1 +MINPROTO_VERSION_SECRET_HASH = 1 + +PROTOCOL_VERSION_ADAPTOR_SIG = 2 +MINPROTO_VERSION_ADAPTOR_SIG = 2 + non_script_type_coins = (Coins.XMR, Coins.PART_ANON) @@ -1413,7 +1419,7 @@ class BasicSwap(BaseApp): msg_buf = OfferMessage() - msg_buf.protocol_version = 1 + msg_buf.protocol_version = PROTOCOL_VERSION_ADAPTOR_SIG if swap_type == SwapTypes.XMR_SWAP else PROTOCOL_VERSION_SECRET_HASH msg_buf.coin_from = int(coin_from) msg_buf.coin_to = int(coin_to) msg_buf.amount_from = int(amount) @@ -2078,7 +2084,7 @@ class BasicSwap(BaseApp): self.mxDB.acquire() try: msg_buf = BidMessage() - msg_buf.protocol_version = 1 + msg_buf.protocol_version = PROTOCOL_VERSION_SECRET_HASH msg_buf.offer_msg_id = offer_id msg_buf.time_valid = valid_for_seconds msg_buf.amount = int(amount) # amount of coin_from @@ -2417,7 +2423,7 @@ class BasicSwap(BaseApp): ensure(balance_to > amount_to, '{} spendable balance is too low: {}'.format(ci_to.coin_name(), ci_to.format_amount(balance_to))) msg_buf = XmrBidMessage() - msg_buf.protocol_version = 1 + msg_buf.protocol_version = PROTOCOL_VERSION_ADAPTOR_SIG msg_buf.offer_msg_id = offer_id msg_buf.time_valid = valid_for_seconds msg_buf.amount = int(amount) # Amount of coin_from @@ -4115,6 +4121,7 @@ class BasicSwap(BaseApp): ensure(msg['sent'] + offer_data.time_valid >= now, 'Offer expired') if offer_data.swap_type == SwapTypes.SELLER_FIRST: + ensure(offer_data.protocol_version >= MINPROTO_VERSION_SECRET_HASH, 'Invalid protocol version') ensure(len(offer_data.proof_address) == 0, 'Unexpected data') ensure(len(offer_data.proof_signature) == 0, 'Unexpected data') ensure(len(offer_data.pkhash_seller) == 0, 'Unexpected data') @@ -4122,6 +4129,7 @@ class BasicSwap(BaseApp): elif offer_data.swap_type == SwapTypes.BUYER_FIRST: raise ValueError('TODO') elif offer_data.swap_type == SwapTypes.XMR_SWAP: + ensure(offer_data.protocol_version >= MINPROTO_VERSION_ADAPTOR_SIG, 'Invalid protocol version') ensure(coin_from not in non_script_type_coins, 'Invalid coin from type') ensure(ci_from.has_segwit(), 'Coin from must support segwit') ensure(len(offer_data.proof_address) == 0, 'Unexpected data') @@ -4344,6 +4352,7 @@ class BasicSwap(BaseApp): bid_data.ParseFromString(bid_bytes) # Validate data + ensure(bid_data.protocol_version >= MINPROTO_VERSION_SECRET_HASH, 'Invalid protocol version') ensure(len(bid_data.offer_msg_id) == 28, 'Bad offer_id length') offer_id = bid_data.offer_msg_id @@ -4620,11 +4629,13 @@ class BasicSwap(BaseApp): bid_data.ParseFromString(bid_bytes) # Validate data + ensure(bid_data.protocol_version >= MINPROTO_VERSION_ADAPTOR_SIG, 'Invalid protocol version') ensure(len(bid_data.offer_msg_id) == 28, 'Bad offer_id length') offer_id = bid_data.offer_msg_id offer, xmr_offer = self.getXmrOffer(offer_id, sent=True) ensure(offer and offer.was_sent, 'Offer not found: {}.'.format(offer_id.hex())) + ensure(offer.swap_type == SwapTypes.XMR_SWAP, 'Bid/offer swap type mismatch') ensure(xmr_offer, 'XMR offer not found: {}.'.format(offer_id.hex())) ci_from = self.ci(offer.coin_from) diff --git a/tests/basicswap/test_other.py b/tests/basicswap/test_other.py index 6f7d716..88f18d8 100644 --- a/tests/basicswap/test_other.py +++ b/tests/basicswap/test_other.py @@ -1,7 +1,7 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -# Copyright (c) 2019-2022 tecnovert +# Copyright (c) 2019-2023 tecnovert # Distributed under the MIT software license, see the accompanying # file LICENSE or http://www.opensource.org/licenses/mit-license.php. @@ -214,6 +214,26 @@ class Test(unittest.TestCase): assert (len(sig) == 64) ci.verifyCompactSig(pk, 'test signing message', sig) + # Nonce is set deterministically (using default libsecp256k1 method rfc6979) + sig2 = ci.signCompact(vk, 'test signing message') + assert (sig == sig2) + + def test_sign_recoverable(self): + coin_settings = {'rpcport': 0, 'rpcauth': 'none'} + coin_settings.update(self.REQUIRED_SETTINGS) + ci = BTCInterface(coin_settings, 'regtest') + + vk = i2b(ci.getNewSecretKey()) + pk = ci.getPubkey(vk) + sig = ci.signRecoverable(vk, 'test signing message') + assert (len(sig) == 65) + pk_rec = ci.verifySigAndRecover(sig, 'test signing message') + assert (pk == pk_rec) + + # Nonce is set deterministically (using default libsecp256k1 method rfc6979) + sig2 = ci.signRecoverable(vk, 'test signing message') + assert (sig == sig2) + def test_pubkey_to_address(self): coin_settings = {'rpcport': 0, 'rpcauth': 'none'} coin_settings.update(self.REQUIRED_SETTINGS)