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