libsodium_rs/crypto_sign.rs
1//! # Digital Signatures
2//!
3//! This module provides functions for creating and verifying digital signatures using
4//! the Ed25519 signature scheme, which is based on the Edwards-curve Digital Signature
5//! Algorithm (`EdDSA`) using the edwards25519 curve.
6//!
7//! ## Overview
8//!
9//! Digital signatures provide a way to verify the authenticity and integrity of messages or data.
10//! They serve as the digital equivalent of handwritten signatures, but with stronger security
11//! properties. When you sign a message with your secret key, anyone with your public key can
12//! verify that:
13//!
14//! 1. The message was signed by someone who possesses the corresponding secret key
15//! 2. The message has not been altered since it was signed
16//!
17//! The Ed25519 signature scheme is based on the Edwards-curve Digital Signature Algorithm (EdDSA)
18//! using the edwards25519 curve with a SHA-512 hash function
19//!
20//! Ed25519 is a modern, high-security, high-performance signature algorithm that is resistant
21//! to many types of attacks and side-channel leaks.
22//!
23//! ## Features
24//!
25//! - **Fast and secure signatures** with small keys and signatures
26//! - **Public key size**: 32 bytes
27//! - **Secret key size**: 64 bytes (includes the seed and the public key for optimization)
28//! - **Signature size**: 64 bytes
29//! - **Batch signature verification** for improved performance
30//! - **Protection against side-channel attacks**
31//! - **Deterministic signatures** (same message + same key = same signature)
32//! - **Collision resistance** against hash function attacks
33//! - **No random number generator needed** during signing (prevents RNG-related vulnerabilities)
34//!
35//! ## Use Cases
36//!
37//! - **Document signing**: Verify the authenticity of documents
38//! - **Software distribution**: Ensure software packages haven't been tampered with
39//! - **Secure messaging**: Authenticate the sender of messages
40//! - **API authentication**: Verify API requests are coming from authorized clients
41//! - **Blockchain transactions**: Sign transactions to prove ownership
42//!
43//! ## Basic Usage
44//!
45//! ```rust
46//! use libsodium_rs as sodium;
47//! use sodium::crypto_sign;
48//! use sodium::ensure_init;
49//!
50//! // Initialize libsodium
51//! ensure_init().expect("Failed to initialize libsodium");
52//!
53//! // Generate a key pair
54//! let keypair = crypto_sign::KeyPair::generate().unwrap();
55//! let public_key = keypair.public_key;
56//! let secret_key = keypair.secret_key;
57//!
58//! // Message to sign
59//! let message = b"Hello, world!";
60//!
61//! // Sign the message (combined mode)
62//! let signed_message = crypto_sign::sign(message, &secret_key).unwrap();
63//!
64//! // Verify the signature and get the original message
65//! let original_message = crypto_sign::verify(&signed_message, &public_key).unwrap();
66//! assert_eq!(original_message, message);
67//!
68//! // Alternatively, use detached signatures
69//! let signature = crypto_sign::sign_detached(message, &secret_key).unwrap();
70//! assert!(crypto_sign::verify_detached(&signature, message, &public_key));
71//! ```
72//!
73//! ## Combined vs. Detached Signatures
74//!
75//! This module supports two signature modes:
76//!
77//! 1. **Combined mode**: The signature is prepended to the message, creating a single byte array
78//! containing both. This is convenient when you want to transmit both together.
79//! - Use `sign()` to create combined signatures
80//! - Use `verify()` to verify combined signatures
81//!
82//! 2. **Detached mode**: The signature is separate from the message. This is useful when you
83//! want to keep the original message intact or transmit the signature separately.
84//! - Use `sign_detached()` to create detached signatures
85//! - Use `verify_detached()` to verify detached signatures
86//!
87//! ## Key Management
88//!
89//! Proper key management is crucial for the security of digital signatures. Here are some
90//! best practices:
91//!
92//! ```rust
93//! use libsodium_rs as sodium;
94//! use sodium::crypto_sign;
95//! use sodium::ensure_init;
96//! use std::fs;
97//! use std::io::{self, Read, Write};
98//!
99//! // Initialize libsodium
100//! ensure_init().expect("Failed to initialize libsodium");
101//!
102//! // Generate keys (typically done once)
103//! fn generate_and_save_keys() -> io::Result<()> {
104//! let keypair = crypto_sign::KeyPair::generate().unwrap();
105//! let public_key = keypair.public_key;
106//! let secret_key = keypair.secret_key;
107//!
108//! // Save public key (can be shared)
109//! fs::write("public_key.bin", public_key.as_bytes())?;
110//!
111//! // Save secret key (must be kept secure)
112//! // In a real application, you would encrypt this or use a secure key storage solution
113//! fs::write("secret_key.bin", secret_key.as_bytes())?;
114//!
115//! Ok(())
116//! }
117//!
118//! // Load keys for signing
119//! fn load_secret_key() -> io::Result<crypto_sign::SecretKey> {
120//! let mut key_data = [0u8; crypto_sign::SECRETKEYBYTES];
121//! let mut file = fs::File::open("secret_key.bin")?;
122//! file.read_exact(&mut key_data)?;
123//!
124//! Ok(crypto_sign::SecretKey::from_bytes(&key_data).unwrap())
125//! }
126//!
127//! // Load keys for verification
128//! fn load_public_key() -> io::Result<crypto_sign::PublicKey> {
129//! let mut key_data = [0u8; crypto_sign::PUBLICKEYBYTES];
130//! let mut file = fs::File::open("public_key.bin")?;
131//! file.read_exact(&mut key_data)?;
132//!
133//! Ok(crypto_sign::PublicKey::from_bytes(&key_data).unwrap())
134//! }
135//!
136//! // Sign a document
137//! fn sign_document(document: &[u8]) -> io::Result<Vec<u8>> {
138//! let secret_key = load_secret_key()?;
139//! let signature = crypto_sign::sign_detached(document, &secret_key).unwrap();
140//!
141//! // Save or transmit both the document and signature
142//! let mut signed_data = Vec::new();
143//! signed_data.extend_from_slice(&signature);
144//! signed_data.extend_from_slice(document);
145//!
146//! Ok(signed_data)
147//! }
148//!
149//! // Verify a signed document
150//! fn verify_document(signed_data: &[u8]) -> io::Result<bool> {
151//! if signed_data.len() < crypto_sign::BYTES {
152//! return Ok(false);
153//! }
154//!
155//! let signature = <[u8; crypto_sign::BYTES]>::try_from(&signed_data[..crypto_sign::BYTES]).unwrap();
156//! let document = &signed_data[crypto_sign::BYTES..];
157//!
158//! let public_key = load_public_key()?;
159//! let result = crypto_sign::verify_detached(&signature, document, &public_key);
160//!
161//! Ok(result)
162//! }
163//! ```
164//!
165//! ## Security Considerations
166//!
167//! - **Secret key protection**: The secret key should be kept confidential at all times. Consider using
168//! hardware security modules (HSMs) or secure enclaves for high-security applications.
169//!
170//!
171//! - **Signature malleability**: Ed25519 signatures are not malleable, meaning an attacker cannot
172//! modify a valid signature to create another valid signature for the same message.
173//!
174//! - **Forward secrecy**: Digital signatures do not provide forward secrecy. If a secret key is
175//! compromised, all previous signatures created with that key can be attributed to the attacker.
176//!
177//! - **Deterministic**: Ed25519 is deterministic, meaning the same message signed with the same key
178//! will always produce the same signature. This eliminates the need for a random number generator
179//! during signing, which can be a source of vulnerabilities.
180//!
181//! - **Cofactor**: Ed25519 has a cofactor of 8, but the signature verification process ensures
182//! that signatures are secure despite this property.
183//!
184//! - **Quantum resistance**: Ed25519 is not resistant to quantum computing attacks. For long-term
185//! security against quantum computers, consider using post-quantum signature schemes.
186//!
187//! - **This implementation** uses constant-time operations to prevent timing attacks.
188
189use crate::{Result, SodiumError};
190use std::convert::TryFrom;
191use std::fmt;
192
193/// Number of bytes in a public key (32)
194///
195/// The public key is used to verify signatures and can be shared publicly.
196pub const PUBLICKEYBYTES: usize = libsodium_sys::crypto_sign_PUBLICKEYBYTES as usize;
197
198/// Number of bytes in a secret key (64)
199///
200/// The secret key is used to create signatures and should be kept private.
201/// Note that the secret key contains both the secret scalar and the public key.
202pub const SECRETKEYBYTES: usize = libsodium_sys::crypto_sign_SECRETKEYBYTES as usize;
203
204/// Number of bytes in a signature (64)
205///
206/// Ed25519 signatures are 64 bytes long, consisting of an R value (32 bytes)
207/// and an S value (32 bytes) concatenated together.
208pub const BYTES: usize = libsodium_sys::crypto_sign_BYTES as usize;
209
210/// Number of bytes in a seed (32)
211///
212/// The seed is used to deterministically generate a keypair.
213pub const SEEDBYTES: usize = libsodium_sys::crypto_sign_SEEDBYTES as usize;
214
215/// Maximum message length in bytes
216///
217/// This is the maximum length of a message that can be signed.
218pub fn messagebytes_max() -> usize {
219 unsafe { libsodium_sys::crypto_sign_messagebytes_max() }
220}
221
222/// Size of the state for multi-part signatures
223pub const STATEBYTES: usize = std::mem::size_of::<libsodium_sys::crypto_sign_state>();
224
225/// The primitive used by this module ("ed25519")
226pub const PRIMITIVE: &str = "ed25519";
227
228/// A public key for Ed25519 digital signatures
229///
230/// Used to verify signatures created with the corresponding `SecretKey`.
231/// The public key is derived from the secret key and can be shared publicly.
232///
233/// ## Properties
234///
235/// - Size: 32 bytes (256 bits)
236/// - Can be safely shared with anyone
237/// - Used to verify the authenticity of signed messages
238/// - Represents a point on the edwards25519 elliptic curve
239///
240/// ## Usage
241///
242/// Public keys are typically distributed to anyone who needs to verify signatures.
243/// They can be safely shared over insecure channels and stored without special protection.
244///
245/// ```rust
246/// use libsodium_rs as sodium;
247/// use sodium::crypto_sign;
248/// use sodium::ensure_init;
249/// use std::convert::TryFrom;
250///
251/// // Initialize libsodium
252/// ensure_init().expect("Failed to initialize libsodium");
253///
254/// // Generate a keypair
255/// let keypair = crypto_sign::KeyPair::generate().unwrap();
256/// let public_key = keypair.public_key;
257///
258/// // Get the raw bytes of the public key (for storage or transmission)
259/// let key_bytes = public_key.as_bytes();
260///
261/// // Later, reconstruct the public key from bytes
262/// let reconstructed_key = crypto_sign::PublicKey::from_bytes(key_bytes).unwrap();
263/// // Or using TryFrom with owned array
264/// let reconstructed_key2 = crypto_sign::PublicKey::try_from(*key_bytes).unwrap();
265///
266/// assert_eq!(public_key, reconstructed_key);
267/// assert_eq!(public_key, reconstructed_key2);
268/// ```
269#[derive(Debug, Clone, Eq, PartialEq)]
270pub struct PublicKey([u8; PUBLICKEYBYTES]);
271
272/// A secret key for Ed25519 digital signatures
273///
274/// Used to create signatures that can be verified with the corresponding `PublicKey`.
275/// The secret key must be kept private to maintain security.
276///
277/// ## Properties
278///
279/// - Size: 64 bytes (512 bits)
280/// - Contains both the secret scalar (32 bytes) and the public key (32 bytes)
281/// - Must be kept confidential
282/// - Used to sign messages
283///
284/// ## Security Considerations
285///
286/// The secret key is the most sensitive component in the digital signature system.
287/// If compromised, an attacker can create valid signatures for any message, impersonating
288/// the legitimate owner of the key.
289///
290/// Best practices for secret key management:
291///
292/// - Store secret keys in secure, encrypted storage
293/// - Consider using hardware security modules (HSMs) for high-security applications
294/// - Implement proper access controls to limit who can use the signing key
295/// - Rotate keys periodically according to your security policy
296/// - Have a revocation plan in case a key is compromised
297///
298/// ## Usage
299///
300/// ```rust
301/// use libsodium_rs as sodium;
302/// use sodium::crypto_sign;
303/// use sodium::ensure_init;
304///
305/// // Initialize libsodium
306/// ensure_init().expect("Failed to initialize libsodium");
307///
308/// // Generate a key pair
309/// let keypair = crypto_sign::KeyPair::generate().unwrap();
310/// let secret_key = keypair.secret_key;
311///
312/// // Sign a message
313/// let message = b"Important document";
314/// let signature = crypto_sign::sign_detached(message, &secret_key).unwrap();
315///
316/// // In a real application, you would securely store the secret key
317/// // and implement proper key management procedures
318/// ```
319#[derive(Debug, Clone, Eq, PartialEq, zeroize::Zeroize, zeroize::ZeroizeOnDrop)]
320pub struct SecretKey([u8; SECRETKEYBYTES]);
321
322/// A key pair for digital signatures
323///
324/// Contains both a public key and a secret key for use with `crypto_sign` functions.
325pub struct KeyPair {
326 /// Public key
327 pub public_key: PublicKey,
328 /// Secret key
329 pub secret_key: SecretKey,
330}
331
332impl PublicKey {
333 /// Generate a new public key from bytes
334 ///
335 /// # Arguments
336 /// * `bytes` - The bytes to create the public key from
337 ///
338 /// # Returns
339 /// * `Result<Self>` - The public key or an error if the input is invalid
340 ///
341 /// # Errors
342 /// Returns an error if the input is not exactly `PUBLICKEYBYTES` bytes long
343 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
344 if bytes.len() != PUBLICKEYBYTES {
345 return Err(SodiumError::InvalidInput(format!(
346 "public key must be exactly {} bytes, got {}",
347 PUBLICKEYBYTES,
348 bytes.len()
349 )));
350 }
351
352 let mut key = [0u8; PUBLICKEYBYTES];
353 key.copy_from_slice(bytes);
354 Ok(Self(key))
355 }
356
357 /// Extract the public key from a secret key
358 ///
359 /// This function extracts the public key that is embedded in an Ed25519 secret key.
360 /// In the Ed25519 implementation, the secret key (64 bytes) actually contains both
361 /// the secret seed (32 bytes) and the public key (32 bytes) for optimization purposes.
362 ///
363 /// The public key is deterministically derived from the secret seed, but storing it
364 /// as part of the secret key allows for faster signing operations by avoiding the
365 /// need to recompute the public key for each signature.
366 ///
367 /// # Arguments
368 /// * `secret_key` - The secret key to extract the public key from
369 ///
370 /// # Returns
371 /// * `Result<PublicKey>` - The extracted public key or an error
372 ///
373 /// # Errors
374 /// Returns an error if the extraction fails (extremely rare)
375 ///
376 /// # Security Considerations
377 ///
378 /// - This operation does not compromise the security of the secret key
379 /// - The public key is safe to share publicly
380 /// - The same public key will always be extracted from the same secret key
381 ///
382 /// # Example
383 ///
384 /// ```rust
385 /// use libsodium_rs as sodium;
386 /// use sodium::crypto_sign::{KeyPair, PublicKey};
387 /// use sodium::ensure_init;
388 ///
389 /// // Initialize libsodium
390 /// ensure_init().expect("Failed to initialize libsodium");
391 ///
392 /// // Generate a key pair
393 /// let keypair = KeyPair::generate().unwrap();
394 /// let secret_key = keypair.secret_key;
395 ///
396 /// // Extract the public key from the secret key
397 /// let extracted_pk = PublicKey::from_secret_key(&secret_key).unwrap();
398 ///
399 /// // The extracted public key should match the original public key
400 /// assert_eq!(extracted_pk, keypair.public_key);
401 /// ```
402 pub fn from_secret_key(secret_key: &SecretKey) -> Result<Self> {
403 let mut pk = [0u8; PUBLICKEYBYTES];
404
405 let result = unsafe {
406 libsodium_sys::crypto_sign_ed25519_sk_to_pk(
407 pk.as_mut_ptr(),
408 secret_key.as_bytes().as_ptr(),
409 )
410 };
411
412 if result != 0 {
413 return Err(SodiumError::OperationError(
414 "Failed to extract public key from secret key".into(),
415 ));
416 }
417
418 Ok(PublicKey(pk))
419 }
420
421 /// Get the bytes of the public key
422 ///
423 /// # Returns
424 /// * `&[u8; PUBLICKEYBYTES]` - A reference to the public key bytes
425 pub fn as_bytes(&self) -> &[u8; PUBLICKEYBYTES] {
426 &self.0
427 }
428
429 /// Create a public key from a fixed-size byte array
430 ///
431 /// # Arguments
432 /// * `bytes` - Byte array of exactly PUBLICKEYBYTES length
433 ///
434 /// # Returns
435 /// * `Self` - A new public key
436 pub const fn from_bytes_exact(bytes: [u8; PUBLICKEYBYTES]) -> Self {
437 Self(bytes)
438 }
439}
440
441impl AsRef<[u8]> for PublicKey {
442 fn as_ref(&self) -> &[u8] {
443 &self.0
444 }
445}
446
447impl From<[u8; PUBLICKEYBYTES]> for PublicKey {
448 fn from(bytes: [u8; PUBLICKEYBYTES]) -> Self {
449 Self(bytes)
450 }
451}
452
453impl From<PublicKey> for [u8; PUBLICKEYBYTES] {
454 fn from(key: PublicKey) -> [u8; PUBLICKEYBYTES] {
455 key.0
456 }
457}
458
459impl SecretKey {
460 /// Generate a new secret key from bytes
461 ///
462 /// # Arguments
463 /// * `bytes` - The bytes to create the secret key from
464 ///
465 /// # Returns
466 /// * `Result<Self>` - The secret key or an error if the input is invalid
467 ///
468 /// # Errors
469 /// Returns an error if the input is not exactly `SECRETKEYBYTES` bytes long
470 pub fn from_bytes(bytes: &[u8]) -> Result<Self> {
471 if bytes.len() != SECRETKEYBYTES {
472 return Err(SodiumError::InvalidInput(format!(
473 "secret key must be exactly {} bytes, got {}",
474 SECRETKEYBYTES,
475 bytes.len()
476 )));
477 }
478
479 let mut key = [0u8; SECRETKEYBYTES];
480 key.copy_from_slice(bytes);
481 Ok(SecretKey(key))
482 }
483
484 /// Get the bytes of the secret key
485 ///
486 /// # Returns
487 /// * `&[u8; SECRETKEYBYTES]` - A reference to the secret key bytes
488 pub fn as_bytes(&self) -> &[u8; SECRETKEYBYTES] {
489 &self.0
490 }
491
492 /// Create a secret key from a fixed-size byte array
493 ///
494 /// # Arguments
495 /// * `bytes` - Byte array of exactly SECRETKEYBYTES length
496 ///
497 /// # Returns
498 /// * `Self` - A new secret key
499 pub const fn from_bytes_exact(bytes: [u8; SECRETKEYBYTES]) -> Self {
500 Self(bytes)
501 }
502}
503
504impl AsRef<[u8]> for SecretKey {
505 fn as_ref(&self) -> &[u8] {
506 &self.0
507 }
508}
509
510impl From<[u8; SECRETKEYBYTES]> for SecretKey {
511 fn from(bytes: [u8; SECRETKEYBYTES]) -> Self {
512 Self(bytes)
513 }
514}
515
516impl From<SecretKey> for [u8; SECRETKEYBYTES] {
517 fn from(key: SecretKey) -> [u8; SECRETKEYBYTES] {
518 key.0
519 }
520}
521
522impl KeyPair {
523 /// Generate a new Ed25519 key pair for digital signatures
524 ///
525 /// This function generates a new random Ed25519 key pair suitable for creating and verifying
526 /// digital signatures. The key pair consists of a public key that can be shared and a secret
527 /// key that must be kept private.
528 ///
529 /// The key generation process uses a cryptographically secure random number generator to
530 /// create a 32-byte seed, which is then used to deterministically derive both the secret
531 /// and public keys according to the Ed25519 algorithm specification.
532 ///
533 /// ## Key Properties
534 ///
535 /// - **Public Key**: 32 bytes, can be safely shared with anyone
536 /// - **Secret Key**: 64 bytes, contains both the seed (32 bytes) and public key (32 bytes)
537 /// - **Security Level**: Equivalent to 128-bit symmetric encryption (highly secure)
538 ///
539 /// ## Security Considerations
540 ///
541 /// - The secret key must be kept confidential to maintain security
542 /// - The public key can be freely distributed
543 /// - Key generation is non-deterministic due to the use of a random seed
544 /// - For deterministic key generation, use `KeyPair::from_seed` instead
545 /// - The generated keys use the Ed25519 curve, which has strong security properties
546 /// including resistance to many side-channel attacks
547 ///
548 /// # Example
549 ///
550 /// ```rust
551 /// use libsodium_rs as sodium;
552 /// use sodium::crypto_sign;
553 /// use sodium::ensure_init;
554 ///
555 /// // Initialize libsodium
556 /// ensure_init().expect("Failed to initialize libsodium");
557 ///
558 /// // Generate a key pair
559 /// let keypair = crypto_sign::KeyPair::generate().unwrap();
560 /// let public_key = keypair.public_key;
561 /// let secret_key = keypair.secret_key;
562 ///
563 /// // Use the keys for signing and verification
564 /// let message = b"Hello, world!";
565 /// let signature = crypto_sign::sign_detached(message, &secret_key).unwrap();
566 /// assert!(crypto_sign::verify_detached(&signature, message, &public_key));
567 ///
568 /// // In a real application, you would securely store the secret key
569 /// // and distribute the public key to verifiers
570 /// ```
571 ///
572 /// # Returns
573 /// * `Result<KeyPair>` - A newly generated key pair or an error
574 ///
575 /// # Errors
576 /// Returns an error if key generation fails (extremely rare, typically only due to system issues)
577 /// such as random number generator failure
578 pub fn generate() -> Result<Self> {
579 crate::ensure_init()?;
580
581 let mut pk = [0u8; PUBLICKEYBYTES];
582 let mut sk = [0u8; SECRETKEYBYTES];
583
584 unsafe {
585 let ret = libsodium_sys::crypto_sign_keypair(pk.as_mut_ptr(), sk.as_mut_ptr());
586 if ret != 0 {
587 return Err(SodiumError::OperationError("key generation failed".into()));
588 }
589 }
590
591 Ok(Self {
592 public_key: PublicKey(pk),
593 secret_key: SecretKey(sk),
594 })
595 }
596
597 /// Generate a new Ed25519 key pair from a seed.
598 ///
599 /// The seed must be exactly 32 bytes long.
600 ///
601 /// # Example
602 ///
603 /// ```rust
604 /// use libsodium_rs::{ensure_init, crypto_sign, random};
605 ///
606 /// // Initialize libsodium
607 /// ensure_init().expect("Failed to initialize libsodium");
608 ///
609 /// // Generate a random seed
610 /// let mut seed = [0u8; 32];
611 /// random::fill_bytes(&mut seed);
612 ///
613 /// // Generate a keypair from the seed
614 /// let keypair = crypto_sign::KeyPair::from_seed(&seed).unwrap();
615 ///
616 /// // The same seed will always produce the same keypair
617 /// let keypair2 = crypto_sign::KeyPair::from_seed(&seed).unwrap();
618 /// assert_eq!(keypair.public_key, keypair2.public_key);
619 /// assert_eq!(keypair.secret_key, keypair2.secret_key);
620 /// ```
621 pub fn from_seed(seed: &[u8]) -> Result<Self> {
622 crate::ensure_init()?;
623
624 if seed.len() != SEEDBYTES {
625 return Err(SodiumError::InvalidInput(format!(
626 "invalid seed length: expected {}, got {}",
627 SEEDBYTES,
628 seed.len()
629 )));
630 }
631
632 let mut pk = [0u8; PUBLICKEYBYTES];
633 let mut sk = [0u8; SECRETKEYBYTES];
634
635 unsafe {
636 let ret = libsodium_sys::crypto_sign_seed_keypair(
637 pk.as_mut_ptr(),
638 sk.as_mut_ptr(),
639 seed.as_ptr(),
640 );
641 if ret != 0 {
642 return Err(SodiumError::OperationError(
643 "Failed to generate keypair from seed".into(),
644 ));
645 }
646 }
647
648 Ok(Self {
649 public_key: PublicKey(pk),
650 secret_key: SecretKey(sk),
651 })
652 }
653
654 /// Convert the KeyPair into a tuple of (PublicKey, SecretKey)
655 pub fn into_tuple(self) -> (PublicKey, SecretKey) {
656 (self.public_key, self.secret_key)
657 }
658}
659
660/// Sign a message using a secret key (combined mode)
661///
662/// This function signs a message using the provided secret key and prepends the signature
663/// to the message. The resulting signed message contains both the signature and the original
664/// message concatenated together.
665///
666/// ## Combined Mode
667///
668/// This is known as "combined mode" because the signature and message are combined into
669/// a single byte array. For detached signatures (where the signature is separate from the
670/// message), use the `sign_detached` function instead.
671///
672/// ## Algorithm Details
673///
674/// Ed25519 signing works as follows:
675/// 1. Compute a deterministic nonce from the secret key and message using SHA-512
676/// 2. Compute point R = nonce * G (where G is the base point of the edwards25519 curve)
677/// 3. Compute S = nonce + (hash(R || public_key || message) * secret_scalar)
678/// 4. The signature is the concatenation of R and S
679///
680/// ## Example
681///
682/// ```rust
683/// use libsodium_rs as sodium;
684/// use sodium::crypto_sign;
685/// use sodium::ensure_init;
686///
687/// // Initialize libsodium
688/// ensure_init().expect("Failed to initialize libsodium");
689///
690/// // Generate a key pair
691/// let keypair = crypto_sign::KeyPair::generate().unwrap();
692/// let public_key = keypair.public_key;
693/// let secret_key = keypair.secret_key;
694///
695/// // Sign a message
696/// let message = b"Hello, world!";
697/// let signed_message = crypto_sign::sign(message, &secret_key).unwrap();
698///
699/// // The signed message contains both the signature and the original message
700/// assert_eq!(signed_message.len(), message.len() + crypto_sign::BYTES);
701///
702/// // Verify the signature and extract the original message
703/// let original_message = crypto_sign::verify(&signed_message, &public_key).unwrap();
704/// assert_eq!(original_message, message);
705///
706/// // Tamper with the signed message - verification should fail
707/// let mut tampered = signed_message.clone();
708/// tampered[0] ^= 1; // Flip a bit in the signature
709/// assert!(crypto_sign::verify(&tampered, &public_key).is_none());
710/// ```
711///
712/// # Arguments
713/// * `message` - The message to sign
714/// * `secret_key` - The secret key to sign with
715///
716/// # Returns
717/// * `Result<Vec<u8>>` - The signed message (signature + original message) or an error
718///
719/// # Errors
720/// Returns an error if signing fails (extremely rare, typically only due to system issues)
721pub fn sign(message: &[u8], secret_key: &SecretKey) -> Result<Vec<u8>> {
722 let mut signed_message = vec![0u8; message.len() + BYTES];
723 let mut signed_len = 0u64;
724
725 let result = unsafe {
726 libsodium_sys::crypto_sign(
727 signed_message.as_mut_ptr(),
728 &mut signed_len,
729 message.as_ptr(),
730 message.len() as u64,
731 secret_key.as_bytes().as_ptr(),
732 )
733 };
734
735 if result != 0 {
736 return Err(SodiumError::OperationError("Ed25519 signing failed".into()));
737 }
738
739 signed_message.truncate(signed_len as usize);
740 Ok(signed_message)
741}
742
743/// Verify a signed message using a public key (combined mode)
744///
745/// This function verifies a signed message using the provided public key and extracts
746/// the original message if the signature is valid. The signed message must have been
747/// created using the `sign` function.
748///
749/// ## Combined Mode
750///
751/// This function works with "combined mode" signatures, where the signature and message
752/// are combined into a single byte array. For verifying detached signatures, use the
753/// `verify_detached` function instead.
754///
755/// ## Algorithm Details
756///
757/// Ed25519 verification works as follows:
758/// 1. Extract R and S from the signature
759/// 2. Compute h = hash(R || public_key || message)
760/// 3. Verify that R == S*G - h*public_key
761///
762/// ## Security Considerations
763///
764/// - The verification is performed in constant time to prevent timing attacks
765/// - If verification fails, no part of the message is considered authentic
766///
767/// ## Example
768///
769/// ```rust
770/// use libsodium_rs as sodium;
771/// use sodium::crypto_sign;
772/// use sodium::ensure_init;
773///
774/// // Initialize libsodium
775/// ensure_init().expect("Failed to initialize libsodium");
776///
777/// // Generate a key pair
778/// let keypair = crypto_sign::KeyPair::generate().unwrap();
779/// let public_key = keypair.public_key;
780/// let secret_key = keypair.secret_key;
781///
782/// // Sign a message
783/// let message = b"Hello, world!";
784/// let signed_message = crypto_sign::sign(message, &secret_key).unwrap();
785///
786/// // Verify the signature and extract the original message
787/// let original_message = crypto_sign::verify(&signed_message, &public_key).unwrap();
788/// assert_eq!(original_message, message);
789///
790/// // Tamper with the signed message - verification should fail
791/// let mut tampered = signed_message.clone();
792/// tampered[0] ^= 1; // Flip a bit in the signature
793/// assert!(crypto_sign::verify(&tampered, &public_key).is_none());
794/// ```
795///
796/// # Arguments
797/// * `signed_message` - The signed message to verify
798/// * `public_key` - The public key to verify with
799///
800/// # Returns
801/// * `Option<Vec<u8>>` - The original message if verification succeeds, or `None` if verification fails
802pub fn verify(signed_message: &[u8], public_key: &PublicKey) -> Option<Vec<u8>> {
803 if signed_message.len() < BYTES {
804 return None;
805 }
806
807 let mut message = vec![0u8; signed_message.len() - BYTES];
808 let mut message_len = 0u64;
809
810 let result = unsafe {
811 libsodium_sys::crypto_sign_open(
812 message.as_mut_ptr(),
813 &mut message_len,
814 signed_message.as_ptr(),
815 signed_message.len() as u64,
816 public_key.as_bytes().as_ptr(),
817 )
818 };
819
820 if result != 0 {
821 return None;
822 }
823
824 message.truncate(message_len as usize);
825 Some(message)
826}
827
828/// Create a detached signature for a message
829///
830/// This function creates a signature for a message using the provided secret key, but
831/// unlike `sign`, it returns only the signature, not the message with the signature.
832/// This is useful when you want to transmit the signature separately from the message.
833///
834/// ## Detached Mode
835///
836/// This is known as "detached mode" because the signature is separate from the message.
837/// For combined signatures (where the signature is prepended to the message), use the
838/// `sign` function instead.
839///
840/// ## Signature Format
841///
842/// The signature is a 64-byte array containing:
843/// - An R value (32 bytes): A point on the Edwards curve derived from a deterministic nonce
844/// - An S value (32 bytes): A scalar value that proves knowledge of the secret key
845///
846/// ## Security Properties
847///
848/// - **Deterministic**: The same message signed with the same key always produces the same signature
849/// - **Non-malleable**: Signatures cannot be modified to create new valid signatures
850/// - **Forward secure**: Even if a signature is compromised, the secret key remains secure
851/// - **Collision resistant**: Finding two different messages that produce the same signature is computationally infeasible
852///
853/// ## Use Cases
854///
855/// - **Document signing**: When you need to keep the original document intact
856/// - **Large data**: When the data being signed is too large to duplicate in memory
857/// - **Separate storage**: When you want to store or transmit signatures separately from the data
858/// - **Signature databases**: When maintaining a database of signatures for verification
859///
860/// # Example
861///
862/// ```rust
863/// use libsodium_rs as sodium;
864/// use sodium::crypto_sign;
865/// use sodium::ensure_init;
866///
867/// // Initialize libsodium
868/// ensure_init().expect("Failed to initialize libsodium");
869///
870/// // Generate a key pair
871/// let keypair = crypto_sign::KeyPair::generate().unwrap();
872/// let public_key = keypair.public_key;
873/// let secret_key = keypair.secret_key;
874///
875/// // Sign a message
876/// let message = b"Hello, world!";
877/// let signature = crypto_sign::sign_detached(message, &secret_key).unwrap();
878///
879/// // Verify the signature
880/// assert!(crypto_sign::verify_detached(&signature, message, &public_key));
881///
882/// // The signature can be stored or transmitted separately from the message
883/// // For example, you might store it in a database or send it in a separate packet
884/// let signature_hex = signature.iter().map(|b| format!("{:02x}", b)).collect::<String>();
885/// println!("Signature: {}", signature_hex);
886/// ```
887///
888/// # Arguments
889/// * `message` - The message to sign
890/// * `secret_key` - The secret key to sign with
891///
892/// # Returns
893/// * `Result<[u8; BYTES]>` - The 64-byte signature or an error
894///
895/// # Errors
896/// Returns an error if signing fails (extremely rare, typically only due to system issues)
897///
898/// # Performance Considerations
899///
900/// - Ed25519 signatures are designed to be fast to verify
901/// - Signing is more computationally intensive than verification
902/// - For large messages, the performance is dominated by the SHA-512 hashing of the message
903pub fn sign_detached(message: &[u8], secret_key: &SecretKey) -> Result<[u8; BYTES]> {
904 let mut signature = [0u8; BYTES];
905 let mut signature_len = 0u64;
906
907 let result = unsafe {
908 libsodium_sys::crypto_sign_detached(
909 signature.as_mut_ptr(),
910 &mut signature_len,
911 message.as_ptr(),
912 message.len() as u64,
913 secret_key.as_bytes().as_ptr(),
914 )
915 };
916
917 if result != 0 {
918 return Err(SodiumError::OperationError(
919 "Ed25519 detached signing failed".into(),
920 ));
921 }
922
923 Ok(signature)
924}
925
926/// Verify a detached signature
927///
928/// This function verifies a detached signature for a message using the provided public key.
929/// The signature must have been created using the `sign_detached` function with the
930/// corresponding secret key.
931///
932/// ## Detached Mode
933///
934/// This function works with "detached mode" signatures, where the signature is separate
935/// from the message. For verifying combined signatures, use the `verify` function instead.
936///
937/// ## Security Considerations
938///
939/// - Verification is **constant-time** with respect to the public key and signature,
940/// protecting against timing attacks
941/// - The function will return false for any invalid input (wrong signature, wrong message,
942/// or wrong public key)
943/// - Ed25519 is resistant to many side-channel attacks
944/// - Batch verification (verifying multiple signatures at once) can be more efficient
945/// for high-throughput applications
946///
947/// ## Common Verification Scenarios
948///
949/// - **Document verification**: Ensuring a document hasn't been tampered with
950/// - **Software updates**: Verifying the authenticity of software packages
951/// - **API authentication**: Verifying that API requests come from authorized sources
952/// - **Certificate validation**: Verifying certificate signatures in PKI systems
953///
954/// ## Example
955///
956/// ```rust
957/// use libsodium_rs as sodium;
958/// use sodium::crypto_sign;
959/// use sodium::ensure_init;
960///
961/// // Initialize libsodium
962/// ensure_init().expect("Failed to initialize libsodium");
963///
964/// // Generate a key pair
965/// let keypair = crypto_sign::KeyPair::generate().unwrap();
966/// let public_key = keypair.public_key;
967/// let secret_key = keypair.secret_key;
968///
969/// // Sign a message
970/// let message = b"Hello, world!";
971/// let signature = crypto_sign::sign_detached(message, &secret_key).unwrap();
972///
973/// // Verify the signature
974/// let is_valid = crypto_sign::verify_detached(&signature, message, &public_key);
975/// assert!(is_valid);
976///
977/// // Verification with a modified message should fail
978/// let wrong_message = b"Modified message";
979/// assert!(!crypto_sign::verify_detached(&signature, wrong_message, &public_key));
980///
981/// // Verification with a wrong public key should fail
982/// let wrong_keypair = crypto_sign::KeyPair::generate().unwrap();
983/// let wrong_public_key = wrong_keypair.public_key;
984/// assert!(!crypto_sign::verify_detached(&signature, message, &wrong_public_key));
985/// ```
986///
987/// # Arguments
988/// * `signature` - The 64-byte signature to verify
989/// * `message` - The message that was signed
990/// * `public_key` - The public key to verify with
991///
992/// # Returns
993/// * `bool` - `true` if the signature is valid, `false` otherwise
994pub fn verify_detached(signature: &[u8; BYTES], message: &[u8], public_key: &PublicKey) -> bool {
995 let result = unsafe {
996 libsodium_sys::crypto_sign_verify_detached(
997 signature.as_ptr(),
998 message.as_ptr(),
999 message.len() as u64,
1000 public_key.as_bytes().as_ptr(),
1001 )
1002 };
1003
1004 result == 0
1005}
1006
1007// Add implementation of Display for PublicKey and SecretKey for easier debugging
1008impl fmt::Display for PublicKey {
1009 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1010 // Show a prefix of the key for debugging, but not the entire key
1011 let bytes = self.as_bytes();
1012 write!(
1013 f,
1014 "PublicKey({:02x}{:02x}..{:02x}{:02x})",
1015 bytes[0],
1016 bytes[1],
1017 bytes[PUBLICKEYBYTES - 2],
1018 bytes[PUBLICKEYBYTES - 1]
1019 )
1020 }
1021}
1022
1023impl fmt::Display for SecretKey {
1024 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1025 // For security reasons, don't show any part of the secret key
1026 // Even in debug output, it's better to be cautious
1027 write!(f, "SecretKey(*****)")
1028 }
1029}
1030
1031// Add implementation of TryFrom for PublicKey and SecretKey for more idiomatic conversions
1032impl TryFrom<&[u8]> for PublicKey {
1033 type Error = SodiumError;
1034
1035 fn try_from(bytes: &[u8]) -> std::result::Result<Self, Self::Error> {
1036 PublicKey::from_bytes(bytes)
1037 }
1038}
1039
1040impl TryFrom<&[u8]> for SecretKey {
1041 type Error = SodiumError;
1042
1043 fn try_from(bytes: &[u8]) -> std::result::Result<Self, Self::Error> {
1044 SecretKey::from_bytes(bytes)
1045 }
1046}
1047
1048/// Generate a new Ed25519 key pair from a seed
1049///
1050/// This function deterministically generates an Ed25519 key pair from a seed. The same seed
1051/// will always produce the same key pair. This is useful for key derivation or when you need
1052/// reproducible keys.
1053///
1054/// ## Security Considerations
1055///
1056/// - The seed must be kept as secret as the secret key itself
1057/// - The seed should be high-entropy (ideally from a CSPRNG)
1058/// ```rust
1059/// use libsodium_rs::{ensure_init, crypto_sign};
1060///
1061/// // Initialize libsodium
1062/// ensure_init().expect("Failed to initialize libsodium");
1063///
1064/// ```
1065///
1066/// # Arguments
1067///
1068/// * `seed` - The seed to generate the key pair from
1069///
1070/// # Returns
1071///
1072/// * `Result<KeyPair>` - The generated key pair or an error
1073///
1074/// # Errors
1075///
1076/// Returns an error if key pair generation fails (extremely rare)
1077pub fn keypair_from_seed(seed: &[u8; SEEDBYTES]) -> Result<KeyPair> {
1078 let mut public_key = [0u8; PUBLICKEYBYTES];
1079 let mut secret_key = [0u8; SECRETKEYBYTES];
1080
1081 let result = unsafe {
1082 libsodium_sys::crypto_sign_seed_keypair(
1083 public_key.as_mut_ptr(),
1084 secret_key.as_mut_ptr(),
1085 seed.as_ptr(),
1086 )
1087 };
1088
1089 if result != 0 {
1090 return Err(SodiumError::OperationError(
1091 "Ed25519 key pair generation failed".into(),
1092 ));
1093 }
1094
1095 Ok(KeyPair {
1096 public_key: PublicKey::from_bytes(&public_key).unwrap(),
1097 secret_key: SecretKey::from_bytes(&secret_key).unwrap(),
1098 })
1099}
1100
1101/// Extract the seed from a secret key
1102///
1103/// This function extracts the seed that was used to generate an Ed25519 secret key.
1104/// The seed is the first 32 bytes of the secret key.
1105///
1106/// ## Security Considerations
1107///
1108/// - The seed is as sensitive as the secret key itself and must be kept confidential
1109/// - This is mainly useful for key derivation or when you need to reconstruct keys
1110///
1111/// ## Example
1112///
1113/// ```rust
1114/// use libsodium_rs as sodium;
1115/// use sodium::crypto_sign;
1116/// use sodium::random;
1117/// use sodium::ensure_init;
1118///
1119/// // Initialize libsodium
1120/// ensure_init().expect("Failed to initialize libsodium");
1121///
1122/// // Generate a random seed
1123/// let mut original_seed = [0u8; crypto_sign::SEEDBYTES];
1124/// random::fill_bytes(&mut original_seed);
1125///
1126/// // Generate a keypair from the seed
1127/// let keypair = crypto_sign::KeyPair::from_seed(&original_seed).unwrap();
1128/// let secret_key = keypair.secret_key;
1129///
1130/// // Extract the seed from the secret key
1131/// let extracted_seed = crypto_sign::secret_key_to_seed(&secret_key).unwrap();
1132///
1133/// // The extracted seed should match the original
1134/// assert_eq!(original_seed, extracted_seed);
1135/// ```
1136///
1137/// # Arguments
1138///
1139/// * `secret_key` - The secret key to extract the seed from
1140///
1141/// # Returns
1142///
1143/// * `Result<[u8; SEEDBYTES]>` - The extracted seed or an error
1144///
1145/// # Errors
1146///
1147/// Returns an error if the extraction fails (extremely rare)
1148pub fn secret_key_to_seed(secret_key: &SecretKey) -> Result<[u8; SEEDBYTES]> {
1149 let mut seed = [0u8; SEEDBYTES];
1150
1151 let result = unsafe {
1152 libsodium_sys::crypto_sign_ed25519_sk_to_seed(
1153 seed.as_mut_ptr(),
1154 secret_key.as_bytes().as_ptr(),
1155 )
1156 };
1157
1158 if result != 0 {
1159 return Err(SodiumError::OperationError(
1160 "Failed to extract seed from secret key".into(),
1161 ));
1162 }
1163
1164 Ok(seed)
1165}
1166
1167/// Convert an Ed25519 public key to a Curve25519 public key
1168///
1169/// This function converts an Ed25519 public key (used for signatures) to a Curve25519
1170/// public key (used for key exchange). This allows using the same key pair for both
1171/// signatures and key exchange.
1172///
1173/// ## Security Considerations
1174///
1175/// - Not all Ed25519 public keys can be converted to Curve25519 public keys
1176/// - This conversion is primarily useful when you want to use the same key pair for
1177/// both signatures and key exchange
1178///
1179/// ## Example
1180///
1181/// ```rust
1182/// use libsodium_rs as sodium;
1183/// use sodium::crypto_sign;
1184/// use sodium::ensure_init;
1185///
1186/// // Initialize libsodium
1187/// ensure_init().expect("Failed to initialize libsodium");
1188///
1189/// // Generate an Ed25519 keypair
1190/// let keypair = crypto_sign::KeyPair::generate().unwrap();
1191/// let ed25519_pk = keypair.public_key;
1192///
1193/// // Convert the Ed25519 public key to a Curve25519 public key
1194/// let curve25519_pk = crypto_sign::ed25519_pk_to_curve25519(&ed25519_pk).unwrap();
1195///
1196/// // The Curve25519 public key can now be used for key exchange
1197/// assert_eq!(curve25519_pk.len(), 32);
1198/// ```
1199///
1200/// # Arguments
1201///
1202/// * `ed25519_pk` - The Ed25519 public key to convert
1203///
1204/// # Returns
1205///
1206/// * `Result<[u8; 32]>` - The converted Curve25519 public key or an error
1207///
1208/// # Errors
1209///
1210/// Returns an error if the conversion fails (which can happen for some Ed25519 public keys)
1211pub fn ed25519_pk_to_curve25519(ed25519_pk: &PublicKey) -> Result<[u8; 32]> {
1212 let mut curve25519_pk = [0u8; 32];
1213
1214 let result = unsafe {
1215 libsodium_sys::crypto_sign_ed25519_pk_to_curve25519(
1216 curve25519_pk.as_mut_ptr(),
1217 ed25519_pk.as_bytes().as_ptr(),
1218 )
1219 };
1220
1221 if result != 0 {
1222 return Err(SodiumError::OperationError(
1223 "Failed to convert Ed25519 public key to Curve25519".into(),
1224 ));
1225 }
1226
1227 Ok(curve25519_pk)
1228}
1229
1230/// Convert an Ed25519 secret key to a Curve25519 secret key
1231///
1232/// This function converts an Ed25519 secret key (used for signatures) to a Curve25519
1233/// secret key (used for key exchange). This allows using the same key pair for both
1234/// signatures and key exchange.
1235///
1236/// ## Security Considerations
1237///
1238/// - The resulting Curve25519 secret key is as sensitive as the Ed25519 secret key
1239/// and must be kept confidential
1240/// - This conversion is primarily useful when you want to use the same key pair for
1241/// both signatures and key exchange
1242///
1243/// ## Example
1244///
1245/// ```rust
1246/// use libsodium_rs as sodium;
1247/// use sodium::crypto_sign;
1248/// use sodium::ensure_init;
1249///
1250/// // Initialize libsodium
1251/// ensure_init().expect("Failed to initialize libsodium");
1252///
1253/// // Generate an Ed25519 keypair
1254/// let keypair = crypto_sign::KeyPair::generate().unwrap();
1255/// let ed25519_sk = keypair.secret_key;
1256///
1257/// // Convert the Ed25519 secret key to a Curve25519 secret key
1258/// let curve25519_sk = crypto_sign::ed25519_sk_to_curve25519(&ed25519_sk).unwrap();
1259///
1260/// // The Curve25519 secret key can now be used for key exchange
1261/// assert_eq!(curve25519_sk.len(), 32);
1262/// ```
1263///
1264/// # Arguments
1265///
1266/// * `ed25519_sk` - The Ed25519 secret key to convert
1267///
1268/// # Returns
1269///
1270/// * `Result<[u8; 32]>` - The converted Curve25519 secret key or an error
1271///
1272/// # Errors
1273///
1274/// Returns an error if the conversion fails (extremely rare)
1275pub fn ed25519_sk_to_curve25519(ed25519_sk: &SecretKey) -> Result<[u8; 32]> {
1276 let mut curve25519_sk = [0u8; 32];
1277
1278 let result = unsafe {
1279 libsodium_sys::crypto_sign_ed25519_sk_to_curve25519(
1280 curve25519_sk.as_mut_ptr(),
1281 ed25519_sk.as_bytes().as_ptr(),
1282 )
1283 };
1284
1285 if result != 0 {
1286 return Err(SodiumError::OperationError(
1287 "Failed to convert Ed25519 secret key to Curve25519".into(),
1288 ));
1289 }
1290
1291 Ok(curve25519_sk)
1292}
1293
1294/// State for multi-part (streaming) signature creation and verification
1295///
1296/// This struct is used for creating or verifying signatures when the message is too large
1297/// to fit in memory at once, or when the message is being received in chunks.
1298#[derive(Debug, Clone)]
1299pub struct State {
1300 state: libsodium_sys::crypto_sign_state,
1301}
1302
1303impl State {
1304 /// Create a new signature state
1305 ///
1306 /// This function initializes a new state for multi-part signature creation or verification.
1307 ///
1308 /// ## Example
1309 ///
1310 /// ```rust
1311 /// use libsodium_rs as sodium;
1312 /// use sodium::crypto_sign;
1313 /// use sodium::ensure_init;
1314 ///
1315 /// // Initialize libsodium
1316 /// ensure_init().expect("Failed to initialize libsodium");
1317 ///
1318 /// // Create a new signature state
1319 /// let state = crypto_sign::State::new().unwrap();
1320 /// ```
1321 ///
1322 /// # Returns
1323 /// * `Result<State>` - A new signature state or an error
1324 ///
1325 /// # Errors
1326 /// Returns an error if initialization fails (extremely rare)
1327 pub fn new() -> Result<Self> {
1328 let mut state = unsafe { std::mem::zeroed() };
1329 let result = unsafe { libsodium_sys::crypto_sign_init(&mut state) };
1330
1331 if result != 0 {
1332 return Err(SodiumError::OperationError(
1333 "Failed to initialize signature state".into(),
1334 ));
1335 }
1336
1337 Ok(State { state })
1338 }
1339
1340 /// Update the signature state with a message chunk
1341 ///
1342 /// This function updates the signature state with a chunk of the message to be signed
1343 /// or verified. It can be called multiple times to process a message in chunks.
1344 ///
1345 /// ## Example
1346 ///
1347 /// ```rust
1348 /// use libsodium_rs as sodium;
1349 /// use sodium::crypto_sign;
1350 /// use sodium::ensure_init;
1351 ///
1352 /// // Initialize libsodium
1353 /// ensure_init().expect("Failed to initialize libsodium");
1354 ///
1355 /// // Create a new signature state
1356 /// let mut state = crypto_sign::State::new().unwrap();
1357 ///
1358 /// // Update the state with message chunks
1359 /// state.update(b"Hello, ").unwrap();
1360 /// state.update(b"world!").unwrap();
1361 /// ```
1362 ///
1363 /// # Arguments
1364 /// * `message_chunk` - A chunk of the message to update the state with
1365 ///
1366 /// # Returns
1367 /// * `Result<()>` - Success or an error
1368 ///
1369 /// # Errors
1370 /// Returns an error if the update fails (extremely rare)
1371 pub fn update(&mut self, message_chunk: &[u8]) -> Result<()> {
1372 let result = unsafe {
1373 libsodium_sys::crypto_sign_update(
1374 &mut self.state,
1375 message_chunk.as_ptr(),
1376 message_chunk.len() as u64,
1377 )
1378 };
1379
1380 if result != 0 {
1381 return Err(SodiumError::OperationError(
1382 "Failed to update signature state".into(),
1383 ));
1384 }
1385
1386 Ok(())
1387 }
1388
1389 /// Finalize the signature creation process
1390 ///
1391 /// This function finalizes the signature creation process and returns the signature.
1392 /// It should be called after all message chunks have been processed with `update()`.
1393 ///
1394 /// ## Example
1395 ///
1396 /// ```rust
1397 /// use libsodium_rs as sodium;
1398 /// use sodium::crypto_sign;
1399 /// use sodium::ensure_init;
1400 ///
1401 /// // Initialize libsodium
1402 /// ensure_init().expect("Failed to initialize libsodium");
1403 ///
1404 /// // Generate a keypair
1405 /// let keypair = crypto_sign::KeyPair::generate().unwrap();
1406 /// let secret_key = keypair.secret_key;
1407 ///
1408 /// // Create a multi-part signature
1409 /// let mut state = crypto_sign::State::new().unwrap();
1410 /// state.update(b"Hello, ").unwrap();
1411 /// state.update(b"world!").unwrap();
1412 ///
1413 /// // Finalize and get the signature
1414 /// let signature = state.finalize_create(&secret_key).unwrap();
1415 /// assert_eq!(signature.len(), crypto_sign::BYTES);
1416 /// ```
1417 ///
1418 /// # Arguments
1419 /// * `secret_key` - The secret key to sign with
1420 ///
1421 /// # Returns
1422 /// * `Result<[u8; BYTES]>` - The signature or an error
1423 ///
1424 /// # Errors
1425 /// Returns an error if finalization fails (extremely rare)
1426 pub fn finalize_create(&mut self, secret_key: &SecretKey) -> Result<[u8; BYTES]> {
1427 let mut sig = [0u8; BYTES];
1428 let mut sig_len: u64 = 0;
1429
1430 let result = unsafe {
1431 libsodium_sys::crypto_sign_final_create(
1432 &mut self.state,
1433 sig.as_mut_ptr(),
1434 &mut sig_len,
1435 secret_key.as_bytes().as_ptr(),
1436 )
1437 };
1438
1439 if result != 0 {
1440 return Err(SodiumError::OperationError(
1441 "Failed to finalize signature creation".into(),
1442 ));
1443 }
1444
1445 Ok(sig)
1446 }
1447
1448 /// Finalize the signature verification process
1449 ///
1450 /// This function finalizes the signature verification process. It should be called
1451 /// after all message chunks have been processed with `update()`.
1452 ///
1453 /// ## Example
1454 ///
1455 /// ```rust
1456 /// use libsodium_rs as sodium;
1457 /// use sodium::crypto_sign;
1458 /// use sodium::ensure_init;
1459 ///
1460 /// // Initialize libsodium
1461 /// ensure_init().expect("Failed to initialize libsodium");
1462 ///
1463 /// // Generate a keypair
1464 /// let keypair = crypto_sign::KeyPair::generate().unwrap();
1465 /// let public_key = keypair.public_key;
1466 /// let secret_key = keypair.secret_key;
1467 ///
1468 /// // Create a multi-part signature
1469 /// let mut sign_state = crypto_sign::State::new().unwrap();
1470 /// sign_state.update(b"Hello, ").unwrap();
1471 /// sign_state.update(b"world!").unwrap();
1472 /// let signature = sign_state.finalize_create(&secret_key).unwrap();
1473 ///
1474 /// // Verify the signature
1475 /// let mut verify_state = crypto_sign::State::new().unwrap();
1476 /// verify_state.update(b"Hello, ").unwrap();
1477 /// verify_state.update(b"world!").unwrap();
1478 /// assert!(verify_state.finalize_verify(&signature, &public_key));
1479 /// ```
1480 ///
1481 /// # Arguments
1482 /// * `signature` - The signature to verify
1483 /// * `public_key` - The public key to verify with
1484 ///
1485 /// # Returns
1486 /// * `bool` - `true` if the signature is valid, `false` otherwise
1487 pub fn finalize_verify(&mut self, signature: &[u8; BYTES], public_key: &PublicKey) -> bool {
1488 let result = unsafe {
1489 libsodium_sys::crypto_sign_final_verify(
1490 &mut self.state,
1491 signature.as_ptr(),
1492 public_key.as_bytes().as_ptr(),
1493 )
1494 };
1495
1496 result == 0
1497 }
1498}
1499
1500/// Returns the name of the primitive used by this module
1501///
1502/// This function returns the string "ed25519", which is the name of the primitive
1503/// used by this module.
1504///
1505/// ## Example
1506///
1507/// ```rust
1508/// use libsodium_rs as sodium;
1509/// use sodium::crypto_sign;
1510///
1511/// assert_eq!(crypto_sign::primitive(), "ed25519");
1512/// ```
1513///
1514/// # Returns
1515/// * `&'static str` - The name of the primitive ("ed25519")
1516pub fn primitive() -> &'static str {
1517 PRIMITIVE
1518}
1519
1520#[cfg(test)]
1521mod tests {
1522 use super::*;
1523
1524 #[test]
1525 fn test_keypair_generation() {
1526 // Generate a new keypair
1527 let keypair = KeyPair::generate().unwrap();
1528 let pk = keypair.public_key;
1529 let sk = keypair.secret_key;
1530
1531 // Verify the key sizes
1532 assert_eq!(pk.as_bytes().len(), PUBLICKEYBYTES);
1533 assert_eq!(sk.as_bytes().len(), SECRETKEYBYTES);
1534 }
1535
1536 #[test]
1537 fn test_sign_verify() {
1538 // Generate a new keypair
1539 let keypair = KeyPair::generate().unwrap();
1540 let pk = keypair.public_key;
1541 let sk = keypair.secret_key;
1542 let message = b"Hello, World!";
1543
1544 // Sign the message
1545 let signed = sign(message, &sk).unwrap();
1546
1547 // Verify the signature and extract the original message
1548 let verified = verify(&signed, &pk).unwrap();
1549
1550 // The extracted message should match the original
1551 assert_eq!(message, &verified[..]);
1552
1553 // Verify that the signed message is longer than the original
1554 assert!(signed.len() > message.len());
1555 assert_eq!(signed.len(), message.len() + BYTES);
1556
1557 // Tamper with the signed message - verification should fail
1558 let mut tampered = signed.clone();
1559 tampered[0] ^= 1; // Flip a bit in the signature
1560 assert!(verify(&tampered, &pk).is_none());
1561 }
1562
1563 #[test]
1564 fn test_verify_detached() {
1565 // Generate a keypair
1566 let keypair = KeyPair::generate().unwrap();
1567 let pk = keypair.public_key;
1568 let sk = keypair.secret_key;
1569
1570 // Sign a message
1571 let message = b"Test message";
1572 let signature = sign_detached(message, &sk).unwrap();
1573
1574 // Verify the signature with the correct message
1575 assert!(verify_detached(&signature, message, &pk));
1576
1577 // Verify with wrong message - should fail
1578 let wrong_message = b"Wrong message";
1579 assert!(!verify_detached(&signature, wrong_message, &pk));
1580
1581 // Generate a new keypair and verify with wrong public key - should fail
1582 let wrong_keypair = KeyPair::generate().unwrap();
1583 let wrong_pk = wrong_keypair.public_key;
1584 assert!(!verify_detached(&signature, message, &wrong_pk));
1585 }
1586
1587 #[test]
1588 fn test_seed_keypair() {
1589 // Generate a random seed
1590 let mut seed = [0u8; SEEDBYTES];
1591 crate::random::fill_bytes(&mut seed);
1592
1593 // Generate two keypairs from the same seed
1594 let keypair1 = KeyPair::from_seed(&seed).unwrap();
1595 let pk1 = keypair1.public_key;
1596 let sk1 = keypair1.secret_key;
1597
1598 // The same seed should produce the same keypair
1599 let keypair2 = KeyPair::from_seed(&seed).unwrap();
1600 let pk2 = keypair2.public_key;
1601 let sk2 = keypair2.secret_key;
1602 assert_eq!(pk1, pk2);
1603 assert_eq!(sk1, sk2);
1604
1605 // Invalid seed length should fail
1606 let invalid_seed = [0u8; SEEDBYTES - 1];
1607 assert!(KeyPair::from_seed(&invalid_seed).is_err());
1608
1609 // Test deterministic key generation
1610 let seed = [0u8; SEEDBYTES];
1611 let keypair = KeyPair::from_seed(&seed).unwrap();
1612 let determ_pk = keypair.public_key;
1613 let determ_sk = keypair.secret_key;
1614 assert_ne!(determ_pk.0, [0u8; PUBLICKEYBYTES]);
1615 assert_ne!(determ_sk.0, [0u8; SECRETKEYBYTES]);
1616 }
1617
1618 #[test]
1619 fn test_key_conversions() {
1620 // Generate a keypair
1621 let keypair = KeyPair::generate().unwrap();
1622 let pk = keypair.public_key;
1623 let sk = keypair.secret_key;
1624
1625 // Extract public key from secret key
1626 let extracted_pk = PublicKey::from_secret_key(&sk).unwrap();
1627 assert_eq!(pk, extracted_pk);
1628
1629 // Test seed extraction (for deterministic keypairs)
1630 let seed = [0u8; SEEDBYTES];
1631 let keypair = KeyPair::from_seed(&seed).unwrap();
1632 let sk = keypair.secret_key;
1633 let extracted_seed = secret_key_to_seed(&sk).unwrap();
1634 assert_eq!(seed, extracted_seed);
1635
1636 // Test conversion to Curve25519 keys
1637 let curve_pk = ed25519_pk_to_curve25519(&pk).unwrap();
1638 let curve_sk = ed25519_sk_to_curve25519(&sk).unwrap();
1639
1640 assert_eq!(curve_pk.len(), 32);
1641 assert_eq!(curve_sk.len(), 32);
1642 }
1643
1644 #[test]
1645 fn test_multipart_signing() {
1646 // Generate a keypair
1647 let keypair = KeyPair::generate().unwrap();
1648 let pk = keypair.public_key;
1649 let sk = keypair.secret_key;
1650
1651 // Create a message in parts
1652 let part1 = b"Hello, ";
1653 let part2 = b"world!";
1654
1655 // Sign using multi-part API
1656 let mut sign_state = State::new().unwrap();
1657 sign_state.update(part1).unwrap();
1658 sign_state.update(part2).unwrap();
1659 let signature = sign_state.finalize_create(&sk).unwrap();
1660
1661 // Verify using multi-part API
1662 let mut verify_state = State::new().unwrap();
1663 verify_state.update(part1).unwrap();
1664 verify_state.update(part2).unwrap();
1665 assert!(verify_state.finalize_verify(&signature, &pk));
1666
1667 // Test with different message - should fail
1668 let mut verify_state2 = State::new().unwrap();
1669 verify_state2.update(b"Different message").unwrap();
1670 assert!(!verify_state2.finalize_verify(&signature, &pk));
1671
1672 // Test with wrong public key - should fail
1673 let wrong_keypair = KeyPair::generate().unwrap();
1674 let wrong_pk = wrong_keypair.public_key;
1675 let mut verify_state3 = State::new().unwrap();
1676 verify_state3.update(part1).unwrap();
1677 verify_state3.update(part2).unwrap();
1678 assert!(!verify_state3.finalize_verify(&signature, &wrong_pk));
1679 }
1680
1681 #[test]
1682 fn test_publickey_traits() {
1683 let keypair = KeyPair::generate().unwrap();
1684 let pk = keypair.public_key;
1685
1686 // Test AsRef<[u8]>
1687 let bytes_ref: &[u8] = pk.as_ref();
1688 assert_eq!(bytes_ref.len(), PUBLICKEYBYTES);
1689 assert_eq!(bytes_ref, pk.as_bytes());
1690
1691 // Test From<[u8; N]> for PublicKey
1692 let bytes: [u8; PUBLICKEYBYTES] = pk.clone().into();
1693 let pk2 = PublicKey::from(bytes);
1694 assert_eq!(pk.as_bytes(), pk2.as_bytes());
1695
1696 // Test From<PublicKey> for [u8; N]
1697 let extracted: [u8; PUBLICKEYBYTES] = pk.into();
1698 assert_eq!(extracted, bytes);
1699 }
1700
1701 #[test]
1702 fn test_secretkey_traits() {
1703 let keypair = KeyPair::generate().unwrap();
1704 let sk = keypair.secret_key;
1705
1706 // Test AsRef<[u8]>
1707 let bytes_ref: &[u8] = sk.as_ref();
1708 assert_eq!(bytes_ref.len(), SECRETKEYBYTES);
1709 assert_eq!(bytes_ref, sk.as_bytes());
1710
1711 // Test From<[u8; N]> for SecretKey
1712 let bytes: [u8; SECRETKEYBYTES] = sk.clone().into();
1713 let sk2 = SecretKey::from(bytes);
1714 assert_eq!(sk.as_bytes(), sk2.as_bytes());
1715
1716 // Test From<SecretKey> for [u8; N]
1717 let extracted: [u8; SECRETKEYBYTES] = sk.into();
1718 assert_eq!(extracted, bytes);
1719 }
1720}