mirror of
https://github.com/comit-network/xmr-btc-swap.git
synced 2025-08-09 15:02:47 -04:00
Merge #209
209: Upgrade to bdk 0.4 r=thomaseizinger a=thomaseizinger Effectively, this also means: - Upgrading to rust-bitcoin 0.26 - Upgrading to miniscript 5 - Upgrading monero to 0.10 - Upgrading curve25519-dalek to 3 - Upgrading bitcoin-harness to rust-bitcoin 0.26 (https://github.com/coblox/bitcoin-harness-rs/pull/21) - Upgrade `ecdsa_fun` to latest version - Replace `cross_curve_dleq` with `sigma_fun` (to avoid an upgrade dance on that library) I refrained from specifying `rev`s in the Cargo.toml because we have a lock-file anyway. This should allow us to update those dependencies easier in the future by just running `cargo update -p <dependency>`. Co-authored-by: Thomas Eizinger <thomas@eizinger.io>
This commit is contained in:
commit
81228c9d5b
20 changed files with 306 additions and 268 deletions
|
@ -28,8 +28,13 @@ use ::bitcoin::{
|
|||
};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use async_trait::async_trait;
|
||||
use ecdsa_fun::{adaptor::Adaptor, fun::Point, nonce::Deterministic, ECDSA};
|
||||
use miniscript::{Descriptor, Segwitv0};
|
||||
use ecdsa_fun::{
|
||||
adaptor::{Adaptor, HashTranscript},
|
||||
fun::Point,
|
||||
nonce::Deterministic,
|
||||
ECDSA,
|
||||
};
|
||||
use miniscript::{descriptor::Wsh, Descriptor, Segwitv0};
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::Sha256;
|
||||
|
@ -93,7 +98,10 @@ impl SecretKey {
|
|||
|
||||
// self = a, Y = S_b, digest = tx_refund
|
||||
pub fn encsign(&self, Y: PublicKey, digest: SigHash) -> EncryptedSignature {
|
||||
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
||||
let adaptor = Adaptor::<
|
||||
HashTranscript<Sha256, rand_chacha::ChaCha20Rng>,
|
||||
Deterministic<Sha256>,
|
||||
>::default();
|
||||
|
||||
adaptor.encrypted_sign(&self.inner, &Y.0, &digest.into_inner())
|
||||
}
|
||||
|
@ -108,6 +116,12 @@ impl From<PublicKey> for Point {
|
|||
}
|
||||
}
|
||||
|
||||
impl From<Point> for PublicKey {
|
||||
fn from(p: Point) -> Self {
|
||||
Self(p)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Scalar> for SecretKey {
|
||||
fn from(scalar: Scalar) -> Self {
|
||||
let ecdsa = ECDSA::<()>::default();
|
||||
|
@ -157,7 +171,7 @@ pub fn verify_encsig(
|
|||
digest: &SigHash,
|
||||
encsig: &EncryptedSignature,
|
||||
) -> Result<()> {
|
||||
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
||||
let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default();
|
||||
|
||||
if adaptor.verify_encrypted_signature(
|
||||
&verification_key.0,
|
||||
|
@ -187,7 +201,7 @@ pub fn build_shared_output_descriptor(A: Point, B: Point) -> Descriptor<bitcoin:
|
|||
let miniscript = miniscript::Miniscript::<bitcoin::PublicKey, Segwitv0>::from_str(&miniscript)
|
||||
.expect("a valid miniscript");
|
||||
|
||||
Descriptor::Wsh(miniscript)
|
||||
Descriptor::Wsh(Wsh::new(miniscript).expect("a valid descriptor"))
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
|
@ -244,7 +258,7 @@ pub trait GetNetwork {
|
|||
}
|
||||
|
||||
pub fn recover(S: PublicKey, sig: Signature, encsig: EncryptedSignature) -> Result<SecretKey> {
|
||||
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
||||
let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default();
|
||||
|
||||
let s = adaptor
|
||||
.recover_decryption_key(&S.0, &sig, &encsig)
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::bitcoin::{
|
|||
use ::bitcoin::{util::bip143::SigHashCache, OutPoint, SigHash, SigHashType, TxIn, TxOut, Txid};
|
||||
use anyhow::Result;
|
||||
use ecdsa_fun::Signature;
|
||||
use miniscript::{Descriptor, NullCtx};
|
||||
use miniscript::{Descriptor, DescriptorTrait};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::{collections::HashMap, ops::Add};
|
||||
|
||||
|
@ -78,7 +78,7 @@ impl TxCancel {
|
|||
|
||||
let tx_out = TxOut {
|
||||
value: tx_lock.lock_amount().as_sat() - TX_FEE,
|
||||
script_pubkey: cancel_output_descriptor.script_pubkey(NullCtx),
|
||||
script_pubkey: cancel_output_descriptor.script_pubkey(),
|
||||
};
|
||||
|
||||
let transaction = Transaction {
|
||||
|
@ -90,7 +90,7 @@ impl TxCancel {
|
|||
|
||||
let digest = SigHashCache::new(&transaction).signature_hash(
|
||||
0, // Only one input: lock_input (lock transaction)
|
||||
&tx_lock.output_descriptor.witness_script(NullCtx),
|
||||
&tx_lock.output_descriptor.script_code(),
|
||||
tx_lock.lock_amount().as_sat(),
|
||||
SigHashType::All,
|
||||
);
|
||||
|
@ -146,7 +146,7 @@ impl TxCancel {
|
|||
let mut tx_cancel = self.inner;
|
||||
tx_lock
|
||||
.output_descriptor
|
||||
.satisfy(&mut tx_cancel.input[0], satisfier, NullCtx)?;
|
||||
.satisfy(&mut tx_cancel.input[0], satisfier)?;
|
||||
|
||||
Ok(tx_cancel)
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::bitcoin::{
|
|||
};
|
||||
use ::bitcoin::{util::psbt::PartiallySignedTransaction, OutPoint, TxIn, TxOut, Txid};
|
||||
use anyhow::Result;
|
||||
use miniscript::{Descriptor, NullCtx};
|
||||
use miniscript::{Descriptor, DescriptorTrait};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
|
||||
|
@ -20,7 +20,7 @@ impl TxLock {
|
|||
{
|
||||
let lock_output_descriptor = build_shared_output_descriptor(A.0, B.0);
|
||||
let address = lock_output_descriptor
|
||||
.address(wallet.get_network().await, NullCtx)
|
||||
.address(wallet.get_network().await)
|
||||
.expect("can derive address from descriptor");
|
||||
|
||||
let psbt = wallet.build_tx_lock_psbt(address, amount).await?;
|
||||
|
@ -54,9 +54,7 @@ impl TxLock {
|
|||
.extract_tx()
|
||||
.output
|
||||
.iter()
|
||||
.position(|output| {
|
||||
output.script_pubkey == self.output_descriptor.script_pubkey(NullCtx)
|
||||
})
|
||||
.position(|output| output.script_pubkey == self.output_descriptor.script_pubkey())
|
||||
.expect("transaction contains lock output")
|
||||
}
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@ use crate::bitcoin::{Address, PublicKey, PunishTimelock, Transaction, TxCancel};
|
|||
use ::bitcoin::{util::bip143::SigHashCache, SigHash, SigHashType};
|
||||
use anyhow::Result;
|
||||
use ecdsa_fun::Signature;
|
||||
use miniscript::NullCtx;
|
||||
use miniscript::DescriptorTrait;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -21,7 +21,7 @@ impl TxPunish {
|
|||
|
||||
let digest = SigHashCache::new(&tx_punish).signature_hash(
|
||||
0, // Only one input: cancel transaction
|
||||
&tx_cancel.output_descriptor.witness_script(NullCtx),
|
||||
&tx_cancel.output_descriptor.script_code(),
|
||||
tx_cancel.amount().as_sat(),
|
||||
SigHashType::All,
|
||||
);
|
||||
|
@ -64,7 +64,7 @@ impl TxPunish {
|
|||
let mut tx_punish = self.inner;
|
||||
tx_cancel
|
||||
.output_descriptor
|
||||
.satisfy(&mut tx_punish.input[0], satisfier, NullCtx)?;
|
||||
.satisfy(&mut tx_punish.input[0], satisfier)?;
|
||||
|
||||
Ok(tx_punish)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::bitcoin::{
|
|||
use ::bitcoin::{util::bip143::SigHashCache, SigHash, SigHashType, Txid};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use ecdsa_fun::Signature;
|
||||
use miniscript::NullCtx;
|
||||
use miniscript::DescriptorTrait;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -22,7 +22,7 @@ impl TxRedeem {
|
|||
|
||||
let digest = SigHashCache::new(&tx_redeem).signature_hash(
|
||||
0, // Only one input: lock_input (lock transaction)
|
||||
&tx_lock.output_descriptor.witness_script(NullCtx),
|
||||
&tx_lock.output_descriptor.script_code(),
|
||||
tx_lock.lock_amount().as_sat(),
|
||||
SigHashType::All,
|
||||
);
|
||||
|
@ -69,7 +69,7 @@ impl TxRedeem {
|
|||
let mut tx_redeem = self.inner;
|
||||
tx_lock
|
||||
.output_descriptor
|
||||
.satisfy(&mut tx_redeem.input[0], satisfier, NullCtx)?;
|
||||
.satisfy(&mut tx_redeem.input[0], satisfier)?;
|
||||
|
||||
Ok(tx_redeem)
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::bitcoin::{
|
|||
use ::bitcoin::{util::bip143::SigHashCache, SigHash, SigHashType, Txid};
|
||||
use anyhow::{bail, Context, Result};
|
||||
use ecdsa_fun::Signature;
|
||||
use miniscript::NullCtx;
|
||||
use miniscript::DescriptorTrait;
|
||||
use std::collections::HashMap;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -20,7 +20,7 @@ impl TxRefund {
|
|||
|
||||
let digest = SigHashCache::new(&tx_punish).signature_hash(
|
||||
0, // Only one input: cancel transaction
|
||||
&tx_cancel.output_descriptor.witness_script(NullCtx),
|
||||
&tx_cancel.output_descriptor.script_code(),
|
||||
tx_cancel.amount().as_sat(),
|
||||
SigHashType::All,
|
||||
);
|
||||
|
@ -67,7 +67,7 @@ impl TxRefund {
|
|||
let mut tx_refund = self.inner;
|
||||
tx_cancel
|
||||
.output_descriptor
|
||||
.satisfy(&mut tx_refund.input[0], satisfier, NullCtx)?;
|
||||
.satisfy(&mut tx_refund.input[0], satisfier)?;
|
||||
|
||||
Ok(tx_refund)
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ use crate::{
|
|||
use ::bitcoin::{util::psbt::PartiallySignedTransaction, Txid};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use async_trait::async_trait;
|
||||
use backoff::{backoff::Constant as ConstantBackoff, tokio::retry};
|
||||
use backoff::{backoff::Constant as ConstantBackoff, future::retry};
|
||||
use bdk::{
|
||||
blockchain::{noop_progress, Blockchain, ElectrumBlockchain},
|
||||
electrum_client::{self, Client, ElectrumApi},
|
||||
|
@ -125,14 +125,12 @@ impl BuildTxLockPsbt for Wallet {
|
|||
output_amount: Amount,
|
||||
) -> Result<PartiallySignedTransaction> {
|
||||
tracing::debug!("building tx lock");
|
||||
let (psbt, _details) = self.inner.lock().await.create_tx(
|
||||
bdk::TxBuilder::with_recipients(vec![(
|
||||
output_address.script_pubkey(),
|
||||
output_amount.as_sat(),
|
||||
)])
|
||||
// todo: get actual fee
|
||||
.fee_rate(FeeRate::from_sat_per_vb(5.0)),
|
||||
)?;
|
||||
let wallet = self.inner.lock().await;
|
||||
|
||||
let mut tx_builder = wallet.build_tx();
|
||||
tx_builder.add_recipient(output_address.script_pubkey(), output_amount.as_sat());
|
||||
tx_builder.fee_rate(FeeRate::from_sat_per_vb(5.0)); // todo: get actual fee
|
||||
let (psbt, _details) = tx_builder.finish()?;
|
||||
tracing::debug!("tx lock built");
|
||||
Ok(psbt)
|
||||
}
|
||||
|
|
|
@ -27,5 +27,6 @@ pub mod protocol;
|
|||
pub mod seed;
|
||||
pub mod trace;
|
||||
|
||||
mod monero_ext;
|
||||
mod network;
|
||||
mod serde_peer_id;
|
||||
|
|
|
@ -5,7 +5,7 @@ use crate::monero::{
|
|||
use ::monero::{Address, Network, PrivateKey, PublicKey};
|
||||
use anyhow::Result;
|
||||
use async_trait::async_trait;
|
||||
use backoff::{backoff::Constant as ConstantBackoff, tokio::retry};
|
||||
use backoff::{backoff::Constant as ConstantBackoff, future::retry};
|
||||
use bitcoin::hashes::core::sync::atomic::AtomicU32;
|
||||
use monero_harness::rpc::wallet;
|
||||
use std::{
|
||||
|
|
20
swap/src/monero_ext.rs
Normal file
20
swap/src/monero_ext.rs
Normal file
|
@ -0,0 +1,20 @@
|
|||
use crate::bitcoin::Scalar;
|
||||
use ecdsa_fun::fun::marker::{Mark, NonZero, Secret};
|
||||
|
||||
pub trait ScalarExt {
|
||||
fn to_secpfun_scalar(&self) -> ecdsa_fun::fun::Scalar;
|
||||
}
|
||||
|
||||
impl ScalarExt for crate::monero::Scalar {
|
||||
fn to_secpfun_scalar(&self) -> Scalar<Secret, NonZero> {
|
||||
let mut little_endian_bytes = self.to_bytes();
|
||||
|
||||
little_endian_bytes.reverse();
|
||||
let big_endian_bytes = little_endian_bytes;
|
||||
|
||||
ecdsa_fun::fun::Scalar::from_bytes(big_endian_bytes)
|
||||
.expect("valid scalar")
|
||||
.mark::<NonZero>()
|
||||
.expect("non-zero scalar")
|
||||
}
|
||||
}
|
|
@ -1,6 +1,20 @@
|
|||
use conquer_once::Lazy;
|
||||
use ecdsa_fun::fun::marker::Mark;
|
||||
use sha2::Sha256;
|
||||
use sigma_fun::{ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQ, HashTranscript};
|
||||
|
||||
pub mod alice;
|
||||
pub mod bob;
|
||||
|
||||
pub static CROSS_CURVE_PROOF_SYSTEM: Lazy<
|
||||
CrossCurveDLEQ<HashTranscript<Sha256, rand_chacha::ChaCha20Rng>>,
|
||||
> = Lazy::new(|| {
|
||||
CrossCurveDLEQ::<HashTranscript<Sha256, rand_chacha::ChaCha20Rng>>::new(
|
||||
(*ecdsa_fun::fun::G).mark::<ecdsa_fun::fun::marker::Normal>(),
|
||||
curve25519_dalek::constants::ED25519_BASEPOINT_POINT,
|
||||
)
|
||||
});
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct StartingBalances {
|
||||
pub xmr: crate::monero::Amount,
|
||||
|
|
|
@ -12,13 +12,14 @@ use anyhow::{Context, Error};
|
|||
use libp2p::PeerId;
|
||||
use libp2p_async_await::BehaviourOutEvent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Message1 {
|
||||
pub(crate) A: bitcoin::PublicKey,
|
||||
pub(crate) S_a_monero: monero::PublicKey,
|
||||
pub(crate) S_a_bitcoin: bitcoin::PublicKey,
|
||||
pub(crate) dleq_proof_s_a: cross_curve_dleq::Proof,
|
||||
pub(crate) dleq_proof_s_a: CrossCurveDLEQProof,
|
||||
pub(crate) v_a: monero::PrivateViewKey,
|
||||
pub(crate) redeem_address: bitcoin::Address,
|
||||
pub(crate) punish_address: bitcoin::Address,
|
||||
|
|
|
@ -7,17 +7,23 @@ use crate::{
|
|||
},
|
||||
execution_params::ExecutionParams,
|
||||
monero,
|
||||
monero_ext::ScalarExt,
|
||||
protocol::{
|
||||
alice::{Message1, Message3, TransferProof},
|
||||
bob::{EncryptedSignature, Message0, Message2, Message4},
|
||||
CROSS_CURVE_PROOF_SYSTEM,
|
||||
},
|
||||
};
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
use ecdsa_fun::{adaptor::Adaptor, nonce::Deterministic};
|
||||
use anyhow::{anyhow, bail, Context, Result};
|
||||
use ecdsa_fun::{
|
||||
adaptor::{Adaptor, HashTranscript},
|
||||
nonce::Deterministic,
|
||||
};
|
||||
use libp2p::PeerId;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::Sha256;
|
||||
use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug)]
|
||||
|
@ -80,9 +86,11 @@ impl fmt::Display for AliceState {
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
||||
pub struct State0 {
|
||||
pub a: bitcoin::SecretKey,
|
||||
pub s_a: cross_curve_dleq::Scalar,
|
||||
pub s_a: monero::Scalar,
|
||||
pub v_a: monero::PrivateViewKey,
|
||||
pub dleq_proof_s_a: cross_curve_dleq::Proof,
|
||||
pub(crate) S_a_monero: monero::PublicKey,
|
||||
pub(crate) S_a_bitcoin: bitcoin::PublicKey,
|
||||
pub dleq_proof_s_a: CrossCurveDLEQProof,
|
||||
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
||||
pub btc: bitcoin::Amount,
|
||||
pub xmr: monero::Amount,
|
||||
|
@ -104,16 +112,21 @@ impl State0 {
|
|||
R: RngCore + CryptoRng,
|
||||
{
|
||||
let a = bitcoin::SecretKey::new_random(rng);
|
||||
let s_a = cross_curve_dleq::Scalar::random(rng);
|
||||
let v_a = monero::PrivateViewKey::new_random(rng);
|
||||
let redeem_address = bitcoin_wallet.new_address().await?;
|
||||
let punish_address = redeem_address.clone();
|
||||
let dleq_proof_s_a = cross_curve_dleq::Proof::new(rng, &s_a);
|
||||
|
||||
let s_a = monero::Scalar::random(rng);
|
||||
let (dleq_proof_s_a, (S_a_bitcoin, S_a_monero)) = CROSS_CURVE_PROOF_SYSTEM.prove(&s_a, rng);
|
||||
|
||||
Ok(Self {
|
||||
a,
|
||||
s_a,
|
||||
v_a,
|
||||
S_a_bitcoin: S_a_bitcoin.into(),
|
||||
S_a_monero: monero::PublicKey {
|
||||
point: S_a_monero.compress(),
|
||||
},
|
||||
dleq_proof_s_a,
|
||||
redeem_address,
|
||||
punish_address,
|
||||
|
@ -125,13 +138,20 @@ impl State0 {
|
|||
}
|
||||
|
||||
pub fn receive(self, msg: Message0) -> Result<State1> {
|
||||
msg.dleq_proof_s_b.verify(
|
||||
msg.S_b_bitcoin.clone().into(),
|
||||
msg.S_b_monero
|
||||
.point
|
||||
.decompress()
|
||||
.ok_or_else(|| anyhow!("S_b is not a monero curve point"))?,
|
||||
)?;
|
||||
let valid = CROSS_CURVE_PROOF_SYSTEM.verify(
|
||||
&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")
|
||||
}
|
||||
|
||||
let v = self.v_a + msg.v_b;
|
||||
|
||||
|
@ -139,6 +159,8 @@ impl State0 {
|
|||
a: self.a,
|
||||
B: msg.B,
|
||||
s_a: self.s_a,
|
||||
S_a_monero: self.S_a_monero,
|
||||
S_a_bitcoin: self.S_a_bitcoin,
|
||||
S_b_monero: msg.S_b_monero,
|
||||
S_b_bitcoin: msg.S_b_bitcoin,
|
||||
v,
|
||||
|
@ -159,12 +181,14 @@ impl State0 {
|
|||
pub struct State1 {
|
||||
a: bitcoin::SecretKey,
|
||||
B: bitcoin::PublicKey,
|
||||
s_a: cross_curve_dleq::Scalar,
|
||||
s_a: monero::Scalar,
|
||||
S_a_monero: monero::PublicKey,
|
||||
S_a_bitcoin: bitcoin::PublicKey,
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
v_a: monero::PrivateViewKey,
|
||||
dleq_proof_s_a: cross_curve_dleq::Proof,
|
||||
dleq_proof_s_a: CrossCurveDLEQProof,
|
||||
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
||||
btc: bitcoin::Amount,
|
||||
xmr: monero::Amount,
|
||||
|
@ -179,10 +203,8 @@ impl State1 {
|
|||
pub fn next_message(&self) -> Message1 {
|
||||
Message1 {
|
||||
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(),
|
||||
S_a_monero: self.S_a_monero,
|
||||
S_a_bitcoin: self.S_a_bitcoin,
|
||||
dleq_proof_s_a: self.dleq_proof_s_a.clone(),
|
||||
v_a: self.v_a,
|
||||
redeem_address: self.redeem_address.clone(),
|
||||
|
@ -214,7 +236,7 @@ impl State1 {
|
|||
pub struct State2 {
|
||||
a: bitcoin::SecretKey,
|
||||
B: bitcoin::PublicKey,
|
||||
s_a: cross_curve_dleq::Scalar,
|
||||
s_a: monero::Scalar,
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
|
@ -284,7 +306,7 @@ impl State2 {
|
|||
pub struct State3 {
|
||||
pub a: bitcoin::SecretKey,
|
||||
pub B: bitcoin::PublicKey,
|
||||
pub s_a: cross_curve_dleq::Scalar,
|
||||
pub s_a: monero::Scalar,
|
||||
pub S_b_monero: monero::PublicKey,
|
||||
pub S_b_bitcoin: bitcoin::PublicKey,
|
||||
pub v: monero::PrivateViewKey,
|
||||
|
@ -332,7 +354,7 @@ impl State3 {
|
|||
pub struct State4 {
|
||||
a: bitcoin::SecretKey,
|
||||
B: bitcoin::PublicKey,
|
||||
s_a: cross_curve_dleq::Scalar,
|
||||
s_a: monero::Scalar,
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
|
@ -352,9 +374,7 @@ impl State4 {
|
|||
where
|
||||
W: monero::Transfer,
|
||||
{
|
||||
let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey {
|
||||
scalar: self.s_a.into_ed25519(),
|
||||
});
|
||||
let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: self.s_a });
|
||||
let S_b = self.S_b_monero;
|
||||
|
||||
let (tx_lock_proof, fee) = monero_wallet
|
||||
|
@ -425,7 +445,7 @@ impl State4 {
|
|||
pub struct State5 {
|
||||
a: bitcoin::SecretKey,
|
||||
B: bitcoin::PublicKey,
|
||||
s_a: cross_curve_dleq::Scalar,
|
||||
s_a: monero::Scalar,
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
|
@ -475,7 +495,7 @@ impl State5 {
|
|||
pub struct State6 {
|
||||
a: bitcoin::SecretKey,
|
||||
B: bitcoin::PublicKey,
|
||||
s_a: cross_curve_dleq::Scalar,
|
||||
s_a: monero::Scalar,
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
|
@ -496,13 +516,13 @@ impl State6 {
|
|||
&self,
|
||||
bitcoin_wallet: &W,
|
||||
) -> Result<()> {
|
||||
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
||||
let adaptor = Adaptor::<HashTranscript<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());
|
||||
adaptor.decrypt_signature(&self.s_a.to_secpfun_scalar(), self.tx_redeem_encsig.clone());
|
||||
|
||||
let sig_tx_redeem =
|
||||
tx_redeem.add_signatures(&self.tx_lock, (self.a.public(), sig_a), (self.B, sig_b))?;
|
||||
|
|
|
@ -15,7 +15,10 @@ use crate::{
|
|||
},
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
use ecdsa_fun::{adaptor::Adaptor, nonce::Deterministic};
|
||||
use ecdsa_fun::{
|
||||
adaptor::{Adaptor, HashTranscript},
|
||||
nonce::Deterministic,
|
||||
};
|
||||
use futures::{
|
||||
future::{select, Either},
|
||||
pin_mut,
|
||||
|
@ -61,9 +64,7 @@ pub async fn lock_xmr<W>(
|
|||
where
|
||||
W: Transfer,
|
||||
{
|
||||
let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey {
|
||||
scalar: state3.s_a.into_ed25519(),
|
||||
});
|
||||
let S_a = monero::PublicKey::from_private_key(&monero::PrivateKey { scalar: state3.s_a });
|
||||
|
||||
let public_spend_key = S_a + state3.S_b_monero;
|
||||
let public_view_key = state3.v.public();
|
||||
|
@ -103,24 +104,24 @@ pub fn build_bitcoin_redeem_transaction(
|
|||
encrypted_signature: EncryptedSignature,
|
||||
tx_lock: &TxLock,
|
||||
a: bitcoin::SecretKey,
|
||||
s_a: cross_curve_dleq::Scalar,
|
||||
s_a: ecdsa_fun::fun::Scalar,
|
||||
B: bitcoin::PublicKey,
|
||||
redeem_address: &bitcoin::Address,
|
||||
) -> Result<bitcoin::Transaction> {
|
||||
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
||||
let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default();
|
||||
|
||||
let tx_redeem = bitcoin::TxRedeem::new(tx_lock, redeem_address);
|
||||
|
||||
bitcoin::verify_encsig(
|
||||
B,
|
||||
s_a.into_secp256k1().into(),
|
||||
bitcoin::PublicKey::from(s_a.clone()),
|
||||
&tx_redeem.digest(),
|
||||
&encrypted_signature,
|
||||
)
|
||||
.context("Invalid encrypted signature received")?;
|
||||
|
||||
let sig_a = a.sign(tx_redeem.digest());
|
||||
let sig_b = adaptor.decrypt_signature(&s_a.into_secp256k1(), encrypted_signature);
|
||||
let sig_b = adaptor.decrypt_signature(&s_a, encrypted_signature);
|
||||
|
||||
let tx = tx_redeem
|
||||
.add_signatures(&tx_lock, (a.public(), sig_a), (B, sig_b))
|
||||
|
@ -224,13 +225,11 @@ where
|
|||
pub fn extract_monero_private_key(
|
||||
published_refund_tx: bitcoin::Transaction,
|
||||
tx_refund: TxRefund,
|
||||
s_a: cross_curve_dleq::Scalar,
|
||||
s_a: monero::Scalar,
|
||||
a: bitcoin::SecretKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
) -> Result<monero::PrivateKey> {
|
||||
let s_a = monero::PrivateKey {
|
||||
scalar: s_a.into_ed25519(),
|
||||
};
|
||||
let s_a = monero::PrivateKey { scalar: s_a };
|
||||
|
||||
let tx_refund_sig = tx_refund
|
||||
.extract_signature_by_key(published_refund_tx, a.public())
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
|||
execution_params::ExecutionParams,
|
||||
monero,
|
||||
monero::CreateWalletForOutput,
|
||||
monero_ext::ScalarExt,
|
||||
protocol::{
|
||||
alice,
|
||||
alice::{
|
||||
|
@ -199,7 +200,7 @@ async fn run_until_internal(
|
|||
*encrypted_signature,
|
||||
&state3.tx_lock,
|
||||
state3.a.clone(),
|
||||
state3.s_a,
|
||||
state3.s_a.to_secpfun_scalar(),
|
||||
state3.B,
|
||||
&state3.redeem_address,
|
||||
) {
|
||||
|
|
|
@ -10,6 +10,7 @@ use anyhow::{Context, Error, Result};
|
|||
use libp2p::PeerId;
|
||||
use libp2p_async_await::BehaviourOutEvent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof;
|
||||
use std::sync::Arc;
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
|
@ -17,7 +18,7 @@ pub struct Message0 {
|
|||
pub(crate) B: crate::bitcoin::PublicKey,
|
||||
pub(crate) S_b_monero: monero::PublicKey,
|
||||
pub(crate) S_b_bitcoin: crate::bitcoin::PublicKey,
|
||||
pub(crate) dleq_proof_s_b: cross_curve_dleq::Proof,
|
||||
pub(crate) dleq_proof_s_b: CrossCurveDLEQProof,
|
||||
pub(crate) v_b: crate::monero::PrivateViewKey,
|
||||
pub(crate) refund_address: bitcoin::Address,
|
||||
}
|
||||
|
|
|
@ -8,17 +8,24 @@ use crate::{
|
|||
execution_params::ExecutionParams,
|
||||
monero,
|
||||
monero::{monero_private_key, InsufficientFunds, TransferProof},
|
||||
monero_ext::ScalarExt,
|
||||
protocol::{
|
||||
alice::{Message1, Message3},
|
||||
bob::{EncryptedSignature, Message0, Message2, Message4},
|
||||
CROSS_CURVE_PROOF_SYSTEM,
|
||||
},
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use ecdsa_fun::{adaptor::Adaptor, nonce::Deterministic, Signature};
|
||||
use anyhow::{anyhow, bail, Result};
|
||||
use ecdsa_fun::{
|
||||
adaptor::{Adaptor, HashTranscript},
|
||||
nonce::Deterministic,
|
||||
Signature,
|
||||
};
|
||||
use monero_harness::rpc::wallet::BlockHeight;
|
||||
use rand::{CryptoRng, RngCore};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use sha2::Sha256;
|
||||
use sigma_fun::ext::dl_secp256k1_ed25519_eq::CrossCurveDLEQProof;
|
||||
use std::fmt;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -73,9 +80,11 @@ impl fmt::Display for BobState {
|
|||
#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
|
||||
pub struct State0 {
|
||||
b: bitcoin::SecretKey,
|
||||
s_b: cross_curve_dleq::Scalar,
|
||||
s_b: monero::Scalar,
|
||||
S_b_monero: monero::PublicKey,
|
||||
S_b_bitcoin: bitcoin::PublicKey,
|
||||
v_b: monero::PrivateViewKey,
|
||||
dleq_proof_s_b: cross_curve_dleq::Proof,
|
||||
dleq_proof_s_b: CrossCurveDLEQProof,
|
||||
#[serde(with = "::bitcoin::util::amount::serde::as_sat")]
|
||||
btc: bitcoin::Amount,
|
||||
xmr: monero::Amount,
|
||||
|
@ -97,14 +106,19 @@ impl State0 {
|
|||
) -> Self {
|
||||
let b = bitcoin::SecretKey::new_random(rng);
|
||||
|
||||
let s_b = cross_curve_dleq::Scalar::random(rng);
|
||||
let s_b = monero::Scalar::random(rng);
|
||||
let v_b = monero::PrivateViewKey::new_random(rng);
|
||||
let dleq_proof_s_b = cross_curve_dleq::Proof::new(rng, &s_b);
|
||||
|
||||
let (dleq_proof_s_b, (S_b_bitcoin, S_b_monero)) = CROSS_CURVE_PROOF_SYSTEM.prove(&s_b, rng);
|
||||
|
||||
Self {
|
||||
b,
|
||||
s_b,
|
||||
v_b,
|
||||
S_b_bitcoin: bitcoin::PublicKey::from(S_b_bitcoin),
|
||||
S_b_monero: monero::PublicKey {
|
||||
point: S_b_monero.compress(),
|
||||
},
|
||||
btc,
|
||||
xmr,
|
||||
dleq_proof_s_b,
|
||||
|
@ -118,10 +132,8 @@ impl State0 {
|
|||
pub fn next_message(&self) -> Message0 {
|
||||
Message0 {
|
||||
B: self.b.public(),
|
||||
S_b_monero: monero::PublicKey::from_private_key(&monero::PrivateKey {
|
||||
scalar: self.s_b.into_ed25519(),
|
||||
}),
|
||||
S_b_bitcoin: self.s_b.into_secp256k1().into(),
|
||||
S_b_monero: self.S_b_monero,
|
||||
S_b_bitcoin: self.S_b_bitcoin,
|
||||
dleq_proof_s_b: self.dleq_proof_s_b.clone(),
|
||||
v_b: self.v_b,
|
||||
refund_address: self.refund_address.clone(),
|
||||
|
@ -132,13 +144,20 @@ impl State0 {
|
|||
where
|
||||
W: BuildTxLockPsbt + GetNetwork,
|
||||
{
|
||||
msg.dleq_proof_s_a.verify(
|
||||
msg.S_a_bitcoin.clone().into(),
|
||||
msg.S_a_monero
|
||||
.point
|
||||
.decompress()
|
||||
.ok_or_else(|| anyhow!("S_a is not a monero curve point"))?,
|
||||
)?;
|
||||
let valid = CROSS_CURVE_PROOF_SYSTEM.verify(
|
||||
&msg.dleq_proof_s_a,
|
||||
(
|
||||
msg.S_a_bitcoin.clone().into(),
|
||||
msg.S_a_monero
|
||||
.point
|
||||
.decompress()
|
||||
.ok_or_else(|| anyhow!("S_a is not a monero curve point"))?,
|
||||
),
|
||||
);
|
||||
|
||||
if !valid {
|
||||
bail!("Alice's dleq proof doesn't verify")
|
||||
}
|
||||
|
||||
let tx_lock = bitcoin::TxLock::new(wallet, self.btc, msg.A, self.b.public()).await?;
|
||||
let v = msg.v_a + self.v_b;
|
||||
|
@ -166,7 +185,7 @@ impl State0 {
|
|||
pub struct State1 {
|
||||
A: bitcoin::PublicKey,
|
||||
b: bitcoin::SecretKey,
|
||||
s_b: cross_curve_dleq::Scalar,
|
||||
s_b: monero::Scalar,
|
||||
S_a_monero: monero::PublicKey,
|
||||
S_a_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
|
@ -194,7 +213,7 @@ impl State1 {
|
|||
bitcoin::verify_sig(&self.A, &tx_cancel.digest(), &msg.tx_cancel_sig)?;
|
||||
bitcoin::verify_encsig(
|
||||
self.A,
|
||||
self.s_b.into_secp256k1().into(),
|
||||
bitcoin::PublicKey::from(self.s_b.to_secpfun_scalar()),
|
||||
&tx_refund.digest(),
|
||||
&msg.tx_refund_encsig,
|
||||
)?;
|
||||
|
@ -224,7 +243,7 @@ impl State1 {
|
|||
pub struct State2 {
|
||||
A: bitcoin::PublicKey,
|
||||
b: bitcoin::SecretKey,
|
||||
s_b: cross_curve_dleq::Scalar,
|
||||
s_b: monero::Scalar,
|
||||
S_a_monero: monero::PublicKey,
|
||||
S_a_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
|
@ -289,7 +308,7 @@ impl State2 {
|
|||
pub struct State3 {
|
||||
A: bitcoin::PublicKey,
|
||||
b: bitcoin::SecretKey,
|
||||
s_b: cross_curve_dleq::Scalar,
|
||||
s_b: monero::Scalar,
|
||||
S_a_monero: monero::PublicKey,
|
||||
S_a_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
|
@ -314,9 +333,8 @@ impl State3 {
|
|||
where
|
||||
W: monero::WatchForTransfer,
|
||||
{
|
||||
let S_b_monero = monero::PublicKey::from_private_key(&monero::PrivateKey::from_scalar(
|
||||
self.s_b.into_ed25519(),
|
||||
));
|
||||
let S_b_monero =
|
||||
monero::PublicKey::from_private_key(&monero::PrivateKey::from_scalar(self.s_b));
|
||||
let S = self.S_a_monero + S_b_monero;
|
||||
|
||||
if let Err(e) = xmr_wallet
|
||||
|
@ -401,7 +419,7 @@ impl State3 {
|
|||
pub struct State4 {
|
||||
A: bitcoin::PublicKey,
|
||||
b: bitcoin::SecretKey,
|
||||
s_b: cross_curve_dleq::Scalar,
|
||||
s_b: monero::Scalar,
|
||||
S_a_bitcoin: bitcoin::PublicKey,
|
||||
v: monero::PrivateViewKey,
|
||||
cancel_timelock: CancelTimelock,
|
||||
|
@ -536,11 +554,11 @@ impl State4 {
|
|||
bitcoin::TxCancel::new(&self.tx_lock, self.cancel_timelock, self.A, self.b.public());
|
||||
let tx_refund = bitcoin::TxRefund::new(&tx_cancel, &self.refund_address);
|
||||
|
||||
let adaptor = Adaptor::<Sha256, Deterministic<Sha256>>::default();
|
||||
let adaptor = Adaptor::<HashTranscript<Sha256>, Deterministic<Sha256>>::default();
|
||||
|
||||
let sig_b = self.b.sign(tx_refund.digest());
|
||||
let sig_a =
|
||||
adaptor.decrypt_signature(&self.s_b.into_secp256k1(), self.tx_refund_encsig.clone());
|
||||
adaptor.decrypt_signature(&self.s_b.to_secpfun_scalar(), self.tx_refund_encsig.clone());
|
||||
|
||||
let signed_tx_refund = tx_refund.add_signatures(
|
||||
&tx_cancel.clone(),
|
||||
|
@ -568,7 +586,7 @@ impl State4 {
|
|||
pub struct State5 {
|
||||
#[serde(with = "monero_private_key")]
|
||||
s_a: monero::PrivateKey,
|
||||
s_b: cross_curve_dleq::Scalar,
|
||||
s_b: monero::Scalar,
|
||||
v: monero::PrivateViewKey,
|
||||
tx_lock: bitcoin::TxLock,
|
||||
monero_wallet_restore_blockheight: u32,
|
||||
|
@ -579,9 +597,7 @@ impl State5 {
|
|||
where
|
||||
W: monero::CreateWalletForOutput,
|
||||
{
|
||||
let s_b = monero::PrivateKey {
|
||||
scalar: self.s_b.into_ed25519(),
|
||||
};
|
||||
let s_b = monero::PrivateKey { scalar: self.s_b };
|
||||
|
||||
let s = self.s_a + s_b;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue