Make as many fields of Alice's states private as possible

To achieve this, we need to add some pure helpers to the state structs.
This has the added benefit that we can reduce the amount of code within
the swap function.
This commit is contained in:
Thomas Eizinger 2021-03-24 16:48:05 +11:00
parent 7f5715e147
commit e130448200
No known key found for this signature in database
GPG Key ID: 651AC83A6C6C8B96
2 changed files with 74 additions and 64 deletions

View File

@ -4,6 +4,7 @@ use crate::bitcoin::{
use crate::env::Config;
use crate::monero::wallet::{TransferRequest, WatchRequest};
use crate::monero::TransferProof;
use crate::monero_ext::ScalarExt;
use crate::protocol::alice::{Message1, Message3};
use crate::protocol::bob::{Message0, Message2, Message4};
use crate::protocol::CROSS_CURVE_PROOF_SYSTEM;
@ -76,18 +77,18 @@ impl fmt::Display for AliceState {
#[derive(Clone, Debug, PartialEq)]
pub struct State0 {
pub a: bitcoin::SecretKey,
pub s_a: monero::Scalar,
pub v_a: monero::PrivateViewKey,
pub(crate) S_a_monero: monero::PublicKey,
pub(crate) S_a_bitcoin: bitcoin::PublicKey,
pub dleq_proof_s_a: CrossCurveDLEQProof,
pub btc: bitcoin::Amount,
pub xmr: monero::Amount,
pub cancel_timelock: CancelTimelock,
pub punish_timelock: PunishTimelock,
pub redeem_address: bitcoin::Address,
pub punish_address: bitcoin::Address,
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,
}
impl State0 {
@ -292,23 +293,23 @@ impl State2 {
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
pub struct State3 {
pub a: bitcoin::SecretKey,
pub B: bitcoin::PublicKey,
pub s_a: monero::Scalar,
pub S_b_monero: monero::PublicKey,
pub S_b_bitcoin: bitcoin::PublicKey,
a: bitcoin::SecretKey,
B: bitcoin::PublicKey,
s_a: monero::Scalar,
S_b_monero: monero::PublicKey,
S_b_bitcoin: bitcoin::PublicKey,
pub v: monero::PrivateViewKey,
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
pub btc: bitcoin::Amount,
pub xmr: monero::Amount,
btc: bitcoin::Amount,
xmr: monero::Amount,
pub cancel_timelock: CancelTimelock,
pub punish_timelock: PunishTimelock,
pub refund_address: bitcoin::Address,
pub redeem_address: bitcoin::Address,
pub punish_address: bitcoin::Address,
refund_address: bitcoin::Address,
redeem_address: bitcoin::Address,
punish_address: bitcoin::Address,
pub tx_lock: bitcoin::TxLock,
pub tx_punish_sig_bob: bitcoin::Signature,
pub tx_cancel_sig_bob: bitcoin::Signature,
tx_punish_sig_bob: bitcoin::Signature,
tx_cancel_sig_bob: bitcoin::Signature,
}
impl State3 {
@ -364,15 +365,48 @@ impl State3 {
TxCancel::new(&self.tx_lock, self.cancel_timelock, self.a.public(), self.B)
}
pub fn tx_punish(&self) -> TxPunish {
pub fn tx_refund(&self) -> TxRefund {
bitcoin::TxRefund::new(&self.tx_cancel(), &self.refund_address)
}
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> {
bitcoin::TxRedeem::new(&self.tx_lock, &self.redeem_address)
.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 {
bitcoin::TxPunish::new(
&self.tx_cancel(),
&self.punish_address,
self.punish_timelock,
)
}
pub fn tx_refund(&self) -> TxRefund {
bitcoin::TxRefund::new(&self.tx_cancel(), &self.refund_address)
}
}

View File

@ -1,8 +1,7 @@
//! Run an XMR/BTC swap in the role of Alice.
//! Alice holds XMR and wishes receive BTC.
use crate::bitcoin::{ExpiredTimelocks, TxRedeem};
use crate::bitcoin::ExpiredTimelocks;
use crate::env::Config;
use crate::monero_ext::ScalarExt;
use crate::protocol::alice;
use crate::protocol::alice::event_loop::EventLoopHandle;
use crate::protocol::alice::AliceState;
@ -158,12 +157,7 @@ async fn next_state(
} => match state3.expired_timelocks(bitcoin_wallet).await? {
ExpiredTimelocks::None => {
let tx_lock_status = bitcoin_wallet.subscribe_to(state3.tx_lock.clone()).await;
match TxRedeem::new(&state3.tx_lock, &state3.redeem_address).complete(
*encrypted_signature,
state3.a.clone(),
state3.s_a.to_secpfun_scalar(),
state3.B,
) {
match state3.signed_redeem_transaction(*encrypted_signature) {
Ok(tx) => match bitcoin_wallet.broadcast(tx, "redeem").await {
Ok((_, subscription)) => match subscription.wait_until_final().await {
Ok(_) => AliceState::BtcRedeemed,
@ -205,18 +199,14 @@ async fn next_state(
state3,
monero_wallet_restore_blockheight,
} => {
let tx_cancel = state3.tx_cancel();
let transaction = state3.signed_cancel_transaction()?;
// If Bob hasn't yet broadcasted the tx cancel, we do it
if bitcoin_wallet
.get_raw_transaction(tx_cancel.txid())
.get_raw_transaction(transaction.txid())
.await
.is_err()
{
let transaction = tx_cancel
.complete_as_alice(state3.a.clone(), state3.B, state3.tx_cancel_sig_bob.clone())
.context("Failed to complete Bitcoin cancel transaction")?;
if let Err(e) = bitcoin_wallet.broadcast(transaction, "cancel").await {
tracing::debug!(
"Assuming transaction is already broadcasted because: {:#}",
@ -243,14 +233,9 @@ async fn next_state(
select! {
seen_refund = tx_refund_status.wait_until_seen() => {
seen_refund.context("Failed to monitor refund transaction")?;
let published_refund_tx = bitcoin_wallet.get_raw_transaction(state3.tx_refund().txid()).await?;
let spend_key = state3.tx_refund().extract_monero_private_key(
published_refund_tx,
state3.s_a,
state3.a.clone(),
state3.S_b_bitcoin,
)?;
let published_refund_tx = bitcoin_wallet.get_raw_transaction(state3.tx_refund().txid()).await?;
let spend_key = state3.extract_monero_private_key(published_refund_tx)?;
AliceState::BtcRefunded {
spend_key,
@ -283,11 +268,7 @@ async fn next_state(
state3,
monero_wallet_restore_blockheight,
} => {
let signed_tx_punish = state3.tx_punish().complete(
state3.tx_punish_sig_bob.clone(),
state3.a.clone(),
state3.B,
)?;
let signed_tx_punish = state3.signed_punish_transaction()?;
let punish = async {
let (txid, subscription) =
@ -313,16 +294,11 @@ async fn next_state(
// because a punish tx failure is not recoverable (besides re-trying) if the
// refund tx was not included.
let tx_refund = state3.tx_refund();
let published_refund_tx =
bitcoin_wallet.get_raw_transaction(tx_refund.txid()).await?;
let published_refund_tx = bitcoin_wallet
.get_raw_transaction(state3.tx_refund().txid())
.await?;
let spend_key = tx_refund.extract_monero_private_key(
published_refund_tx,
state3.s_a,
state3.a.clone(),
state3.S_b_bitcoin,
)?;
let spend_key = state3.extract_monero_private_key(published_refund_tx)?;
AliceState::BtcRefunded {
spend_key,