breez_sdk_spark/signer/
lnurl_auth.rs

1use std::sync::Arc;
2
3use bitcoin::bip32::{ChildNumber, DerivationPath};
4use bitcoin::secp256k1::Message;
5use breez_sdk_common::lnurl::auth::LnurlAuthSigner;
6use breez_sdk_common::lnurl::error::{LnurlError, LnurlResult};
7
8use crate::signer::BreezSigner;
9
10/// Adapter that implements `LnurlAuthSigner` by delegating to `BreezSigner`
11pub struct LnurlAuthSignerAdapter {
12    signer: Arc<dyn BreezSigner>,
13}
14
15impl LnurlAuthSignerAdapter {
16    pub fn new(signer: Arc<dyn BreezSigner>) -> Self {
17        Self { signer }
18    }
19}
20
21#[macros::async_trait]
22impl LnurlAuthSigner for LnurlAuthSignerAdapter {
23    async fn derive_public_key(
24        &self,
25        derivation_path: &[ChildNumber],
26    ) -> LnurlResult<bitcoin::secp256k1::PublicKey> {
27        // Convert ChildNumber slice to DerivationPath
28        let path = DerivationPath::from(derivation_path.to_vec());
29
30        // Delegate to BreezSigner to get public key directly
31        self.signer
32            .derive_public_key(&path)
33            .await
34            .map_err(|e| LnurlError::General(e.to_string()))
35    }
36
37    async fn sign_ecdsa(
38        &self,
39        msg: &[u8],
40        derivation_path: &[ChildNumber],
41    ) -> LnurlResult<Vec<u8>> {
42        let path = DerivationPath::from(derivation_path.to_vec());
43
44        // LNURL-auth requires single SHA256 hash of the k1 challenge
45        let message = Message::from_digest(
46            msg.try_into()
47                .map_err(|_| LnurlError::General("Invalid lnurl message".to_string()))?,
48        );
49
50        // Delegate to BreezSigner for ECDSA signing
51        let sig = self
52            .signer
53            .sign_ecdsa(message, &path)
54            .await
55            .map_err(|e| LnurlError::General(e.to_string()))?;
56
57        // Return DER-encoded signature
58        Ok(sig.serialize_der().to_vec())
59    }
60
61    async fn hmac_sha256(
62        &self,
63        key_derivation_path: &[ChildNumber],
64        input: &[u8],
65    ) -> LnurlResult<Vec<u8>> {
66        use bitcoin::hashes::Hash;
67
68        let path = DerivationPath::from(key_derivation_path.to_vec());
69
70        // Delegate to BreezSigner for HMAC-SHA256
71        let hmac = self
72            .signer
73            .hmac_sha256(&path, input)
74            .await
75            .map_err(|e| LnurlError::General(e.to_string()))?;
76
77        // Convert Hmac<sha256::Hash> to Vec<u8>
78        Ok(hmac.as_byte_array().to_vec())
79    }
80}