#[cfg(any(feature = "std", not(feature = "no-std")))]
use std::collections::BTreeMap;
#[cfg(all(feature = "no-std", not(feature = "std")))]
use alloc::collections::BTreeMap;
use crate::{signatures_to_secret, util::get_sig_hash_msg, DlcTransactions, PartyParams, Payout};
use super::Error;
use bitcoin::{
absolute::LockTime, ecdsa::Signature, sighash::EcdsaSighashType, Address, Amount, OutPoint,
PublicKey, Script, ScriptBuf, Sequence, Transaction, TxIn, TxOut, Witness,
};
use miniscript::Descriptor;
use secp256k1_zkp::{
schnorr::Signature as SchnorrSignature, EcdsaAdaptorSignature, PublicKey as SecpPublicKey,
Secp256k1, SecretKey, Signing, Verification,
};
use std::iter::FromIterator;
const BUFFER_TX_WEIGHT: usize = 599;
const CET_EXTRA_WEIGHT: usize = 330;
const SETTLE_INPUT_WEIGHT: usize = 428;
const SETTLE_OUTPUT_WEIGHT: usize = 172;
const PUNISH_BUFFER_INPUT_WEIGHT: usize = 758;
const PUNISH_SETTLE_INPUT_WEIGHT: usize = 575;
const N_VALUE_WEIGHT: usize = 8 * 4;
#[derive(Clone, Debug)]
pub struct RevokeParams {
pub own_pk: PublicKey,
pub publish_pk: PublicKey,
pub revoke_pk: PublicKey,
}
pub struct DlcChannelTransactions {
pub dlc_transactions: DlcTransactions,
pub buffer_transaction: Transaction,
pub buffer_script_pubkey: ScriptBuf,
}
pub fn create_buffer_transaction(
fund_tx_in: &TxIn,
descriptor: &Descriptor<PublicKey>,
total_collateral: Amount,
lock_time: u32,
) -> Transaction {
Transaction {
version: super::TX_VERSION,
lock_time: LockTime::from_consensus(lock_time),
input: vec![fund_tx_in.clone()],
output: vec![TxOut {
value: total_collateral,
script_pubkey: descriptor.script_pubkey(),
}],
}
}
pub fn get_tx_adaptor_signature<C: Signing>(
secp: &Secp256k1<C>,
tx: &Transaction,
input_value: Amount,
script_pubkey: &Script,
own_fund_sk: &SecretKey,
other_publish_key: &SecpPublicKey,
) -> Result<EcdsaAdaptorSignature, Error> {
let sighash = get_sig_hash_msg(tx, 0, script_pubkey, input_value)?;
#[cfg(feature = "std")]
let res = EcdsaAdaptorSignature::encrypt(secp, &sighash, own_fund_sk, other_publish_key);
#[cfg(not(feature = "std"))]
let res =
EcdsaAdaptorSignature::encrypt_no_aux_rand(secp, &sighash, own_fund_sk, other_publish_key);
Ok(res)
}
pub fn verify_tx_adaptor_signature<C: Verification>(
secp: &Secp256k1<C>,
tx: &Transaction,
input_value: Amount,
script_pubkey: &Script,
other_fund_pk: &SecpPublicKey,
own_publish_key: &SecpPublicKey,
adaptor_sig: &EcdsaAdaptorSignature,
) -> Result<(), Error> {
let sighash = get_sig_hash_msg(tx, 0, script_pubkey, input_value)?;
adaptor_sig.verify(secp, &sighash, other_fund_pk, own_publish_key)?;
Ok(())
}
pub fn create_settle_transaction(
fund_tx_in: &TxIn,
offer_revoke_params: &RevokeParams,
accept_revoke_params: &RevokeParams,
offer_payout: Amount,
accept_payout: Amount,
csv_timelock: u32,
lock_time: u32,
fund_output_value: Amount,
fee_rate_per_vb: u64,
) -> Result<Transaction, Error> {
let offer_descriptor = settle_descriptor(
offer_revoke_params,
&accept_revoke_params.own_pk,
csv_timelock,
);
let accept_descriptor = settle_descriptor(
accept_revoke_params,
&offer_revoke_params.own_pk,
csv_timelock,
);
let mut output = crate::util::discard_dust(
vec![
TxOut {
value: offer_payout,
script_pubkey: offer_descriptor.script_pubkey(),
},
TxOut {
value: accept_payout,
script_pubkey: accept_descriptor.script_pubkey(),
},
],
crate::DUST_LIMIT,
);
let remaining_fee = (fund_output_value
- offer_payout
- accept_payout
- crate::util::weight_to_fee(
SETTLE_INPUT_WEIGHT + output.len() * SETTLE_OUTPUT_WEIGHT,
fee_rate_per_vb,
)?)
/ (output.len() as u64);
for o in &mut output {
o.value += remaining_fee;
}
Ok(Transaction {
version: super::TX_VERSION,
lock_time: LockTime::from_consensus(lock_time),
input: vec![fund_tx_in.clone()],
output,
})
}
pub fn create_channel_transactions(
offer_params: &PartyParams,
accept_params: &PartyParams,
offer_revoke_params: &RevokeParams,
accept_revoke_params: &RevokeParams,
payouts: &[Payout],
refund_lock_time: u32,
fee_rate_per_vb: u64,
fund_lock_time: u32,
cet_lock_time: u32,
fund_output_serial_id: u64,
cet_nsequence: Sequence,
) -> Result<DlcChannelTransactions, Error> {
let extra_fee =
super::util::weight_to_fee(BUFFER_TX_WEIGHT + CET_EXTRA_WEIGHT, fee_rate_per_vb)?;
let (fund, funding_script_pubkey) = super::create_fund_transaction_with_fees(
offer_params,
accept_params,
fee_rate_per_vb,
fund_lock_time,
fund_output_serial_id,
extra_fee,
)?;
create_renewal_channel_transactions(
offer_params,
accept_params,
offer_revoke_params,
accept_revoke_params,
&fund,
&funding_script_pubkey,
payouts,
refund_lock_time,
fee_rate_per_vb,
cet_lock_time,
cet_nsequence,
)
}
pub fn create_renewal_channel_transactions(
offer_params: &PartyParams,
accept_params: &PartyParams,
offer_revoke_params: &RevokeParams,
accept_revoke_params: &RevokeParams,
fund_tx: &Transaction,
funding_script_pubkey: &Script,
payouts: &[Payout],
refund_lock_time: u32,
fee_rate_per_vb: u64,
cet_lock_time: u32,
cet_nsequence: Sequence,
) -> Result<DlcChannelTransactions, Error> {
let extra_fee =
super::util::weight_to_fee(BUFFER_TX_WEIGHT + CET_EXTRA_WEIGHT, fee_rate_per_vb)?;
let (fund_vout, fund_output) =
super::util::get_output_for_script_pubkey(fund_tx, &funding_script_pubkey.to_p2wsh())
.expect("to find the funding script pubkey");
let outpoint = OutPoint {
txid: fund_tx.compute_txid(),
vout: fund_vout as u32,
};
let tx_in = TxIn {
previous_output: outpoint,
sequence: super::util::get_sequence(cet_lock_time),
script_sig: ScriptBuf::default(),
witness: Witness::default(),
};
let buffer_descriptor = buffer_descriptor(offer_revoke_params, accept_revoke_params);
let buffer_transaction = create_buffer_transaction(
&tx_in,
&buffer_descriptor,
fund_output.value - extra_fee,
cet_lock_time,
);
let outpoint = OutPoint {
txid: buffer_transaction.compute_txid(),
vout: 0,
};
let (cets, refund) = super::create_cets_and_refund_tx(
offer_params,
accept_params,
outpoint,
payouts,
refund_lock_time,
cet_lock_time,
Some(cet_nsequence),
)?;
Ok(DlcChannelTransactions {
dlc_transactions: DlcTransactions {
fund: fund_tx.clone(),
cets,
refund,
funding_script_pubkey: funding_script_pubkey.to_owned(),
},
buffer_transaction,
buffer_script_pubkey: buffer_descriptor.script_code()?,
})
}
pub fn sign_cet<C: Signing>(
secp: &Secp256k1<C>,
cet: &mut Transaction,
input_amount: Amount,
offer_params: &RevokeParams,
accept_params: &RevokeParams,
own_sk: &SecretKey,
counter_pubkey: &PublicKey,
adaptor_signature: &EcdsaAdaptorSignature,
oracle_signatures: &[Vec<SchnorrSignature>],
) -> Result<(), Error> {
let adaptor_secret = signatures_to_secret(oracle_signatures)?;
let adapted_sig = adaptor_signature.decrypt(&adaptor_secret)?;
let descriptor = buffer_descriptor(offer_params, accept_params);
let own_sig = super::util::get_raw_sig_for_tx_input(
secp,
cet,
0,
&descriptor.script_code()?,
input_amount,
own_sk,
)?;
let own_pk = SecpPublicKey::from_secret_key(secp, own_sk);
let sigs = BTreeMap::from_iter([
(
PublicKey {
inner: own_pk,
compressed: true,
},
bitcoin::ecdsa::Signature {
signature: own_sig,
sighash_type: EcdsaSighashType::All,
},
),
(
*counter_pubkey,
bitcoin::ecdsa::Signature {
signature: adapted_sig,
sighash_type: EcdsaSighashType::All,
},
),
]);
descriptor
.satisfy(&mut cet.input[0], sigs)
.map_err(|_| Error::InvalidArgument)?;
Ok(())
}
pub fn create_and_sign_punish_buffer_transaction<C: Signing>(
secp: &Secp256k1<C>,
offer_params: &RevokeParams,
accept_params: &RevokeParams,
own_sk: &SecretKey,
counter_publish_sk: &SecretKey,
counter_revoke_sk: &SecretKey,
prev_tx: &Transaction,
dest_address: &Address,
lock_time: u32,
fee_rate_per_vb: u64,
) -> Result<Transaction, Error> {
let descriptor = buffer_descriptor(offer_params, accept_params);
let tx_in = TxIn {
previous_output: OutPoint {
txid: prev_tx.compute_txid(),
vout: 0,
},
sequence: Sequence::ZERO,
script_sig: ScriptBuf::default(),
witness: Witness::default(),
};
let dest_script_pk_len = dest_address.script_pubkey().len();
let var_int_prefix_len = crate::util::compute_var_int_prefix_size(dest_script_pk_len);
let output_weight = N_VALUE_WEIGHT + var_int_prefix_len + dest_script_pk_len * 4;
let tx_fee =
crate::util::weight_to_fee(PUNISH_BUFFER_INPUT_WEIGHT + output_weight, fee_rate_per_vb)?;
let output_value = prev_tx.output[0].value - tx_fee;
let mut tx = Transaction {
version: super::TX_VERSION,
lock_time: LockTime::from_consensus(lock_time),
input: vec![tx_in],
output: vec![TxOut {
value: output_value,
script_pubkey: dest_address.script_pubkey(),
}],
};
let mut sigs = BTreeMap::new();
for sk in &[&own_sk, &counter_publish_sk, &counter_revoke_sk] {
let pk = PublicKey {
inner: SecpPublicKey::from_secret_key(secp, sk),
compressed: true,
};
let pkh = pk.pubkey_hash().to_raw_hash();
sigs.insert(
pkh,
(
pk,
bitcoin::ecdsa::Signature {
signature: super::util::get_raw_sig_for_tx_input(
secp,
&tx,
0,
&descriptor.script_code()?,
prev_tx.output[0].value,
sk,
)?,
sighash_type: EcdsaSighashType::All,
},
),
);
}
descriptor
.satisfy(&mut tx.input[0], sigs)
.map_err(|_| Error::InvalidArgument)?;
Ok(tx)
}
pub fn create_and_sign_punish_settle_transaction<C: Signing>(
secp: &Secp256k1<C>,
offer_params: &RevokeParams,
accept_params: &RevokeParams,
own_sk: &SecretKey,
counter_publish_sk: &SecretKey,
counter_revoke_sk: &SecretKey,
prev_tx: &Transaction,
dest_address: &Address,
csv_timelock: u32,
lock_time: u32,
fee_rate_per_vb: u64,
is_offer: bool,
) -> Result<Transaction, Error> {
let (own_params, counter_params) = if is_offer {
(offer_params, accept_params)
} else {
(accept_params, offer_params)
};
let descriptor = settle_descriptor(counter_params, &own_params.own_pk, csv_timelock);
let vout = u32::from(is_offer);
let tx_in = TxIn {
previous_output: OutPoint {
txid: prev_tx.compute_txid(),
vout,
},
sequence: Sequence::ZERO,
script_sig: ScriptBuf::default(),
witness: Witness::default(),
};
let input_value = prev_tx.output[vout as usize].value;
let dest_script_pk_len = dest_address.script_pubkey().len();
let var_int_prefix_len = crate::util::compute_var_int_prefix_size(dest_script_pk_len);
let output_weight = N_VALUE_WEIGHT + var_int_prefix_len + dest_script_pk_len * 4;
let tx_fee =
crate::util::weight_to_fee(PUNISH_SETTLE_INPUT_WEIGHT + output_weight, fee_rate_per_vb)?;
let mut tx = Transaction {
version: super::TX_VERSION,
lock_time: LockTime::from_consensus(lock_time),
input: vec![tx_in],
output: vec![TxOut {
value: input_value - tx_fee,
script_pubkey: dest_address.script_pubkey(),
}],
};
let mut sigs = BTreeMap::new();
for sk in &[&own_sk, &counter_publish_sk, &counter_revoke_sk] {
let pk = PublicKey {
inner: SecpPublicKey::from_secret_key(secp, sk),
compressed: true,
};
sigs.insert(
pk,
Signature::sighash_all(super::util::get_raw_sig_for_tx_input(
secp,
&tx,
0,
&descriptor.script_code()?,
input_value,
sk,
)?),
);
}
descriptor
.satisfy(&mut tx.input[0], sigs)
.map_err(|_| Error::InvalidArgument)?;
Ok(tx)
}
pub fn create_collaborative_close_transaction(
offer_params: &PartyParams,
offer_payout: Amount,
accept_params: &PartyParams,
accept_payout: Amount,
fund_outpoint: OutPoint,
_fund_output_amount: Amount,
) -> Transaction {
let input = TxIn {
previous_output: fund_outpoint,
witness: Witness::default(),
script_sig: ScriptBuf::default(),
sequence: crate::util::DISABLE_LOCKTIME,
};
let offer_output = TxOut {
value: offer_payout,
script_pubkey: offer_params.payout_script_pubkey.clone(),
};
let accept_output = TxOut {
value: accept_payout,
script_pubkey: accept_params.payout_script_pubkey.clone(),
};
let mut output: Vec<TxOut> = if offer_params.payout_serial_id < accept_params.payout_serial_id {
vec![offer_output, accept_output]
} else {
vec![accept_output, offer_output]
};
output = crate::util::discard_dust(output, crate::DUST_LIMIT);
Transaction {
version: crate::TX_VERSION,
lock_time: LockTime::ZERO,
input: vec![input],
output,
}
}
pub fn buffer_descriptor(
offer_revoke_params: &RevokeParams,
accept_revoke_params: &RevokeParams,
) -> Descriptor<PublicKey> {
let offer_pk = offer_revoke_params.own_pk;
let accept_pk = accept_revoke_params.own_pk;
let accept_publish_pk = accept_revoke_params.publish_pk;
let accept_revoke_pk = accept_revoke_params.revoke_pk;
let offer_publish_pk = offer_revoke_params.publish_pk;
let offer_revoke_pk = offer_revoke_params.revoke_pk;
let (first_pk, second_pk) = if offer_pk < accept_pk {
(offer_pk, accept_pk)
} else {
(accept_pk, offer_pk)
};
let script = format!("wsh(c:andor(pk({first_pk}),pk_k({second_pk}),or_i(and_v(v:pkh({offer_pk_hash}),and_v(v:pkh({accept_publish_pk_hash}),pk_h({accept_revoke_pk_hash}))),and_v(v:pkh({accept_pk_hash}),and_v(v:pkh({offer_publish_pk_hash}),pk_h({offer_revoke_pk_hash}))))))",
first_pk = first_pk,
second_pk = second_pk,
offer_pk_hash = offer_pk,
accept_pk_hash = accept_pk,
accept_publish_pk_hash = accept_publish_pk,
accept_revoke_pk_hash = accept_revoke_pk,
offer_publish_pk_hash = offer_publish_pk,
offer_revoke_pk_hash = offer_revoke_pk);
script.parse().expect("a valid miniscript")
}
pub fn settle_descriptor(
payee_revoke_params: &RevokeParams,
counter_pk: &PublicKey,
csv_timelock: u32,
) -> Descriptor<PublicKey> {
let script = format!("wsh(andor(pk({payee_pk}),older({csv_timelock}),and_v(v:pk({counter_pk}),and_v(v:pk({payee_publish_pk}),pk({payee_revoke_pk})))))",
payee_pk = payee_revoke_params.own_pk,
csv_timelock = csv_timelock,
counter_pk = counter_pk,
payee_publish_pk = payee_revoke_params.publish_pk,
payee_revoke_pk = payee_revoke_params.revoke_pk,
);
script.parse().expect("a valid miniscript")
}
#[cfg(test)]
mod tests {
use std::{iter::FromIterator, str::FromStr};
use bitcoin::{Network, PrivateKey};
use secp256k1_zkp::{rand::thread_rng, SECP256K1};
use super::*;
const FEE_RATE_PER_VB: u64 = 2;
struct RevokePrivateParams {
pub own_priv: PrivateKey,
pub publish_priv: PrivateKey,
pub revoke_priv: PrivateKey,
}
impl RevokePrivateParams {
fn new(network: Network) -> Self {
Self {
own_priv: PrivateKey::new(SecretKey::new(&mut thread_rng()), network),
publish_priv: PrivateKey::new(SecretKey::new(&mut thread_rng()), network),
revoke_priv: PrivateKey::new(SecretKey::new(&mut thread_rng()), network),
}
}
fn public_params<C: Signing>(&self, secp: &Secp256k1<C>) -> RevokeParams {
RevokeParams::from_priv_params(secp, self)
}
}
impl RevokeParams {
fn from_priv_params<C: Signing>(
secp: &Secp256k1<C>,
priv_params: &RevokePrivateParams,
) -> Self {
RevokeParams {
own_pk: priv_params.own_priv.public_key(secp),
publish_pk: priv_params.publish_priv.public_key(secp),
revoke_pk: priv_params.revoke_priv.public_key(secp),
}
}
}
#[test]
fn create_and_sign_penalty_from_buffer_transaction_test() {
let offer_priv_params = RevokePrivateParams::new(Network::Regtest);
let accept_priv_params = RevokePrivateParams::new(Network::Regtest);
let offer_params = offer_priv_params.public_params(SECP256K1);
let accept_params = accept_priv_params.public_params(SECP256K1);
let dest_address = Address::p2pkh(
&PublicKey::from_private_key(
SECP256K1,
&PrivateKey::new(SecretKey::new(&mut thread_rng()), Network::Regtest),
),
Network::Regtest,
);
let total_collateral = Amount::ONE_BTC;
let descriptor = buffer_descriptor(&offer_params, &accept_params);
let buffer_tx =
create_buffer_transaction(&TxIn::default(), &descriptor, total_collateral, 0);
create_and_sign_punish_buffer_transaction(
SECP256K1,
&offer_params,
&accept_params,
&offer_priv_params.own_priv.inner,
&accept_priv_params.publish_priv.inner,
&accept_priv_params.revoke_priv.inner,
&buffer_tx,
&dest_address,
0,
FEE_RATE_PER_VB,
)
.expect("to be able to create and sign the punish transaction");
create_and_sign_punish_buffer_transaction(
SECP256K1,
&offer_params,
&accept_params,
&accept_priv_params.own_priv.inner,
&offer_priv_params.publish_priv.inner,
&offer_priv_params.revoke_priv.inner,
&buffer_tx,
&dest_address,
0,
FEE_RATE_PER_VB,
)
.expect("to be able to create and sign the punish transaction");
assert!(create_and_sign_punish_buffer_transaction(
SECP256K1,
&offer_params,
&accept_params,
&offer_priv_params.own_priv.inner,
&offer_priv_params.publish_priv.inner,
&offer_priv_params.revoke_priv.inner,
&buffer_tx,
&dest_address,
0,
FEE_RATE_PER_VB,
)
.is_err());
assert!(create_and_sign_punish_buffer_transaction(
SECP256K1,
&offer_params,
&accept_params,
&accept_priv_params.own_priv.inner,
&accept_priv_params.publish_priv.inner,
&accept_priv_params.revoke_priv.inner,
&buffer_tx,
&dest_address,
0,
FEE_RATE_PER_VB,
)
.is_err());
}
#[test]
fn two_parties_sigs_satisfy_buffer_descriptor_test() {
let offer_priv_params = RevokePrivateParams::new(Network::Regtest);
let accept_priv_params = RevokePrivateParams::new(Network::Regtest);
let offer_params = offer_priv_params.public_params(SECP256K1);
let accept_params = accept_priv_params.public_params(SECP256K1);
let descriptor = buffer_descriptor(&offer_params, &accept_params);
let sig = bitcoin::ecdsa::Signature {
signature: secp256k1_zkp::ecdsa::Signature::from_str(
"3045\
0221\
00f7c3648c390d87578cd79c8016940aa8e3511c4104cb78daa8fb8e429375efc1\
0220\
531d75c136272f127a5dc14acc0722301cbddc222262934151f140da345af177",
)
.unwrap(),
sighash_type: EcdsaSighashType::All,
};
let satisfier = BTreeMap::from_iter(vec![
(offer_params.own_pk, sig),
(accept_params.own_pk, sig),
]);
descriptor
.satisfy(&mut TxIn::default(), satisfier)
.expect("to be able to satisfy the descriptor");
}
#[test]
fn create_and_sign_penalty_from_settle_transaction_test() {
let offer_priv_params = RevokePrivateParams::new(Network::Regtest);
let accept_priv_params = RevokePrivateParams::new(Network::Regtest);
let offer_params = offer_priv_params.public_params(SECP256K1);
let accept_params = accept_priv_params.public_params(SECP256K1);
let dest_address = Address::p2pkh(
&PublicKey::from_private_key(
SECP256K1,
&PrivateKey::new(SecretKey::new(&mut thread_rng()), Network::Regtest),
),
Network::Regtest,
);
let payout = Amount::ONE_BTC;
let csv_timelock = 100;
let settle_tx = create_settle_transaction(
&TxIn::default(),
&offer_params,
&accept_params,
payout,
payout,
csv_timelock,
0,
Amount::from_sat(200020000),
FEE_RATE_PER_VB,
)
.unwrap();
create_and_sign_punish_settle_transaction(
SECP256K1,
&offer_params,
&accept_params,
&offer_priv_params.own_priv.inner,
&accept_priv_params.publish_priv.inner,
&accept_priv_params.revoke_priv.inner,
&settle_tx,
&dest_address,
csv_timelock,
0,
FEE_RATE_PER_VB,
true,
)
.expect("to be able to create and sign the punish transaction");
create_and_sign_punish_settle_transaction(
SECP256K1,
&offer_params,
&accept_params,
&accept_priv_params.own_priv.inner,
&offer_priv_params.publish_priv.inner,
&offer_priv_params.revoke_priv.inner,
&settle_tx,
&dest_address,
csv_timelock,
0,
FEE_RATE_PER_VB,
false,
)
.expect("to be able to create and sign the punish transaction");
assert!(create_and_sign_punish_settle_transaction(
SECP256K1,
&offer_params,
&accept_params,
&offer_priv_params.own_priv.inner,
&offer_priv_params.publish_priv.inner,
&offer_priv_params.revoke_priv.inner,
&settle_tx,
&dest_address,
csv_timelock,
0,
FEE_RATE_PER_VB,
true
)
.is_err());
assert!(create_and_sign_punish_settle_transaction(
SECP256K1,
&offer_params,
&accept_params,
&accept_priv_params.own_priv.inner,
&accept_priv_params.publish_priv.inner,
&accept_priv_params.revoke_priv.inner,
&settle_tx,
&dest_address,
csv_timelock,
0,
FEE_RATE_PER_VB,
false
)
.is_err());
}
#[test]
fn one_party_sig_satisfies_settle_descriptor_test() {
let offer_priv_params = RevokePrivateParams::new(Network::Regtest);
let accept_priv_params = RevokePrivateParams::new(Network::Regtest);
let offer_params = offer_priv_params.public_params(SECP256K1);
let accept_params = accept_priv_params.public_params(SECP256K1);
let csv = 100;
let descriptor = settle_descriptor(&offer_params, &accept_params.own_pk, csv);
let sig = bitcoin::ecdsa::Signature {
signature: secp256k1_zkp::ecdsa::Signature::from_str(
"3045\
0221\
00f7c3648c390d87578cd79c8016940aa8e3511c4104cb78daa8fb8e429375efc1\
0220\
531d75c136272f127a5dc14acc0722301cbddc222262934151f140da345af177",
)
.unwrap(),
sighash_type: EcdsaSighashType::All,
};
let satisfier = BTreeMap::from_iter(vec![(offer_params.own_pk, sig)]);
descriptor
.satisfy(
&mut TxIn {
sequence: Sequence(csv + 1),
..Default::default()
},
(satisfier, Sequence(csv)),
)
.expect("to be able to satisfy the descriptor");
}
#[test]
fn get_verify_tx_adaptor_signature_test() {
let offer_priv_params = RevokePrivateParams::new(Network::Regtest);
let accept_priv_params = RevokePrivateParams::new(Network::Regtest);
let offer_params = offer_priv_params.public_params(SECP256K1);
let accept_params = accept_priv_params.public_params(SECP256K1);
let total_collateral = Amount::ONE_BTC;
let descriptor = buffer_descriptor(&offer_params, &accept_params);
let buffer_tx =
create_buffer_transaction(&TxIn::default(), &descriptor, total_collateral, 0);
let input_value = total_collateral + Amount::from_sat(10000);
let adaptor_sec_key = SecretKey::new(&mut thread_rng());
let adaptor_sig = get_tx_adaptor_signature(
SECP256K1,
&buffer_tx,
input_value,
&descriptor.script_code().expect("a valid script code"),
&adaptor_sec_key,
&accept_params.publish_pk.inner,
)
.expect("to be able to create the adaptor sig");
verify_tx_adaptor_signature(
SECP256K1,
&buffer_tx,
input_value,
&descriptor.script_code().expect("a valid script code"),
&secp256k1_zkp::PublicKey::from_secret_key(SECP256K1, &adaptor_sec_key),
&accept_params.publish_pk.inner,
&adaptor_sig,
)
.expect("the signature to be valid");
}
}