spark_rust/signer/traits/
frost_signing.rs

1//! # FROST threshold signing operations for Spark wallet
2//!
3//! This module defines the FROST (Flexible Round-Optimized Schnorr Threshold) signing
4//! capabilities for the Spark wallet. FROST is the threshold signature scheme used by
5//! Spark to enable secure multi-party signing, where both the user and Spark Operators
6//! participate in creating signatures without revealing their private keys.
7//!
8//! The module supports:
9//! - Creating and verifying FROST signature shares
10//! - Aggregating signature shares into complete signatures
11//! - Specialized signing methods for various Spark operations
12//!
13//! In Spark's security model, threshold signing is critical because it ensures that:
14//! 1. Neither the user nor Spark Operators alone can spend funds
15//! 2. Signatures appear as standard Schnorr signatures on-chain
16//! 3. The user maintains control of their portion of the signing key
17//!
18//! This implementation is customized to support Taproot tweaking, enabling
19//! compatibility with Bitcoin's Taproot script system.
20
21// use std::cell::RefCell;
22use std::collections::HashMap;
23use std::sync::Arc;
24
25use bitcoin::secp256k1::PublicKey;
26use frost_secp256k1_tr_unofficial::round1::SigningCommitments;
27use parking_lot::RwLock;
28use spark_protos::common::SigningCommitment;
29use spark_protos::frost::AggregateFrostRequest;
30use spark_protos::frost::AggregateFrostResponse;
31use spark_protos::frost::FrostSigningJob;
32use spark_protos::frost::SignFrostResponse;
33use spark_protos::spark::LeafRefundTxSigningResult;
34use spark_protos::spark::NodeSignatures;
35use spark_protos::spark::RequestedSigningCommitments;
36
37use crate::error::SparkSdkError;
38use crate::wallet::internal_handlers::traits::create_tree::DepositAddressTree;
39use crate::wallet::internal_handlers::traits::transfer::LeafKeyTweak;
40use crate::wallet::internal_handlers::traits::transfer::LeafRefundSigningData;
41
42/// Trait for FROST threshold signing operations in the Spark wallet.
43///
44/// This trait provides methods for performing threshold signing using the FROST
45/// (Flexible Round-Optimized Schnorr Threshold) protocol. FROST enables multiple
46/// parties (the user and Spark Operators) to jointly sign a message without revealing
47/// their private keys.
48///
49/// In the Spark protocol, FROST signing is used for:
50/// - Signing Bitcoin transactions on leaves (UTXOs)
51/// - Creating refund transactions for security guarantees
52/// - Facilitating Lightning Network operations
53/// - Supporting deposit address creation
54///
55/// The implementation is customized to support Taproot tweaking, allowing
56/// compatibility with Bitcoin's Taproot script system while maintaining the
57/// security properties of threshold signatures.
58pub trait SparkSignerFrostSigning {
59    /// Signs messages using the FROST threshold signature scheme.
60    ///
61    /// This method generates signature shares for a set of signing jobs.
62    /// Each job represents a distinct message to be signed with a specific
63    /// key and set of participants.
64    ///
65    /// # Arguments
66    /// * `signing_jobs` - A vector of `FrostSigningJob` objects, each containing:
67    ///   - The message to sign
68    ///   - The key package (containing signing material)
69    ///   - The verifying key
70    ///   - Nonce commitments from all participants
71    ///   - Optional adaptor public key for adaptor signatures
72    ///
73    /// # Returns
74    /// * `Ok(SignFrostResponse)` - Contains the generated signature shares for each job
75    /// * `Err(SparkSdkError)` - If signing fails for any reason
76    ///
77    /// # Security Considerations
78    /// The security of FROST depends on proper nonce generation. The implementation
79    /// should ensure nonces are never reused for different messages.
80    fn sign_frost(
81        &self,
82        signing_jobs: Vec<FrostSigningJob>,
83    ) -> Result<SignFrostResponse, SparkSdkError>;
84
85    /// Aggregates multiple FROST signature shares into a complete signature.
86    ///
87    /// This method combines signature shares from all participants (the user and
88    /// Spark Operators) into a single signature that can be verified using the
89    /// threshold public key.
90    ///
91    /// # Arguments
92    /// * `request` - An `AggregateFrostRequest` containing:
93    ///   - The message that was signed
94    ///   - Signature shares from all participants
95    ///   - Public key shares from all participants
96    ///   - The verifying key (threshold public key)
97    ///   - Nonce commitments from all participants
98    ///   - Optional adaptor public key for adaptor signatures
99    ///
100    /// # Returns
101    /// * `Ok(AggregateFrostResponse)` - Contains the aggregated signature
102    /// * `Err(SparkSdkError)` - If aggregation fails
103    ///
104    /// # Security Considerations
105    /// The aggregation process must verify that all signature shares are valid
106    /// before combining them to prevent rogue key attacks.
107    fn aggregate_frost(
108        &self,
109        request: AggregateFrostRequest,
110    ) -> Result<AggregateFrostResponse, SparkSdkError>;
111
112    /// Signs all nodes in a deposit tree in breadth-first order.
113    ///
114    /// This method traverses a deposit tree structure and signs each node's transaction
115    /// and refund transaction using FROST. The tree represents a hierarchical structure
116    /// of UTXOs created during the deposit process.
117    ///
118    /// # Arguments
119    /// * `tx` - The parent transaction for the tree
120    /// * `vout` - The output index in the parent transaction
121    /// * `internal_tree_root` - The root of the internal tree structure
122    /// * `request_tree_root` - The tree creation request data
123    /// * `creation_result_tree_root` - The tree creation response data containing operator signatures
124    ///
125    /// # Returns
126    /// * `Ok((Vec<NodeSignatures>, Vec<Vec<u8>>))` - Contains:
127    ///   - Signatures for each node in the tree
128    ///   - The signing public keys used
129    /// * `Err(SparkSdkError)` - If signing fails for any node
130    fn sign_created_tree_in_bfs_order(
131        &self,
132        tx: bitcoin::Transaction,
133        vout: u32,
134        internal_tree_root: Arc<RwLock<DepositAddressTree>>,
135        request_tree_root: spark_protos::spark::CreationNode,
136        creation_result_tree_root: spark_protos::spark::CreationResponseNode,
137    ) -> Result<(Vec<NodeSignatures>, Vec<Vec<u8>>), SparkSdkError>;
138
139    /// Signs refund transactions for transfer leaves.
140    ///
141    /// This method signs refund transactions that provide security guarantees
142    /// during transfers. Refund transactions allow the user to recover funds
143    /// in case the transfer process is interrupted.
144    ///
145    /// # Arguments
146    /// * `leaf_data_map` - A map of leaf IDs to their refund signing data
147    /// * `operator_signing_results` - Signature shares from Spark Operators
148    /// * `adaptor_public_key` - Public key used for adaptor signatures
149    ///
150    /// # Returns
151    /// * `Ok(Vec<NodeSignatures>)` - Signatures for each refund transaction
152    /// * `Err(SparkSdkError)` - If signing fails for any refund transaction
153    fn sign_transfer_refunds(
154        &self,
155        leaf_data_map: &HashMap<String, LeafRefundSigningData>,
156        operator_signing_results: &Vec<LeafRefundTxSigningResult>,
157        adaptor_public_key: Vec<u8>,
158    ) -> Result<Vec<NodeSignatures>, SparkSdkError>;
159
160    /// Signs transactions for a Lightning swap operation.
161    ///
162    /// This method generates signatures for transactions involved in a Lightning
163    /// payment, where the user's leaves are swapped with the SSP in exchange for
164    /// the Lightning payment execution.
165    ///
166    /// # Arguments
167    /// * `leaves` - The leaves involved in the swap
168    /// * `signing_commitments` - Nonce commitments for signing
169    /// * `receiver_identity_pubkey` - The identity public key of the receiver
170    ///
171    /// # Returns
172    /// * `Ok((SignFrostResponse, Vec<Vec<u8>>, Vec<SigningCommitment>))` - Contains:
173    ///   - The signature shares
174    ///   - The refund transaction data
175    ///   - The user's signing commitments
176    /// * `Err(SparkSdkError)` - If signing fails
177    #[allow(clippy::type_complexity)]
178    fn sign_for_lightning_swap(
179        &self,
180        leaves: &Vec<LeafKeyTweak>,
181        signing_commitments: &Vec<RequestedSigningCommitments>,
182        receiver_identity_pubkey: PublicKey,
183    ) -> Result<(SignFrostResponse, Vec<Vec<u8>>, Vec<SigningCommitment>), SparkSdkError>;
184
185    /// Signs root node and refund transactions during tree creation.
186    ///
187    /// This method signs the root node transaction and its corresponding refund
188    /// transaction during the deposit tree creation process.
189    ///
190    /// # Arguments
191    /// * `signing_pubkey_bytes` - The signing public key as bytes
192    /// * `verifying_pubkey_bytes` - The verifying public key as bytes
193    /// * `root_tx_bytes` - The root transaction bytes
194    /// * `refund_tx_bytes` - The refund transaction bytes
195    /// * `root_tx_sighash` - The sighash of the root transaction
196    /// * `refund_tx_sighash` - The sighash of the refund transaction
197    /// * `root_nonce_commitment` - Nonce commitment for the root transaction
198    /// * `refund_nonce_commitment` - Nonce commitment for the refund transaction
199    /// * `tree_creation_response` - Response from Spark Operators with their signature shares
200    ///
201    /// # Returns
202    /// * `Ok(Vec<Vec<u8>>)` - Signatures for the root and refund transactions
203    /// * `Err(SparkSdkError)` - If signing fails
204    fn sign_root_creation(
205        &self,
206        signing_pubkey_bytes: Vec<u8>,
207        verifying_pubkey_bytes: Vec<u8>,
208        root_tx_bytes: Vec<u8>,
209        refund_tx_bytes: Vec<u8>,
210        root_tx_sighash: Vec<u8>,
211        refund_tx_sighash: Vec<u8>,
212        root_nonce_commitment: SigningCommitments,
213        refund_nonce_commitment: SigningCommitments,
214        tree_creation_response: spark_protos::spark::StartTreeCreationResponse,
215    ) -> Result<Vec<Vec<u8>>, SparkSdkError>;
216
217    /// Signs a message using the new FROST signing flow.
218    ///
219    /// This is an improved signing method that provides a more streamlined
220    /// interface for FROST signing operations.
221    ///
222    /// # Arguments
223    /// * `message` - The message to sign
224    /// * `private_as_pubkey` - The private key represented as a public key (for lookup)
225    /// * `verifying_key` - The verifying key for signature verification
226    /// * `self_commitment` - The user's nonce commitment
227    /// * `spark_commitments` - Nonce commitments from Spark Operators
228    /// * `adaptor_public_key` - Optional adaptor public key for adaptor signatures
229    ///
230    /// # Returns
231    /// * `Ok(Vec<u8>)` - The signature share
232    /// * `Err(SparkSdkError)` - If signing fails
233    fn sign_frost_new(
234        &self,
235        message: Vec<u8>,
236        private_as_pubkey: Vec<u8>,
237        verifying_key: Vec<u8>,
238        self_commitment: SigningCommitments,
239        spark_commitments: HashMap<String, SigningCommitment>,
240        adaptor_public_key: Option<Vec<u8>>,
241    ) -> Result<Vec<u8>, SparkSdkError>;
242}