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