2020-10-07 20:07:37 -04:00
|
|
|
use anyhow::{anyhow, Result};
|
|
|
|
use ecdsa_fun::{
|
|
|
|
adaptor::{Adaptor, EncryptedSignature},
|
|
|
|
nonce::Deterministic,
|
|
|
|
};
|
2021-01-07 18:52:07 -05:00
|
|
|
use libp2p::request_response::ResponseChannel;
|
2020-10-07 20:07:37 -04:00
|
|
|
use rand::{CryptoRng, RngCore};
|
2020-10-13 18:32:25 -04:00
|
|
|
use serde::{Deserialize, Serialize};
|
2020-09-28 02:18:50 -04:00
|
|
|
use sha2::Sha256;
|
2021-01-07 18:52:07 -05:00
|
|
|
use std::fmt;
|
2021-01-04 22:08:36 -05:00
|
|
|
use tracing::info;
|
2020-10-23 08:05:34 -04:00
|
|
|
|
2021-01-04 22:08:36 -05:00
|
|
|
use crate::{
|
|
|
|
bitcoin,
|
|
|
|
bitcoin::{
|
|
|
|
current_epoch, timelocks::Timelock, wait_for_cancel_timelock_to_expire, GetBlockHeight,
|
2021-01-07 18:52:07 -05:00
|
|
|
TransactionBlockHeight, TxCancel, TxRefund, WatchForRawTransaction,
|
2021-01-04 22:08:36 -05:00
|
|
|
},
|
|
|
|
monero,
|
|
|
|
monero::CreateWalletForOutput,
|
2021-01-07 18:52:07 -05:00
|
|
|
network::request_response::AliceToBob,
|
2021-01-04 22:08:36 -05:00
|
|
|
protocol::{alice, bob},
|
2021-01-07 18:52:07 -05:00
|
|
|
ExpiredTimelocks, SwapAmounts,
|
2021-01-04 22:08:36 -05:00
|
|
|
};
|
2020-09-28 02:18:50 -04:00
|
|
|
|
2021-01-07 18:52:07 -05:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum AliceState {
|
|
|
|
Started {
|
|
|
|
amounts: SwapAmounts,
|
|
|
|
state0: State0,
|
|
|
|
},
|
|
|
|
Negotiated {
|
|
|
|
channel: Option<ResponseChannel<AliceToBob>>,
|
|
|
|
amounts: SwapAmounts,
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
BtcLocked {
|
|
|
|
channel: Option<ResponseChannel<AliceToBob>>,
|
|
|
|
amounts: SwapAmounts,
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
XmrLocked {
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
EncSigLearned {
|
|
|
|
encrypted_signature: EncryptedSignature,
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
BtcRedeemed,
|
|
|
|
BtcCancelled {
|
|
|
|
tx_cancel: TxCancel,
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
BtcRefunded {
|
|
|
|
spend_key: monero::PrivateKey,
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
BtcPunishable {
|
|
|
|
tx_refund: TxRefund,
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
XmrRefunded,
|
|
|
|
CancelTimelockExpired {
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
BtcPunished,
|
|
|
|
SafelyAborted,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fmt::Display for AliceState {
|
|
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
|
|
match self {
|
|
|
|
AliceState::Started { .. } => write!(f, "started"),
|
|
|
|
AliceState::Negotiated { .. } => write!(f, "negotiated"),
|
|
|
|
AliceState::BtcLocked { .. } => write!(f, "btc is locked"),
|
|
|
|
AliceState::XmrLocked { .. } => write!(f, "xmr is locked"),
|
|
|
|
AliceState::EncSigLearned { .. } => write!(f, "encrypted signature is learned"),
|
|
|
|
AliceState::BtcRedeemed => write!(f, "btc is redeemed"),
|
|
|
|
AliceState::BtcCancelled { .. } => write!(f, "btc is cancelled"),
|
|
|
|
AliceState::BtcRefunded { .. } => write!(f, "btc is refunded"),
|
|
|
|
AliceState::BtcPunished => write!(f, "btc is punished"),
|
|
|
|
AliceState::SafelyAborted => write!(f, "safely aborted"),
|
|
|
|
AliceState::BtcPunishable { .. } => write!(f, "btc is punishable"),
|
|
|
|
AliceState::XmrRefunded => write!(f, "xmr is refunded"),
|
|
|
|
AliceState::CancelTimelockExpired { .. } => write!(f, "cancel timelock is expired"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-12-22 00:28:14 -05:00
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
2020-09-28 02:18:50 -04:00
|
|
|
pub struct State0 {
|
2020-12-14 17:11:53 -05:00
|
|
|
pub a: bitcoin::SecretKey,
|
|
|
|
pub s_a: cross_curve_dleq::Scalar,
|
|
|
|
pub v_a: monero::PrivateViewKey,
|
2020-10-22 00:06:05 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
2020-12-14 01:24:23 -05:00
|
|
|
pub btc: bitcoin::Amount,
|
|
|
|
pub xmr: monero::Amount,
|
2020-12-23 00:04:06 -05:00
|
|
|
pub cancel_timelock: Timelock,
|
|
|
|
pub punish_timelock: Timelock,
|
2020-12-14 01:24:23 -05:00
|
|
|
pub redeem_address: bitcoin::Address,
|
|
|
|
pub punish_address: bitcoin::Address,
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State0 {
|
2020-11-30 23:38:24 -05:00
|
|
|
#[allow(clippy::too_many_arguments)]
|
2020-11-24 22:37:37 -05:00
|
|
|
pub fn new(
|
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
s_a: cross_curve_dleq::Scalar,
|
|
|
|
v_a: monero::PrivateViewKey,
|
2020-09-28 02:18:50 -04:00
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
2020-12-23 00:04:06 -05:00
|
|
|
cancel_timelock: Timelock,
|
|
|
|
punish_timelock: Timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
redeem_address: bitcoin::Address,
|
|
|
|
punish_address: bitcoin::Address,
|
|
|
|
) -> Self {
|
|
|
|
Self {
|
|
|
|
a,
|
|
|
|
s_a,
|
|
|
|
v_a,
|
|
|
|
redeem_address,
|
|
|
|
punish_address,
|
|
|
|
btc,
|
|
|
|
xmr,
|
2020-12-21 23:47:09 -05:00
|
|
|
cancel_timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
punish_timelock,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-01-04 22:08:36 -05:00
|
|
|
pub fn next_message<R: RngCore + CryptoRng>(&self, rng: &mut R) -> alice::Message0 {
|
2020-10-27 20:46:45 -04:00
|
|
|
info!("Producing first message");
|
2020-09-28 02:18:50 -04:00
|
|
|
let dleq_proof_s_a = cross_curve_dleq::Proof::new(rng, &self.s_a);
|
|
|
|
|
2021-01-04 22:08:36 -05:00
|
|
|
alice::Message0 {
|
2020-09-28 02:18:50 -04:00
|
|
|
A: self.a.public(),
|
|
|
|
S_a_monero: monero::PublicKey::from_private_key(&monero::PrivateKey {
|
|
|
|
scalar: self.s_a.into_ed25519(),
|
|
|
|
}),
|
|
|
|
S_a_bitcoin: self.s_a.into_secp256k1().into(),
|
|
|
|
dleq_proof_s_a,
|
|
|
|
v_a: self.v_a,
|
|
|
|
redeem_address: self.redeem_address.clone(),
|
|
|
|
punish_address: self.punish_address.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn receive(self, msg: bob::Message0) -> Result<State1> {
|
|
|
|
msg.dleq_proof_s_b.verify(
|
2020-10-21 00:28:50 -04:00
|
|
|
msg.S_b_bitcoin.clone().into(),
|
2020-09-28 02:18:50 -04:00
|
|
|
msg.S_b_monero
|
|
|
|
.point
|
|
|
|
.decompress()
|
|
|
|
.ok_or_else(|| anyhow!("S_b is not a monero curve point"))?,
|
|
|
|
)?;
|
|
|
|
|
|
|
|
let v = self.v_a + msg.v_b;
|
|
|
|
|
|
|
|
Ok(State1 {
|
|
|
|
a: self.a,
|
|
|
|
B: msg.B,
|
|
|
|
s_a: self.s_a,
|
|
|
|
S_b_monero: msg.S_b_monero,
|
|
|
|
S_b_bitcoin: msg.S_b_bitcoin,
|
|
|
|
v,
|
|
|
|
btc: self.btc,
|
|
|
|
xmr: self.xmr,
|
2020-12-21 23:47:09 -05:00
|
|
|
cancel_timelock: self.cancel_timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
punish_timelock: self.punish_timelock,
|
|
|
|
refund_address: msg.refund_address,
|
|
|
|
redeem_address: self.redeem_address,
|
|
|
|
punish_address: self.punish_address,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 18:18:57 -04:00
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
2020-09-28 02:18:50 -04:00
|
|
|
pub struct State1 {
|
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
B: bitcoin::PublicKey,
|
|
|
|
s_a: cross_curve_dleq::Scalar,
|
|
|
|
S_b_monero: monero::PublicKey,
|
|
|
|
S_b_bitcoin: bitcoin::PublicKey,
|
|
|
|
v: monero::PrivateViewKey,
|
2020-10-22 00:06:05 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
2020-09-28 02:18:50 -04:00
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
2020-12-23 00:04:06 -05:00
|
|
|
cancel_timelock: Timelock,
|
|
|
|
punish_timelock: Timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
refund_address: bitcoin::Address,
|
|
|
|
redeem_address: bitcoin::Address,
|
|
|
|
punish_address: bitcoin::Address,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl State1 {
|
|
|
|
pub fn receive(self, msg: bob::Message1) -> State2 {
|
|
|
|
State2 {
|
|
|
|
a: self.a,
|
|
|
|
B: self.B,
|
|
|
|
s_a: self.s_a,
|
|
|
|
S_b_monero: self.S_b_monero,
|
|
|
|
S_b_bitcoin: self.S_b_bitcoin,
|
|
|
|
v: self.v,
|
|
|
|
btc: self.btc,
|
|
|
|
xmr: self.xmr,
|
2020-12-21 23:47:09 -05:00
|
|
|
cancel_timelock: self.cancel_timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
punish_timelock: self.punish_timelock,
|
|
|
|
refund_address: self.refund_address,
|
|
|
|
redeem_address: self.redeem_address,
|
|
|
|
punish_address: self.punish_address,
|
|
|
|
tx_lock: msg.tx_lock,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 18:18:57 -04:00
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
2020-09-28 02:18:50 -04:00
|
|
|
pub struct State2 {
|
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
B: bitcoin::PublicKey,
|
|
|
|
s_a: cross_curve_dleq::Scalar,
|
|
|
|
S_b_monero: monero::PublicKey,
|
|
|
|
S_b_bitcoin: bitcoin::PublicKey,
|
|
|
|
v: monero::PrivateViewKey,
|
2020-10-22 00:06:05 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
2020-09-28 02:18:50 -04:00
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
2020-12-23 00:04:06 -05:00
|
|
|
cancel_timelock: Timelock,
|
|
|
|
punish_timelock: Timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
refund_address: bitcoin::Address,
|
|
|
|
redeem_address: bitcoin::Address,
|
|
|
|
punish_address: bitcoin::Address,
|
|
|
|
tx_lock: bitcoin::TxLock,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl State2 {
|
2021-01-04 22:08:36 -05:00
|
|
|
pub fn next_message(&self) -> alice::Message1 {
|
2020-12-03 01:28:23 -05:00
|
|
|
let tx_cancel =
|
2020-12-21 23:47:09 -05:00
|
|
|
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B);
|
2020-09-28 02:18:50 -04:00
|
|
|
|
|
|
|
let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address);
|
|
|
|
// Alice encsigns the refund transaction(bitcoin) digest with Bob's monero
|
|
|
|
// pubkey(S_b). The refund transaction spends the output of
|
|
|
|
// tx_lock_bitcoin to Bob's refund address.
|
|
|
|
// recover(encsign(a, S_b, d), sign(a, d), S_b) = s_b where d is a digest, (a,
|
|
|
|
// A) is alice's keypair and (s_b, S_b) is bob's keypair.
|
2020-12-03 01:28:23 -05:00
|
|
|
let tx_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_refund.digest());
|
2020-09-28 02:18:50 -04:00
|
|
|
|
|
|
|
let tx_cancel_sig = self.a.sign(tx_cancel.digest());
|
2021-01-04 22:08:36 -05:00
|
|
|
alice::Message1 {
|
2020-09-28 02:18:50 -04:00
|
|
|
tx_refund_encsig,
|
|
|
|
tx_cancel_sig,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn receive(self, msg: bob::Message2) -> Result<State3> {
|
2020-12-03 01:28:23 -05:00
|
|
|
let tx_cancel =
|
2020-12-21 23:47:09 -05:00
|
|
|
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B);
|
2020-09-28 02:18:50 -04:00
|
|
|
bitcoin::verify_sig(&self.B, &tx_cancel.digest(), &msg.tx_cancel_sig)?;
|
|
|
|
let tx_punish =
|
|
|
|
bitcoin::TxPunish::new(&tx_cancel, &self.punish_address, self.punish_timelock);
|
|
|
|
bitcoin::verify_sig(&self.B, &tx_punish.digest(), &msg.tx_punish_sig)?;
|
|
|
|
|
|
|
|
Ok(State3 {
|
|
|
|
a: self.a,
|
|
|
|
B: self.B,
|
|
|
|
s_a: self.s_a,
|
|
|
|
S_b_monero: self.S_b_monero,
|
|
|
|
S_b_bitcoin: self.S_b_bitcoin,
|
|
|
|
v: self.v,
|
2020-11-18 00:27:50 -05:00
|
|
|
// TODO(Franck): Review if these amounts are actually needed
|
2020-09-28 02:18:50 -04:00
|
|
|
btc: self.btc,
|
|
|
|
xmr: self.xmr,
|
2020-12-21 23:47:09 -05:00
|
|
|
cancel_timelock: self.cancel_timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
punish_timelock: self.punish_timelock,
|
|
|
|
refund_address: self.refund_address,
|
|
|
|
redeem_address: self.redeem_address,
|
|
|
|
punish_address: self.punish_address,
|
|
|
|
tx_lock: self.tx_lock,
|
|
|
|
tx_punish_sig_bob: msg.tx_punish_sig,
|
|
|
|
tx_cancel_sig_bob: msg.tx_cancel_sig,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-11-02 23:26:47 -05:00
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
2020-09-28 02:18:50 -04:00
|
|
|
pub struct State3 {
|
2020-10-16 02:04:03 -04:00
|
|
|
pub a: bitcoin::SecretKey,
|
|
|
|
pub B: bitcoin::PublicKey,
|
|
|
|
pub s_a: cross_curve_dleq::Scalar,
|
|
|
|
pub S_b_monero: monero::PublicKey,
|
|
|
|
pub S_b_bitcoin: bitcoin::PublicKey,
|
|
|
|
pub v: monero::PrivateViewKey,
|
2020-10-22 00:06:05 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
2020-10-22 04:25:54 -04:00
|
|
|
pub btc: bitcoin::Amount,
|
|
|
|
pub xmr: monero::Amount,
|
2020-12-23 00:04:06 -05:00
|
|
|
pub cancel_timelock: Timelock,
|
|
|
|
pub punish_timelock: Timelock,
|
2020-10-22 04:25:54 -04:00
|
|
|
pub refund_address: bitcoin::Address,
|
|
|
|
pub redeem_address: bitcoin::Address,
|
|
|
|
pub punish_address: bitcoin::Address,
|
|
|
|
pub tx_lock: bitcoin::TxLock,
|
|
|
|
pub tx_punish_sig_bob: bitcoin::Signature,
|
|
|
|
pub tx_cancel_sig_bob: bitcoin::Signature,
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State3 {
|
|
|
|
pub async fn watch_for_lock_btc<W>(self, bitcoin_wallet: &W) -> Result<State4>
|
|
|
|
where
|
2020-10-07 19:53:30 -04:00
|
|
|
W: bitcoin::WatchForRawTransaction,
|
2020-09-28 02:18:50 -04:00
|
|
|
{
|
2020-10-08 17:49:17 -04:00
|
|
|
tracing::info!("watching for lock btc with txid: {}", self.tx_lock.txid());
|
2020-09-29 01:36:50 -04:00
|
|
|
let tx = bitcoin_wallet
|
2020-10-07 19:53:30 -04:00
|
|
|
.watch_for_raw_transaction(self.tx_lock.txid())
|
2020-10-15 06:17:42 -04:00
|
|
|
.await;
|
2020-09-28 02:18:50 -04:00
|
|
|
|
2020-10-08 17:49:17 -04:00
|
|
|
tracing::info!("tx lock seen with txid: {}", tx.txid());
|
2020-09-29 01:36:50 -04:00
|
|
|
|
2020-09-28 02:18:50 -04:00
|
|
|
Ok(State4 {
|
|
|
|
a: self.a,
|
|
|
|
B: self.B,
|
|
|
|
s_a: self.s_a,
|
|
|
|
S_b_monero: self.S_b_monero,
|
|
|
|
S_b_bitcoin: self.S_b_bitcoin,
|
|
|
|
v: self.v,
|
|
|
|
btc: self.btc,
|
|
|
|
xmr: self.xmr,
|
2020-12-21 23:47:09 -05:00
|
|
|
cancel_timelock: self.cancel_timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
punish_timelock: self.punish_timelock,
|
|
|
|
refund_address: self.refund_address,
|
|
|
|
redeem_address: self.redeem_address,
|
|
|
|
punish_address: self.punish_address,
|
|
|
|
tx_lock: self.tx_lock,
|
|
|
|
tx_punish_sig_bob: self.tx_punish_sig_bob,
|
|
|
|
tx_cancel_sig_bob: self.tx_cancel_sig_bob,
|
|
|
|
})
|
|
|
|
}
|
2020-12-11 00:49:19 -05:00
|
|
|
|
2020-12-21 23:47:09 -05:00
|
|
|
pub async fn wait_for_cancel_timelock_to_expire<W>(&self, bitcoin_wallet: &W) -> Result<()>
|
2020-12-11 00:49:19 -05:00
|
|
|
where
|
2020-12-22 23:40:56 -05:00
|
|
|
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
2020-12-11 00:49:19 -05:00
|
|
|
{
|
2020-12-21 23:47:09 -05:00
|
|
|
wait_for_cancel_timelock_to_expire(
|
|
|
|
bitcoin_wallet,
|
|
|
|
self.cancel_timelock,
|
|
|
|
self.tx_lock.txid(),
|
|
|
|
)
|
|
|
|
.await
|
2020-12-11 00:49:19 -05:00
|
|
|
}
|
|
|
|
|
2020-12-21 23:47:09 -05:00
|
|
|
pub async fn expired_timelocks<W>(&self, bitcoin_wallet: &W) -> Result<ExpiredTimelocks>
|
2020-12-11 00:49:19 -05:00
|
|
|
where
|
2020-12-22 23:40:56 -05:00
|
|
|
W: WatchForRawTransaction + TransactionBlockHeight + GetBlockHeight,
|
2020-12-11 00:49:19 -05:00
|
|
|
{
|
2020-12-22 00:45:30 -05:00
|
|
|
current_epoch(
|
2020-12-21 01:33:18 -05:00
|
|
|
bitcoin_wallet,
|
2020-12-21 23:47:09 -05:00
|
|
|
self.cancel_timelock,
|
2020-12-21 01:33:18 -05:00
|
|
|
self.punish_timelock,
|
|
|
|
self.tx_lock.txid(),
|
|
|
|
)
|
|
|
|
.await
|
2020-12-11 00:49:19 -05:00
|
|
|
}
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
2020-10-21 18:18:57 -04:00
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
2020-09-28 02:18:50 -04:00
|
|
|
pub struct State4 {
|
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
B: bitcoin::PublicKey,
|
|
|
|
s_a: cross_curve_dleq::Scalar,
|
|
|
|
S_b_monero: monero::PublicKey,
|
|
|
|
S_b_bitcoin: bitcoin::PublicKey,
|
|
|
|
v: monero::PrivateViewKey,
|
2020-10-22 00:06:05 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
2020-09-28 02:18:50 -04:00
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
2020-12-23 00:04:06 -05:00
|
|
|
cancel_timelock: Timelock,
|
|
|
|
punish_timelock: Timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
refund_address: bitcoin::Address,
|
|
|
|
redeem_address: bitcoin::Address,
|
|
|
|
punish_address: bitcoin::Address,
|
|
|
|
tx_lock: bitcoin::TxLock,
|
|
|
|
tx_punish_sig_bob: bitcoin::Signature,
|
|
|
|
tx_cancel_sig_bob: bitcoin::Signature,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl State4 {
|
2020-09-29 01:36:50 -04:00
|
|
|
pub async fn lock_xmr<W>(self, monero_wallet: &W) -> Result<State5>
|
2020-09-28 02:18:50 -04:00
|
|
|
where
|
|
|
|
W: monero::Transfer,
|
|
|
|
{
|
|
|
|
let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey {
|
|
|
|
scalar: self.s_a.into_ed25519(),
|
|
|
|
});
|
|
|
|
let S_b = self.S_b_monero;
|
|
|
|
|
|
|
|
let (tx_lock_proof, fee) = monero_wallet
|
|
|
|
.transfer(S_a + S_b, self.v.public(), self.xmr)
|
|
|
|
.await?;
|
|
|
|
|
2020-09-29 01:36:50 -04:00
|
|
|
Ok(State5 {
|
|
|
|
a: self.a,
|
|
|
|
B: self.B,
|
|
|
|
s_a: self.s_a,
|
|
|
|
S_b_monero: self.S_b_monero,
|
|
|
|
S_b_bitcoin: self.S_b_bitcoin,
|
|
|
|
v: self.v,
|
|
|
|
btc: self.btc,
|
|
|
|
xmr: self.xmr,
|
2020-12-21 23:47:09 -05:00
|
|
|
cancel_timelock: self.cancel_timelock,
|
2020-09-29 01:36:50 -04:00
|
|
|
punish_timelock: self.punish_timelock,
|
|
|
|
refund_address: self.refund_address,
|
|
|
|
redeem_address: self.redeem_address,
|
|
|
|
punish_address: self.punish_address,
|
|
|
|
tx_lock: self.tx_lock,
|
|
|
|
tx_lock_proof,
|
|
|
|
tx_punish_sig_bob: self.tx_punish_sig_bob,
|
|
|
|
tx_cancel_sig_bob: self.tx_cancel_sig_bob,
|
|
|
|
lock_xmr_fee: fee,
|
|
|
|
})
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub async fn punish<W: bitcoin::BroadcastSignedTransaction>(
|
|
|
|
&self,
|
|
|
|
bitcoin_wallet: &W,
|
|
|
|
) -> Result<()> {
|
2020-12-03 01:28:23 -05:00
|
|
|
let tx_cancel =
|
2020-12-21 23:47:09 -05:00
|
|
|
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B);
|
2020-09-28 02:18:50 -04:00
|
|
|
let tx_punish =
|
|
|
|
bitcoin::TxPunish::new(&tx_cancel, &self.punish_address, self.punish_timelock);
|
|
|
|
|
|
|
|
{
|
|
|
|
let sig_a = self.a.sign(tx_cancel.digest());
|
|
|
|
let sig_b = self.tx_cancel_sig_bob.clone();
|
|
|
|
|
|
|
|
let signed_tx_cancel = tx_cancel.clone().add_signatures(
|
|
|
|
&self.tx_lock,
|
|
|
|
(self.a.public(), sig_a),
|
2020-12-03 01:28:23 -05:00
|
|
|
(self.B, sig_b),
|
2020-09-28 02:18:50 -04:00
|
|
|
)?;
|
|
|
|
|
|
|
|
let _ = bitcoin_wallet
|
|
|
|
.broadcast_signed_transaction(signed_tx_cancel)
|
|
|
|
.await?;
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
let sig_a = self.a.sign(tx_punish.digest());
|
|
|
|
let sig_b = self.tx_punish_sig_bob.clone();
|
|
|
|
|
2020-12-03 01:28:23 -05:00
|
|
|
let signed_tx_punish =
|
|
|
|
tx_punish.add_signatures(&tx_cancel, (self.a.public(), sig_a), (self.B, sig_b))?;
|
2020-09-28 02:18:50 -04:00
|
|
|
|
|
|
|
let _ = bitcoin_wallet
|
|
|
|
.broadcast_signed_transaction(signed_tx_punish)
|
|
|
|
.await?;
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 18:18:57 -04:00
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
2020-09-29 01:36:50 -04:00
|
|
|
pub struct State5 {
|
2020-09-28 02:18:50 -04:00
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
B: bitcoin::PublicKey,
|
|
|
|
s_a: cross_curve_dleq::Scalar,
|
|
|
|
S_b_monero: monero::PublicKey,
|
|
|
|
S_b_bitcoin: bitcoin::PublicKey,
|
|
|
|
v: monero::PrivateViewKey,
|
2020-10-22 00:06:05 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
2020-09-28 02:18:50 -04:00
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
2020-12-23 00:04:06 -05:00
|
|
|
cancel_timelock: Timelock,
|
|
|
|
punish_timelock: Timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
refund_address: bitcoin::Address,
|
|
|
|
redeem_address: bitcoin::Address,
|
|
|
|
punish_address: bitcoin::Address,
|
|
|
|
tx_lock: bitcoin::TxLock,
|
|
|
|
tx_lock_proof: monero::TransferProof,
|
2020-10-21 18:52:57 -04:00
|
|
|
|
2020-09-28 02:18:50 -04:00
|
|
|
tx_punish_sig_bob: bitcoin::Signature,
|
2020-10-21 18:52:57 -04:00
|
|
|
|
2020-09-28 02:18:50 -04:00
|
|
|
tx_cancel_sig_bob: bitcoin::Signature,
|
2020-09-29 01:36:50 -04:00
|
|
|
lock_xmr_fee: monero::Amount,
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
2020-09-29 01:36:50 -04:00
|
|
|
impl State5 {
|
2021-01-04 22:08:36 -05:00
|
|
|
pub fn next_message(&self) -> alice::Message2 {
|
|
|
|
alice::Message2 {
|
2020-09-28 02:18:50 -04:00
|
|
|
tx_lock_proof: self.tx_lock_proof.clone(),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-09-29 01:36:50 -04:00
|
|
|
pub fn receive(self, msg: bob::Message3) -> State6 {
|
|
|
|
State6 {
|
2020-09-28 02:18:50 -04:00
|
|
|
a: self.a,
|
|
|
|
B: self.B,
|
|
|
|
s_a: self.s_a,
|
|
|
|
S_b_monero: self.S_b_monero,
|
|
|
|
S_b_bitcoin: self.S_b_bitcoin,
|
|
|
|
v: self.v,
|
|
|
|
btc: self.btc,
|
|
|
|
xmr: self.xmr,
|
2020-12-21 23:47:09 -05:00
|
|
|
cancel_timelock: self.cancel_timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
punish_timelock: self.punish_timelock,
|
|
|
|
refund_address: self.refund_address,
|
|
|
|
redeem_address: self.redeem_address,
|
|
|
|
punish_address: self.punish_address,
|
|
|
|
tx_lock: self.tx_lock,
|
|
|
|
tx_punish_sig_bob: self.tx_punish_sig_bob,
|
|
|
|
tx_redeem_encsig: msg.tx_redeem_encsig,
|
2020-09-29 01:36:50 -04:00
|
|
|
lock_xmr_fee: self.lock_xmr_fee,
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// watch for refund on btc, recover s_b and refund xmr
|
|
|
|
pub async fn refund_xmr<B, M>(self, bitcoin_wallet: &B, monero_wallet: &M) -> Result<()>
|
|
|
|
where
|
2020-10-07 19:53:30 -04:00
|
|
|
B: WatchForRawTransaction,
|
2020-10-07 20:27:54 -04:00
|
|
|
M: CreateWalletForOutput,
|
2020-09-28 02:18:50 -04:00
|
|
|
{
|
2020-12-03 01:28:23 -05:00
|
|
|
let tx_cancel =
|
2020-12-21 23:47:09 -05:00
|
|
|
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B);
|
2020-09-28 02:18:50 -04:00
|
|
|
|
|
|
|
let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address);
|
|
|
|
|
2020-12-03 01:28:23 -05:00
|
|
|
let tx_refund_encsig = self.a.encsign(self.S_b_bitcoin, tx_refund.digest());
|
2020-09-28 02:18:50 -04:00
|
|
|
|
2020-10-07 19:53:30 -04:00
|
|
|
let tx_refund_candidate = bitcoin_wallet
|
|
|
|
.watch_for_raw_transaction(tx_refund.txid())
|
2020-10-15 06:17:42 -04:00
|
|
|
.await;
|
2020-09-28 02:18:50 -04:00
|
|
|
|
|
|
|
let tx_refund_sig =
|
|
|
|
tx_refund.extract_signature_by_key(tx_refund_candidate, self.a.public())?;
|
|
|
|
|
|
|
|
let s_b = bitcoin::recover(self.S_b_bitcoin, tx_refund_sig, tx_refund_encsig)?;
|
2020-11-08 19:07:06 -05:00
|
|
|
let s_b = monero::private_key_from_secp256k1_scalar(s_b.into());
|
2020-09-28 02:18:50 -04:00
|
|
|
|
|
|
|
let s = s_b.scalar + self.s_a.into_ed25519();
|
|
|
|
|
|
|
|
// NOTE: This actually generates and opens a new wallet, closing the currently
|
|
|
|
// open one.
|
|
|
|
monero_wallet
|
2020-10-07 20:27:54 -04:00
|
|
|
.create_and_load_wallet_for_output(monero::PrivateKey::from_scalar(s), self.v)
|
2020-09-28 02:18:50 -04:00
|
|
|
.await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-10-21 18:18:57 -04:00
|
|
|
#[derive(Clone, Debug, Deserialize, Serialize)]
|
2020-09-29 01:36:50 -04:00
|
|
|
pub struct State6 {
|
2020-09-28 02:18:50 -04:00
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
B: bitcoin::PublicKey,
|
|
|
|
s_a: cross_curve_dleq::Scalar,
|
|
|
|
S_b_monero: monero::PublicKey,
|
|
|
|
S_b_bitcoin: bitcoin::PublicKey,
|
|
|
|
v: monero::PrivateViewKey,
|
2020-10-22 00:06:05 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
2020-09-28 02:18:50 -04:00
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
2020-12-23 00:04:06 -05:00
|
|
|
cancel_timelock: Timelock,
|
|
|
|
punish_timelock: Timelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
refund_address: bitcoin::Address,
|
|
|
|
redeem_address: bitcoin::Address,
|
|
|
|
punish_address: bitcoin::Address,
|
|
|
|
tx_lock: bitcoin::TxLock,
|
2020-10-21 18:52:57 -04:00
|
|
|
|
2020-09-28 02:18:50 -04:00
|
|
|
tx_punish_sig_bob: bitcoin::Signature,
|
|
|
|
tx_redeem_encsig: EncryptedSignature,
|
2020-09-29 01:36:50 -04:00
|
|
|
lock_xmr_fee: monero::Amount,
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
2020-09-29 01:36:50 -04:00
|
|
|
impl State6 {
|
2020-09-28 02:18:50 -04:00
|
|
|
pub async fn redeem_btc<W: bitcoin::BroadcastSignedTransaction>(
|
|
|
|
&self,
|
|
|
|
bitcoin_wallet: &W,
|
|
|
|
) -> Result<()> {
|
|
|
|
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
|
|
|
|
|
|
|
let tx_redeem = bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address);
|
|
|
|
|
|
|
|
let sig_a = self.a.sign(tx_redeem.digest());
|
|
|
|
let sig_b =
|
|
|
|
adaptor.decrypt_signature(&self.s_a.into_secp256k1(), self.tx_redeem_encsig.clone());
|
|
|
|
|
2020-12-03 01:28:23 -05:00
|
|
|
let sig_tx_redeem =
|
|
|
|
tx_redeem.add_signatures(&self.tx_lock, (self.a.public(), sig_a), (self.B, sig_b))?;
|
2020-09-28 02:18:50 -04:00
|
|
|
bitcoin_wallet
|
|
|
|
.broadcast_signed_transaction(sig_tx_redeem)
|
|
|
|
.await?;
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
2020-09-29 01:36:50 -04:00
|
|
|
|
|
|
|
pub fn lock_xmr_fee(&self) -> monero::Amount {
|
|
|
|
self.lock_xmr_fee
|
|
|
|
}
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|