1use bitcoin::constants::ChainHash;
2use bitcoin::Network;
3pub use lightning::offers::offer::{Offer, Amount as OfferAmount};
4pub use lightning::offers::invoice::Bolt12Invoice;
5
6use std::str::FromStr;
7use std::{fmt, io};
8
9use bitcoin::Amount;
10use bitcoin::bech32::{encode_to_fmt, EncodeError, Hrp, NoChecksum, primitives::decode::CheckedHrpstring};
11use bitcoin::hashes::{sha256, Hash};
12use bitcoin::secp256k1::{Message, PublicKey};
13use bitcoin::taproot::TaprootSpendInfo;
14use lightning::offers::parse::Bolt12ParseError;
15use lightning::util::ser::Writeable;
16use lightning_invoice::Bolt11Invoice;
17
18use serde::{Deserialize, Serialize};
19
20use bitcoin_ext::P2TR_DUST;
21
22use crate::{scripts, ProtocolDecodingError};
23use crate::{musig, ProtocolEncoding, encode::{WriteExt, ReadExt}};
24use crate::SECP;
25
26const BECH32_BOLT12_INVOICE_HRP: &str = "lni";
27
28pub const HTLC_MIN_FEE: Amount = P2TR_DUST;
30
31
32#[derive(Clone, Copy, PartialEq, Eq, Hash)]
34pub struct Preimage([u8; 32]);
35impl_byte_newtype!(Preimage, 32);
36
37impl Preimage {
38 pub fn random() -> Preimage {
40 Preimage(rand::random())
41 }
42
43 pub fn compute_payment_hash(&self) -> PaymentHash {
45 sha256::Hash::hash(self.as_ref()).into()
46 }
47}
48
49#[derive(Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
51pub struct PaymentHash([u8; 32]);
52impl_byte_newtype!(PaymentHash, 32);
53
54impl From<sha256::Hash> for PaymentHash {
55 fn from(hash: sha256::Hash) -> Self {
56 PaymentHash(hash.to_byte_array())
57 }
58}
59
60impl From<Preimage> for PaymentHash {
61 fn from(preimage: Preimage) -> Self {
62 preimage.compute_payment_hash()
63 }
64}
65
66impl From<lightning::types::payment::PaymentHash> for PaymentHash {
67 fn from(hash: lightning::types::payment::PaymentHash) -> Self {
68 PaymentHash(hash.0)
69 }
70}
71
72impl<'a> From<&'a Bolt11Invoice> for PaymentHash {
73 fn from(i: &'a Bolt11Invoice) -> Self {
74 (*i.payment_hash()).into()
75 }
76}
77
78impl From<Bolt11Invoice> for PaymentHash {
79 fn from(i: Bolt11Invoice) -> Self {
80 (&i).into()
81 }
82}
83
84impl PaymentHash {
85 pub fn to_sha256_hash(&self) -> bitcoin::hashes::sha256::Hash {
87 bitcoin::hashes::sha256::Hash::from_slice(&self.0)
88 .expect("PaymentHash must be 32 bytes, which is always valid for sha256::Hash")
89 }
90}
91
92pub fn server_htlc_send_taproot(
111 payment_hash: PaymentHash,
112 server_pubkey: PublicKey,
113 user_pubkey: PublicKey,
114 exit_delta: u16,
115 htlc_expiry: u32,
116) -> TaprootSpendInfo {
117 let server_branch = scripts::hash_delay_sign(
118 payment_hash.to_sha256_hash(), exit_delta, server_pubkey.x_only_public_key().0,
119 );
120 let user_branch = scripts::delay_timelock_sign(
121 2 * exit_delta, htlc_expiry, user_pubkey.x_only_public_key().0,
122 );
123
124 let combined_pk = musig::combine_keys([user_pubkey, server_pubkey]);
125 bitcoin::taproot::TaprootBuilder::new()
126 .add_leaf(1, server_branch).unwrap()
127 .add_leaf(1, user_branch).unwrap()
128 .finalize(&SECP, combined_pk).unwrap()
129}
130
131pub fn server_htlc_receive_taproot(
149 payment_hash: PaymentHash,
150 server_pubkey: PublicKey,
151 user_pubkey: PublicKey,
152 exit_delta: u16,
153 htlc_expiry: u32,
154) -> TaprootSpendInfo {
155 let server_branch =
156 scripts::delay_timelock_sign(exit_delta, htlc_expiry, server_pubkey.x_only_public_key().0);
157 let user_branch = scripts::hash_delay_sign(
158 payment_hash.to_sha256_hash(),
159 2 * exit_delta,
160 user_pubkey.x_only_public_key().0,
161 );
162
163 let combined_pk = musig::combine_keys([user_pubkey, server_pubkey]);
164 bitcoin::taproot::TaprootBuilder::new()
165 .add_leaf(1, server_branch).unwrap()
166 .add_leaf(1, user_branch).unwrap()
167 .finalize(&SECP, combined_pk).unwrap()
168}
169
170
171#[derive(Debug, Clone)]
172pub enum PaymentStatus {
173 Pending,
174 Complete,
175 Failed,
176}
177
178impl fmt::Display for PaymentStatus {
179 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
180 fmt::Debug::fmt(self, f)
181 }
182}
183
184#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
188pub enum Invoice {
189 Bolt11(Bolt11Invoice),
190 #[serde(with = "crate::encode::serde")]
191 Bolt12(Bolt12Invoice),
192}
193
194#[derive(Debug, thiserror::Error)]
195#[error("cannot parse invoice")]
196pub struct InvoiceParseError;
197
198impl FromStr for Invoice {
199 type Err = InvoiceParseError;
200
201 fn from_str(s: &str) -> Result<Self, Self::Err> {
202 if let Ok(bolt11) = Bolt11Invoice::from_str(s) {
203 Ok(Invoice::Bolt11(bolt11))
204 } else if let Ok(bolt12) = Bolt12Invoice::from_str(s) {
205 Ok(Invoice::Bolt12(bolt12))
206 } else {
207 Err(InvoiceParseError)
208 }
209 }
210}
211
212#[derive(Debug, thiserror::Error)]
213#[error("invalid invoice signature: {0}")]
214pub struct CheckSignatureError(pub String);
215
216impl Invoice {
217 pub fn into_bolt11(self) -> Option<Bolt11Invoice> {
218 match self {
219 Invoice::Bolt11(invoice) => Some(invoice),
220 Invoice::Bolt12(_) => None
221 }
222 }
223
224 pub fn payment_hash(&self) -> PaymentHash {
225 match self {
226 Invoice::Bolt11(invoice) => PaymentHash::from(*invoice.payment_hash().as_byte_array()),
227 Invoice::Bolt12(invoice) => PaymentHash::from(invoice.payment_hash()),
228 }
229 }
230
231 pub fn network(&self) -> Network {
232 match self {
233 Invoice::Bolt11(invoice) => invoice.network(),
234 Invoice::Bolt12(invoice) => match invoice.chain() {
235 ChainHash::BITCOIN => Network::Bitcoin,
236 ChainHash::TESTNET3 => Network::Testnet,
237 ChainHash::TESTNET4 => Network::Testnet4,
238 ChainHash::SIGNET => Network::Signet,
239 ChainHash::REGTEST => Network::Regtest,
240 _ => panic!("unsupported network"),
241 },
242 }
243 }
244
245 pub fn amount_milli_satoshis(&self) -> Option<u64> {
246 match self {
247 Invoice::Bolt11(invoice) => invoice.amount_milli_satoshis(),
248 Invoice::Bolt12(invoice) => invoice.amount_milli_satoshis(),
249 }
250 }
251
252 pub fn check_signature(&self) -> Result<(), CheckSignatureError> {
253 match self {
254 Invoice::Bolt11(invoice) => invoice
255 .check_signature()
256 .map_err(|e| CheckSignatureError(e.to_string())),
257 Invoice::Bolt12(invoice) => invoice.check_signature(),
258 }
259 }
260}
261
262impl fmt::Display for Invoice {
263 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
264 match self {
265 Invoice::Bolt11(invoice) => write!(f, "{}", invoice.to_string()),
266 Invoice::Bolt12(invoice) => encode_to_fmt::<NoChecksum, _>(
267 f,
268 Hrp::parse("lni").unwrap(),
269 &invoice.bytes(),
270 )
271 .map_err(|e| match e {
272 EncodeError::Fmt(e) => e,
273 _ => fmt::Error {},
274 }),
275 }
276 }
277}
278
279pub trait Bolt12InvoiceExt: Sized {
280 fn payment_hash(&self) -> PaymentHash;
281 fn amount_milli_satoshis(&self) -> Option<u64>;
282 fn check_signature(&self) -> Result<(), CheckSignatureError>;
283 fn bytes(&self) -> Vec<u8>;
284 fn from_bytes(bytes: &[u8]) -> Result<Self, Bolt12ParseError>;
285 fn validate_issuance(&self, offer: Offer) -> Result<(), CheckSignatureError>;
286 fn from_str(s: &str) -> Result<Bolt12Invoice, Bolt12ParseError>;
287}
288
289impl Bolt12InvoiceExt for Bolt12Invoice {
290 fn payment_hash(&self) -> PaymentHash { PaymentHash::from(self.payment_hash()) }
291
292 fn amount_milli_satoshis(&self) -> Option<u64> {
293 Some(self.amount_msats())
294 }
295
296 fn check_signature(&self) -> Result<(), CheckSignatureError> {
297 let message = Message::from_digest(self.signable_hash());
298 let signature = self.signature();
299
300 if let Some(pubkey) = self.issuer_signing_pubkey() {
301 Ok(SECP.verify_schnorr(&signature, &message, &pubkey.into())
302 .map_err(|_| CheckSignatureError("invalid signature".to_string()))?)
303 } else {
304 Err(CheckSignatureError("no pubkey on offer, cannot verify signature".to_string()))
305 }
306 }
307
308 fn bytes(&self) -> Vec<u8> {
309 let mut bytes = Vec::new();
310 self.write(&mut bytes).expect("Writing into a Vec is infallible");
311 bytes
312 }
313
314 fn from_bytes(bytes: &[u8]) -> Result<Self, Bolt12ParseError> {
315 Bolt12Invoice::try_from(bytes.to_vec())
316 }
317
318 fn validate_issuance(&self, offer: Offer) -> Result<(), CheckSignatureError> {
319 if self.issuer_signing_pubkey() != offer.issuer_signing_pubkey() {
320 Err(CheckSignatureError("public keys mismatch".to_string()))
321 } else {
322 Ok(())
323 }
324 }
325
326 fn from_str(s: &str) -> Result<Self, Bolt12ParseError> {
327 let dec = CheckedHrpstring::new::<NoChecksum>(&s)?;
328 if dec.hrp().to_lowercase() != BECH32_BOLT12_INVOICE_HRP {
329 return Err(Bolt12ParseError::InvalidBech32Hrp);
330 }
331
332 let data = dec.byte_iter().collect::<Vec<_>>();
333 Bolt12Invoice::try_from(data)
334 }
335}
336
337impl<T: Bolt12InvoiceExt> ProtocolEncoding for T {
338 fn encode<W: io::Write + ?Sized>(&self, writer: &mut W) -> Result<(), io::Error> {
339 writer.emit_slice(&self.bytes())
340 }
341
342 fn decode<R: io::Read + ?Sized>(reader: &mut R) -> Result<Self, ProtocolDecodingError> {
343 let mut bytes = Vec::new();
344 reader.read_slice(&mut bytes)?;
345 Self::from_bytes(&bytes).map_err(|e| ProtocolDecodingError::invalid(format!("{:?}", e)))
346 }
347}