2021-03-03 19:28:58 -05:00
|
|
|
use crate::bitcoin::{
|
2021-03-11 02:16:00 -05:00
|
|
|
current_epoch, CancelTimelock, ExpiredTimelocks, PunishTimelock, TxCancel, TxPunish, TxRefund,
|
2021-04-30 20:16:16 -04:00
|
|
|
TX_PUNISH_ESTIMATED_WEIGHT, TX_REDEEM_ESTIMATED_WEIGHT,
|
2021-01-04 22:08:36 -05:00
|
|
|
};
|
2021-03-16 23:55:42 -04:00
|
|
|
use crate::env::Config;
|
2021-03-16 04:24:41 -04:00
|
|
|
use crate::monero::wallet::{TransferRequest, WatchRequest};
|
|
|
|
use crate::monero::TransferProof;
|
2021-03-24 01:48:05 -04:00
|
|
|
use crate::monero_ext::ScalarExt;
|
2021-03-24 01:55:00 -04:00
|
|
|
use crate::protocol::{Message0, Message1, Message2, Message3, Message4, CROSS_CURVE_PROOF_SYSTEM};
|
2021-03-03 19:28:58 -05:00
|
|
|
use crate::{bitcoin, monero};
|
2021-02-17 21:33:50 -05:00
|
|
|
use anyhow::{anyhow, bail, Context, Result};
|
2021-02-24 01:38:35 -05:00
|
|
|
use monero_rpc::wallet::BlockHeight;
|
2021-01-20 19:20:57 -05:00
|
|
|
use rand::{CryptoRng, RngCore};
|
|
|
|
use serde::{Deserialize, Serialize};
|
2021-02-18 20:22:55 -05:00
|
|
|
use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof;
|
2021-01-20 19:20:57 -05:00
|
|
|
use std::fmt;
|
2021-04-08 04:56:26 -04:00
|
|
|
use uuid::Uuid;
|
2020-09-28 02:18:50 -04:00
|
|
|
|
2021-01-07 18:52:07 -05:00
|
|
|
#[derive(Debug)]
|
|
|
|
pub enum AliceState {
|
|
|
|
Started {
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
BtcLocked {
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
2021-03-25 04:55:54 -04:00
|
|
|
XmrLockTransactionSent {
|
|
|
|
monero_wallet_restore_blockheight: BlockHeight,
|
|
|
|
transfer_proof: TransferProof,
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
2021-01-07 18:52:07 -05:00
|
|
|
XmrLocked {
|
2021-03-25 04:55:54 -04:00
|
|
|
monero_wallet_restore_blockheight: BlockHeight,
|
|
|
|
transfer_proof: TransferProof,
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
XmrLockTransferProofSent {
|
2021-02-24 01:38:35 -05:00
|
|
|
monero_wallet_restore_blockheight: BlockHeight,
|
2021-03-29 20:53:21 -04:00
|
|
|
transfer_proof: TransferProof,
|
2021-01-07 18:52:07 -05:00
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
EncSigLearned {
|
2021-02-24 01:38:35 -05:00
|
|
|
monero_wallet_restore_blockheight: BlockHeight,
|
2021-03-29 20:53:21 -04:00
|
|
|
transfer_proof: TransferProof,
|
2021-02-04 01:10:18 -05:00
|
|
|
encrypted_signature: Box<bitcoin::EncryptedSignature>,
|
2021-01-07 18:52:07 -05:00
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
BtcRedeemed,
|
|
|
|
BtcCancelled {
|
2021-02-24 01:38:35 -05:00
|
|
|
monero_wallet_restore_blockheight: BlockHeight,
|
2021-03-29 20:53:21 -04:00
|
|
|
transfer_proof: TransferProof,
|
2021-01-07 18:52:07 -05:00
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
BtcRefunded {
|
2021-02-24 01:38:35 -05:00
|
|
|
monero_wallet_restore_blockheight: BlockHeight,
|
2021-03-29 20:53:21 -04:00
|
|
|
transfer_proof: TransferProof,
|
2021-01-07 18:52:07 -05:00
|
|
|
spend_key: monero::PrivateKey,
|
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
BtcPunishable {
|
2021-02-24 01:38:35 -05:00
|
|
|
monero_wallet_restore_blockheight: BlockHeight,
|
2021-03-29 20:53:21 -04:00
|
|
|
transfer_proof: TransferProof,
|
2021-01-07 18:52:07 -05:00
|
|
|
state3: Box<State3>,
|
|
|
|
},
|
|
|
|
XmrRefunded,
|
|
|
|
CancelTimelockExpired {
|
2021-02-24 01:38:35 -05:00
|
|
|
monero_wallet_restore_blockheight: BlockHeight,
|
2021-03-29 20:53:21 -04:00
|
|
|
transfer_proof: TransferProof,
|
2021-01-07 18:52:07 -05:00
|
|
|
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::BtcLocked { .. } => write!(f, "btc is locked"),
|
2021-03-25 04:55:54 -04:00
|
|
|
AliceState::XmrLockTransactionSent { .. } => write!(f, "xmr lock transaction sent"),
|
2021-01-07 18:52:07 -05:00
|
|
|
AliceState::XmrLocked { .. } => write!(f, "xmr is locked"),
|
2021-03-25 04:55:54 -04:00
|
|
|
AliceState::XmrLockTransferProofSent { .. } => {
|
|
|
|
write!(f, "xmr lock transfer proof sent")
|
|
|
|
}
|
2021-01-07 18:52:07 -05:00
|
|
|
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"),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-24 01:31:49 -04:00
|
|
|
#[derive(Clone, Debug, PartialEq)]
|
2020-09-28 02:18:50 -04:00
|
|
|
pub struct State0 {
|
2021-03-24 01:48:05 -04:00
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
s_a: monero::Scalar,
|
|
|
|
v_a: monero::PrivateViewKey,
|
|
|
|
S_a_monero: monero::PublicKey,
|
|
|
|
S_a_bitcoin: bitcoin::PublicKey,
|
|
|
|
dleq_proof_s_a: CrossCurveDLEQProof,
|
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
|
|
|
cancel_timelock: CancelTimelock,
|
|
|
|
punish_timelock: PunishTimelock,
|
|
|
|
redeem_address: bitcoin::Address,
|
|
|
|
punish_address: bitcoin::Address,
|
2021-04-28 03:08:00 -04:00
|
|
|
tx_redeem_fee: bitcoin::Amount,
|
2021-04-28 20:40:04 -04:00
|
|
|
tx_punish_fee: bitcoin::Amount,
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State0 {
|
2021-02-04 01:01:08 -05:00
|
|
|
pub async fn new<R>(
|
2020-09-28 02:18:50 -04:00
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
2021-03-16 23:55:42 -04:00
|
|
|
env_config: Config,
|
2021-02-04 01:01:08 -05:00
|
|
|
bitcoin_wallet: &bitcoin::Wallet,
|
2021-02-02 23:25:05 -05:00
|
|
|
rng: &mut R,
|
2021-02-04 01:01:08 -05:00
|
|
|
) -> Result<Self>
|
2021-02-02 23:25:05 -05:00
|
|
|
where
|
|
|
|
R: RngCore + CryptoRng,
|
|
|
|
{
|
2021-02-04 01:01:08 -05:00
|
|
|
let a = bitcoin::SecretKey::new_random(rng);
|
|
|
|
let v_a = monero::PrivateViewKey::new_random(rng);
|
|
|
|
let redeem_address = bitcoin_wallet.new_address().await?;
|
2021-03-17 00:26:44 -04:00
|
|
|
let punish_address = bitcoin_wallet.new_address().await?;
|
2021-02-17 21:33:50 -05:00
|
|
|
|
|
|
|
let s_a = monero::Scalar::random(rng);
|
2021-02-18 20:22:55 -05:00
|
|
|
let (dleq_proof_s_a, (S_a_bitcoin, S_a_monero)) = CROSS_CURVE_PROOF_SYSTEM.prove(&s_a, rng);
|
2021-02-02 23:25:05 -05:00
|
|
|
|
2021-04-30 20:08:54 -04:00
|
|
|
let tx_redeem_fee = bitcoin_wallet
|
2021-04-30 20:16:16 -04:00
|
|
|
.estimate_fee(TX_REDEEM_ESTIMATED_WEIGHT)
|
2021-04-30 20:08:54 -04:00
|
|
|
.await?;
|
|
|
|
let tx_punish_fee = bitcoin_wallet
|
2021-04-30 20:16:16 -04:00
|
|
|
.estimate_fee(TX_PUNISH_ESTIMATED_WEIGHT)
|
2021-04-30 20:08:54 -04:00
|
|
|
.await?;
|
2021-02-04 01:01:08 -05:00
|
|
|
Ok(Self {
|
2020-09-28 02:18:50 -04:00
|
|
|
a,
|
|
|
|
s_a,
|
|
|
|
v_a,
|
2021-02-17 21:33:50 -05:00
|
|
|
S_a_bitcoin: S_a_bitcoin.into(),
|
|
|
|
S_a_monero: monero::PublicKey {
|
|
|
|
point: S_a_monero.compress(),
|
|
|
|
},
|
2021-02-02 23:25:05 -05:00
|
|
|
dleq_proof_s_a,
|
2020-09-28 02:18:50 -04:00
|
|
|
redeem_address,
|
|
|
|
punish_address,
|
|
|
|
btc,
|
|
|
|
xmr,
|
2021-03-16 23:55:42 -04:00
|
|
|
cancel_timelock: env_config.bitcoin_cancel_timelock,
|
|
|
|
punish_timelock: env_config.bitcoin_punish_timelock,
|
2021-04-30 20:08:54 -04:00
|
|
|
tx_redeem_fee,
|
|
|
|
tx_punish_fee,
|
2021-02-04 01:01:08 -05:00
|
|
|
})
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
2021-04-08 04:56:26 -04:00
|
|
|
pub fn receive(self, msg: Message0) -> Result<(Uuid, State1)> {
|
2021-02-18 20:22:55 -05:00
|
|
|
let valid = CROSS_CURVE_PROOF_SYSTEM.verify(
|
2021-02-17 21:33:50 -05:00
|
|
|
&msg.dleq_proof_s_b,
|
|
|
|
(
|
|
|
|
msg.S_b_bitcoin.into(),
|
|
|
|
msg.S_b_monero
|
|
|
|
.point
|
|
|
|
.decompress()
|
|
|
|
.ok_or_else(|| anyhow!("S_b is not a monero curve point"))?,
|
|
|
|
),
|
|
|
|
);
|
|
|
|
|
|
|
|
if !valid {
|
|
|
|
bail!("Bob's dleq proof doesn't verify")
|
|
|
|
}
|
2020-09-28 02:18:50 -04:00
|
|
|
|
|
|
|
let v = self.v_a + msg.v_b;
|
|
|
|
|
2021-04-08 04:56:26 -04:00
|
|
|
Ok((msg.swap_id, State1 {
|
2020-09-28 02:18:50 -04:00
|
|
|
a: self.a,
|
|
|
|
B: msg.B,
|
|
|
|
s_a: self.s_a,
|
2021-02-17 21:33:50 -05:00
|
|
|
S_a_monero: self.S_a_monero,
|
|
|
|
S_a_bitcoin: self.S_a_bitcoin,
|
2020-09-28 02:18:50 -04:00
|
|
|
S_b_monero: msg.S_b_monero,
|
|
|
|
S_b_bitcoin: msg.S_b_bitcoin,
|
|
|
|
v,
|
2021-02-05 00:40:11 -05:00
|
|
|
v_a: self.v_a,
|
|
|
|
dleq_proof_s_a: self.dleq_proof_s_a,
|
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: msg.refund_address,
|
|
|
|
redeem_address: self.redeem_address,
|
|
|
|
punish_address: self.punish_address,
|
2021-04-28 03:08:00 -04:00
|
|
|
tx_redeem_fee: self.tx_redeem_fee,
|
2021-04-28 20:40:04 -04:00
|
|
|
tx_punish_fee: self.tx_punish_fee,
|
|
|
|
tx_refund_fee: msg.tx_refund_fee,
|
2021-04-28 20:59:40 -04:00
|
|
|
tx_cancel_fee: msg.tx_cancel_fee,
|
2021-04-08 04:56:26 -04:00
|
|
|
}))
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-24 01:31:49 -04:00
|
|
|
#[derive(Clone, Debug)]
|
2020-09-28 02:18:50 -04:00
|
|
|
pub struct State1 {
|
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
B: bitcoin::PublicKey,
|
2021-02-17 21:33:50 -05:00
|
|
|
s_a: monero::Scalar,
|
|
|
|
S_a_monero: monero::PublicKey,
|
|
|
|
S_a_bitcoin: bitcoin::PublicKey,
|
2020-09-28 02:18:50 -04:00
|
|
|
S_b_monero: monero::PublicKey,
|
|
|
|
S_b_bitcoin: bitcoin::PublicKey,
|
|
|
|
v: monero::PrivateViewKey,
|
2021-02-05 00:40:11 -05:00
|
|
|
v_a: monero::PrivateViewKey,
|
2021-02-17 21:33:50 -05:00
|
|
|
dleq_proof_s_a: CrossCurveDLEQProof,
|
2020-09-28 02:18:50 -04:00
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
2021-02-14 20:19:43 -05:00
|
|
|
cancel_timelock: CancelTimelock,
|
|
|
|
punish_timelock: PunishTimelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
refund_address: bitcoin::Address,
|
|
|
|
redeem_address: bitcoin::Address,
|
|
|
|
punish_address: bitcoin::Address,
|
2021-04-28 03:08:00 -04:00
|
|
|
tx_redeem_fee: bitcoin::Amount,
|
2021-04-28 20:40:04 -04:00
|
|
|
tx_punish_fee: bitcoin::Amount,
|
|
|
|
tx_refund_fee: bitcoin::Amount,
|
2021-04-28 20:59:40 -04:00
|
|
|
tx_cancel_fee: bitcoin::Amount,
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State1 {
|
2021-02-05 00:40:11 -05:00
|
|
|
pub fn next_message(&self) -> Message1 {
|
|
|
|
Message1 {
|
|
|
|
A: self.a.public(),
|
2021-02-17 21:33:50 -05:00
|
|
|
S_a_monero: self.S_a_monero,
|
|
|
|
S_a_bitcoin: self.S_a_bitcoin,
|
2021-02-05 00:40:11 -05:00
|
|
|
dleq_proof_s_a: self.dleq_proof_s_a.clone(),
|
|
|
|
v_a: self.v_a,
|
|
|
|
redeem_address: self.redeem_address.clone(),
|
|
|
|
punish_address: self.punish_address.clone(),
|
2021-04-28 03:08:00 -04:00
|
|
|
tx_redeem_fee: self.tx_redeem_fee,
|
2021-04-28 20:40:04 -04:00
|
|
|
tx_punish_fee: self.tx_punish_fee,
|
2021-02-05 00:40:11 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-24 03:30:55 -04:00
|
|
|
pub fn receive(self, msg: Message2) -> Result<State2> {
|
|
|
|
let tx_lock = bitcoin::TxLock::from_psbt(msg.psbt, self.a.public(), self.B, self.btc)
|
|
|
|
.context("Failed to re-construct TxLock from received PSBT")?;
|
|
|
|
|
|
|
|
Ok(State2 {
|
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,
|
2021-03-24 03:30:55 -04:00
|
|
|
tx_lock,
|
2021-04-28 03:08:00 -04:00
|
|
|
tx_redeem_fee: self.tx_redeem_fee,
|
2021-04-28 20:40:04 -04:00
|
|
|
tx_punish_fee: self.tx_punish_fee,
|
|
|
|
tx_refund_fee: self.tx_refund_fee,
|
2021-04-28 20:59:40 -04:00
|
|
|
tx_cancel_fee: self.tx_cancel_fee,
|
2021-03-24 03:30:55 -04:00
|
|
|
})
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-24 01:31:49 -04:00
|
|
|
#[derive(Clone, Debug)]
|
2020-09-28 02:18:50 -04:00
|
|
|
pub struct State2 {
|
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
B: bitcoin::PublicKey,
|
2021-02-17 21:33:50 -05:00
|
|
|
s_a: monero::Scalar,
|
2020-09-28 02:18:50 -04:00
|
|
|
S_b_monero: monero::PublicKey,
|
|
|
|
S_b_bitcoin: bitcoin::PublicKey,
|
|
|
|
v: monero::PrivateViewKey,
|
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
2021-02-14 20:19:43 -05:00
|
|
|
cancel_timelock: CancelTimelock,
|
|
|
|
punish_timelock: PunishTimelock,
|
2020-09-28 02:18:50 -04:00
|
|
|
refund_address: bitcoin::Address,
|
|
|
|
redeem_address: bitcoin::Address,
|
|
|
|
punish_address: bitcoin::Address,
|
|
|
|
tx_lock: bitcoin::TxLock,
|
2021-04-28 03:08:00 -04:00
|
|
|
tx_redeem_fee: bitcoin::Amount,
|
2021-04-28 20:40:04 -04:00
|
|
|
tx_punish_fee: bitcoin::Amount,
|
|
|
|
tx_refund_fee: bitcoin::Amount,
|
2021-04-28 20:59:40 -04:00
|
|
|
tx_cancel_fee: bitcoin::Amount,
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State2 {
|
2021-02-03 19:45:54 -05:00
|
|
|
pub fn next_message(&self) -> Message3 {
|
2021-04-28 20:59:40 -04:00
|
|
|
let tx_cancel = bitcoin::TxCancel::new(
|
|
|
|
&self.tx_lock,
|
|
|
|
self.cancel_timelock,
|
|
|
|
self.a.public(),
|
|
|
|
self.B,
|
|
|
|
self.tx_cancel_fee,
|
|
|
|
);
|
2020-09-28 02:18:50 -04:00
|
|
|
|
2021-04-28 20:40:04 -04:00
|
|
|
let tx_refund =
|
|
|
|
bitcoin::TxRefund::new(&tx_cancel, &self.refund_address, self.tx_refund_fee);
|
2020-09-28 02:18:50 -04:00
|
|
|
// 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-02-03 19:45:54 -05:00
|
|
|
Message3 {
|
2020-09-28 02:18:50 -04:00
|
|
|
tx_refund_encsig,
|
|
|
|
tx_cancel_sig,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-02-03 19:43:07 -05:00
|
|
|
pub fn receive(self, msg: Message4) -> Result<State3> {
|
2021-04-28 20:59:40 -04:00
|
|
|
let tx_cancel = bitcoin::TxCancel::new(
|
|
|
|
&self.tx_lock,
|
|
|
|
self.cancel_timelock,
|
|
|
|
self.a.public(),
|
|
|
|
self.B,
|
|
|
|
self.tx_cancel_fee,
|
|
|
|
);
|
2021-01-06 22:44:31 -05:00
|
|
|
bitcoin::verify_sig(&self.B, &tx_cancel.digest(), &msg.tx_cancel_sig)
|
|
|
|
.context("Failed to verify cancel transaction")?;
|
2021-04-28 20:40:04 -04:00
|
|
|
let tx_punish = bitcoin::TxPunish::new(
|
|
|
|
&tx_cancel,
|
|
|
|
&self.punish_address,
|
|
|
|
self.punish_timelock,
|
|
|
|
self.tx_punish_fee,
|
|
|
|
);
|
2021-01-06 22:44:31 -05:00
|
|
|
bitcoin::verify_sig(&self.B, &tx_punish.digest(), &msg.tx_punish_sig)
|
2021-01-07 19:31:21 -05:00
|
|
|
.context("Failed to verify punish transaction")?;
|
2020-09-28 02:18:50 -04:00
|
|
|
|
|
|
|
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,
|
|
|
|
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,
|
2021-04-28 03:08:00 -04:00
|
|
|
tx_redeem_fee: self.tx_redeem_fee,
|
2021-04-28 20:40:04 -04:00
|
|
|
tx_punish_fee: self.tx_punish_fee,
|
|
|
|
tx_refund_fee: self.tx_refund_fee,
|
2021-04-28 20:59:40 -04:00
|
|
|
tx_cancel_fee: self.tx_cancel_fee,
|
2020-09-28 02:18:50 -04:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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 {
|
2021-03-24 01:48:05 -04:00
|
|
|
a: bitcoin::SecretKey,
|
|
|
|
B: bitcoin::PublicKey,
|
|
|
|
s_a: monero::Scalar,
|
|
|
|
S_b_monero: monero::PublicKey,
|
|
|
|
S_b_bitcoin: bitcoin::PublicKey,
|
2020-10-16 02:04:03 -04:00
|
|
|
pub v: monero::PrivateViewKey,
|
2020-10-22 00:06:05 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
2021-03-24 01:48:05 -04:00
|
|
|
btc: bitcoin::Amount,
|
|
|
|
xmr: monero::Amount,
|
2021-02-14 20:19:43 -05:00
|
|
|
pub cancel_timelock: CancelTimelock,
|
|
|
|
pub punish_timelock: PunishTimelock,
|
2021-03-24 01:48:05 -04:00
|
|
|
refund_address: bitcoin::Address,
|
|
|
|
redeem_address: bitcoin::Address,
|
|
|
|
punish_address: bitcoin::Address,
|
2020-10-22 04:25:54 -04:00
|
|
|
pub tx_lock: bitcoin::TxLock,
|
2021-03-24 01:48:05 -04:00
|
|
|
tx_punish_sig_bob: bitcoin::Signature,
|
|
|
|
tx_cancel_sig_bob: bitcoin::Signature,
|
2021-04-28 03:08:00 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
|
|
|
tx_redeem_fee: bitcoin::Amount,
|
2021-04-28 20:40:04 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
|
|
|
tx_punish_fee: bitcoin::Amount,
|
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
|
|
|
tx_refund_fee: bitcoin::Amount,
|
2021-04-28 20:59:40 -04:00
|
|
|
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
|
|
|
tx_cancel_fee: bitcoin::Amount,
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
impl State3 {
|
2021-03-01 20:22:23 -05:00
|
|
|
pub async fn expired_timelocks(
|
|
|
|
&self,
|
|
|
|
bitcoin_wallet: &bitcoin::Wallet,
|
|
|
|
) -> Result<ExpiredTimelocks> {
|
2021-03-16 03:31:13 -04:00
|
|
|
let tx_cancel = self.tx_cancel();
|
2021-03-11 02:16:00 -05:00
|
|
|
|
2021-03-16 04:11:14 -04:00
|
|
|
let tx_lock_status = bitcoin_wallet.status_of_script(&self.tx_lock).await?;
|
|
|
|
let tx_cancel_status = bitcoin_wallet.status_of_script(&tx_cancel).await?;
|
2021-03-11 02:16:00 -05:00
|
|
|
|
|
|
|
Ok(current_epoch(
|
2020-12-21 23:47:09 -05:00
|
|
|
self.cancel_timelock,
|
2020-12-21 01:33:18 -05:00
|
|
|
self.punish_timelock,
|
2021-03-11 02:16:00 -05:00
|
|
|
tx_lock_status,
|
|
|
|
tx_cancel_status,
|
|
|
|
))
|
2020-12-11 00:49:19 -05:00
|
|
|
}
|
2021-03-16 03:02:31 -04:00
|
|
|
|
2021-03-17 21:27:08 -04:00
|
|
|
pub fn lock_xmr_transfer_request(&self) -> TransferRequest {
|
|
|
|
let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: self.s_a });
|
|
|
|
|
|
|
|
let public_spend_key = S_a + self.S_b_monero;
|
|
|
|
let public_view_key = self.v.public();
|
|
|
|
|
|
|
|
TransferRequest {
|
|
|
|
public_spend_key,
|
|
|
|
public_view_key,
|
|
|
|
amount: self.xmr,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-16 04:24:41 -04:00
|
|
|
pub fn lock_xmr_watch_request(
|
|
|
|
&self,
|
|
|
|
transfer_proof: TransferProof,
|
2021-03-28 21:05:20 -04:00
|
|
|
conf_target: u64,
|
2021-03-16 04:24:41 -04:00
|
|
|
) -> WatchRequest {
|
|
|
|
let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: self.s_a });
|
|
|
|
|
|
|
|
let public_spend_key = S_a + self.S_b_monero;
|
|
|
|
let public_view_key = self.v.public();
|
|
|
|
WatchRequest {
|
|
|
|
public_spend_key,
|
|
|
|
public_view_key,
|
|
|
|
transfer_proof,
|
|
|
|
conf_target,
|
|
|
|
expected: self.xmr,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-03-16 03:31:13 -04:00
|
|
|
pub fn tx_cancel(&self) -> TxCancel {
|
2021-04-28 20:59:40 -04:00
|
|
|
TxCancel::new(
|
|
|
|
&self.tx_lock,
|
|
|
|
self.cancel_timelock,
|
|
|
|
self.a.public(),
|
|
|
|
self.B,
|
|
|
|
self.tx_cancel_fee,
|
|
|
|
)
|
2021-03-16 03:31:13 -04:00
|
|
|
}
|
|
|
|
|
2021-03-24 01:48:05 -04:00
|
|
|
pub fn tx_refund(&self) -> TxRefund {
|
2021-04-28 20:40:04 -04:00
|
|
|
bitcoin::TxRefund::new(&self.tx_cancel(), &self.refund_address, self.tx_refund_fee)
|
2021-03-24 01:48:05 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn extract_monero_private_key(
|
|
|
|
&self,
|
|
|
|
published_refund_tx: bitcoin::Transaction,
|
|
|
|
) -> Result<monero::PrivateKey> {
|
|
|
|
self.tx_refund().extract_monero_private_key(
|
|
|
|
published_refund_tx,
|
|
|
|
self.s_a,
|
|
|
|
self.a.clone(),
|
|
|
|
self.S_b_bitcoin,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn signed_redeem_transaction(
|
|
|
|
&self,
|
|
|
|
sig: bitcoin::EncryptedSignature,
|
|
|
|
) -> Result<bitcoin::Transaction> {
|
2021-04-28 03:08:00 -04:00
|
|
|
bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address, self.tx_redeem_fee)
|
2021-03-24 01:48:05 -04:00
|
|
|
.complete(sig, self.a.clone(), self.s_a.to_secpfun_scalar(), self.B)
|
|
|
|
.context("Failed to complete Bitcoin redeem transaction")
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn signed_cancel_transaction(&self) -> Result<bitcoin::Transaction> {
|
|
|
|
self.tx_cancel()
|
|
|
|
.complete_as_alice(self.a.clone(), self.B, self.tx_cancel_sig_bob.clone())
|
|
|
|
.context("Failed to complete Bitcoin cancel transaction")
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn signed_punish_transaction(&self) -> Result<bitcoin::Transaction> {
|
|
|
|
self.tx_punish()
|
|
|
|
.complete(self.tx_punish_sig_bob.clone(), self.a.clone(), self.B)
|
|
|
|
.context("Failed to complete Bitcoin punish transaction")
|
|
|
|
}
|
|
|
|
|
|
|
|
fn tx_punish(&self) -> TxPunish {
|
2021-03-16 03:31:13 -04:00
|
|
|
bitcoin::TxPunish::new(
|
|
|
|
&self.tx_cancel(),
|
|
|
|
&self.punish_address,
|
|
|
|
self.punish_timelock,
|
2021-04-28 20:40:04 -04:00
|
|
|
self.tx_punish_fee,
|
2021-03-16 03:31:13 -04:00
|
|
|
)
|
|
|
|
}
|
2020-09-28 02:18:50 -04:00
|
|
|
}
|