mirror of
https://github.com/basicswap/basicswap.git
synced 2025-01-19 00:54:35 +00:00
protocol: Sign for key halves when not swapping XMR
This commit is contained in:
parent
2b2b98505b
commit
9645e87961
4 changed files with 82 additions and 28 deletions
|
@ -30,6 +30,7 @@ from typing import Optional
|
|||
from sqlalchemy.orm import sessionmaker, scoped_session
|
||||
from sqlalchemy.orm.session import close_all_sessions
|
||||
|
||||
from .interface import Curves
|
||||
from .interface.part import PARTInterface, PARTInterfaceAnon, PARTInterfaceBlind
|
||||
from .interface.btc import BTCInterface
|
||||
from .interface.ltc import LTCInterface
|
||||
|
@ -2438,7 +2439,7 @@ class BasicSwap(BaseApp):
|
|||
xmr_swap.contract_count = self.getNewContractId()
|
||||
xmr_swap.dest_af = msg_buf.dest_af
|
||||
|
||||
for_ed25519 = True if coin_to == Coins.XMR else False
|
||||
for_ed25519 = True if ci_to.curve_type() == Curves.ed25519 else False
|
||||
kbvf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, KeyTypes.KBVF, for_ed25519)
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid_created_at, xmr_swap.contract_count, KeyTypes.KBSF, for_ed25519)
|
||||
|
||||
|
@ -2450,19 +2451,26 @@ class BasicSwap(BaseApp):
|
|||
|
||||
xmr_swap.pkaf = ci_from.getPubkey(kaf)
|
||||
|
||||
if coin_to == Coins.XMR:
|
||||
if ci_to.curve_type() == Curves.ed25519:
|
||||
xmr_swap.kbsf_dleag = ci_to.proveDLEAG(kbsf)
|
||||
xmr_swap.pkasf = xmr_swap.kbsf_dleag[0: 33]
|
||||
msg_buf.kbsf_dleag = xmr_swap.kbsf_dleag[:16000]
|
||||
elif ci_to.curve_type() == Curves.secp256k1:
|
||||
for i in range(10):
|
||||
xmr_swap.kbsf_dleag = ci_to.signRecoverable(kbsf, 'proof kbsf owned for swap')
|
||||
pk_recovered = ci_to.verifySigAndRecover(xmr_swap.kbsf_dleag, 'proof kbsf owned for swap')
|
||||
if pk_recovered == xmr_swap.pkbsf:
|
||||
break
|
||||
self.log.debug('kbsl recovered pubkey mismatch, retrying.')
|
||||
assert (pk_recovered == xmr_swap.pkbsf)
|
||||
xmr_swap.pkasf = xmr_swap.pkbsf
|
||||
msg_buf.kbsf_dleag = xmr_swap.kbsf_dleag
|
||||
else:
|
||||
xmr_swap.kbsf_dleag = xmr_swap.pkbsf
|
||||
xmr_swap.pkasf = xmr_swap.kbsf_dleag[0: 33]
|
||||
raise ValueError('Unknown curve')
|
||||
assert (xmr_swap.pkasf == ci_from.getPubkey(kbsf))
|
||||
|
||||
msg_buf.pkaf = xmr_swap.pkaf
|
||||
msg_buf.kbvf = kbvf
|
||||
if coin_to == Coins.XMR:
|
||||
msg_buf.kbsf_dleag = xmr_swap.kbsf_dleag[:16000]
|
||||
else:
|
||||
msg_buf.kbsf_dleag = xmr_swap.kbsf_dleag
|
||||
|
||||
bid_bytes = msg_buf.SerializeToString()
|
||||
payload_hex = str.format('{:02x}', MessageTypes.XMR_BID_FL) + bid_bytes.hex()
|
||||
|
@ -2472,7 +2480,7 @@ class BasicSwap(BaseApp):
|
|||
msg_valid = max(self.SMSG_SECONDS_IN_HOUR * 1, valid_for_seconds)
|
||||
xmr_swap.bid_id = self.sendSmsg(bid_addr, offer.addr_from, payload_hex, msg_valid)
|
||||
|
||||
if coin_to == Coins.XMR:
|
||||
if ci_to.curve_type() == Curves.ed25519:
|
||||
msg_buf2 = XmrSplitMessage(
|
||||
msg_id=xmr_swap.bid_id,
|
||||
msg_type=XmrSplitMsgTypes.BID,
|
||||
|
@ -2562,7 +2570,7 @@ class BasicSwap(BaseApp):
|
|||
if xmr_swap.contract_count is None:
|
||||
xmr_swap.contract_count = self.getNewContractId()
|
||||
|
||||
for_ed25519 = True if coin_to == Coins.XMR else False
|
||||
for_ed25519 = True if ci_to.curve_type() == Curves.ed25519 else False
|
||||
kbvl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, KeyTypes.KBVL, for_ed25519)
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, KeyTypes.KBSL, for_ed25519)
|
||||
|
||||
|
@ -2579,11 +2587,6 @@ class BasicSwap(BaseApp):
|
|||
|
||||
xmr_swap.pkal = ci_from.getPubkey(kal)
|
||||
|
||||
if coin_to == Coins.XMR:
|
||||
xmr_swap.kbsl_dleag = ci_to.proveDLEAG(kbsl)
|
||||
else:
|
||||
xmr_swap.kbsl_dleag = xmr_swap.pkbsl
|
||||
|
||||
# MSG2F
|
||||
pi = self.pi(SwapTypes.XMR_SWAP)
|
||||
xmr_swap.a_lock_tx_script = pi.genScriptLockTxScript(ci_from, xmr_swap.pkal, xmr_swap.pkaf)
|
||||
|
@ -2660,10 +2663,21 @@ class BasicSwap(BaseApp):
|
|||
msg_buf.bid_msg_id = bid_id
|
||||
msg_buf.pkal = xmr_swap.pkal
|
||||
msg_buf.kbvl = kbvl
|
||||
if coin_to == Coins.XMR:
|
||||
|
||||
if ci_to.curve_type() == Curves.ed25519:
|
||||
xmr_swap.kbsl_dleag = ci_to.proveDLEAG(kbsl)
|
||||
msg_buf.kbsl_dleag = xmr_swap.kbsl_dleag[:16000]
|
||||
else:
|
||||
elif ci_to.curve_type() == Curves.secp256k1:
|
||||
for i in range(10):
|
||||
xmr_swap.kbsl_dleag = ci_to.signRecoverable(kbsl, 'proof kbsl owned for swap')
|
||||
pk_recovered = ci_to.verifySigAndRecover(xmr_swap.kbsl_dleag, 'proof kbsl owned for swap')
|
||||
if pk_recovered == xmr_swap.pkbsl:
|
||||
break
|
||||
self.log.debug('kbsl recovered pubkey mismatch, retrying.')
|
||||
assert (pk_recovered == xmr_swap.pkbsl)
|
||||
msg_buf.kbsl_dleag = xmr_swap.kbsl_dleag
|
||||
else:
|
||||
raise ValueError('Unknown curve')
|
||||
|
||||
# MSG2F
|
||||
msg_buf.a_lock_tx = xmr_swap.a_lock_tx
|
||||
|
@ -2680,7 +2694,7 @@ class BasicSwap(BaseApp):
|
|||
bid.accept_msg_id = self.sendSmsg(offer.addr_from, bid.bid_addr, payload_hex, msg_valid)
|
||||
xmr_swap.bid_accept_msg_id = bid.accept_msg_id
|
||||
|
||||
if coin_to == Coins.XMR:
|
||||
if ci_to.curve_type() == Curves.ed25519:
|
||||
msg_buf2 = XmrSplitMessage(
|
||||
msg_id=bid_id,
|
||||
msg_type=XmrSplitMsgTypes.BID_ACCEPT,
|
||||
|
@ -4496,7 +4510,7 @@ class BasicSwap(BaseApp):
|
|||
ci_from = self.ci(Coins(offer.coin_from))
|
||||
ci_to = self.ci(Coins(offer.coin_to))
|
||||
|
||||
if offer.coin_to == Coins.XMR:
|
||||
if ci_to.curve_type() == Curves.ed25519:
|
||||
if len(xmr_swap.kbsf_dleag) < ci_to.lengthDLEAG():
|
||||
q = session.query(XmrSplitData).filter(sa.and_(XmrSplitData.bid_id == bid.bid_id, XmrSplitData.msg_type == XmrSplitMsgTypes.BID)).order_by(XmrSplitData.msg_sequence.asc())
|
||||
for row in q:
|
||||
|
@ -4514,11 +4528,13 @@ class BasicSwap(BaseApp):
|
|||
xmr_swap.pkbsf = xmr_swap.kbsf_dleag[33: 33 + 32]
|
||||
if not ci_to.verifyPubkey(xmr_swap.pkbsf):
|
||||
raise ValueError('Invalid coin b pubkey.')
|
||||
else:
|
||||
xmr_swap.pkasf = xmr_swap.kbsf_dleag[0: 33]
|
||||
elif ci_to.curve_type() == Curves.secp256k1:
|
||||
xmr_swap.pkasf = ci_to.verifySigAndRecover(xmr_swap.kbsf_dleag, 'proof kbsf owned for swap')
|
||||
if not ci_from.verifyPubkey(xmr_swap.pkasf):
|
||||
raise ValueError('Invalid coin a pubkey.')
|
||||
xmr_swap.pkbsf = xmr_swap.pkasf
|
||||
else:
|
||||
raise ValueError('Unknown curve')
|
||||
|
||||
ensure(ci_to.verifyKey(xmr_swap.vkbvf), 'Invalid key, vkbvf')
|
||||
ensure(ci_from.verifyPubkey(xmr_swap.pkaf), 'Invalid pubkey, pkaf')
|
||||
|
@ -4548,7 +4564,7 @@ class BasicSwap(BaseApp):
|
|||
ci_from = self.ci(offer.coin_from)
|
||||
ci_to = self.ci(offer.coin_to)
|
||||
|
||||
if offer.coin_to == Coins.XMR:
|
||||
if ci_to.curve_type() == Curves.ed25519:
|
||||
if len(xmr_swap.kbsl_dleag) < ci_to.lengthDLEAG():
|
||||
q = session.query(XmrSplitData).filter(sa.and_(XmrSplitData.bid_id == bid.bid_id, XmrSplitData.msg_type == XmrSplitMsgTypes.BID_ACCEPT)).order_by(XmrSplitData.msg_sequence.asc())
|
||||
for row in q:
|
||||
|
@ -4565,11 +4581,13 @@ class BasicSwap(BaseApp):
|
|||
xmr_swap.pkbsl = xmr_swap.kbsl_dleag[33: 33 + 32]
|
||||
if not ci_to.verifyPubkey(xmr_swap.pkbsl):
|
||||
raise ValueError('Invalid coin b pubkey.')
|
||||
else:
|
||||
xmr_swap.pkasl = xmr_swap.kbsl_dleag[0: 33]
|
||||
elif ci_to.curve_type() == Curves.secp256k1:
|
||||
xmr_swap.pkasl = ci_to.verifySigAndRecover(xmr_swap.kbsl_dleag, 'proof kbsl owned for swap')
|
||||
if not ci_from.verifyPubkey(xmr_swap.pkasl):
|
||||
raise ValueError('Invalid coin a pubkey.')
|
||||
xmr_swap.pkbsl = xmr_swap.pkasl
|
||||
else:
|
||||
raise ValueError('Unknown curve')
|
||||
|
||||
# vkbv and vkbvl are verified in processXmrBidAccept
|
||||
xmr_swap.pkbv = ci_to.sumPubkeys(xmr_swap.pkbvl, xmr_swap.pkbvf)
|
||||
|
@ -5023,7 +5041,7 @@ class BasicSwap(BaseApp):
|
|||
ci_from = self.ci(coin_from)
|
||||
ci_to = self.ci(coin_to)
|
||||
|
||||
for_ed25519 = True if coin_to == Coins.XMR else False
|
||||
for_ed25519 = True if ci_to.curve_type() == Curves.ed25519 else False
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, KeyTypes.KBSF, for_ed25519)
|
||||
kaf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, KeyTypes.KAF)
|
||||
|
||||
|
@ -5085,7 +5103,7 @@ class BasicSwap(BaseApp):
|
|||
kbsf = ci_from.recoverEncKey(xmr_swap.al_lock_spend_tx_esig, xmr_swap.al_lock_spend_tx_sig, xmr_swap.pkasf)
|
||||
assert (kbsf is not None)
|
||||
|
||||
for_ed25519 = True if coin_to == Coins.XMR else False
|
||||
for_ed25519 = True if ci_to.curve_type() == Curves.ed25519 else False
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, KeyTypes.KBSL, for_ed25519)
|
||||
vkbs = ci_to.sumKeys(kbsl, kbsf)
|
||||
|
||||
|
@ -5144,7 +5162,7 @@ class BasicSwap(BaseApp):
|
|||
kbsl = ci_from.recoverEncKey(xmr_swap.af_lock_refund_spend_tx_esig, af_lock_refund_spend_tx_sig, xmr_swap.pkasl)
|
||||
assert (kbsl is not None)
|
||||
|
||||
for_ed25519 = True if coin_to == Coins.XMR else False
|
||||
for_ed25519 = True if ci_to.curve_type() == Curves.ed25519 else False
|
||||
kbsf = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, KeyTypes.KBSF, for_ed25519)
|
||||
vkbs = ci_to.sumKeys(kbsl, kbsf)
|
||||
|
||||
|
@ -5245,7 +5263,7 @@ class BasicSwap(BaseApp):
|
|||
xmr_swap.af_lock_refund_spend_tx_esig = msg_data.af_lock_refund_spend_tx_esig
|
||||
xmr_swap.af_lock_refund_tx_sig = msg_data.af_lock_refund_tx_sig
|
||||
|
||||
for_ed25519 = True if coin_to == Coins.XMR else False
|
||||
for_ed25519 = True if ci_to.curve_type() == Curves.ed25519 else False
|
||||
kbsl = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, KeyTypes.KBSL, for_ed25519)
|
||||
kal = self.getPathKey(coin_from, coin_to, bid.created_at, xmr_swap.contract_count, KeyTypes.KAL)
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (c) 2023 tecnovert
|
||||
# Distributed under the MIT software license, see the accompanying
|
||||
# file LICENSE or http://www.opensource.org/licenses/mit-license.php.
|
||||
|
||||
from enum import IntEnum
|
||||
|
||||
|
||||
class Curves(IntEnum):
|
||||
secp256k1 = 1
|
||||
ed25519 = 2
|
|
@ -14,6 +14,8 @@ from io import BytesIO
|
|||
|
||||
from basicswap.contrib.test_framework import segwit_addr
|
||||
|
||||
from basicswap.interface import (
|
||||
Curves)
|
||||
from basicswap.util import (
|
||||
ensure,
|
||||
make_int,
|
||||
|
@ -109,6 +111,10 @@ def find_vout_for_address_from_txobj(tx_obj, addr: str) -> int:
|
|||
|
||||
|
||||
class BTCInterface(CoinInterface):
|
||||
@staticmethod
|
||||
def curve_type():
|
||||
return Curves.secp256k1
|
||||
|
||||
@staticmethod
|
||||
def coin_type():
|
||||
return Coins.BTC
|
||||
|
@ -1167,12 +1173,23 @@ class BTCInterface(CoinInterface):
|
|||
privkey = PrivateKey(k)
|
||||
return privkey.sign_recoverable(message_hash, hasher=None)[:64]
|
||||
|
||||
def signRecoverable(self, k, message):
|
||||
message_hash = hashlib.sha256(bytes(message, 'utf-8')).digest()
|
||||
|
||||
privkey = PrivateKey(k)
|
||||
return privkey.sign_recoverable(message_hash, hasher=None)
|
||||
|
||||
def verifyCompactSig(self, K, message, sig):
|
||||
message_hash = hashlib.sha256(bytes(message, 'utf-8')).digest()
|
||||
pubkey = PublicKey(K)
|
||||
rv = pubkey.verify_compact(sig, message_hash, hasher=None)
|
||||
assert (rv is True)
|
||||
|
||||
def verifySigAndRecover(self, sig, message):
|
||||
message_hash = hashlib.sha256(bytes(message, 'utf-8')).digest()
|
||||
pubkey = PublicKey.from_signature_and_message(sig, message_hash, hasher=None)
|
||||
return pubkey.format()
|
||||
|
||||
def verifyMessage(self, address: str, message: str, signature: str, message_magic: str = None) -> bool:
|
||||
if message_magic is None:
|
||||
message_magic = self.chainparams()['message_magic']
|
||||
|
|
|
@ -24,6 +24,8 @@ from coincurve.dleag import (
|
|||
verify_ed25519_point,
|
||||
)
|
||||
|
||||
from basicswap.interface import (
|
||||
Curves)
|
||||
from basicswap.util import (
|
||||
dumpj,
|
||||
ensure,
|
||||
|
@ -38,6 +40,10 @@ from basicswap.chainparams import XMR_COIN, CoinInterface, Coins
|
|||
|
||||
|
||||
class XMRInterface(CoinInterface):
|
||||
@staticmethod
|
||||
def curve_type():
|
||||
return Curves.ed25519
|
||||
|
||||
@staticmethod
|
||||
def coin_type():
|
||||
return Coins.XMR
|
||||
|
|
Loading…
Reference in a new issue