Skip to main content

breez_sdk_spark/signer/
external_spark.rs

1//! External (foreign) high-level Spark signer trait.
2//!
3//! Mirrors `spark_wallet::SparkSigner` using FFI-compatible types so an
4//! integrator can implement the Spark flow-signing surface directly.
5//! The SDK wraps an implementation in
6//! [`ExternalSparkSignerAdapter`](super::ExternalSparkSignerAdapter) to obtain a
7//! native `spark_wallet::SparkSigner`.
8
9use crate::error::SignerError;
10
11use super::external_spark_types::{
12    ExternalFrostJob, ExternalFrostShareResult, ExternalPrepareClaimRequest,
13    ExternalPrepareLightningReceiveRequest, ExternalPrepareStaticDepositClaimRequest,
14    ExternalPrepareStaticDepositRequest, ExternalPrepareTokenTransactionRequest,
15    ExternalPrepareTransferRequest, ExternalPreparedClaim, ExternalPreparedLightningReceive,
16    ExternalPreparedStaticDeposit, ExternalPreparedStaticDepositClaim,
17    ExternalPreparedTokenTransaction, ExternalPreparedTransfer, ExternalSignSparkInvoiceRequest,
18    ExternalSignStaticDepositRefundRequest, ExternalSignWatchtowerExitRecoveryRequest,
19    ExternalSignedSparkInvoice, ExternalStartStaticDepositRefundRequest,
20    ExternalStartWatchtowerExitRecoveryRequest, ExternalStartedStaticDepositRefund,
21    ExternalStartedWatchtowerExitRecovery,
22};
23use super::external_types::{
24    EcdsaSignatureBytes, ExternalFrostSignature, ExternalTreeNodeId, PublicKeyBytes,
25    SchnorrSignatureBytes,
26};
27
28/// FFI-compatible mirror of `spark_wallet::SparkSigner`.
29#[cfg_attr(
30    feature = "uniffi",
31    uniffi::export(with_foreign, async_runtime = "tokio")
32)]
33#[macros::async_trait]
34pub trait ExternalSparkSigner: Send + Sync {
35    /// The wallet identity public key (33 bytes compressed).
36    async fn get_identity_public_key(&self) -> Result<PublicKeyBytes, SignerError>;
37
38    /// The public key of the leaf signing key derived from `leaf_id`.
39    async fn get_public_key_for_leaf(
40        &self,
41        leaf_id: ExternalTreeNodeId,
42    ) -> Result<PublicKeyBytes, SignerError>;
43
44    /// Whether this signer is backed by a remote service, so its operations are
45    /// network round-trips rather than local computation. Local signers return
46    /// false; a hosted signer like Turnkey returns true. With a remote signer the
47    /// SDK skips redundant calls, e.g. re-deriving keys for leaves it has already
48    /// verified, and does not support the watchtower fee ladder.
49    fn is_remote(&self) -> bool {
50        false
51    }
52
53    /// The static-deposit signing public key at `index`.
54    async fn get_static_deposit_public_key(
55        &self,
56        index: u32,
57    ) -> Result<PublicKeyBytes, SignerError>;
58
59    /// ECDSA-sign a server authentication challenge with the identity key.
60    async fn sign_authentication_challenge(
61        &self,
62        challenge: Vec<u8>,
63    ) -> Result<EcdsaSignatureBytes, SignerError>;
64
65    /// ECDSA-sign an arbitrary user message with the identity key.
66    async fn sign_message(&self, message: Vec<u8>) -> Result<EcdsaSignatureBytes, SignerError>;
67
68    /// Schnorr-sign `sighash` to spend a tree leaf's P2TR refund output as a
69    /// BIP341 key-path spend (empty script tree), with the leaf signing key
70    /// derived from `leaf_id`.
71    async fn sign_leaf_refund_spend(
72        &self,
73        leaf_id: ExternalTreeNodeId,
74        sighash: Vec<u8>,
75    ) -> Result<SchnorrSignatureBytes, SignerError>;
76
77    /// Produce FROST shares for a batch of jobs.
78    async fn sign_frost(
79        &self,
80        jobs: Vec<ExternalFrostJob>,
81    ) -> Result<Vec<ExternalFrostShareResult>, SignerError>;
82
83    /// Prepare an outbound transfer (key-tweak + packages + payload signature).
84    async fn prepare_transfer(
85        &self,
86        request: ExternalPrepareTransferRequest,
87    ) -> Result<ExternalPreparedTransfer, SignerError>;
88
89    /// Claim an inbound transfer (key-tweak step).
90    async fn prepare_claim(
91        &self,
92        request: ExternalPrepareClaimRequest,
93    ) -> Result<ExternalPreparedClaim, SignerError>;
94
95    /// Prepare a Lightning receive (in-enclave preimage + Feldman split).
96    async fn prepare_lightning_receive(
97        &self,
98        request: ExternalPrepareLightningReceiveRequest,
99    ) -> Result<ExternalPreparedLightningReceive, SignerError>;
100
101    /// Prepare a static deposit (export secret to SSP + FROST-sign tree txs).
102    async fn prepare_static_deposit(
103        &self,
104        request: ExternalPrepareStaticDepositRequest,
105    ) -> Result<ExternalPreparedStaticDeposit, SignerError>;
106
107    /// Begin a static-deposit refund (user-commits-first).
108    ///
109    /// The implementation keeps the nonce behind the returned commitment until
110    /// [`sign_static_deposit_refund`](Self::sign_static_deposit_refund)
111    /// consumes it, and signs with it once: signing twice under one nonce leaks
112    /// the signing share.
113    async fn start_static_deposit_refund(
114        &self,
115        request: ExternalStartStaticDepositRefundRequest,
116    ) -> Result<ExternalStartedStaticDepositRefund, SignerError>;
117
118    /// Finish a static-deposit refund (aggregate into the final signature).
119    async fn sign_static_deposit_refund(
120        &self,
121        request: ExternalSignStaticDepositRefundRequest,
122    ) -> Result<ExternalFrostSignature, SignerError>;
123
124    /// Begin the recovery of a watchtower-exited leaf: return the public key of
125    /// the leaf's signing key (derived from `leaf_id`), a fresh FROST nonce
126    /// commitment, and the identity key's ECDSA signature over the SHA-256 hash
127    /// of `user_statement`.
128    ///
129    /// The implementation keeps the nonce behind the returned commitment until
130    /// [`sign_watchtower_exit_recovery`](Self::sign_watchtower_exit_recovery)
131    /// consumes it, and signs with it once: signing twice under one nonce leaks
132    /// the signing share.
133    async fn start_watchtower_exit_recovery(
134        &self,
135        request: ExternalStartWatchtowerExitRecoveryRequest,
136    ) -> Result<ExternalStartedWatchtowerExitRecovery, SignerError>;
137
138    /// Finish the recovery: sign with the leaf's signing key under the nonce
139    /// committed by `start_watchtower_exit_recovery`, and aggregate the
140    /// operators' shares into the final signature.
141    async fn sign_watchtower_exit_recovery(
142        &self,
143        request: ExternalSignWatchtowerExitRecoveryRequest,
144    ) -> Result<ExternalFrostSignature, SignerError>;
145
146    /// Schnorr-sign a Spark invoice (sats or tokens) with the identity key.
147    async fn sign_spark_invoice(
148        &self,
149        request: ExternalSignSparkInvoiceRequest,
150    ) -> Result<ExternalSignedSparkInvoice, SignerError>;
151
152    /// Schnorr-sign a token-transaction digest with the identity key.
153    async fn prepare_token_transaction(
154        &self,
155        request: ExternalPrepareTokenTransactionRequest,
156    ) -> Result<ExternalPreparedTokenTransaction, SignerError>;
157
158    /// Prepare a static-deposit claim (export secret in the clear + sign).
159    async fn prepare_static_deposit_claim(
160        &self,
161        request: ExternalPrepareStaticDepositClaimRequest,
162    ) -> Result<ExternalPreparedStaticDepositClaim, SignerError>;
163}