1212//! - **Security First**: Mandatory cryptographic RNG, proper key validation, secure memory clearing
1313//! - **No-std Compatible**: Works in embedded environments without standard library
1414//! - **Comprehensive Error Handling**: Detailed error types for proper debugging and security
15- //! - **Zero-copy Serialization**: Efficient serialization using `zerocopy` traits
15+ //! - **Optional Serialization**: Flexible serialization support for software keys, with hardware key compatibility
1616//!
1717//! ## Architecture
1818//!
2424//! └── Scalar: IntoBytes + FromBytes
2525//!
2626//! Key Management
27- //! ├── PrivateKey<C>: Zeroize + Serialization + Validation
28- //! └── PublicKey<C>: Serialization + Coordinate Access + Validation
27+ //! ├── PrivateKey<C>: Zeroize + Validation
28+ //! ├── SerializablePrivateKey<C>: PrivateKey<C> + Serialization (optional)
29+ //! ├── PublicKey<C>: Coordinate Access + Validation
30+ //! └── SerializablePublicKey<C>: PublicKey<C> + Serialization (optional)
2931//!
3032//! Signatures
31- //! └── Signature<C>: Serialization + Component Access + Validation
33+ //! ├── Signature<C>: Component Access + Validation
34+ //! └── SerializableSignature<C>: Signature<C> + Serialization (optional)
3235//!
3336//! Operations
3437//! ├── EcdsaKeyGen<C>: Key pair generation
3942//! ├── Error: Debug → ErrorKind mapping
4043//! ├── ErrorType: Associated error types
4144//! └── ErrorKind: Common error classifications
45+ //!
46+ //! Key Storage Patterns
47+ //! ├── Software Keys: Implement SerializablePrivateKey for persistence
48+ //! ├── Hardware Keys: Implement only PrivateKey for HSM/secure enclave
49+ //! └── Hybrid Systems: Mix both patterns as needed
4250//! ```
4351//!
4452//! ## Usage Example
4856//! # use rand_core::{RngCore, CryptoRng};
4957//! #
5058//! # fn example() -> Result<(), Box<dyn std::error::Error>> {
51- //! // This example shows the basic pattern for ECDSA operations
52- //! // Actual implementations would provide concrete curve types
59+ //! // This example shows both software and hardware key patterns
5360//!
54- //! // Key generation pattern :
55- //! // let mut key_generator = YourKeyGenImpl ::new();
61+ //! // SOFTWARE KEYS (with optional serialization) :
62+ //! // let mut key_generator = SoftwareKeyGen ::new();
5663//! // let mut rng = YourCryptoRng::new();
5764//! // let (private_key, public_key) = key_generator.generate_keypair(&mut rng)?;
58- //!
59- //! // Key validation pattern:
60- //! // private_key.validate()?;
61- //! // public_key.validate()?;
62- //!
63- //! // Signing pattern:
65+ //!
66+ //! // Software keys can be serialized:
67+ //! // let private_bytes = private_key.as_bytes(); // SerializablePrivateKey
68+ //! // let public_bytes = public_key.as_bytes(); // SerializablePublicKey
69+ //!
70+ //! // HARDWARE KEYS (no serialization):
71+ //! // let mut hsm_generator = HsmKeyGen::new();
72+ //! // let (hsm_private, hsm_public) = hsm_generator.generate_keypair(&mut rng)?;
73+ //!
74+ //! // Hardware keys cannot be serialized (no IntoBytes/FromBytes bounds)
75+ //! // but can still be used for cryptographic operations:
76+ //! // hsm_private.validate()?; // PrivateKey trait method
77+ //!
78+ //! // Both key types work the same for crypto operations:
6479//! // let mut signer = YourSignerImpl::new();
6580//! // let message_digest = your_hash_function(message);
6681//! // let signature = signer.sign(&private_key, &message_digest, &mut rng)?;
67- //!
68- //! // Verification pattern:
69- //! // let mut verifier = YourVerifierImpl::new();
70- //! // let is_valid = verifier.verify(&public_key, &message_digest, &signature)?;
82+ //! // let signature_hsm = signer.sign(&hsm_private, &message_digest, &mut rng)?;
7183//!
7284//! # Ok(())
7385//! # }
7890//! - **Always validate inputs**: Use the `validate()` methods on keys and signatures
7991//! - **Use cryptographic RNG**: Only `CryptoRng + RngCore` is accepted for signing
8092//! - **Clear sensitive data**: Private keys implement `Zeroize` for secure memory clearing
93+ //! - **Hardware key support**: Private keys can be non-serializable for HSM/secure enclave use
8194//! - **Constant-time operations**: Implementers should use constant-time algorithms where possible
8295//! - **Side-channel protection**: Be aware of timing attacks in verification operations
8396
@@ -276,16 +289,28 @@ pub enum ErrorKind {
276289/// - Validate keys are within the valid scalar range (1 < key < curve_order)
277290/// - Implement constant-time operations where possible
278291/// - Clear sensitive data from memory using [`Zeroize`]
292+ /// - Hardware keys may store only handles/references, not actual key material
293+ ///
294+ /// # Hardware Key Considerations
295+ ///
296+ /// For hardware-based keys (HSMs, TPMs, secure enclaves):
297+ /// - The `Zeroize` implementation may clear key handles/references
298+ /// - Actual key material remains securely stored in hardware
299+ /// - Consider calling hardware APIs to invalidate keys during zeroization
300+ /// - Some implementations may use no-op zeroization if hardware manages lifecycle
279301///
280302/// # Example
281303///
282304/// ```rust,ignore
283- /// use openprot_hal_blocking::ecdsa::{PrivateKey, Curve, ErrorKind};
305+ /// use openprot_hal_blocking::ecdsa::{PrivateKey, SerializablePrivateKey, Curve, ErrorKind};
284306/// use zeroize::Zeroize;
307+ /// use zerocopy::{IntoBytes, FromBytes};
285308///
286- /// struct MyPrivateKey([u8; 32]);
309+ /// // Software private key (can be serialized)
310+ /// #[derive(IntoBytes, FromBytes)]
311+ /// struct SoftwarePrivateKey([u8; 32]);
287312///
288- /// impl<C: Curve> PrivateKey<C> for MyPrivateKey {
313+ /// impl<C: Curve> PrivateKey<C> for SoftwarePrivateKey {
289314/// fn validate(&self) -> Result<(), ErrorKind> {
290315/// // Check if key is zero or equal to curve order
291316/// if self.0.iter().all(|&b| b == 0) {
@@ -294,8 +319,26 @@ pub enum ErrorKind {
294319/// Ok(())
295320/// }
296321/// }
322+ ///
323+ /// // Implement optional serialization
324+ /// impl<C: Curve> SerializablePrivateKey<C> for SoftwarePrivateKey {}
325+ ///
326+ /// // Hardware private key (cannot be serialized)
327+ /// struct HardwarePrivateKey {
328+ /// key_handle: u32, // Handle to key in HSM
329+ /// }
330+ ///
331+ /// impl<C: Curve> PrivateKey<C> for HardwarePrivateKey {
332+ /// fn validate(&self) -> Result<(), ErrorKind> {
333+ /// // Validate key exists in hardware
334+ /// // (implementation would call into HSM API)
335+ /// Ok(())
336+ /// }
337+ /// }
338+ ///
339+ /// // No SerializablePrivateKey implementation for hardware keys
297340/// ```
298- pub trait PrivateKey < C : Curve > : IntoBytes + FromBytes + Zeroize {
341+ pub trait PrivateKey < C : Curve > : Zeroize {
299342 /// Validate that this private key is valid for the curve.
300343 ///
301344 /// This method should verify that the private key is within the valid
@@ -364,33 +407,22 @@ pub trait Curve {
364407/// }
365408///
366409/// impl<C: Curve> Signature<C> for MySignature {
367- /// fn r(&self) -> &C::Scalar {
368- /// // Return reference to r component
369- /// unimplemented!()
370- /// }
371- ///
372- /// fn s(&self) -> &C::Scalar {
373- /// // Return reference to s component
374- /// unimplemented!()
375- /// }
376- ///
377- /// fn from_components(r: C::Scalar, s: C::Scalar) -> Result<Self, ErrorKind> {
378- /// // Validate components and create signature
379- /// unimplemented!()
410+ /// fn from_coordinates(r: C::Scalar, s: C::Scalar) -> Result<Self, ErrorKind> {
411+ /// // Validate that r and s are in valid range [1, curve_order)
412+ /// if r.iter().all(|&b| b == 0) || s.iter().all(|&b| b == 0) {
413+ /// return Err(ErrorKind::InvalidSignature);
414+ /// }
415+ /// Ok(Self { r, s })
380416/// }
381417///
382- /// fn new_unchecked(r: C::Scalar, s: C::Scalar) -> Self {
383- /// // Create signature without validation (use with caution)
384- /// unimplemented!()
418+ /// fn coordinates(&self, r_out: &mut C::Scalar, s_out: &mut C::Scalar) {
419+ /// // Zero-allocation coordinate access for embedded environments
420+ /// *r_out = self.r;
421+ /// *s_out = self.s;
385422/// }
386423/// }
387424/// ```
388- pub trait Signature < C : Curve > : IntoBytes + FromBytes {
389- /// Get the r component of the signature.
390- fn r ( & self ) -> & C :: Scalar ;
391- /// Get the s component of the signature.
392- fn s ( & self ) -> & C :: Scalar ;
393-
425+ pub trait Signature < C : Curve > {
394426 /// Create a new signature from r and s components with validation.
395427 ///
396428 /// This method validates that both r and s are within the valid range
@@ -403,24 +435,17 @@ pub trait Signature<C: Curve>: IntoBytes + FromBytes {
403435 /// # Returns
404436 /// - `Ok(Self)`: Valid signature
405437 /// - `Err(ErrorKind::InvalidSignature)`: If r or s are invalid (zero or ≥ curve order)
406- fn from_components ( r : C :: Scalar , s : C :: Scalar ) -> Result < Self , ErrorKind >
438+ fn from_coordinates ( r : C :: Scalar , s : C :: Scalar ) -> Result < Self , ErrorKind >
407439 where
408440 Self : Sized ;
409441
410- /// Validate that this signature has valid r and s components.
411- ///
412- /// # Returns
413- /// - `Ok(())`: The signature components are valid
414- /// - `Err(ErrorKind::InvalidSignature)`: Invalid r or s component
415- fn validate ( & self ) -> Result < ( ) , ErrorKind > ;
416442
417- /// Create a new signature from r and s components without validation .
443+ /// Write coordinates to output buffers (zero-allocation for embedded) .
418444 ///
419- /// # Safety
420- /// This method should only be used when the caller can guarantee that
421- /// r and s are valid for the curve. Use `from_components` for safe
422- /// construction with validation.
423- fn new_unchecked ( r : C :: Scalar , s : C :: Scalar ) -> Self ;
445+ /// This method provides zero-allocation coordinate access for embedded
446+ /// environments. Implementations can extract coordinates directly into
447+ /// the provided buffers without temporary allocation.
448+ fn coordinates ( & self , x_out : & mut C :: Scalar , y_out : & mut C :: Scalar ) ;
424449}
425450
426451/// A trait representing a public key associated with a specific elliptic curve.
@@ -447,41 +472,32 @@ pub trait Signature<C: Curve>: IntoBytes + FromBytes {
447472/// }
448473///
449474/// impl<C: Curve> PublicKey<C> for MyPublicKey {
450- /// fn x(&self) -> &C::Scalar {
451- /// // Return reference to x coordinate
452- /// unimplemented!()
453- /// }
454- ///
455- /// fn y(&self) -> &C::Scalar {
456- /// // Return reference to y coordinate
457- /// unimplemented!()
475+ /// fn coordinates(&self, x_out: &mut C::Scalar, y_out: &mut C::Scalar) {
476+ /// // Zero-allocation coordinate access
477+ /// *x_out = self.x;
478+ /// *y_out = self.y;
458479/// }
459480///
460481/// fn from_coordinates(x: C::Scalar, y: C::Scalar) -> Result<Self, ErrorKind> {
461- /// // Validate point is on curve and create public key
462- /// unimplemented!()
463- /// }
464- ///
465- /// fn validate(&self) -> Result<(), ErrorKind> {
466- /// // Check if point lies on the curve
467- /// unimplemented!()
468- /// }
469- ///
470- /// fn new_unchecked(x: C::Scalar, y: C::Scalar) -> Self {
471- /// // Create key without validation (use with caution)
472- /// unimplemented!()
482+ /// // Validate point is on curve during construction
483+ /// // (validation logic would go here)
484+ /// Ok(Self { x, y })
473485/// }
474486/// }
475487/// ```
476- pub trait PublicKey < C : Curve > : IntoBytes + FromBytes {
477- /// Get the x coordinate of the public key.
478- fn x ( & self ) -> & C :: Scalar ;
479- /// Get the y coordinate of the public key.
480- fn y ( & self ) -> & C :: Scalar ;
488+ pub trait PublicKey < C : Curve > {
489+ /// Write coordinates to output buffers (zero-allocation for embedded).
490+ ///
491+ /// This method provides zero-allocation coordinate access for embedded
492+ /// environments. Implementations can extract coordinates directly into
493+ /// the provided buffers without temporary allocation.
494+ fn coordinates ( & self , x_out : & mut C :: Scalar , y_out : & mut C :: Scalar ) ;
481495
482496 /// Create a new public key from x and y coordinates with validation.
483497 ///
484- /// This method validates that the point (x, y) lies on the specified curve.
498+ /// This method validates that the point (x, y) lies on the specified curve
499+ /// and is cryptographically valid. Validation is performed during construction
500+ /// to ensure all created public keys are valid.
485501 ///
486502 /// # Parameters
487503 /// - `x`: The x coordinate of the point
@@ -494,26 +510,72 @@ pub trait PublicKey<C: Curve>: IntoBytes + FromBytes {
494510 fn from_coordinates ( x : C :: Scalar , y : C :: Scalar ) -> Result < Self , ErrorKind >
495511 where
496512 Self : Sized ;
513+ }
497514
498- /// Validate that this public key represents a valid point on the curve.
499- ///
500- /// This method should be called before using a public key for verification
501- /// to ensure it represents a valid curve point and is not a weak key.
502- ///
503- /// # Returns
504- /// - `Ok(())`: The public key is valid
505- /// - `Err(ErrorKind::InvalidPoint)`: The point is not on the curve
506- /// - `Err(ErrorKind::WeakKey)`: The point is the identity element or otherwise weak
507- fn validate ( & self ) -> Result < ( ) , ErrorKind > ;
515+ /// Optional serialization support for private keys.
516+ ///
517+ /// This trait provides serialization capabilities for private keys that support it,
518+ /// such as software-based keys. Hardware-based keys (HSMs, secure enclaves, etc.)
519+ /// do not need to implement this trait.
520+ ///
521+ /// # Security Note
522+ ///
523+ /// Implementing this trait exposes private key material as bytes. Only implement
524+ /// this for software keys where serialization is appropriate and secure.
525+ ///
526+ /// # Example
527+ ///
528+ /// ```rust,ignore
529+ /// use openprot_hal_blocking::ecdsa::{PrivateKey, SerializablePrivateKey, Curve};
530+ /// use zerocopy::{IntoBytes, FromBytes};
531+ ///
532+ /// #[derive(IntoBytes, FromBytes)]
533+ /// struct SoftwarePrivateKey([u8; 32]);
534+ ///
535+ /// impl<C: Curve> PrivateKey<C> for SoftwarePrivateKey { /* ... */ }
536+ /// impl<C: Curve> SerializablePrivateKey<C> for SoftwarePrivateKey {}
537+ /// ```
538+ pub trait SerializablePrivateKey < C : Curve > : PrivateKey < C > + IntoBytes + FromBytes { }
508539
509- /// Create a new public key from x and y coordinates without validation.
510- ///
511- /// # Safety
512- /// This method should only be used when the caller can guarantee that
513- /// the coordinates represent a valid point on the curve. Use `from_coordinates`
514- /// for safe construction with validation.
515- fn new_unchecked ( x : C :: Scalar , y : C :: Scalar ) -> Self ;
516- }
540+ /// Optional serialization support for public keys.
541+ ///
542+ /// This trait provides serialization capabilities for public keys that support it.
543+ /// Most public key implementations should implement this since public keys are
544+ /// not sensitive and often need to be transmitted or stored.
545+ ///
546+ /// # Example
547+ ///
548+ /// ```rust,ignore
549+ /// use openprot_hal_blocking::ecdsa::{PublicKey, SerializablePublicKey, Curve};
550+ /// use zerocopy::{IntoBytes, FromBytes};
551+ ///
552+ /// #[derive(IntoBytes, FromBytes)]
553+ /// struct MyPublicKey { /* ... */ }
554+ ///
555+ /// impl<C: Curve> PublicKey<C> for MyPublicKey { /* ... */ }
556+ /// impl<C: Curve> SerializablePublicKey<C> for MyPublicKey {}
557+ /// ```
558+ pub trait SerializablePublicKey < C : Curve > : PublicKey < C > + IntoBytes + FromBytes { }
559+
560+ /// Optional serialization support for signatures.
561+ ///
562+ /// This trait provides serialization capabilities for signatures that support it.
563+ /// Most signature implementations should implement this since signatures need
564+ /// to be transmitted and verified.
565+ ///
566+ /// # Example
567+ ///
568+ /// ```rust,ignore
569+ /// use openprot_hal_blocking::ecdsa::{Signature, SerializableSignature, Curve};
570+ /// use zerocopy::{IntoBytes, FromBytes};
571+ ///
572+ /// #[derive(IntoBytes, FromBytes)]
573+ /// struct MySignature { /* ... */ }
574+ ///
575+ /// impl<C: Curve> Signature<C> for MySignature { /* ... */ }
576+ /// impl<C: Curve> SerializableSignature<C> for MySignature {}
577+ /// ```
578+ pub trait SerializableSignature < C : Curve > : Signature < C > + IntoBytes + FromBytes { }
517579
518580/// Trait for ECDSA key generation over a specific elliptic curve.
519581///
0 commit comments