Skip to main content

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}