1use std::str::FromStr;
6
7use bitcoin::hashes::sha256::Hash as Sha256Hash;
8use bitcoin::hashes::Hash;
9use bitcoin::secp256k1::schnorr::Signature;
10use serde::{Deserialize, Serialize};
11use thiserror::Error;
12
13use super::nut00::Witness;
14use super::nut10::Secret;
15use super::nut11::valid_signatures;
16use super::{Conditions, Proof};
17use crate::ensure_cdk;
18use crate::util::unix_time;
19
20pub mod serde_htlc_witness;
21
22#[derive(Debug, Error)]
24pub enum Error {
25 #[error("Secret is not a HTLC secret")]
27 IncorrectSecretKind,
28 #[error("Locktime in past")]
30 LocktimeInPast,
31 #[error("Hash required")]
33 HashRequired,
34 #[error("Hash is not valid")]
36 InvalidHash,
37 #[error("Preimage does not match")]
39 Preimage,
40 #[error("Witness did not provide signatures")]
42 SignaturesNotProvided,
43 #[error(transparent)]
45 Secp256k1(#[from] bitcoin::secp256k1::Error),
46 #[error(transparent)]
48 NUT11(#[from] super::nut11::Error),
49 #[error(transparent)]
50 Serde(#[from] serde_json::Error),
52}
53
54#[derive(Default, Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
56#[cfg_attr(feature = "swagger", derive(utoipa::ToSchema))]
57pub struct HTLCWitness {
58 pub preimage: String,
60 #[serde(skip_serializing_if = "Option::is_none")]
62 pub signatures: Option<Vec<String>>,
63}
64
65impl Proof {
66 pub fn verify_htlc(&self) -> Result<(), Error> {
68 let secret: Secret = self.secret.clone().try_into()?;
69 let conditions: Option<Conditions> =
70 secret.secret_data.tags.and_then(|c| c.try_into().ok());
71
72 let htlc_witness = match &self.witness {
73 Some(Witness::HTLCWitness(witness)) => witness,
74 _ => return Err(Error::IncorrectSecretKind),
75 };
76
77 if let Some(conditions) = conditions {
78 if let Some(locktime) = conditions.locktime {
80 if locktime.lt(&unix_time()) && conditions.refund_keys.is_none() {
82 return Ok(());
83 }
84
85 if let (Some(refund_key), Some(signatures)) =
87 (conditions.refund_keys, &self.witness)
88 {
89 let signatures = signatures
90 .signatures()
91 .ok_or(Error::SignaturesNotProvided)?
92 .iter()
93 .map(|s| Signature::from_str(s))
94 .collect::<Result<Vec<Signature>, _>>()?;
95
96 if valid_signatures(self.secret.as_bytes(), &refund_key, &signatures)?.ge(&1) {
98 return Ok(());
99 }
100 }
101 }
102 if let Some(pubkey) = conditions.pubkeys {
104 let req_sigs = conditions.num_sigs.unwrap_or(1);
105
106 let signatures = htlc_witness
107 .signatures
108 .as_ref()
109 .ok_or(Error::SignaturesNotProvided)?;
110
111 let signatures = signatures
112 .iter()
113 .map(|s| Signature::from_str(s))
114 .collect::<Result<Vec<Signature>, _>>()?;
115
116 let valid_sigs = valid_signatures(self.secret.as_bytes(), &pubkey, &signatures)?;
117 ensure_cdk!(valid_sigs >= req_sigs, Error::IncorrectSecretKind);
118 }
119 }
120
121 if secret.kind.ne(&super::Kind::HTLC) {
122 return Err(Error::IncorrectSecretKind);
123 }
124
125 let hash_lock =
126 Sha256Hash::from_str(&secret.secret_data.data).map_err(|_| Error::InvalidHash)?;
127
128 let preimage_hash = Sha256Hash::hash(htlc_witness.preimage.as_bytes());
129
130 if hash_lock.ne(&preimage_hash) {
131 return Err(Error::Preimage);
132 }
133
134 Ok(())
135 }
136
137 #[inline]
139 pub fn add_preimage(&mut self, preimage: String) {
140 self.witness = Some(Witness::HTLCWitness(HTLCWitness {
141 preimage,
142 signatures: None,
143 }))
144 }
145}