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, Debug, Serialize, Deserialize)]
129#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
130pub struct SecretBytes {
131 pub bytes: Vec<u8>,
132}
133
134impl SecretBytes {
135 pub fn from_secret_key(sk: &secp256k1::SecretKey) -> Self {
136 Self {
137 bytes: sk.secret_bytes().to_vec(),
138 }
139 }
140
141 pub fn to_secret_key(&self) -> Result<secp256k1::SecretKey, SdkError> {
142 secp256k1::SecretKey::from_slice(&self.bytes)
143 .map_err(|e| SdkError::Generic(format!("Invalid private key bytes: {e}")))
144 }
145}
146
147pub fn derivation_path_to_string(path: &DerivationPath) -> String {
149 path.to_string()
150}
151
152pub fn string_to_derivation_path(s: &str) -> Result<DerivationPath, SdkError> {
153 DerivationPath::from_str(s)
154 .map_err(|e| SdkError::Generic(format!("Invalid derivation path '{s}': {e}")))
155}
156
157#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
159#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
160pub struct ExternalTreeNodeId {
161 pub id: String,
163}
164
165impl ExternalTreeNodeId {
166 pub fn from_tree_node_id(id: &spark_wallet::TreeNodeId) -> Result<Self, SdkError> {
167 Ok(Self { id: id.to_string() })
168 }
169
170 pub fn to_tree_node_id(&self) -> Result<spark_wallet::TreeNodeId, SdkError> {
171 spark_wallet::TreeNodeId::from_str(&self.id)
172 .map_err(|e| SdkError::Generic(format!("Invalid TreeNodeId: {e}")))
173 }
174}
175
176#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
178#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
179pub struct ExternalEncryptedSecret {
180 pub ciphertext: Vec<u8>,
182}
183
184impl ExternalEncryptedSecret {
185 pub fn from_encrypted_secret(key: &spark_wallet::EncryptedSecret) -> Result<Self, SdkError> {
186 Ok(Self {
187 ciphertext: key.as_slice().to_vec(),
188 })
189 }
190
191 pub fn to_encrypted_private_key(&self) -> Result<spark_wallet::EncryptedSecret, SdkError> {
192 Ok(spark_wallet::EncryptedSecret::new(self.ciphertext.clone()))
193 }
194}
195
196#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
198#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
199pub enum ExternalSecretSource {
200 Derived { node_id: ExternalTreeNodeId },
202 Encrypted { key: ExternalEncryptedSecret },
204}
205
206impl ExternalSecretSource {
207 pub fn from_secret_source(source: &spark_wallet::SecretSource) -> Result<Self, SdkError> {
208 match source {
209 spark_wallet::SecretSource::Derived(node_id) => Ok(Self::Derived {
210 node_id: ExternalTreeNodeId::from_tree_node_id(node_id)?,
211 }),
212 spark_wallet::SecretSource::Encrypted(key) => Ok(Self::Encrypted {
213 key: ExternalEncryptedSecret::from_encrypted_secret(key)?,
214 }),
215 }
216 }
217
218 pub fn to_secret_source(&self) -> Result<spark_wallet::SecretSource, SdkError> {
219 match self {
220 Self::Derived { node_id } => Ok(spark_wallet::SecretSource::Derived(
221 node_id.to_tree_node_id()?,
222 )),
223 Self::Encrypted { key } => Ok(spark_wallet::SecretSource::Encrypted(
224 key.to_encrypted_private_key()?,
225 )),
226 }
227 }
228}
229
230#[derive(Clone, Debug, Serialize, Deserialize)]
232#[cfg_attr(feature = "uniffi", derive(uniffi::Enum))]
233pub enum ExternalSecretToSplit {
234 SecretSource { source: ExternalSecretSource },
236 Preimage { data: Vec<u8> },
238}
239
240impl ExternalSecretToSplit {
241 pub fn from_secret_to_split(secret: &spark_wallet::SecretToSplit) -> Result<Self, SdkError> {
242 match secret {
243 spark_wallet::SecretToSplit::SecretSource(source) => Ok(Self::SecretSource {
244 source: ExternalSecretSource::from_secret_source(source)?,
245 }),
246 spark_wallet::SecretToSplit::Preimage(data) => {
247 Ok(Self::Preimage { data: data.clone() })
248 }
249 }
250 }
251
252 pub fn to_secret_to_split(&self) -> Result<spark_wallet::SecretToSplit, SdkError> {
253 match self {
254 Self::SecretSource { source } => Ok(spark_wallet::SecretToSplit::SecretSource(
255 source.to_secret_source()?,
256 )),
257 Self::Preimage { data } => Ok(spark_wallet::SecretToSplit::Preimage(data.clone())),
258 }
259 }
260}
261
262#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
264#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
265pub struct ExternalScalar {
266 pub bytes: Vec<u8>,
268}
269
270#[derive(Clone, Debug, Serialize, Deserialize)]
272#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
273pub struct ExternalSecretShare {
274 pub threshold: u32,
276 pub index: ExternalScalar,
278 pub share: ExternalScalar,
280}
281
282#[derive(Clone, Debug, Serialize, Deserialize)]
284#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
285pub struct ExternalVerifiableSecretShare {
286 pub secret_share: ExternalSecretShare,
288 pub proofs: Vec<Vec<u8>>,
290}
291
292impl ExternalVerifiableSecretShare {
293 pub fn from_verifiable_secret_share(
294 share: &spark_wallet::VerifiableSecretShare,
295 ) -> Result<Self, SdkError> {
296 use k256::elliptic_curve::sec1::ToEncodedPoint;
297
298 let secret_share = ExternalSecretShare {
299 threshold: share
300 .secret_share
301 .threshold
302 .try_into()
303 .map_err(|_| SdkError::Generic("Threshold value too large".to_string()))?,
304 index: ExternalScalar {
305 bytes: share.secret_share.index.to_bytes().to_vec(),
306 },
307 share: ExternalScalar {
308 bytes: share.secret_share.share.to_bytes().to_vec(),
309 },
310 };
311
312 let proofs = share
313 .proofs
314 .iter()
315 .map(|pk| pk.to_encoded_point(true).as_bytes().to_vec())
316 .collect();
317
318 Ok(Self {
319 secret_share,
320 proofs,
321 })
322 }
323
324 pub fn to_verifiable_secret_share(
325 &self,
326 ) -> Result<spark_wallet::VerifiableSecretShare, SdkError> {
327 use k256::elliptic_curve::PrimeField;
328 use k256::{FieldBytes, PublicKey as k256PublicKey, Scalar};
329
330 let index_bytes: [u8; 32] = self.secret_share.index.bytes[..]
331 .try_into()
332 .map_err(|_| SdkError::Generic("Invalid index scalar length".into()))?;
333 let index = Scalar::from_repr(FieldBytes::clone_from_slice(&index_bytes))
334 .into_option()
335 .ok_or_else(|| SdkError::Generic("Invalid index scalar".into()))?;
336
337 let share_bytes: [u8; 32] = self.secret_share.share.bytes[..]
338 .try_into()
339 .map_err(|_| SdkError::Generic("Invalid share scalar length".into()))?;
340 let share = Scalar::from_repr(FieldBytes::clone_from_slice(&share_bytes))
341 .into_option()
342 .ok_or_else(|| SdkError::Generic("Invalid share scalar".into()))?;
343
344 let proofs: Vec<k256PublicKey> = self
345 .proofs
346 .iter()
347 .map(|bytes| {
348 k256PublicKey::from_sec1_bytes(bytes)
349 .map_err(|e| SdkError::Generic(format!("Invalid proof public key: {e}")))
350 })
351 .collect::<Result<Vec<_>, _>>()?;
352
353 Ok(spark_wallet::VerifiableSecretShare {
354 secret_share: spark_wallet::SecretShare {
355 threshold: self.secret_share.threshold as usize,
356 index,
357 share,
358 },
359 proofs,
360 })
361 }
362}
363
364#[derive(Clone, Debug, Serialize, Deserialize)]
366#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
367pub struct ExternalFrostSignatureShare {
368 pub bytes: Vec<u8>,
370}
371
372impl ExternalFrostSignatureShare {
373 pub fn from_signature_share(
374 share: &frost_secp256k1_tr::round2::SignatureShare,
375 ) -> Result<Self, SdkError> {
376 let bytes = share.serialize();
377 Ok(Self { bytes })
378 }
379
380 pub fn to_signature_share(
381 &self,
382 ) -> Result<frost_secp256k1_tr::round2::SignatureShare, SdkError> {
383 frost_secp256k1_tr::round2::SignatureShare::deserialize(&self.bytes)
384 .map_err(|e| SdkError::Generic(format!("Failed to deserialize SignatureShare: {e}")))
385 }
386}
387
388#[derive(Clone, Debug, Serialize, Deserialize)]
390#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
391pub struct ExternalFrostSignature {
392 pub bytes: Vec<u8>,
394}
395
396impl ExternalFrostSignature {
397 pub fn from_frost_signature(sig: &frost_secp256k1_tr::Signature) -> Result<Self, SdkError> {
398 let bytes = sig
399 .serialize()
400 .map_err(|e| SdkError::Generic(format!("Failed to serialize Frost signature: {e}")))?;
401 let bytes = bytes.clone();
402 Ok(Self { bytes })
403 }
404
405 pub fn to_frost_signature(&self) -> Result<frost_secp256k1_tr::Signature, SdkError> {
406 frost_secp256k1_tr::Signature::deserialize(&self.bytes)
407 .map_err(|e| SdkError::Generic(format!("Failed to deserialize Frost signature: {e}")))
408 }
409}
410
411#[derive(Clone, Debug, Serialize, Deserialize)]
413#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
414pub struct ExternalFrostCommitments {
415 pub hiding_commitment: Vec<u8>,
417 pub binding_commitment: Vec<u8>,
419 pub nonces_ciphertext: Vec<u8>,
421}
422
423impl ExternalFrostCommitments {
424 pub fn from_frost_commitments(
425 commitments: &spark_wallet::FrostSigningCommitmentsWithNonces,
426 ) -> Result<Self, SdkError> {
427 let hiding_commitment = commitments.commitments.hiding().serialize().map_err(|e| {
428 SdkError::Generic(format!("Failed to serialize hiding commitment: {e}"))
429 })?;
430 let binding_commitment = commitments.commitments.binding().serialize().map_err(|e| {
431 SdkError::Generic(format!("Failed to serialize binding commitment: {e}"))
432 })?;
433
434 Ok(Self {
435 hiding_commitment,
436 binding_commitment,
437 nonces_ciphertext: commitments.nonces_ciphertext.clone(),
438 })
439 }
440
441 pub fn to_frost_commitments(
442 &self,
443 ) -> Result<spark_wallet::FrostSigningCommitmentsWithNonces, SdkError> {
444 use frost_secp256k1_tr::round1::{NonceCommitment, SigningCommitments};
445
446 let hiding = NonceCommitment::deserialize(&self.hiding_commitment).map_err(|e| {
447 SdkError::Generic(format!("Failed to deserialize hiding commitment: {e}"))
448 })?;
449 let binding = NonceCommitment::deserialize(&self.binding_commitment).map_err(|e| {
450 SdkError::Generic(format!("Failed to deserialize binding commitment: {e}"))
451 })?;
452
453 let commitments = SigningCommitments::new(hiding, binding);
454
455 Ok(spark_wallet::FrostSigningCommitmentsWithNonces {
456 commitments,
457 nonces_ciphertext: self.nonces_ciphertext.clone(),
458 })
459 }
460}
461
462#[derive(Clone, Debug, Serialize, Deserialize, PartialEq)]
464#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
465pub struct ExternalIdentifier {
466 pub bytes: Vec<u8>,
468}
469
470impl ExternalIdentifier {
471 pub fn from_identifier(id: &frost_secp256k1_tr::Identifier) -> Self {
472 Self {
473 bytes: id.serialize(),
474 }
475 }
476
477 pub fn to_identifier(&self) -> Result<frost_secp256k1_tr::Identifier, SdkError> {
478 frost_secp256k1_tr::Identifier::deserialize(&self.bytes)
479 .map_err(|e| SdkError::Generic(format!("Invalid identifier: {e}")))
480 }
481}
482
483#[derive(Clone, Debug, Serialize, Deserialize)]
485#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
486pub struct ExternalSigningCommitments {
487 pub hiding: Vec<u8>,
489 pub binding: Vec<u8>,
491}
492
493impl ExternalSigningCommitments {
494 pub fn from_signing_commitments(
495 commitments: &frost_secp256k1_tr::round1::SigningCommitments,
496 ) -> Result<Self, SdkError> {
497 let hiding = commitments.hiding().serialize().map_err(|e| {
498 SdkError::Generic(format!("Failed to serialize hiding commitment: {e}"))
499 })?;
500 let binding = commitments.binding().serialize().map_err(|e| {
501 SdkError::Generic(format!("Failed to serialize binding commitment: {e}"))
502 })?;
503 Ok(Self { hiding, binding })
504 }
505
506 pub fn to_signing_commitments(
507 &self,
508 ) -> Result<frost_secp256k1_tr::round1::SigningCommitments, SdkError> {
509 use frost_secp256k1_tr::round1::NonceCommitment;
510
511 let hiding = NonceCommitment::deserialize(&self.hiding)
512 .map_err(|e| SdkError::Generic(format!("Failed to deserialize hiding: {e}")))?;
513 let binding = NonceCommitment::deserialize(&self.binding)
514 .map_err(|e| SdkError::Generic(format!("Failed to deserialize binding: {e}")))?;
515
516 Ok(frost_secp256k1_tr::round1::SigningCommitments::new(
517 hiding, binding,
518 ))
519 }
520}
521
522#[derive(Clone, Debug, Serialize, Deserialize)]
524#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
525pub struct IdentifierCommitmentPair {
526 pub identifier: ExternalIdentifier,
527 pub commitment: ExternalSigningCommitments,
528}
529
530#[derive(Clone, Debug, Serialize, Deserialize)]
532#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
533pub struct IdentifierSignaturePair {
534 pub identifier: ExternalIdentifier,
535 pub signature: ExternalFrostSignatureShare,
536}
537
538#[derive(Clone, Debug, Serialize, Deserialize)]
540#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
541pub struct IdentifierPublicKeyPair {
542 pub identifier: ExternalIdentifier,
543 pub public_key: Vec<u8>,
544}
545
546#[derive(Clone, Debug, Serialize, Deserialize)]
548#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
549pub struct ExternalSignFrostRequest {
550 pub message: Vec<u8>,
552 pub public_key: Vec<u8>,
554 pub secret: ExternalSecretSource,
556 pub verifying_key: Vec<u8>,
558 pub self_nonce_commitment: ExternalFrostCommitments,
560 pub statechain_commitments: Vec<IdentifierCommitmentPair>,
562 pub adaptor_public_key: Option<Vec<u8>>,
564}
565
566impl ExternalSignFrostRequest {
567 pub fn from_sign_frost_request(
568 request: &spark_wallet::SignFrostRequest,
569 ) -> Result<Self, SdkError> {
570 let statechain_commitments = request
571 .statechain_commitments
572 .iter()
573 .map(|(id, comm)| {
574 Ok(IdentifierCommitmentPair {
575 identifier: ExternalIdentifier::from_identifier(id),
576 commitment: ExternalSigningCommitments::from_signing_commitments(comm)?,
577 })
578 })
579 .collect::<Result<Vec<_>, SdkError>>()?;
580
581 Ok(Self {
582 message: request.message.to_vec(),
583 public_key: request.public_key.serialize().to_vec(),
584 secret: ExternalSecretSource::from_secret_source(request.private_key)?,
585 verifying_key: request.verifying_key.serialize().to_vec(),
586 self_nonce_commitment: ExternalFrostCommitments::from_frost_commitments(
587 request.self_nonce_commitment,
588 )?,
589 statechain_commitments,
590 adaptor_public_key: request.adaptor_public_key.map(|pk| pk.serialize().to_vec()),
591 })
592 }
593
594 pub fn to_sign_frost_request(
595 &self,
596 ) -> Result<spark_wallet::SignFrostRequest<'static>, SdkError> {
597 use std::collections::BTreeMap;
598
599 let public_key = secp256k1::PublicKey::from_slice(&self.public_key)
600 .map_err(|e| SdkError::Generic(format!("Invalid public key: {e}")))?;
601 let verifying_key = secp256k1::PublicKey::from_slice(&self.verifying_key)
602 .map_err(|e| SdkError::Generic(format!("Invalid verifying key: {e}")))?;
603
604 let statechain_commitments: BTreeMap<_, _> = self
605 .statechain_commitments
606 .iter()
607 .map(|pair| {
608 Ok((
609 pair.identifier.to_identifier()?,
610 pair.commitment.to_signing_commitments()?,
611 ))
612 })
613 .collect::<Result<_, SdkError>>()?;
614
615 let adaptor_public_key = self
616 .adaptor_public_key
617 .as_ref()
618 .map(|bytes| {
619 secp256k1::PublicKey::from_slice(bytes)
620 .map_err(|e| SdkError::Generic(format!("Invalid adaptor public key: {e}")))
621 })
622 .transpose()?;
623
624 Ok(spark_wallet::SignFrostRequest {
627 message: Box::leak(self.message.clone().into_boxed_slice()),
628 public_key: Box::leak(Box::new(public_key)),
629 private_key: Box::leak(Box::new(self.secret.to_secret_source()?)),
630 verifying_key: Box::leak(Box::new(verifying_key)),
631 self_nonce_commitment: Box::leak(Box::new(
632 self.self_nonce_commitment.to_frost_commitments()?,
633 )),
634 statechain_commitments,
635 adaptor_public_key: adaptor_public_key.map(|pk| Box::leak(Box::new(pk)) as &_),
636 })
637 }
638}
639
640#[derive(Clone, Debug, Serialize, Deserialize)]
642#[cfg_attr(feature = "uniffi", derive(uniffi::Record))]
643pub struct ExternalAggregateFrostRequest {
644 pub message: Vec<u8>,
646 pub statechain_signatures: Vec<IdentifierSignaturePair>,
648 pub statechain_public_keys: Vec<IdentifierPublicKeyPair>,
650 pub verifying_key: Vec<u8>,
652 pub statechain_commitments: Vec<IdentifierCommitmentPair>,
654 pub self_commitment: ExternalSigningCommitments,
656 pub public_key: Vec<u8>,
658 pub self_signature: ExternalFrostSignatureShare,
660 pub adaptor_public_key: Option<Vec<u8>>,
662}
663
664impl ExternalAggregateFrostRequest {
665 pub fn from_aggregate_frost_request(
666 request: &spark_wallet::AggregateFrostRequest,
667 ) -> Result<Self, SdkError> {
668 let statechain_signatures = request
669 .statechain_signatures
670 .iter()
671 .map(|(id, share)| {
672 Ok(IdentifierSignaturePair {
673 identifier: ExternalIdentifier::from_identifier(id),
674 signature: ExternalFrostSignatureShare::from_signature_share(share)?,
675 })
676 })
677 .collect::<Result<Vec<_>, SdkError>>()?;
678
679 let statechain_public_keys = request
680 .statechain_public_keys
681 .iter()
682 .map(|(id, pk)| IdentifierPublicKeyPair {
683 identifier: ExternalIdentifier::from_identifier(id),
684 public_key: pk.serialize().to_vec(),
685 })
686 .collect();
687
688 let statechain_commitments = request
689 .statechain_commitments
690 .iter()
691 .map(|(id, comm)| {
692 Ok(IdentifierCommitmentPair {
693 identifier: ExternalIdentifier::from_identifier(id),
694 commitment: ExternalSigningCommitments::from_signing_commitments(comm)?,
695 })
696 })
697 .collect::<Result<Vec<_>, SdkError>>()?;
698
699 Ok(Self {
700 message: request.message.to_vec(),
701 statechain_signatures,
702 statechain_public_keys,
703 verifying_key: request.verifying_key.serialize().to_vec(),
704 statechain_commitments,
705 self_commitment: ExternalSigningCommitments::from_signing_commitments(
706 request.self_commitment,
707 )?,
708 public_key: request.public_key.serialize().to_vec(),
709 self_signature: ExternalFrostSignatureShare::from_signature_share(
710 request.self_signature,
711 )?,
712 adaptor_public_key: request.adaptor_public_key.map(|pk| pk.serialize().to_vec()),
713 })
714 }
715
716 pub fn to_aggregate_frost_request(
717 &self,
718 ) -> Result<spark_wallet::AggregateFrostRequest<'static>, SdkError> {
719 use std::collections::BTreeMap;
720
721 let statechain_signatures: BTreeMap<_, _> = self
722 .statechain_signatures
723 .iter()
724 .map(|pair| {
725 Ok((
726 pair.identifier.to_identifier()?,
727 pair.signature.to_signature_share()?,
728 ))
729 })
730 .collect::<Result<_, SdkError>>()?;
731
732 let statechain_public_keys: BTreeMap<_, _> = self
733 .statechain_public_keys
734 .iter()
735 .map(|pair| {
736 Ok((
737 pair.identifier.to_identifier()?,
738 secp256k1::PublicKey::from_slice(&pair.public_key)
739 .map_err(|e| SdkError::Generic(format!("Invalid public key: {e}")))?,
740 ))
741 })
742 .collect::<Result<_, SdkError>>()?;
743
744 let verifying_key = secp256k1::PublicKey::from_slice(&self.verifying_key)
745 .map_err(|e| SdkError::Generic(format!("Invalid verifying key: {e}")))?;
746
747 let statechain_commitments: BTreeMap<_, _> = self
748 .statechain_commitments
749 .iter()
750 .map(|pair| {
751 Ok((
752 pair.identifier.to_identifier()?,
753 pair.commitment.to_signing_commitments()?,
754 ))
755 })
756 .collect::<Result<_, SdkError>>()?;
757
758 let public_key = secp256k1::PublicKey::from_slice(&self.public_key)
759 .map_err(|e| SdkError::Generic(format!("Invalid public key: {e}")))?;
760
761 let adaptor_public_key = self
762 .adaptor_public_key
763 .as_ref()
764 .map(|bytes| {
765 secp256k1::PublicKey::from_slice(bytes)
766 .map_err(|e| SdkError::Generic(format!("Invalid adaptor public key: {e}")))
767 })
768 .transpose()?;
769
770 Ok(spark_wallet::AggregateFrostRequest {
771 message: Box::leak(self.message.clone().into_boxed_slice()),
772 statechain_signatures,
773 statechain_public_keys,
774 verifying_key: Box::leak(Box::new(verifying_key)),
775 statechain_commitments,
776 self_commitment: Box::leak(Box::new(self.self_commitment.to_signing_commitments()?)),
777 public_key: Box::leak(Box::new(public_key)),
778 self_signature: Box::leak(Box::new(self.self_signature.to_signature_share()?)),
779 adaptor_public_key: adaptor_public_key.map(|pk| Box::leak(Box::new(pk)) as &_),
780 })
781 }
782}