bc_components/signing/signing_private_key.rs
1use std::{cell::RefCell, rc::Rc};
2
3use bc_rand::{RandomNumberGenerator, SecureRandomNumberGenerator};
4use bc_ur::prelude::*;
5use ssh_key::{HashAlg, LineEnding, private::PrivateKey as SSHPrivateKey};
6
7use super::Verifier;
8use crate::{
9 ECKey, ECPrivateKey, Ed25519PrivateKey, Error, MLDSAPrivateKey, Result,
10 Signature, Signer, SigningPublicKey, tags,
11};
12
13/// Options for configuring signature creation.
14///
15/// Different signature schemes may require specific options:
16///
17/// - `Schnorr`: Requires a random number generator for signature creation
18/// - `Ssh`: Requires a namespace and hash algorithm
19///
20/// Other signature types like ECDSA, Ed25519, and ML-DSA don't require options.
21///
22/// # Examples
23///
24/// Creating Schnorr signing options:
25///
26/// ```
27/// use std::{cell::RefCell, rc::Rc};
28///
29/// use bc_components::SigningOptions;
30/// use bc_rand::SecureRandomNumberGenerator;
31///
32/// let rng = Rc::new(RefCell::new(SecureRandomNumberGenerator));
33/// let options = SigningOptions::Schnorr { rng };
34/// ```
35///
36/// Creating SSH signing options:
37///
38/// ```
39/// use bc_components::SigningOptions;
40/// use ssh_key::HashAlg;
41///
42/// let options = SigningOptions::Ssh {
43/// namespace: "ssh".to_string(),
44/// hash_alg: HashAlg::Sha512,
45/// };
46/// ```
47#[derive(Clone)]
48pub enum SigningOptions {
49 /// Options for Schnorr signatures
50 Schnorr {
51 /// Non-default random number generator used for signature creation
52 rng: Rc<RefCell<dyn RandomNumberGenerator>>,
53 },
54
55 /// Options for SSH signatures
56 Ssh {
57 /// The namespace used for SSH signatures
58 namespace: String,
59
60 /// The hash algorithm used for SSH signatures
61 hash_alg: HashAlg,
62 },
63}
64
65/// A private key used for creating digital signatures.
66///
67/// `SigningPrivateKey` is an enum representing different types of signing
68/// private keys, including elliptic curve schemes (ECDSA, Schnorr), Edwards
69/// curve schemes (Ed25519), post-quantum schemes (ML-DSA), and SSH keys.
70///
71/// This type implements the `Signer` trait, allowing it to create signatures of
72/// the appropriate type.
73///
74/// # Examples
75///
76/// Creating a new Schnorr signing key and using it to sign a message:
77///
78/// ```
79/// use bc_components::{ECPrivateKey, Signer, SigningPrivateKey, Verifier};
80///
81/// // Create a new Schnorr signing key
82/// let private_key = SigningPrivateKey::new_schnorr(ECPrivateKey::new());
83///
84/// // Get the corresponding public key
85/// let public_key = private_key.public_key().unwrap();
86///
87/// // Sign a message
88/// let message = b"Hello, world!";
89/// let signature = private_key.sign(&message).unwrap();
90///
91/// // Verify the signature
92/// assert!(public_key.verify(&signature, &message));
93/// ```
94///
95/// # CBOR Serialization
96///
97/// `SigningPrivateKey` can be serialized to and from CBOR with appropriate
98/// tags:
99///
100/// ```
101/// use bc_components::{ECPrivateKey, SigningPrivateKey};
102/// use dcbor::prelude::*;
103///
104/// // Create a key
105/// let private_key = SigningPrivateKey::new_schnorr(ECPrivateKey::new());
106///
107/// // Convert to CBOR
108/// let cbor: CBOR = private_key.clone().into();
109/// let data = cbor.to_cbor_data();
110///
111/// // Convert back from CBOR
112/// let recovered = SigningPrivateKey::from_tagged_cbor_data(&data).unwrap();
113///
114/// // The keys should be equal
115/// assert_eq!(private_key, recovered);
116/// ```
117#[derive(Clone, PartialEq)]
118pub enum SigningPrivateKey {
119 /// A Schnorr private key based on the secp256k1 curve
120 Schnorr(ECPrivateKey),
121
122 /// An ECDSA private key based on the secp256k1 curve
123 ECDSA(ECPrivateKey),
124
125 /// An Ed25519 private key
126 Ed25519(Ed25519PrivateKey),
127
128 /// An SSH private key
129 SSH(Box<SSHPrivateKey>),
130
131 /// A post-quantum ML-DSA private key
132 MLDSA(MLDSAPrivateKey),
133}
134
135/// Implementation of hashing for SigningPrivateKey
136impl std::hash::Hash for SigningPrivateKey {
137 /// Hashes the key's data.
138 ///
139 /// This is used for collections that require hash support.
140 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
141 match self {
142 Self::Schnorr(key) => key.hash(state),
143 Self::ECDSA(key) => key.hash(state),
144 Self::Ed25519(key) => key.hash(state),
145 Self::SSH(key) => key.to_bytes().unwrap().hash(state),
146 Self::MLDSA(key) => key.as_bytes().hash(state),
147 }
148 }
149}
150
151impl Eq for SigningPrivateKey {}
152
153impl SigningPrivateKey {
154 /// Creates a new Schnorr signing private key from an `ECPrivateKey`.
155 ///
156 /// # Arguments
157 ///
158 /// * `key` - The elliptic curve private key to use
159 ///
160 /// # Returns
161 ///
162 /// A new Schnorr signing private key
163 ///
164 /// # Examples
165 ///
166 /// ```
167 /// use bc_components::{ECPrivateKey, SigningPrivateKey};
168 ///
169 /// // Create a new EC private key
170 /// let ec_key = ECPrivateKey::new();
171 ///
172 /// // Create a Schnorr signing key from it
173 /// let signing_key = SigningPrivateKey::new_schnorr(ec_key);
174 /// ```
175 pub const fn new_schnorr(key: ECPrivateKey) -> Self { Self::Schnorr(key) }
176
177 /// Creates a new ECDSA signing private key from an `ECPrivateKey`.
178 ///
179 /// # Arguments
180 ///
181 /// * `key` - The elliptic curve private key to use
182 ///
183 /// # Returns
184 ///
185 /// A new ECDSA signing private key
186 ///
187 /// # Examples
188 ///
189 /// ```
190 /// use bc_components::{ECPrivateKey, SigningPrivateKey};
191 ///
192 /// // Create a new EC private key
193 /// let ec_key = ECPrivateKey::new();
194 ///
195 /// // Create an ECDSA signing key from it
196 /// let signing_key = SigningPrivateKey::new_ecdsa(ec_key);
197 /// ```
198 pub const fn new_ecdsa(key: ECPrivateKey) -> Self { Self::ECDSA(key) }
199
200 /// Creates a new Ed25519 signing private key from an `Ed25519PrivateKey`.
201 ///
202 /// # Arguments
203 ///
204 /// * `key` - The Ed25519 private key to use
205 ///
206 /// # Returns
207 ///
208 /// A new Ed25519 signing private key
209 ///
210 /// # Examples
211 ///
212 /// ```
213 /// use bc_components::{Ed25519PrivateKey, SigningPrivateKey};
214 ///
215 /// // Create a new Ed25519 private key
216 /// let ed_key = Ed25519PrivateKey::new();
217 ///
218 /// // Create an Ed25519 signing key from it
219 /// let signing_key = SigningPrivateKey::new_ed25519(ed_key);
220 /// ```
221 pub const fn new_ed25519(key: Ed25519PrivateKey) -> Self {
222 Self::Ed25519(key)
223 }
224
225 /// Creates a new SSH signing private key from an `SSHPrivateKey`.
226 ///
227 /// # Arguments
228 ///
229 /// * `key` - The SSH private key to use
230 ///
231 /// # Returns
232 ///
233 /// A new SSH signing private key
234 pub fn new_ssh(key: SSHPrivateKey) -> Self { Self::SSH(Box::new(key)) }
235
236 /// Returns the underlying Schnorr private key if this is a Schnorr key.
237 ///
238 /// # Returns
239 ///
240 /// Some reference to the EC private key if this is a Schnorr key,
241 /// or None if it's a different key type.
242 ///
243 /// # Examples
244 ///
245 /// ```
246 /// use bc_components::{ECPrivateKey, SigningPrivateKey};
247 ///
248 /// // Create a Schnorr key
249 /// let schnorr_key = SigningPrivateKey::new_schnorr(ECPrivateKey::new());
250 /// assert!(schnorr_key.to_schnorr().is_some());
251 ///
252 /// // Create an ECDSA key
253 /// let ecdsa_key = SigningPrivateKey::new_ecdsa(ECPrivateKey::new());
254 /// assert!(ecdsa_key.to_schnorr().is_none());
255 /// ```
256 pub fn to_schnorr(&self) -> Option<&ECPrivateKey> {
257 match self {
258 Self::Schnorr(key) => Some(key),
259 _ => None,
260 }
261 }
262
263 /// Checks if this is a Schnorr signing key.
264 ///
265 /// # Returns
266 ///
267 /// `true` if this is a Schnorr key, `false` otherwise
268 pub fn is_schnorr(&self) -> bool { self.to_schnorr().is_some() }
269
270 /// Returns the underlying ECDSA private key if this is an ECDSA key.
271 ///
272 /// # Returns
273 ///
274 /// Some reference to the EC private key if this is an ECDSA key,
275 /// or None if it's a different key type.
276 pub fn to_ecdsa(&self) -> Option<&ECPrivateKey> {
277 match self {
278 Self::ECDSA(key) => Some(key),
279 _ => None,
280 }
281 }
282
283 /// Checks if this is an ECDSA signing key.
284 ///
285 /// # Returns
286 ///
287 /// `true` if this is an ECDSA key, `false` otherwise
288 pub fn is_ecdsa(&self) -> bool { self.to_ecdsa().is_some() }
289
290 /// Returns the underlying SSH private key if this is an SSH key.
291 ///
292 /// # Returns
293 ///
294 /// Some reference to the SSH private key if this is an SSH key,
295 /// or None if it's a different key type.
296 pub fn to_ssh(&self) -> Option<&SSHPrivateKey> {
297 match self {
298 Self::SSH(key) => Some(key),
299 _ => None,
300 }
301 }
302
303 /// Checks if this is an SSH signing key.
304 ///
305 /// # Returns
306 ///
307 /// `true` if this is an SSH key, `false` otherwise
308 pub fn is_ssh(&self) -> bool { self.to_ssh().is_some() }
309
310 /// Derives the corresponding public key for this private key.
311 ///
312 /// # Returns
313 ///
314 /// A `Result` containing the public key, or an error if the public key
315 /// cannot be derived (e.g., for MLDSA keys).
316 ///
317 /// # Examples
318 ///
319 /// ```
320 /// use bc_components::{ECPrivateKey, SigningPrivateKey};
321 ///
322 /// // Create a Schnorr signing key
323 /// let private_key = SigningPrivateKey::new_schnorr(ECPrivateKey::new());
324 ///
325 /// // Derive the public key
326 /// let public_key = private_key.public_key().unwrap();
327 /// ```
328 pub fn public_key(&self) -> Result<SigningPublicKey> {
329 match self {
330 Self::Schnorr(key) => {
331 Ok(SigningPublicKey::from_schnorr(key.schnorr_public_key()))
332 }
333 Self::ECDSA(key) => {
334 Ok(SigningPublicKey::from_ecdsa(key.public_key()))
335 }
336 Self::Ed25519(key) => {
337 Ok(SigningPublicKey::from_ed25519(key.public_key()))
338 }
339 Self::SSH(key) => {
340 Ok(SigningPublicKey::from_ssh(key.public_key().clone()))
341 }
342 Self::MLDSA(_) => {
343 Err(Error::general("Deriving MLDSA public key not supported"))
344 }
345 }
346 }
347}
348
349impl SigningPrivateKey {
350 /// Signs a message using ECDSA.
351 ///
352 /// This method is only valid for ECDSA keys.
353 ///
354 /// # Arguments
355 ///
356 /// * `message` - The message to sign
357 ///
358 /// # Returns
359 ///
360 /// A `Result` containing the ECDSA signature, or an error if the key is not
361 /// an ECDSA key.
362 ///
363 /// # Examples
364 ///
365 /// ```
366 /// use bc_components::{ECPrivateKey, Signer, SigningPrivateKey};
367 ///
368 /// // Create an ECDSA key
369 /// let private_key = SigningPrivateKey::new_ecdsa(ECPrivateKey::new());
370 ///
371 /// // Sign a message
372 /// let message = b"Hello, world!";
373 /// let signature = private_key.sign(&message).unwrap();
374 /// ```
375 fn ecdsa_sign(&self, message: impl AsRef<[u8]>) -> Result<Signature> {
376 if let Some(private_key) = self.to_ecdsa() {
377 let sig = private_key.ecdsa_sign(message);
378 Ok(Signature::ecdsa_from_data(sig))
379 } else {
380 Err(Error::crypto("Invalid key type for ECDSA signing"))
381 }
382 }
383
384 /// Signs a message using Schnorr with the provided random number generator.
385 ///
386 /// This method is only valid for Schnorr keys.
387 ///
388 /// # Arguments
389 ///
390 /// * `message` - The message to sign
391 /// * `rng` - The random number generator to use for signature creation
392 ///
393 /// # Returns
394 ///
395 /// A `Result` containing the Schnorr signature, or an error if the key is
396 /// not a Schnorr key.
397 ///
398 /// # Examples
399 ///
400 /// ```
401 /// use std::{cell::RefCell, rc::Rc};
402 ///
403 /// use bc_components::{ECPrivateKey, SigningPrivateKey};
404 /// use bc_rand::SecureRandomNumberGenerator;
405 ///
406 /// // Create a Schnorr key
407 /// let private_key = SigningPrivateKey::new_schnorr(ECPrivateKey::new());
408 ///
409 /// // Create an RNG
410 /// let rng = Rc::new(RefCell::new(SecureRandomNumberGenerator));
411 ///
412 /// // Sign a message
413 /// let message = b"Hello, world!";
414 /// let signature = private_key.schnorr_sign(&message, rng).unwrap();
415 /// ```
416 pub fn schnorr_sign(
417 &self,
418 message: impl AsRef<[u8]>,
419 rng: Rc<RefCell<dyn RandomNumberGenerator>>,
420 ) -> Result<Signature> {
421 if let Some(private_key) = self.to_schnorr() {
422 let sig =
423 private_key.schnorr_sign_using(message, &mut *rng.borrow_mut());
424 Ok(Signature::schnorr_from_data(sig))
425 } else {
426 Err(Error::crypto("Invalid key type for Schnorr signing"))
427 }
428 }
429
430 /// Signs a message using Ed25519.
431 ///
432 /// This method is only valid for Ed25519 keys.
433 ///
434 /// # Arguments
435 ///
436 /// * `message` - The message to sign
437 ///
438 /// # Returns
439 ///
440 /// A `Result` containing the Ed25519 signature, or an error if the key is
441 /// not an Ed25519 key.
442 ///
443 /// # Examples
444 ///
445 /// ```
446 /// use bc_components::{Ed25519PrivateKey, Signer, SigningPrivateKey};
447 ///
448 /// // Create an Ed25519 key
449 /// let private_key = SigningPrivateKey::new_ed25519(Ed25519PrivateKey::new());
450 ///
451 /// // Sign a message
452 /// let message = b"Hello, world!";
453 /// let signature = private_key.sign(&message).unwrap();
454 /// ```
455 pub fn ed25519_sign(&self, message: impl AsRef<[u8]>) -> Result<Signature> {
456 if let Self::Ed25519(key) = self {
457 let sig = key.sign(message.as_ref());
458 Ok(Signature::ed25519_from_data(sig))
459 } else {
460 Err(Error::crypto("Invalid key type for Ed25519 signing"))
461 }
462 }
463
464 /// Signs a message using SSH.
465 ///
466 /// This method is only valid for SSH keys.
467 ///
468 /// # Arguments
469 ///
470 /// * `message` - The message to sign
471 /// * `namespace` - The SSH namespace string
472 /// * `hash_alg` - The hash algorithm to use
473 ///
474 /// # Returns
475 ///
476 /// A `Result` containing the SSH signature, or an error if the key is not
477 /// an SSH key.
478 fn ssh_sign(
479 &self,
480 message: impl AsRef<[u8]>,
481 namespace: impl AsRef<str>,
482 hash_alg: HashAlg,
483 ) -> Result<Signature> {
484 if let Some(private) = self.to_ssh() {
485 let sig =
486 private.sign(namespace.as_ref(), hash_alg, message.as_ref())?;
487 Ok(Signature::from_ssh(sig))
488 } else {
489 Err(Error::ssh("Invalid key type for SSH signing"))
490 }
491 }
492
493 /// Signs a message using ML-DSA.
494 ///
495 /// This method is only valid for ML-DSA keys.
496 ///
497 /// # Arguments
498 ///
499 /// * `message` - The message to sign
500 ///
501 /// # Returns
502 ///
503 /// A `Result` containing the ML-DSA signature, or an error if the key is
504 /// not an ML-DSA key.
505 fn mldsa_sign(&self, message: impl AsRef<[u8]>) -> Result<Signature> {
506 if let Self::MLDSA(key) = self {
507 let sig = key.sign(message.as_ref());
508 Ok(Signature::MLDSA(sig))
509 } else {
510 Err(Error::post_quantum("Invalid key type for MLDSA signing"))
511 }
512 }
513}
514
515/// Implementation of the Signer trait for SigningPrivateKey
516impl Signer for SigningPrivateKey {
517 /// Signs a message with the appropriate algorithm based on the key type.
518 ///
519 /// This method dispatches to the appropriate signing method based on the
520 /// key type and provided options.
521 ///
522 /// # Arguments
523 ///
524 /// * `message` - The message to sign
525 /// * `options` - Optional signing options (algorithm-specific parameters)
526 ///
527 /// # Returns
528 ///
529 /// A `Result` containing the signature, or an error if signing fails
530 ///
531 /// # Examples
532 ///
533 /// ```
534 /// use std::{cell::RefCell, rc::Rc};
535 ///
536 /// use bc_components::{
537 /// ECPrivateKey, Signer, SigningOptions, SigningPrivateKey,
538 /// };
539 /// use bc_rand::SecureRandomNumberGenerator;
540 ///
541 /// // Create a Schnorr key
542 /// let private_key = SigningPrivateKey::new_schnorr(ECPrivateKey::new());
543 ///
544 /// // Create Schnorr signing options
545 /// let rng = Rc::new(RefCell::new(SecureRandomNumberGenerator));
546 /// let options = SigningOptions::Schnorr { rng };
547 ///
548 /// // Sign a message with options
549 /// let message = b"Hello, world!";
550 /// let signature = private_key
551 /// .sign_with_options(&message, Some(options))
552 /// .unwrap();
553 /// ```
554 fn sign_with_options(
555 &self,
556 message: &dyn AsRef<[u8]>,
557 options: Option<SigningOptions>,
558 ) -> Result<Signature> {
559 match self {
560 Self::Schnorr(_) => {
561 if let Some(SigningOptions::Schnorr { rng }) = options {
562 self.schnorr_sign(message, rng)
563 } else {
564 self.schnorr_sign(
565 message,
566 Rc::new(RefCell::new(SecureRandomNumberGenerator)),
567 )
568 }
569 }
570 Self::ECDSA(_) => self.ecdsa_sign(message),
571 Self::Ed25519(_) => self.ed25519_sign(message),
572 Self::SSH(_) => {
573 if let Some(SigningOptions::Ssh { namespace, hash_alg }) =
574 options
575 {
576 self.ssh_sign(message, namespace, hash_alg)
577 } else {
578 Err(Error::ssh(
579 "Missing namespace and hash algorithm for SSH signing",
580 ))
581 }
582 }
583 Self::MLDSA(_) => self.mldsa_sign(message),
584 }
585 }
586}
587
588/// Implementation of the Verifier trait for SigningPrivateKey
589impl Verifier for SigningPrivateKey {
590 /// Verifies a signature against a message.
591 ///
592 /// This method is only implemented for Schnorr keys, where it derives the
593 /// public key and uses it to verify the signature. For other key types,
594 /// this method always returns `false`.
595 ///
596 /// # Arguments
597 ///
598 /// * `signature` - The signature to verify
599 /// * `message` - The message that was allegedly signed
600 ///
601 /// # Returns
602 ///
603 /// `true` if the signature is valid for the message, `false` otherwise
604 fn verify(&self, signature: &Signature, message: &dyn AsRef<[u8]>) -> bool {
605 match self {
606 Self::Schnorr(key) => {
607 if let Signature::Schnorr(sig) = signature {
608 key.schnorr_public_key().schnorr_verify(sig, message)
609 } else {
610 false
611 }
612 }
613 _ => false,
614 }
615 }
616}
617
618/// Implementation of the CBORTagged trait for SigningPrivateKey
619impl CBORTagged for SigningPrivateKey {
620 /// Returns the CBOR tags used for this type.
621 ///
622 /// For SigningPrivateKey, the tag is 40021.
623 fn cbor_tags() -> Vec<Tag> {
624 tags_for_values(&[tags::TAG_SIGNING_PRIVATE_KEY])
625 }
626}
627
628/// Conversion from SigningPrivateKey to CBOR
629impl From<SigningPrivateKey> for CBOR {
630 /// Converts a SigningPrivateKey to a tagged CBOR value.
631 fn from(value: SigningPrivateKey) -> Self { value.tagged_cbor() }
632}
633
634/// Implementation of the CBORTaggedEncodable trait for SigningPrivateKey
635impl CBORTaggedEncodable for SigningPrivateKey {
636 /// Converts the SigningPrivateKey to an untagged CBOR value.
637 ///
638 /// The CBOR encoding depends on the key type:
639 ///
640 /// - Schnorr: A byte string containing the 32-byte private key
641 /// - ECDSA: An array containing the discriminator 1 and the 32-byte private
642 /// key
643 /// - Ed25519: An array containing the discriminator 2 and the 32-byte
644 /// private key
645 /// - SSH: A tagged text string containing the OpenSSH-encoded private key
646 /// - ML-DSA: Delegates to the MLDSAPrivateKey implementation
647 fn untagged_cbor(&self) -> CBOR {
648 match self {
649 SigningPrivateKey::Schnorr(key) => CBOR::to_byte_string(key.data()),
650 SigningPrivateKey::ECDSA(key) => {
651 vec![(1).into(), CBOR::to_byte_string(key.data())].into()
652 }
653 SigningPrivateKey::Ed25519(key) => {
654 vec![(2).into(), CBOR::to_byte_string(key.data())].into()
655 }
656 SigningPrivateKey::SSH(key) => {
657 let string = key.to_openssh(LineEnding::LF).unwrap();
658 CBOR::to_tagged_value(
659 tags::TAG_SSH_TEXT_PRIVATE_KEY,
660 (*string).clone(),
661 )
662 }
663 SigningPrivateKey::MLDSA(key) => key.clone().into(),
664 }
665 }
666}
667
668/// TryFrom implementation for converting CBOR to SigningPrivateKey
669impl TryFrom<CBOR> for SigningPrivateKey {
670 type Error = dcbor::Error;
671
672 /// Tries to convert a CBOR value to a SigningPrivateKey.
673 ///
674 /// This is a convenience method that calls from_tagged_cbor.
675 fn try_from(cbor: CBOR) -> dcbor::Result<Self> {
676 Self::from_tagged_cbor(cbor)
677 }
678}
679
680/// Implementation of the CBORTaggedDecodable trait for SigningPrivateKey
681impl CBORTaggedDecodable for SigningPrivateKey {
682 /// Creates a SigningPrivateKey from an untagged CBOR value.
683 ///
684 /// # Arguments
685 ///
686 /// * `untagged_cbor` - The CBOR value to decode
687 ///
688 /// # Returns
689 ///
690 /// A Result containing the decoded SigningPrivateKey or an error if
691 /// decoding fails.
692 ///
693 /// # Format
694 ///
695 /// The CBOR value must be one of:
696 /// - A byte string (interpreted as a Schnorr private key)
697 /// - An array where the first element is a discriminator (1 for ECDSA, 2
698 /// for Ed25519) and the second element is a byte string containing the
699 /// key data
700 /// - A tagged value with a tag for ML-DSA or SSH keys
701 fn from_untagged_cbor(untagged_cbor: CBOR) -> dcbor::Result<Self> {
702 match untagged_cbor.into_case() {
703 CBORCase::ByteString(data) => {
704 Ok(Self::Schnorr(ECPrivateKey::from_data_ref(data)?))
705 }
706 CBORCase::Array(mut elements) => {
707 let discriminator = usize::try_from(elements.remove(0))?;
708 match discriminator {
709 1 => {
710 let data = elements.remove(0).try_into_byte_string()?;
711 let key = ECPrivateKey::from_data_ref(data)?;
712 Ok(Self::ECDSA(key))
713 }
714 2 => {
715 let data = elements.remove(0).try_into_byte_string()?;
716 let key = Ed25519PrivateKey::from_data_ref(data)?;
717 Ok(Self::Ed25519(key))
718 }
719 _ => Err(format!(
720 "Invalid discriminator for SigningPrivateKey: {}",
721 discriminator
722 )
723 .into()),
724 }
725 }
726 CBORCase::Tagged(tag, item) => {
727 let value = tag.value();
728 match value {
729 tags::TAG_SSH_TEXT_PRIVATE_KEY => {
730 let string = item.try_into_text()?;
731 let key = SSHPrivateKey::from_openssh(string).map_err(
732 |_| dcbor::Error::msg("Invalid SSH private key"),
733 )?;
734 Ok(Self::SSH(Box::new(key)))
735 }
736 tags::TAG_MLDSA_PRIVATE_KEY => {
737 let key = MLDSAPrivateKey::from_untagged_cbor(item)?;
738 Ok(Self::MLDSA(key))
739 }
740 _ => Err(format!(
741 "Invalid CBOR tag for SigningPrivateKey: {value}"
742 )
743 .into()),
744 }
745 }
746 _ => Err("Invalid CBOR case for SigningPrivateKey".into()),
747 }
748 }
749}
750
751/// Debug implementation for SigningPrivateKey
752impl std::fmt::Debug for SigningPrivateKey {
753 /// Formats the SigningPrivateKey for display.
754 ///
755 /// For security reasons, the private key data is not displayed.
756 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
757 write!(f, "SigningPrivateKey")
758 }
759}
760
761/// Implementation of the From trait for reference to SigningPrivateKey
762impl From<&SigningPrivateKey> for SigningPrivateKey {
763 /// Clones a SigningPrivateKey from a reference.
764 fn from(key: &SigningPrivateKey) -> Self { key.clone() }
765}