Skip to main content

dryoc/
sign.rs

1//! # Public-key signatures
2//!
3//! This module implements libsodium's public-key signature functions. The
4//! signatures are based on Ed25519 (EdDSA). It provides both a
5//! [single-part](SigningKeyPair::sign) and [multi-part](IncrementalSigner)
6//! interface.
7//!
8//! The single-part interface is convenient for short
9//! messages, such as those small enough to fit in memory. The multi-part
10//! interface may be more appropriate for lengthy messages, those which don't
11//! fit in memory, or those for which the entire message isn't known at once
12//! (i.e., during network communication, or reading a large file).
13//!
14//! The single-part and multi-part variants use slightly different algorithms,
15//! and thus they are not compatible with each other.
16//!
17//! Use this module when you want to:
18//!
19//! * share a message with other parties, and provide a proof that the message
20//!   is authentic
21//! * verify that the message from another party was signed using their secret
22//!   key, without having knowledge of the original secret
23//!
24//! The public key of the signer must be known to the verifier.
25//!
26//! Keep signing and encryption keys separate. Although Ed25519 keys can be
27//! converted to X25519 keys or derived from the same seed, doing so couples two
28//! distinct security roles.
29//!
30//! Signing secret keys include both the seed and public key. Use
31//! [`secret_key_to_seed`], [`secret_key_to_public_key`],
32//! [`SigningKeyPair::to_seed`], or [`SigningKeyPair::to_public_key`] to extract
33//! those parts when interoperating with libsodium-style key storage.
34//!
35//! ## Rustaceous API example, single-part
36//!
37//! ```
38//! use dryoc::sign::*;
39//!
40//! // Generate a random keypair, using default types
41//! let keypair = SigningKeyPair::<PublicKey, SecretKey>::generate();
42//! let message = b"Fair is foul, and foul is fair: Hover through the fog and filthy air.";
43//!
44//! // Sign the message, using default types (stack-allocated byte array, Vec<u8>)
45//! let signed_message = keypair.sign_with_defaults(message).expect("signing failed");
46//!
47//! // Verify the message signature
48//! signed_message
49//!     .verify(&keypair.public_key)
50//!     .expect("verification failed");
51//! ```
52//!
53//! ## Extracting key material
54//!
55//! ```
56//! use dryoc::sign::*;
57//!
58//! let seed = Seed::from([7u8; dryoc::constants::CRYPTO_SIGN_SEEDBYTES]);
59//! let keypair = SigningKeyPair::<PublicKey, SecretKey>::from_seed(&seed);
60//!
61//! let extracted_seed: Seed = keypair.to_seed();
62//! let extracted_public_key: PublicKey = keypair.to_public_key();
63//!
64//! assert_eq!(extracted_seed, seed);
65//! assert_eq!(extracted_public_key, keypair.public_key);
66//! ```
67//!
68//! ## Incremental (multi-part) interface
69//!
70//! ```
71//! use dryoc::sign::*;
72//!
73//! // Generate a random keypair, using default types
74//! let keypair = SigningKeyPair::<PublicKey, SecretKey>::generate();
75//!
76//! // Initialize the incremental signer interface
77//! let mut signer = IncrementalSigner::new();
78//! signer.update(b"This above all: to thine ownself be true.");
79//! signer.update(b"And it must follow, as the night the day,");
80//! signer.update(b"Thou canst not then be false to any man.");
81//!
82//! let signature: Signature = signer
83//!     .finalize(&keypair.secret_key)
84//!     .expect("signing failed");
85//! ```
86//!
87//! ## Additional resources
88//!
89//! * See <https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures>
90//!   for additional details on public-key signatures
91//! * For secret-key based encryption, see
92//!   [`DryocSecretBox`](crate::dryocsecretbox)
93//! * For stream encryption, see [`DryocStream`](crate::dryocstream)
94//! * See the [protected] mod for an example using the protected memory features
95
96use std::fmt;
97
98#[cfg(feature = "serde")]
99use serde::{Deserialize, Serialize};
100use subtle::ConstantTimeEq;
101use zeroize::{Zeroize, ZeroizeOnDrop, Zeroizing};
102
103use crate::classic::crypto_sign::{
104    SignerState, crypto_sign_detached, crypto_sign_ed25519_sk_to_pk,
105    crypto_sign_ed25519_sk_to_seed, crypto_sign_final_create, crypto_sign_final_verify,
106    crypto_sign_init, crypto_sign_keypair_inplace, crypto_sign_seed_keypair_inplace,
107    crypto_sign_update, crypto_sign_verify_detached,
108};
109use crate::constants::{
110    CRYPTO_SIGN_BYTES, CRYPTO_SIGN_PUBLICKEYBYTES, CRYPTO_SIGN_SECRETKEYBYTES,
111    CRYPTO_SIGN_SEEDBYTES,
112};
113use crate::error::Error;
114use crate::types::*;
115
116/// Stack-allocated public key for message signing.
117pub type PublicKey = StackByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>;
118/// Stack-allocated secret key for message signing.
119pub type SecretKey = StackByteArray<CRYPTO_SIGN_SECRETKEYBYTES>;
120/// Stack-allocated seed for message signing.
121pub type Seed = StackByteArray<CRYPTO_SIGN_SEEDBYTES>;
122/// Stack-allocated signature for message signing.
123pub type Signature = StackByteArray<CRYPTO_SIGN_BYTES>;
124/// Heap-allocated message for message signing.
125pub type Message = Vec<u8>;
126
127/// Extracts the Ed25519 seed from a signing secret key.
128pub fn secret_key_to_seed<
129    SeedOut: NewByteArray<CRYPTO_SIGN_SEEDBYTES>,
130    SigningSecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES>,
131>(
132    secret_key: &SigningSecretKey,
133) -> SeedOut {
134    let mut seed = SeedOut::new_byte_array();
135    crypto_sign_ed25519_sk_to_seed(seed.as_mut_array(), secret_key.as_array());
136    seed
137}
138
139/// Extracts the Ed25519 public key from a signing secret key.
140pub fn secret_key_to_public_key<
141    PublicKeyOut: NewByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>,
142    SigningSecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES>,
143>(
144    secret_key: &SigningSecretKey,
145) -> PublicKeyOut {
146    let mut public_key = PublicKeyOut::new_byte_array();
147    crypto_sign_ed25519_sk_to_pk(public_key.as_mut_array(), secret_key.as_array());
148    public_key
149}
150
151#[cfg_attr(
152    feature = "serde",
153    derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize, Clone)
154)]
155#[cfg_attr(not(feature = "serde"), derive(Zeroize, ZeroizeOnDrop, Clone))]
156/// An Ed25519 keypair for public-key signatures
157pub struct SigningKeyPair<
158    PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
159    SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
160> {
161    /// Public key
162    pub public_key: PublicKey,
163    /// Secret key
164    pub secret_key: SecretKey,
165}
166
167impl<
168    PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
169    SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
170> fmt::Debug for SigningKeyPair<PublicKey, SecretKey>
171{
172    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
173        f.debug_struct("SigningKeyPair")
174            .field("public_key", &"[REDACTED]")
175            .field("secret_key", &"[REDACTED]")
176            .finish()
177    }
178}
179
180impl<
181    PublicKey: NewByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
182    SecretKey: NewByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
183> SigningKeyPair<PublicKey, SecretKey>
184{
185    /// Creates a new, empty signing keypair.
186    pub fn new() -> Self {
187        Self {
188            public_key: PublicKey::new_byte_array(),
189            secret_key: SecretKey::new_byte_array(),
190        }
191    }
192
193    /// Generates a random signing keypair.
194    pub fn generate() -> Self {
195        let mut public_key = PublicKey::new_byte_array();
196        let mut secret_key = SecretKey::new_byte_array();
197        crypto_sign_keypair_inplace(public_key.as_mut_array(), secret_key.as_mut_array());
198        Self {
199            public_key,
200            secret_key,
201        }
202    }
203
204    /// Generates a random signing keypair.
205    ///
206    /// Prefer [`generate`](Self::generate). `gen` is retained for compatibility
207    /// with older Rust editions.
208    #[deprecated(note = "use generate() instead")]
209    pub fn r#gen() -> Self {
210        Self::generate()
211    }
212
213    /// Derives a signing keypair from `secret_key`, and consumes it, returning
214    /// a new keypair.
215    pub fn from_secret_key(secret_key: SecretKey) -> Self {
216        let mut seed = Zeroizing::new([0u8; 32]);
217        seed.copy_from_slice(&secret_key.as_slice()[..32]);
218
219        Self::from_seed(&*seed)
220    }
221
222    /// Derives a signing keypair from `seed`, returning
223    /// a new keypair.
224    pub fn from_seed<Seed: ByteArray<CRYPTO_SIGN_SEEDBYTES>>(seed: &Seed) -> Self {
225        let mut public_key = PublicKey::new_byte_array();
226        let mut secret_key = SecretKey::new_byte_array();
227
228        crypto_sign_seed_keypair_inplace(
229            public_key.as_mut_array(),
230            secret_key.as_mut_array(),
231            seed.as_array(),
232        );
233
234        Self {
235            public_key,
236            secret_key,
237        }
238    }
239}
240
241impl<
242    PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
243    SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
244> SigningKeyPair<PublicKey, SecretKey>
245{
246    /// Extracts the Ed25519 seed from this keypair's secret key.
247    pub fn to_seed<SeedOut: NewByteArray<CRYPTO_SIGN_SEEDBYTES>>(&self) -> SeedOut {
248        secret_key_to_seed(&self.secret_key)
249    }
250
251    /// Extracts the Ed25519 public key embedded in this keypair's secret key.
252    pub fn to_public_key<PublicKeyOut: NewByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>(
253        &self,
254    ) -> PublicKeyOut {
255        secret_key_to_public_key(&self.secret_key)
256    }
257}
258
259impl
260    SigningKeyPair<
261        StackByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>,
262        StackByteArray<CRYPTO_SIGN_SECRETKEYBYTES>,
263    >
264{
265    /// Randomly generates a new signing keypair, using default types
266    /// (stack-allocated byte arrays). Provided for convenience.
267    pub fn generate_with_defaults() -> Self {
268        Self::generate()
269    }
270
271    /// Randomly generates a new signing keypair, using default types
272    /// (stack-allocated byte arrays). Provided for convenience.
273    ///
274    /// Prefer [`generate_with_defaults`](Self::generate_with_defaults). This
275    /// method is retained for compatibility.
276    #[deprecated(note = "use generate_with_defaults() instead")]
277    pub fn gen_with_defaults() -> Self {
278        Self::generate_with_defaults()
279    }
280}
281
282impl<
283    'a,
284    PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + std::convert::TryFrom<&'a [u8]> + Zeroize,
285    SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + std::convert::TryFrom<&'a [u8]> + Zeroize,
286> SigningKeyPair<PublicKey, SecretKey>
287{
288    /// Constructs a new signing keypair from key slices, consuming them. Does
289    /// not check validity or authenticity of keypair.
290    ///
291    /// # Errors
292    ///
293    /// Returns an error if either slice has the wrong length for its key type,
294    /// or if the target key type rejects the key bytes.
295    pub fn from_slices(public_key: &'a [u8], secret_key: &'a [u8]) -> Result<Self, Error> {
296        validate_length!(
297            exact CRYPTO_SIGN_PUBLICKEYBYTES,
298            public_key.len(),
299            crate::ErrorContext::PublicKey
300        );
301        validate_length!(
302            exact CRYPTO_SIGN_SECRETKEYBYTES,
303            secret_key.len(),
304            crate::ErrorContext::SecretKey
305        );
306
307        Ok(Self {
308            public_key: PublicKey::try_from(public_key)
309                .map_err(|_| Error::invalid_key(crate::ErrorContext::PublicKey))?,
310            secret_key: SecretKey::try_from(secret_key)
311                .map_err(|_| Error::invalid_key(crate::ErrorContext::SecretKey))?,
312        })
313    }
314}
315
316#[cfg(any(all(feature = "protected", any(unix, windows)), all(doc, not(doctest))))]
317#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "protected")))]
318pub mod protected {
319    //! # Protected memory for [`SigningKeyPair`] and [`SignedMessage`]
320    //!
321    //! ## Example
322    //! ```
323    //! use dryoc::sign::SigningKeyPair;
324    //! use dryoc::sign::protected::*;
325    //!
326    //! // Generate a random keypair, using default types
327    //! let keypair = SigningKeyPair::generate_locked_keypair().expect("keypair generate failed");
328    //! let message = Message::from_slice_into_locked(
329    //!     b"Fair is foul, and foul is fair: Hover through the fog and filthy air.",
330    //! )
331    //! .expect("message lock failed");
332    //!
333    //! // Sign the message, using default types (stack-allocated byte array, Vec<u8>)
334    //! let signed_message: LockedSignedMessage = keypair.sign(message).expect("signing failed");
335    //!
336    //! // Verify the message signature
337    //! signed_message
338    //!     .verify(&keypair.public_key)
339    //!     .expect("verification failed");
340    //! ```
341    use super::*;
342    pub use crate::protected::*;
343
344    /// Heap-allocated, page-aligned public-key for signed messages,
345    /// for use with protected memory.
346    pub type PublicKey = HeapByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>;
347    /// Heap-allocated, page-aligned secret-key for signed messages,
348    /// for use with protected memory.
349    pub type SecretKey = HeapByteArray<CRYPTO_SIGN_SECRETKEYBYTES>;
350    /// Heap-allocated, page-aligned seed for signed messages,
351    /// for use with protected memory.
352    pub type Seed = HeapByteArray<CRYPTO_SIGN_SEEDBYTES>;
353    /// Heap-allocated, page-aligned signature for signed messages,
354    /// for use with protected memory.
355    pub type Signature = HeapByteArray<CRYPTO_SIGN_BYTES>;
356    /// Heap-allocated, page-aligned message for signed messages,
357    /// for use with protected memory.
358    pub type Message = HeapBytes;
359
360    /// Heap-allocated, page-aligned public/secret keypair for message signing,
361    /// for use with protected memory.
362    pub type LockedSigningKeyPair = SigningKeyPair<Locked<PublicKey>, Locked<SecretKey>>;
363    /// Heap-allocated, page-aligned signed message, for use with protected
364    /// memory.
365    pub type LockedSignedMessage = SignedMessage<Locked<Signature>, Locked<Message>>;
366
367    impl
368        SigningKeyPair<
369            Locked<HeapByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>,
370            Locked<HeapByteArray<CRYPTO_SIGN_SECRETKEYBYTES>>,
371        >
372    {
373        /// Returns a new locked signing keypair.
374        ///
375        /// # Errors
376        ///
377        /// Returns [`Error::Io`] if either allocation cannot be locked.
378        ///
379        /// # Panics
380        ///
381        /// Panics if either page-aligned allocation cannot be created or its
382        /// size cannot be represented with guard pages.
383        pub fn new_locked_keypair() -> Result<Self, Error> {
384            Ok(Self {
385                public_key: HeapByteArray::<CRYPTO_SIGN_PUBLICKEYBYTES>::new_locked()?,
386                secret_key: HeapByteArray::<CRYPTO_SIGN_SECRETKEYBYTES>::new_locked()?,
387            })
388        }
389
390        /// Returns a new randomly generated locked signing keypair.
391        ///
392        /// # Errors
393        ///
394        /// Returns [`Error::Io`] if either allocation cannot be locked.
395        ///
396        /// # Panics
397        ///
398        /// Panics if either page-aligned allocation cannot be created, its
399        /// size cannot be represented with guard pages, or the operating
400        /// system's random number generator fails.
401        pub fn generate_locked_keypair() -> Result<Self, Error> {
402            let mut res = Self::new_locked_keypair()?;
403
404            crypto_sign_keypair_inplace(
405                res.public_key.as_mut_array(),
406                res.secret_key.as_mut_array(),
407            );
408
409            Ok(res)
410        }
411
412        /// Returns a new randomly generated locked signing keypair.
413        ///
414        /// Prefer [`generate_locked_keypair`](Self::generate_locked_keypair).
415        /// This method is retained for compatibility.
416        ///
417        /// # Errors
418        ///
419        /// Returns the same errors as
420        /// [`generate_locked_keypair`](Self::generate_locked_keypair).
421        ///
422        /// # Panics
423        ///
424        /// Panics under the same conditions as
425        /// [`generate_locked_keypair`](Self::generate_locked_keypair).
426        #[deprecated(note = "use generate_locked_keypair() instead")]
427        pub fn gen_locked_keypair() -> Result<Self, Error> {
428            Self::generate_locked_keypair()
429        }
430    }
431
432    impl
433        SigningKeyPair<
434            LockedRO<HeapByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>,
435            LockedRO<HeapByteArray<CRYPTO_SIGN_SECRETKEYBYTES>>,
436        >
437    {
438        /// Returns a new randomly generated locked, read-only signing keypair.
439        ///
440        /// # Errors
441        ///
442        /// Returns [`Error::Io`] if either allocation cannot be locked or its
443        /// page permissions cannot be changed to read-only.
444        ///
445        /// # Panics
446        ///
447        /// Panics if either page-aligned allocation cannot be created, its
448        /// size cannot be represented with guard pages, or the operating
449        /// system's random number generator fails.
450        pub fn generate_readonly_locked_keypair() -> Result<Self, Error> {
451            let mut public_key = HeapByteArray::<CRYPTO_SIGN_PUBLICKEYBYTES>::new_locked()?;
452            let mut secret_key = HeapByteArray::<CRYPTO_SIGN_SECRETKEYBYTES>::new_locked()?;
453
454            crypto_sign_keypair_inplace(public_key.as_mut_array(), secret_key.as_mut_array());
455
456            let public_key = public_key.mprotect_readonly()?;
457            let secret_key = secret_key.mprotect_readonly()?;
458
459            Ok(Self {
460                public_key,
461                secret_key,
462            })
463        }
464
465        /// Returns a new randomly generated locked, read-only signing keypair.
466        ///
467        /// Prefer
468        /// [`generate_readonly_locked_keypair`](Self::generate_readonly_locked_keypair).
469        /// This method is retained for compatibility.
470        ///
471        /// # Errors
472        ///
473        /// Returns the same errors as
474        /// [`generate_readonly_locked_keypair`](Self::generate_readonly_locked_keypair).
475        ///
476        /// # Panics
477        ///
478        /// Panics under the same conditions as
479        /// [`generate_readonly_locked_keypair`](Self::generate_readonly_locked_keypair).
480        #[deprecated(note = "use generate_readonly_locked_keypair() instead")]
481        pub fn gen_readonly_locked_keypair() -> Result<Self, Error> {
482            Self::generate_readonly_locked_keypair()
483        }
484    }
485}
486
487#[cfg_attr(
488    feature = "serde",
489    derive(Zeroize, Clone, Debug, Serialize, Deserialize)
490)]
491#[cfg_attr(not(feature = "serde"), derive(Zeroize, Clone, Debug))]
492/// A signed message, for use with [`SigningKeyPair`].
493pub struct SignedMessage<
494    Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize,
495    Message: Bytes + Zeroize,
496> {
497    signature: Signature,
498    message: Message,
499}
500
501/// [Vec]-based signed message.
502pub type VecSignedMessage = SignedMessage<Signature, Vec<u8>>;
503
504impl<
505    PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
506    SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
507> SigningKeyPair<PublicKey, SecretKey>
508{
509    /// Signs `message` using this keypair, consuming the message, and returning
510    /// a new [`SignedMessage`]. The type of `message` should match that of the
511    /// target signed message.
512    ///
513    /// # Errors
514    ///
515    /// The fixed-size signature and secret-key types satisfy the current
516    /// implementation's requirements, so this function does not return an
517    /// error for valid type implementations. The [`Result`] is retained for
518    /// compatibility with the underlying signing API.
519    pub fn sign<Signature: NewByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>(
520        &self,
521        message: Message,
522    ) -> Result<SignedMessage<Signature, Message>, Error> {
523        let mut signature = Signature::new_byte_array();
524        crypto_sign_detached(
525            signature.as_mut_array(),
526            message.as_slice(),
527            self.secret_key.as_array(),
528        )?;
529
530        Ok(SignedMessage::<Signature, Message> { signature, message })
531    }
532
533    /// Signs `message`, putting the result into a [`Vec`]. Convenience wrapper
534    /// for [`SigningKeyPair::sign`].
535    ///
536    /// # Errors
537    ///
538    /// The default fixed-size types satisfy the current implementation's
539    /// requirements, so this function does not return an error in normal use.
540    /// The [`Result`] is retained for API compatibility.
541    pub fn sign_with_defaults<Message: Bytes>(
542        &self,
543        message: Message,
544    ) -> Result<SignedMessage<StackByteArray<CRYPTO_SIGN_BYTES>, Vec<u8>>, Error> {
545        self.sign(Vec::from(message.as_slice()))
546    }
547}
548
549impl Default for SigningKeyPair<PublicKey, SecretKey> {
550    fn default() -> Self {
551        Self::new()
552    }
553}
554
555/// Multi-part (incremental)  interface for [`SigningKeyPair`].
556pub struct IncrementalSigner {
557    state: SignerState,
558}
559
560impl IncrementalSigner {
561    /// Returns a new incremental signer instance.
562    pub fn new() -> Self {
563        Self {
564            state: crypto_sign_init(),
565        }
566    }
567
568    /// Updates the state for this incremental signer with `message`.
569    pub fn update<Message: Bytes>(&mut self, message: &Message) {
570        crypto_sign_update(&mut self.state, message.as_slice())
571    }
572
573    /// Finalizes this incremental signer, returning the signature upon
574    /// success.
575    ///
576    /// # Errors
577    ///
578    /// The fixed-size signature and secret-key types satisfy the current
579    /// implementation's requirements, so this function does not return an
580    /// error for valid type implementations. The [`Result`] is retained for
581    /// compatibility with the underlying signing API.
582    pub fn finalize<
583        Signature: NewByteArray<CRYPTO_SIGN_BYTES>,
584        SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES>,
585    >(
586        self,
587        secret_key: &SecretKey,
588    ) -> Result<Signature, Error> {
589        let mut signature = Signature::new_byte_array();
590
591        crypto_sign_final_create(self.state, signature.as_mut_array(), secret_key.as_array())?;
592
593        Ok(signature)
594    }
595
596    /// Verifies `signature` as a valid signature for this signer.
597    ///
598    /// # Errors
599    ///
600    /// Returns an error if `signature` is not valid for the accumulated
601    /// message and `public_key`.
602    pub fn verify<
603        Signature: ByteArray<CRYPTO_SIGN_BYTES>,
604        PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>,
605    >(
606        self,
607        signature: &Signature,
608        public_key: &PublicKey,
609    ) -> Result<(), Error> {
610        crypto_sign_final_verify(self.state, signature.as_array(), public_key.as_array())?;
611
612        Ok(())
613    }
614}
615
616impl Default for IncrementalSigner {
617    fn default() -> Self {
618        Self::new()
619    }
620}
621
622impl<Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>
623    SignedMessage<Signature, Message>
624{
625    /// Verifies that this signed message is valid for `public_key`.
626    ///
627    /// # Errors
628    ///
629    /// Returns an error if the signature is not valid for the message and
630    /// `public_key`.
631    pub fn verify<PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>(
632        &self,
633        public_key: &PublicKey,
634    ) -> Result<(), Error> {
635        crypto_sign_verify_detached(
636            self.signature.as_array(),
637            self.message.as_slice(),
638            public_key.as_array(),
639        )
640    }
641}
642
643impl<
644    'a,
645    Signature: ByteArray<CRYPTO_SIGN_BYTES> + std::convert::TryFrom<&'a [u8]> + Zeroize,
646    Message: Bytes + From<&'a [u8]> + Zeroize,
647> SignedMessage<Signature, Message>
648{
649    /// Initializes a [`SignedMessage`] from a slice. Expects the first
650    /// [`CRYPTO_SIGN_BYTES`] bytes to contain the message signature,
651    /// with the remaining bytes containing the message.
652    ///
653    /// # Errors
654    ///
655    /// Returns an error if `bytes` is shorter than a signature or the
656    /// signature cannot be converted to the requested output type.
657    pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, Error> {
658        if bytes.len() < CRYPTO_SIGN_BYTES {
659            Err(
660                length_error!(crate::ErrorContext::SignedMessage, bytes.len(), min CRYPTO_SIGN_BYTES),
661            )
662        } else {
663            let (signature, message) = bytes.split_at(CRYPTO_SIGN_BYTES);
664            Ok(Self {
665                signature: Signature::try_from(signature)
666                    .map_err(|_| Error::invalid_encoding(crate::ErrorContext::Signature))?,
667                message: Message::from(message),
668            })
669        }
670    }
671}
672
673impl<Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>
674    SignedMessage<Signature, Message>
675{
676    /// Returns a new box with `tag`, `data` and (optional) `ephemeral_pk`,
677    /// consuming each.
678    pub fn from_parts(signature: Signature, message: Message) -> Self {
679        Self { signature, message }
680    }
681
682    /// Copies `self` into a new [`Vec`]
683    pub fn to_vec(&self) -> Vec<u8> {
684        self.to_bytes()
685    }
686
687    /// Moves the tag, data, and (optional) ephemeral public key out of this
688    /// instance, returning them as a tuple.
689    pub fn into_parts(self) -> (Signature, Message) {
690        (self.signature, self.message)
691    }
692
693    /// Copies `self` into the target. Can be used with protected memory.
694    pub fn to_bytes<Bytes: NewBytes + ResizableBytes>(&self) -> Bytes {
695        let mut data = Bytes::new_bytes();
696
697        data.resize(self.signature.len() + self.message.len(), 0);
698        let s = data.as_mut_slice();
699        s[..CRYPTO_SIGN_BYTES].copy_from_slice(self.signature.as_slice());
700        s[CRYPTO_SIGN_BYTES..].copy_from_slice(self.message.as_slice());
701
702        data
703    }
704}
705
706impl<
707    PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
708    SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
709> PartialEq<SigningKeyPair<PublicKey, SecretKey>> for SigningKeyPair<PublicKey, SecretKey>
710{
711    fn eq(&self, other: &Self) -> bool {
712        self.public_key
713            .as_slice()
714            .ct_eq(other.public_key.as_slice())
715            .unwrap_u8()
716            == 1
717            && self
718                .secret_key
719                .as_slice()
720                .ct_eq(other.secret_key.as_slice())
721                .unwrap_u8()
722                == 1
723    }
724}
725
726impl<Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>
727    PartialEq<SignedMessage<Signature, Message>> for SignedMessage<Signature, Message>
728{
729    fn eq(&self, other: &Self) -> bool {
730        self.signature
731            .as_slice()
732            .ct_eq(other.signature.as_slice())
733            .unwrap_u8()
734            == 1
735            && self
736                .message
737                .as_slice()
738                .ct_eq(other.message.as_slice())
739                .unwrap_u8()
740                == 1
741    }
742}
743
744#[cfg(test)]
745mod tests {
746    use super::*;
747
748    #[test]
749    fn signing_keypair_debug_redacts_keys_and_secret_key_reconstructs_keypair() {
750        let keypair = SigningKeyPair::<PublicKey, SecretKey>::generate();
751        let debug = format!("{keypair:?}");
752        let reconstructed = SigningKeyPair::from_secret_key(keypair.secret_key.clone());
753
754        assert_eq!(
755            debug,
756            "SigningKeyPair { public_key: \"[REDACTED]\", secret_key: \"[REDACTED]\" }"
757        );
758        assert_eq!(reconstructed, keypair);
759    }
760
761    #[test]
762    fn test_message_signing() {
763        let keypair = SigningKeyPair::generate_with_defaults();
764        let message = b"hello my frens";
765
766        let signed_message = keypair.sign_with_defaults(message).expect("signing failed");
767
768        signed_message
769            .verify(&keypair.public_key)
770            .expect("verification failed");
771    }
772
773    #[test]
774    fn test_secret_key_extraction() {
775        let seed = Seed::generate();
776        let keypair = SigningKeyPair::<PublicKey, SecretKey>::from_seed(&seed);
777
778        let extracted_seed: Seed = keypair.to_seed();
779        let extracted_public_key: PublicKey = keypair.to_public_key();
780        assert_eq!(extracted_seed, seed);
781        assert_eq!(extracted_public_key, keypair.public_key);
782
783        let extracted_seed_vec: Vec<u8> = secret_key_to_seed(&keypair.secret_key);
784        let extracted_public_key_vec: Vec<u8> = secret_key_to_public_key(&keypair.secret_key);
785        assert_eq!(extracted_seed_vec.as_slice(), seed.as_slice());
786        assert_eq!(
787            extracted_public_key_vec.as_slice(),
788            keypair.public_key.as_slice()
789        );
790    }
791}