Skip to main content

breez_sdk_spark/signer/
breez.rs

1use crate::error::SdkError;
2use bitcoin::bip32::{DerivationPath, Xpriv};
3use bitcoin::hashes::{Hash, HashEngine, Hmac, HmacEngine, sha256};
4use bitcoin::secp256k1::{self, Message, Secp256k1, rand::thread_rng};
5
6use super::{BreezSigner, EciesSigner, HmacSigner};
7
8/// SDK-layer signer for non-Spark operations (LNURL-auth, real-time sync,
9/// message signing, ECIES). It holds a single master key and derives every key
10/// from it by BIP32 path; the Spark layer decides which master to hand it.
11pub struct BreezSignerImpl {
12    master: Xpriv,
13    secp: Secp256k1<secp256k1::All>,
14}
15
16impl BreezSignerImpl {
17    pub fn new(master: Xpriv) -> Self {
18        Self {
19            master,
20            secp: Secp256k1::new(),
21        }
22    }
23}
24
25#[macros::async_trait]
26impl BreezSigner for BreezSignerImpl {
27    async fn derive_public_key(
28        &self,
29        path: &DerivationPath,
30    ) -> Result<secp256k1::PublicKey, SdkError> {
31        let derived = self
32            .master
33            .derive_priv(&self.secp, path)
34            .map_err(|e| SdkError::Generic(e.to_string()))?;
35        Ok(derived.private_key.public_key(&self.secp))
36    }
37
38    async fn sign_ecdsa(
39        &self,
40        message: Message,
41        path: &DerivationPath,
42    ) -> Result<secp256k1::ecdsa::Signature, SdkError> {
43        let derived = self
44            .master
45            .derive_priv(&self.secp, path)
46            .map_err(|e| SdkError::Generic(e.to_string()))?;
47        Ok(self.secp.sign_ecdsa_low_r(&message, &derived.private_key))
48    }
49
50    async fn sign_ecdsa_recoverable(
51        &self,
52        message: Message,
53        path: &DerivationPath,
54    ) -> Result<secp256k1::ecdsa::RecoverableSignature, SdkError> {
55        let derived = self
56            .master
57            .derive_priv(&self.secp, path)
58            .map_err(|e| SdkError::Generic(e.to_string()))?;
59        Ok(self
60            .secp
61            .sign_ecdsa_recoverable(&message, &derived.private_key))
62    }
63
64    async fn sign_hash_schnorr(
65        &self,
66        hash: &[u8],
67        path: &DerivationPath,
68    ) -> Result<secp256k1::schnorr::Signature, SdkError> {
69        let derived = self
70            .master
71            .derive_priv(&self.secp, path)
72            .map_err(|e| SdkError::Generic(e.to_string()))?;
73        let message =
74            Message::from_digest_slice(hash).map_err(|e| SdkError::Generic(e.to_string()))?;
75        let keypair = derived.private_key.keypair(&self.secp);
76
77        // Always use auxiliary randomness for enhanced security
78        let mut rng = thread_rng();
79        Ok(self
80            .secp
81            .sign_schnorr_with_rng(&message, &keypair, &mut rng))
82    }
83}
84
85#[macros::async_trait]
86impl EciesSigner for BreezSignerImpl {
87    async fn encrypt_ecies(
88        &self,
89        message: &[u8],
90        path: &DerivationPath,
91    ) -> Result<Vec<u8>, SdkError> {
92        let derived = self
93            .master
94            .derive_priv(&self.secp, path)
95            .map_err(|e| SdkError::Generic(e.to_string()))?;
96        let rc_pub = derived.private_key.public_key(&self.secp).serialize();
97        utils::ecies::encrypt(&rc_pub, message)
98            .map_err(|err| SdkError::Generic(format!("Could not encrypt data: {err}")))
99    }
100
101    async fn decrypt_ecies(
102        &self,
103        message: &[u8],
104        path: &DerivationPath,
105    ) -> Result<Vec<u8>, SdkError> {
106        let derived = self
107            .master
108            .derive_priv(&self.secp, path)
109            .map_err(|e| SdkError::Generic(e.to_string()))?;
110        let rc_prv = derived.private_key.secret_bytes();
111        utils::ecies::decrypt(&rc_prv, message)
112            .map_err(|err| SdkError::Generic(format!("Could not decrypt data: {err}")))
113    }
114}
115
116#[macros::async_trait]
117impl HmacSigner for BreezSignerImpl {
118    async fn hmac_sha256(
119        &self,
120        key_path: &DerivationPath,
121        input: &[u8],
122    ) -> Result<Hmac<sha256::Hash>, SdkError> {
123        let derived = self
124            .master
125            .derive_priv(&self.secp, key_path)
126            .map_err(|e| SdkError::Generic(e.to_string()))?;
127
128        let mut engine = HmacEngine::<sha256::Hash>::new(&derived.private_key.secret_bytes());
129        engine.input(input);
130        Ok(Hmac::<sha256::Hash>::from_engine(engine))
131    }
132}