1use bitcoin::{Amount, EcdsaSighashType, OutPoint, ScriptBuf, Transaction, Witness};
4use secp256k1_zkp::{ecdsa::Signature, PublicKey, Secp256k1, SecretKey, Signing, Verification};
5
6use crate::{util::finalize_sig, Error, TxInputInfo};
7
8#[derive(Clone, Debug, PartialEq, Eq)]
9#[cfg_attr(feature = "use-serde", derive(serde::Serialize, serde::Deserialize))]
10pub struct DlcInputInfo {
12 pub fund_tx: Transaction,
14 pub fund_vout: u32,
16 pub local_fund_pubkey: PublicKey,
18 pub remote_fund_pubkey: PublicKey,
20 pub fund_amount: Amount,
22 pub max_witness_len: usize,
24 pub input_serial_id: u64,
26 pub contract_id: [u8; 32],
28}
29
30impl From<&DlcInputInfo> for TxInputInfo {
31 fn from(val: &DlcInputInfo) -> Self {
32 TxInputInfo {
33 outpoint: OutPoint::new(val.fund_tx.compute_txid(), val.fund_vout),
34 max_witness_len: val.max_witness_len,
35 redeem_script: ScriptBuf::new(),
36 serial_id: val.input_serial_id,
37 }
38 }
39}
40
41pub fn get_dlc_inputs_weight(dlc_inputs: &[DlcInputInfo]) -> usize {
43 dlc_inputs
44 .iter()
45 .map(|dlc_input| {
46 36 * 4 + 4 + 4 * 4 + dlc_input.max_witness_len
48 })
49 .sum()
50}
51
52pub fn calculate_total_dlc_input_amount(dlc_inputs: &[DlcInputInfo]) -> Amount {
54 dlc_inputs.iter().map(|input| input.fund_amount).sum()
55}
56
57pub fn create_dlc_input_funding_script(dlc_input: &DlcInputInfo) -> ScriptBuf {
59 crate::make_funding_redeemscript(&dlc_input.local_fund_pubkey, &dlc_input.remote_fund_pubkey)
60}
61
62pub fn create_dlc_funding_input_signature<C: Signing>(
64 secp: &Secp256k1<C>,
65 fund_transaction: &Transaction,
66 input_index: usize,
67 dlc_input: &DlcInputInfo,
68 privkey: &SecretKey,
69) -> Result<Vec<u8>, Error> {
70 let funding_script = create_dlc_input_funding_script(dlc_input);
71 let sig_hash_msg = super::util::get_sig_hash_msg(
72 fund_transaction,
73 input_index,
74 &funding_script,
75 dlc_input.fund_amount,
76 )?;
77 let signature = secp.sign_ecdsa_low_r(&sig_hash_msg, privkey);
78 Ok(finalize_sig(&signature, EcdsaSighashType::All))
79}
80
81pub fn verify_dlc_funding_input_signature<V: Verification>(
83 secp: &Secp256k1<V>,
84 fund_transaction: &Transaction,
85 input_index: usize,
86 dlc_input: &DlcInputInfo,
87 signature: Vec<u8>,
88 pubkey: &PublicKey,
89) -> Result<(), Error> {
90 let funding_script = create_dlc_input_funding_script(dlc_input);
91
92 let signature = if signature.len() == 64 {
94 Signature::from_compact(&signature)?
95 } else {
96 let sig_bytes = &signature[..signature.len() - 1];
98 Signature::from_der(sig_bytes)?
99 };
100
101 super::verify_tx_input_sig(
102 secp,
103 &signature,
104 fund_transaction,
105 input_index,
106 &funding_script,
107 dlc_input.fund_amount,
108 pubkey,
109 )
110}
111
112pub fn combine_dlc_input_signatures(
114 dlc_input: &DlcInputInfo,
115 my_signature: &Vec<u8>,
116 other_signature: &Vec<u8>,
117 my_pubkey: &PublicKey,
118 other_pubkey: &PublicKey,
119) -> Witness {
120 let funding_script = create_dlc_input_funding_script(dlc_input);
121
122 let (first_sig, second_sig) = if my_pubkey <= other_pubkey {
124 (my_signature, other_signature)
125 } else {
126 (other_signature, my_signature)
127 };
128
129 let mut witness = Witness::new();
130 witness.push([]);
131 witness.push(first_sig);
132 witness.push(second_sig);
133 witness.push(funding_script.to_bytes());
134
135 witness
136}