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)]
233#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
234pub struct ExternalFrostCommitments {
235 pub hiding_commitment: Vec<u8>,
237 pub binding_commitment: Vec<u8>,
239 pub nonces_ciphertext: Vec<u8>,
241}
242
243impl ExternalFrostCommitments {
244 pub fn from_frost_commitments(
245 commitments: &spark_wallet::FrostSigningCommitmentsWithNonces,
246 ) -> Result<Self, SdkError> {
247 let hiding_commitment = commitments.commitments.hiding().serialize().map_err(|e| {
248 SdkError::Generic(format!("Failed to serialize hiding commitment: {e}"))
249 })?;
250 let binding_commitment = commitments.commitments.binding().serialize().map_err(|e| {
251 SdkError::Generic(format!("Failed to serialize binding commitment: {e}"))
252 })?;
253
254 Ok(Self {
255 hiding_commitment,
256 binding_commitment,
257 nonces_ciphertext: commitments.nonces_ciphertext.clone(),
258 })
259 }
260
261 pub fn to_frost_commitments(
262 &self,
263 ) -> Result<spark_wallet::FrostSigningCommitmentsWithNonces, 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 let commitments = SigningCommitments::new(hiding, binding);
274
275 Ok(spark_wallet::FrostSigningCommitmentsWithNonces {
276 commitments,
277 nonces_ciphertext: self.nonces_ciphertext.clone(),
278 })
279 }
280}
281
282#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
284#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
285pub struct ExternalIdentifier {
286 pub bytes: Vec<u8>,
288}
289
290impl ExternalIdentifier {
291 pub fn from_identifier(id: &frost_secp256k1_tr::Identifier) -> Self {
292 Self {
293 bytes: id.serialize(),
294 }
295 }
296
297 pub fn to_identifier(&self) -> Result<frost_secp256k1_tr::Identifier, SdkError> {
298 frost_secp256k1_tr::Identifier::deserialize(&self.bytes)
299 .map_err(|e| SdkError::Generic(format!("Invalid identifier: {e}")))
300 }
301}
302
303#[derive(Clone, Debug, Serialize, Deserialize)]
305#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
306pub struct ExternalSigningCommitments {
307 pub hiding: Vec<u8>,
309 pub binding: Vec<u8>,
311}
312
313impl ExternalSigningCommitments {
314 pub fn from_signing_commitments(
315 commitments: &frost_secp256k1_tr::round1::SigningCommitments,
316 ) -> Result<Self, SdkError> {
317 let hiding = commitments.hiding().serialize().map_err(|e| {
318 SdkError::Generic(format!("Failed to serialize hiding commitment: {e}"))
319 })?;
320 let binding = commitments.binding().serialize().map_err(|e| {
321 SdkError::Generic(format!("Failed to serialize binding commitment: {e}"))
322 })?;
323 Ok(Self { hiding, binding })
324 }
325
326 pub fn to_signing_commitments(
327 &self,
328 ) -> Result<frost_secp256k1_tr::round1::SigningCommitments, SdkError> {
329 use frost_secp256k1_tr::round1::NonceCommitment;
330
331 let hiding = NonceCommitment::deserialize(&self.hiding)
332 .map_err(|e| SdkError::Generic(format!("Failed to deserialize hiding: {e}")))?;
333 let binding = NonceCommitment::deserialize(&self.binding)
334 .map_err(|e| SdkError::Generic(format!("Failed to deserialize binding: {e}")))?;
335
336 Ok(frost_secp256k1_tr::round1::SigningCommitments::new(
337 hiding, binding,
338 ))
339 }
340}
341
342#[derive(Clone, Debug, Serialize, Deserialize)]
344#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
345pub struct IdentifierCommitmentPair {
346 pub identifier: ExternalIdentifier,
347 pub commitment: ExternalSigningCommitments,
348}
349
350#[derive(Clone, Debug, Serialize, Deserialize)]
352#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
353pub struct IdentifierSignaturePair {
354 pub identifier: ExternalIdentifier,
355 pub signature: ExternalFrostSignatureShare,
356}
357
358#[derive(Clone, Debug, Serialize, Deserialize)]
360#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
361pub struct IdentifierPublicKeyPair {
362 pub identifier: ExternalIdentifier,
363 pub public_key: Vec<u8>,
364}