1use bitcoin::bip32::DerivationPath;
6use bitcoin::hashes::{Hash, Hmac, sha256};
7use bitcoin::secp256k1;
8use serde::{Deserialize, Serialize};
9use std::str::FromStr;
10
11use crate::SdkError;
12
13#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
15#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
16pub struct PublicKeyBytes {
17 pub bytes: Vec<u8>,
18}
19
20impl PublicKeyBytes {
21 pub fn from_public_key(pk: &secp256k1::PublicKey) -> Self {
22 Self {
23 bytes: pk.serialize().to_vec(),
24 }
25 }
26
27 pub fn to_public_key(&self) -> Result<secp256k1::PublicKey, SdkError> {
28 secp256k1::PublicKey::from_slice(&self.bytes)
29 .map_err(|e| SdkError::Generic(format!("Invalid public key bytes: {e}")))
30 }
31}
32
33#[derive(Clone, Debug, Serialize, Deserialize)]
35#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
36pub struct EcdsaSignatureBytes {
37 pub bytes: Vec<u8>,
38}
39
40impl EcdsaSignatureBytes {
41 pub fn from_signature(sig: &secp256k1::ecdsa::Signature) -> Self {
42 Self {
43 bytes: sig.serialize_compact().to_vec(),
44 }
45 }
46
47 pub fn to_signature(&self) -> Result<secp256k1::ecdsa::Signature, SdkError> {
48 secp256k1::ecdsa::Signature::from_compact(&self.bytes)
49 .map_err(|e| SdkError::Generic(format!("Invalid ECDSA signature bytes: {e}")))
50 }
51}
52
53#[derive(Clone, Debug, Serialize, Deserialize)]
55#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
56pub struct SchnorrSignatureBytes {
57 pub bytes: Vec<u8>,
58}
59
60impl SchnorrSignatureBytes {
61 pub fn from_signature(sig: &secp256k1::schnorr::Signature) -> Self {
62 Self {
63 bytes: sig.as_ref().to_vec(),
64 }
65 }
66
67 pub fn to_signature(&self) -> Result<secp256k1::schnorr::Signature, SdkError> {
68 secp256k1::schnorr::Signature::from_slice(&self.bytes)
69 .map_err(|e| SdkError::Generic(format!("Invalid Schnorr signature bytes: {e}")))
70 }
71}
72
73#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
74#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
75pub struct HashedMessageBytes {
76 pub bytes: Vec<u8>,
77}
78
79impl HashedMessageBytes {
80 pub fn from_hmac(hmac: &Hmac<sha256::Hash>) -> Self {
81 Self {
82 bytes: hmac.to_byte_array().to_vec(),
83 }
84 }
85
86 pub fn to_hmac(&self) -> Result<Hmac<sha256::Hash>, SdkError> {
87 Hmac::<sha256::Hash>::from_slice(&self.bytes)
88 .map_err(|e| SdkError::Generic(format!("Invalid HMAC bytes: {e}")))
89 }
90}
91
92#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
94#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
95pub struct MessageBytes {
96 pub bytes: Vec<u8>,
97}
98
99impl MessageBytes {
100 pub fn new(bytes: Vec<u8>) -> Self {
102 Self { bytes }
103 }
104
105 pub fn to_digest(&self) -> Result<[u8; 32], SdkError> {
107 self.bytes
108 .clone()
109 .try_into()
110 .map_err(|_| SdkError::Generic("Message digest must be 32 bytes".to_string()))
111 }
112}
113
114#[derive(Clone, Debug, Serialize, Deserialize)]
116#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
117pub struct RecoverableEcdsaSignatureBytes {
118 pub bytes: Vec<u8>,
119}
120
121impl RecoverableEcdsaSignatureBytes {
122 pub fn new(bytes: Vec<u8>) -> Self {
123 Self { bytes }
124 }
125}
126
127#[derive(Clone, Serialize, Deserialize)]
129#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
130pub struct SecretBytes {
131 pub bytes: Vec<u8>,
132}
133
134impl std::fmt::Debug for SecretBytes {
137 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
138 f.debug_tuple("SecretBytes").field(&"<redacted>").finish()
139 }
140}
141
142impl SecretBytes {
143 pub fn from_secret_key(sk: &secp256k1::SecretKey) -> Self {
144 Self {
145 bytes: sk.secret_bytes().to_vec(),
146 }
147 }
148
149 pub fn to_secret_key(&self) -> Result<secp256k1::SecretKey, SdkError> {
150 secp256k1::SecretKey::from_slice(&self.bytes)
151 .map_err(|e| SdkError::Generic(format!("Invalid private key bytes: {e}")))
152 }
153}
154
155pub fn derivation_path_to_string(path: &DerivationPath) -> String {
157 path.to_string()
158}
159
160pub fn string_to_derivation_path(s: &str) -> Result<DerivationPath, SdkError> {
161 DerivationPath::from_str(s)
162 .map_err(|e| SdkError::Generic(format!("Invalid derivation path '{s}': {e}")))
163}
164
165#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
167#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
168pub struct ExternalTreeNodeId {
169 pub id: String,
171}
172
173impl ExternalTreeNodeId {
174 pub fn from_tree_node_id(id: &spark_wallet::TreeNodeId) -> Result<Self, SdkError> {
175 Ok(Self { id: id.to_string() })
176 }
177
178 pub fn to_tree_node_id(&self) -> Result<spark_wallet::TreeNodeId, SdkError> {
179 spark_wallet::TreeNodeId::from_str(&self.id)
180 .map_err(|e| SdkError::Generic(format!("Invalid TreeNodeId: {e}")))
181 }
182}
183
184#[derive(Clone, Debug, Serialize, Deserialize)]
186#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
187pub struct ExternalFrostSignatureShare {
188 pub bytes: Vec<u8>,
190}
191
192impl ExternalFrostSignatureShare {
193 pub fn from_signature_share(
194 share: &frost_secp256k1_tr::round2::SignatureShare,
195 ) -> Result<Self, SdkError> {
196 let bytes = share.serialize();
197 Ok(Self { bytes })
198 }
199
200 pub fn to_signature_share(
201 &self,
202 ) -> Result<frost_secp256k1_tr::round2::SignatureShare, SdkError> {
203 frost_secp256k1_tr::round2::SignatureShare::deserialize(&self.bytes)
204 .map_err(|e| SdkError::Generic(format!("Failed to deserialize SignatureShare: {e}")))
205 }
206}
207
208#[derive(Clone, Debug, Serialize, Deserialize)]
210#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
211pub struct ExternalFrostSignature {
212 pub bytes: Vec<u8>,
214}
215
216impl ExternalFrostSignature {
217 pub fn from_frost_signature(sig: &frost_secp256k1_tr::Signature) -> Result<Self, SdkError> {
218 let bytes = sig
219 .serialize()
220 .map_err(|e| SdkError::Generic(format!("Failed to serialize Frost signature: {e}")))?;
221 let bytes = bytes.clone();
222 Ok(Self { bytes })
223 }
224
225 pub fn to_frost_signature(&self) -> Result<frost_secp256k1_tr::Signature, SdkError> {
226 frost_secp256k1_tr::Signature::deserialize(&self.bytes)
227 .map_err(|e| SdkError::Generic(format!("Failed to deserialize Frost signature: {e}")))
228 }
229}
230
231#[derive(Clone, Debug, Serialize, Deserialize)]
236#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
237pub struct ExternalFrostCommitments {
238 pub hiding_commitment: Vec<u8>,
240 pub binding_commitment: Vec<u8>,
242}
243
244impl ExternalFrostCommitments {
245 pub fn from_frost_commitments(
246 commitments: &frost_secp256k1_tr::round1::SigningCommitments,
247 ) -> Result<Self, SdkError> {
248 let hiding_commitment = commitments.hiding().serialize().map_err(|e| {
249 SdkError::Generic(format!("Failed to serialize hiding commitment: {e}"))
250 })?;
251 let binding_commitment = commitments.binding().serialize().map_err(|e| {
252 SdkError::Generic(format!("Failed to serialize binding commitment: {e}"))
253 })?;
254
255 Ok(Self {
256 hiding_commitment,
257 binding_commitment,
258 })
259 }
260
261 pub fn to_frost_commitments(
262 &self,
263 ) -> Result<frost_secp256k1_tr::round1::SigningCommitments, SdkError> {
264 use frost_secp256k1_tr::round1::{NonceCommitment, SigningCommitments};
265
266 let hiding = NonceCommitment::deserialize(&self.hiding_commitment).map_err(|e| {
267 SdkError::Generic(format!("Failed to deserialize hiding commitment: {e}"))
268 })?;
269 let binding = NonceCommitment::deserialize(&self.binding_commitment).map_err(|e| {
270 SdkError::Generic(format!("Failed to deserialize binding commitment: {e}"))
271 })?;
272
273 Ok(SigningCommitments::new(hiding, binding))
274 }
275}
276
277#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
279#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
280pub struct ExternalIdentifier {
281 pub bytes: Vec<u8>,
283}
284
285impl ExternalIdentifier {
286 pub fn from_identifier(id: &frost_secp256k1_tr::Identifier) -> Self {
287 Self {
288 bytes: id.serialize(),
289 }
290 }
291
292 pub fn to_identifier(&self) -> Result<frost_secp256k1_tr::Identifier, SdkError> {
293 frost_secp256k1_tr::Identifier::deserialize(&self.bytes)
294 .map_err(|e| SdkError::Generic(format!("Invalid identifier: {e}")))
295 }
296}
297
298#[derive(Clone, Debug, Serialize, Deserialize)]
300#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
301pub struct ExternalSigningCommitments {
302 pub hiding: Vec<u8>,
304 pub binding: Vec<u8>,
306}
307
308impl ExternalSigningCommitments {
309 pub fn from_signing_commitments(
310 commitments: &frost_secp256k1_tr::round1::SigningCommitments,
311 ) -> Result<Self, SdkError> {
312 let hiding = commitments.hiding().serialize().map_err(|e| {
313 SdkError::Generic(format!("Failed to serialize hiding commitment: {e}"))
314 })?;
315 let binding = commitments.binding().serialize().map_err(|e| {
316 SdkError::Generic(format!("Failed to serialize binding commitment: {e}"))
317 })?;
318 Ok(Self { hiding, binding })
319 }
320
321 pub fn to_signing_commitments(
322 &self,
323 ) -> Result<frost_secp256k1_tr::round1::SigningCommitments, SdkError> {
324 use frost_secp256k1_tr::round1::NonceCommitment;
325
326 let hiding = NonceCommitment::deserialize(&self.hiding)
327 .map_err(|e| SdkError::Generic(format!("Failed to deserialize hiding: {e}")))?;
328 let binding = NonceCommitment::deserialize(&self.binding)
329 .map_err(|e| SdkError::Generic(format!("Failed to deserialize binding: {e}")))?;
330
331 Ok(frost_secp256k1_tr::round1::SigningCommitments::new(
332 hiding, binding,
333 ))
334 }
335}
336
337#[derive(Clone, Debug, Serialize, Deserialize)]
339#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
340pub struct IdentifierCommitmentPair {
341 pub identifier: ExternalIdentifier,
342 pub commitment: ExternalSigningCommitments,
343}
344
345#[derive(Clone, Debug, Serialize, Deserialize)]
347#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
348pub struct IdentifierSignaturePair {
349 pub identifier: ExternalIdentifier,
350 pub signature: ExternalFrostSignatureShare,
351}
352
353#[derive(Clone, Debug, Serialize, Deserialize)]
355#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
356pub struct IdentifierPublicKeyPair {
357 pub identifier: ExternalIdentifier,
358 pub public_key: Vec<u8>,
359}