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//! You should use a 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//! One should take note that keys used for signing and encryption should remain
27//! separate. While it's possible to convert Ed25519 keys to X25519 keys (or
28//! derive them from the same seed), one is cautioned against doing so.
29//!
30//! ## Rustaceous API example, single-part
31//!
32//! ```
33//! use dryoc::sign::*;
34//!
35//! // Generate a random keypair, using default types
36//! let keypair = SigningKeyPair::gen_with_defaults();
37//! let message = b"Fair is foul, and foul is fair: Hover through the fog and filthy air.";
38//!
39//! // Sign the message, using default types (stack-allocated byte array, Vec<u8>)
40//! let signed_message = keypair.sign_with_defaults(message).expect("signing failed");
41//!
42//! // Verify the message signature
43//! signed_message
44//!     .verify(&keypair.public_key)
45//!     .expect("verification failed");
46//! ```
47//!
48//! ## Incremental (multi-part) interface
49//!
50//! ```
51//! use dryoc::sign::*;
52//!
53//! // Generate a random keypair, using default types
54//! let keypair = SigningKeyPair::gen_with_defaults();
55//!
56//! // Initialize the incremental signer interface
57//! let mut signer = IncrementalSigner::new();
58//! signer.update(b"This above all: to thine ownself be true.");
59//! signer.update(b"And it must follow, as the night the day,");
60//! signer.update(b"Thou canst not then be false to any man.");
61//!
62//! let signature: Signature = signer
63//!     .finalize(&keypair.secret_key)
64//!     .expect("signing failed");
65//! ```
66//!
67//! ## Additional resources
68//!
69//! * See <https://libsodium.gitbook.io/doc/public-key_cryptography/public-key_signatures>
70//!   for additional details on public-key signatures
71//! * For secret-key based encryption, see
72//!   [`DryocSecretBox`](crate::dryocsecretbox)
73//! * For stream encryption, see [`DryocStream`](crate::dryocstream)
74//! * See the [protected] mod for an example using the protected memory features
75
76#[cfg(feature = "serde")]
77use serde::{Deserialize, Serialize};
78use subtle::ConstantTimeEq;
79use zeroize::{Zeroize, ZeroizeOnDrop};
80
81use crate::classic::crypto_sign::{
82    SignerState, crypto_sign_detached, crypto_sign_final_create, crypto_sign_final_verify,
83    crypto_sign_init, crypto_sign_keypair_inplace, crypto_sign_seed_keypair_inplace,
84    crypto_sign_update, crypto_sign_verify_detached,
85};
86use crate::constants::{
87    CRYPTO_SIGN_BYTES, CRYPTO_SIGN_PUBLICKEYBYTES, CRYPTO_SIGN_SECRETKEYBYTES,
88    CRYPTO_SIGN_SEEDBYTES,
89};
90use crate::error::Error;
91use crate::types::*;
92
93/// Stack-allocated public key for message signing.
94pub type PublicKey = StackByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>;
95/// Stack-allocated secret key for message signing.
96pub type SecretKey = StackByteArray<CRYPTO_SIGN_SECRETKEYBYTES>;
97/// Stack-allocated signature for message signing.
98pub type Signature = StackByteArray<CRYPTO_SIGN_BYTES>;
99/// Heap-allocated message for message signing.
100pub type Message = Vec<u8>;
101
102#[cfg_attr(
103    feature = "serde",
104    derive(Zeroize, ZeroizeOnDrop, Serialize, Deserialize, Debug, Clone)
105)]
106#[cfg_attr(not(feature = "serde"), derive(Zeroize, ZeroizeOnDrop, Debug, Clone))]
107/// An Ed25519 keypair for public-key signatures
108pub struct SigningKeyPair<
109    PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
110    SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
111> {
112    /// Public key
113    pub public_key: PublicKey,
114    /// Secret key
115    pub secret_key: SecretKey,
116}
117
118impl<
119    PublicKey: NewByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
120    SecretKey: NewByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
121> SigningKeyPair<PublicKey, SecretKey>
122{
123    /// Creates a new, empty signing keypair.
124    pub fn new() -> Self {
125        Self {
126            public_key: PublicKey::new_byte_array(),
127            secret_key: SecretKey::new_byte_array(),
128        }
129    }
130
131    /// Generates a random signing keypair.
132    pub fn gen() -> Self {
133        let mut public_key = PublicKey::new_byte_array();
134        let mut secret_key = SecretKey::new_byte_array();
135        crypto_sign_keypair_inplace(public_key.as_mut_array(), secret_key.as_mut_array());
136        Self {
137            public_key,
138            secret_key,
139        }
140    }
141
142    /// Derives a signing keypair from `secret_key`, and consumes it, returning
143    /// a new keypair.
144    pub fn from_secret_key(secret_key: SecretKey) -> Self {
145        let mut seed = [0u8; 32];
146        seed.copy_from_slice(&secret_key.as_slice()[..32]);
147
148        Self::from_seed(&seed)
149    }
150
151    /// Derives a signing keypair from `seed`, returning
152    /// a new keypair.
153    pub fn from_seed<Seed: ByteArray<CRYPTO_SIGN_SEEDBYTES>>(seed: &Seed) -> Self {
154        let mut public_key = PublicKey::new_byte_array();
155        let mut secret_key = SecretKey::new_byte_array();
156
157        crypto_sign_seed_keypair_inplace(
158            public_key.as_mut_array(),
159            secret_key.as_mut_array(),
160            seed.as_array(),
161        );
162
163        Self {
164            public_key,
165            secret_key,
166        }
167    }
168}
169
170impl
171    SigningKeyPair<
172        StackByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>,
173        StackByteArray<CRYPTO_SIGN_SECRETKEYBYTES>,
174    >
175{
176    /// Randomly generates a new signing keypair, using default types
177    /// (stack-allocated byte arrays). Provided for convenience.
178    pub fn gen_with_defaults() -> Self {
179        Self::gen()
180    }
181}
182
183impl<
184    'a,
185    PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + std::convert::TryFrom<&'a [u8]> + Zeroize,
186    SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + std::convert::TryFrom<&'a [u8]> + Zeroize,
187> SigningKeyPair<PublicKey, SecretKey>
188{
189    /// Constructs a new signing keypair from key slices, consuming them. Does
190    /// not check validity or authenticity of keypair.
191    pub fn from_slices(public_key: &'a [u8], secret_key: &'a [u8]) -> Result<Self, Error> {
192        Ok(Self {
193            public_key: PublicKey::try_from(public_key)
194                .map_err(|_e| dryoc_error!("invalid public key"))?,
195            secret_key: SecretKey::try_from(secret_key)
196                .map_err(|_e| dryoc_error!("invalid secret key"))?,
197        })
198    }
199}
200
201#[cfg(any(feature = "nightly", all(doc, not(doctest))))]
202#[cfg_attr(all(feature = "nightly", doc), doc(cfg(feature = "nightly")))]
203pub mod protected {
204    //! #  Protected memory for [`SigningKeyPair`] and [`SignedMessage`].
205    //!
206    //! ## Example
207    //! ```
208    //! use dryoc::sign::SigningKeyPair;
209    //! use dryoc::sign::protected::*;
210    //!
211    //! // Generate a random keypair, using default types
212    //! let keypair = SigningKeyPair::gen_locked_keypair().expect("keypair gen failed");
213    //! let message = Message::from_slice_into_locked(
214    //!     b"Fair is foul, and foul is fair: Hover through the fog and filthy air.",
215    //! )
216    //! .expect("message lock failed");
217    //!
218    //! // Sign the message, using default types (stack-allocated byte array, Vec<u8>)
219    //! let signed_message: LockedSignedMessage = keypair.sign(message).expect("signing failed");
220    //!
221    //! // Verify the message signature
222    //! signed_message
223    //!     .verify(&keypair.public_key)
224    //!     .expect("verification failed");
225    //! ```
226    use super::*;
227    pub use crate::protected::*;
228
229    /// Heap-allocated, page-aligned public-key for signed messages,
230    /// for use with protected memory.
231    pub type PublicKey = HeapByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>;
232    /// Heap-allocated, page-aligned secret-key for signed messages,
233    /// for use with protected memory.
234    pub type SecretKey = HeapByteArray<CRYPTO_SIGN_SECRETKEYBYTES>;
235    /// Heap-allocated, page-aligned signature for signed messages,
236    /// for use with protected memory.
237    pub type Signature = HeapByteArray<CRYPTO_SIGN_BYTES>;
238    /// Heap-allocated, page-aligned message for signed messages,
239    /// for use with protected memory.
240    pub type Message = HeapBytes;
241
242    /// Heap-allocated, page-aligned public/secret keypair for message signing,
243    /// for use with protected memory.
244    pub type LockedSigningKeyPair = SigningKeyPair<Locked<PublicKey>, Locked<SecretKey>>;
245    /// Heap-allocated, page-aligned signed message, for use with protected
246    /// memory.
247    pub type LockedSignedMessage = SignedMessage<Locked<Signature>, Locked<Message>>;
248
249    impl
250        SigningKeyPair<
251            Locked<HeapByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>,
252            Locked<HeapByteArray<CRYPTO_SIGN_SECRETKEYBYTES>>,
253        >
254    {
255        /// Returns a new locked signing keypair.
256        pub fn new_locked_keypair() -> Result<Self, std::io::Error> {
257            Ok(Self {
258                public_key: HeapByteArray::<CRYPTO_SIGN_PUBLICKEYBYTES>::new_locked()?,
259                secret_key: HeapByteArray::<CRYPTO_SIGN_SECRETKEYBYTES>::new_locked()?,
260            })
261        }
262
263        /// Returns a new randomly generated locked signing keypair.
264        pub fn gen_locked_keypair() -> Result<Self, std::io::Error> {
265            let mut res = Self::new_locked_keypair()?;
266
267            crypto_sign_keypair_inplace(
268                res.public_key.as_mut_array(),
269                res.secret_key.as_mut_array(),
270            );
271
272            Ok(res)
273        }
274    }
275
276    impl
277        SigningKeyPair<
278            LockedRO<HeapByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>,
279            LockedRO<HeapByteArray<CRYPTO_SIGN_SECRETKEYBYTES>>,
280        >
281    {
282        /// Returns a new randomly generated locked, read-only signing keypair.
283        pub fn gen_readonly_locked_keypair() -> Result<Self, std::io::Error> {
284            let mut public_key = HeapByteArray::<CRYPTO_SIGN_PUBLICKEYBYTES>::new_locked()?;
285            let mut secret_key = HeapByteArray::<CRYPTO_SIGN_SECRETKEYBYTES>::new_locked()?;
286
287            crypto_sign_keypair_inplace(public_key.as_mut_array(), secret_key.as_mut_array());
288
289            let public_key = public_key.mprotect_readonly()?;
290            let secret_key = secret_key.mprotect_readonly()?;
291
292            Ok(Self {
293                public_key,
294                secret_key,
295            })
296        }
297    }
298}
299
300#[cfg_attr(
301    feature = "serde",
302    derive(Zeroize, Clone, Debug, Serialize, Deserialize)
303)]
304#[cfg_attr(not(feature = "serde"), derive(Zeroize, Clone, Debug))]
305/// A signed message, for use with [`SigningKeyPair`].
306pub struct SignedMessage<
307    Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize,
308    Message: Bytes + Zeroize,
309> {
310    signature: Signature,
311    message: Message,
312}
313
314/// [Vec]-based signed message.
315pub type VecSignedMessage = SignedMessage<Signature, Vec<u8>>;
316
317impl<
318    PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
319    SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
320> SigningKeyPair<PublicKey, SecretKey>
321{
322    /// Signs `message` using this keypair, consuming the message, and returning
323    /// a new [`SignedMessage`]. The type of `message` should match that of the
324    /// target signed message.
325    pub fn sign<Signature: NewByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>(
326        &self,
327        message: Message,
328    ) -> Result<SignedMessage<Signature, Message>, Error> {
329        let mut signature = Signature::new_byte_array();
330        crypto_sign_detached(
331            signature.as_mut_array(),
332            message.as_slice(),
333            self.secret_key.as_array(),
334        )?;
335
336        Ok(SignedMessage::<Signature, Message> { signature, message })
337    }
338
339    /// Signs `message`, putting the result into a [`Vec`]. Convenience wrapper
340    /// for [`SigningKeyPair::sign`].
341    pub fn sign_with_defaults<Message: Bytes>(
342        &self,
343        message: Message,
344    ) -> Result<SignedMessage<StackByteArray<CRYPTO_SIGN_BYTES>, Vec<u8>>, Error> {
345        self.sign(Vec::from(message.as_slice()))
346    }
347}
348
349impl Default for SigningKeyPair<PublicKey, SecretKey> {
350    fn default() -> Self {
351        Self::new()
352    }
353}
354
355/// Multi-part (incremental)  interface for [`SigningKeyPair`].
356pub struct IncrementalSigner {
357    state: SignerState,
358}
359
360impl IncrementalSigner {
361    /// Returns a new incremental signer instance.
362    pub fn new() -> Self {
363        Self {
364            state: crypto_sign_init(),
365        }
366    }
367
368    /// Updates the state for this incremental signer with `message`.
369    pub fn update<Message: Bytes>(&mut self, message: &Message) {
370        crypto_sign_update(&mut self.state, message.as_slice())
371    }
372
373    /// Finalizes this incremental signer, returning the signature upon
374    /// success.
375    pub fn finalize<
376        Signature: NewByteArray<CRYPTO_SIGN_BYTES>,
377        SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES>,
378    >(
379        self,
380        secret_key: &SecretKey,
381    ) -> Result<Signature, Error> {
382        let mut signature = Signature::new_byte_array();
383
384        crypto_sign_final_create(self.state, signature.as_mut_array(), secret_key.as_array())?;
385
386        Ok(signature)
387    }
388
389    /// Verifies `signature` as a valid signature for this signer.
390    pub fn verify<
391        Signature: ByteArray<CRYPTO_SIGN_BYTES>,
392        PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>,
393    >(
394        self,
395        signature: &Signature,
396        public_key: &PublicKey,
397    ) -> Result<(), Error> {
398        crypto_sign_final_verify(self.state, signature.as_array(), public_key.as_array())?;
399
400        Ok(())
401    }
402}
403
404impl Default for IncrementalSigner {
405    fn default() -> Self {
406        Self::new()
407    }
408}
409
410impl<Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>
411    SignedMessage<Signature, Message>
412{
413    /// Verifies that this signed message is valid for `public_key`.
414    pub fn verify<PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES>>(
415        &self,
416        public_key: &PublicKey,
417    ) -> Result<(), Error> {
418        crypto_sign_verify_detached(
419            self.signature.as_array(),
420            self.message.as_slice(),
421            public_key.as_array(),
422        )
423    }
424}
425
426impl<
427    'a,
428    Signature: ByteArray<CRYPTO_SIGN_BYTES> + std::convert::TryFrom<&'a [u8]> + Zeroize,
429    Message: Bytes + From<&'a [u8]> + Zeroize,
430> SignedMessage<Signature, Message>
431{
432    /// Initializes a [`SignedMessage`] from a slice. Expects the first
433    /// [`CRYPTO_SIGN_BYTES`] bytes to contain the message signature,
434    /// with the remaining bytes containing the message.
435    pub fn from_bytes(bytes: &'a [u8]) -> Result<Self, Error> {
436        if bytes.len() < CRYPTO_SIGN_BYTES {
437            Err(dryoc_error!(format!(
438                "bytes of len {} less than expected minimum of {}",
439                bytes.len(),
440                CRYPTO_SIGN_BYTES
441            )))
442        } else {
443            let (signature, message) = bytes.split_at(CRYPTO_SIGN_BYTES);
444            Ok(Self {
445                signature: Signature::try_from(signature)
446                    .map_err(|_e| dryoc_error!("invalid signature"))?,
447                message: Message::from(message),
448            })
449        }
450    }
451}
452
453impl<Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>
454    SignedMessage<Signature, Message>
455{
456    /// Returns a new box with `tag`, `data` and (optional) `ephemeral_pk`,
457    /// consuming each.
458    pub fn from_parts(signature: Signature, message: Message) -> Self {
459        Self { signature, message }
460    }
461
462    /// Copies `self` into a new [`Vec`]
463    pub fn to_vec(&self) -> Vec<u8> {
464        self.to_bytes()
465    }
466
467    /// Moves the tag, data, and (optional) ephemeral public key out of this
468    /// instance, returning them as a tuple.
469    pub fn into_parts(self) -> (Signature, Message) {
470        (self.signature, self.message)
471    }
472
473    /// Copies `self` into the target. Can be used with protected memory.
474    pub fn to_bytes<Bytes: NewBytes + ResizableBytes>(&self) -> Bytes {
475        let mut data = Bytes::new_bytes();
476
477        data.resize(self.signature.len() + self.message.len(), 0);
478        let s = data.as_mut_slice();
479        s[..CRYPTO_SIGN_BYTES].copy_from_slice(self.signature.as_slice());
480        s[CRYPTO_SIGN_BYTES..].copy_from_slice(self.message.as_slice());
481
482        data
483    }
484}
485
486impl<
487    PublicKey: ByteArray<CRYPTO_SIGN_PUBLICKEYBYTES> + Zeroize,
488    SecretKey: ByteArray<CRYPTO_SIGN_SECRETKEYBYTES> + Zeroize,
489> PartialEq<SigningKeyPair<PublicKey, SecretKey>> for SigningKeyPair<PublicKey, SecretKey>
490{
491    fn eq(&self, other: &Self) -> bool {
492        self.public_key
493            .as_slice()
494            .ct_eq(other.public_key.as_slice())
495            .unwrap_u8()
496            == 1
497            && self
498                .secret_key
499                .as_slice()
500                .ct_eq(other.secret_key.as_slice())
501                .unwrap_u8()
502                == 1
503    }
504}
505
506impl<Signature: ByteArray<CRYPTO_SIGN_BYTES> + Zeroize, Message: Bytes + Zeroize>
507    PartialEq<SignedMessage<Signature, Message>> for SignedMessage<Signature, Message>
508{
509    fn eq(&self, other: &Self) -> bool {
510        self.signature
511            .as_slice()
512            .ct_eq(other.signature.as_slice())
513            .unwrap_u8()
514            == 1
515            && self
516                .message
517                .as_slice()
518                .ct_eq(other.message.as_slice())
519                .unwrap_u8()
520                == 1
521    }
522}
523
524#[cfg(test)]
525mod tests {
526    use super::*;
527
528    #[test]
529    fn test_message_signing() {
530        let keypair = SigningKeyPair::gen_with_defaults();
531        let message = b"hello my frens";
532
533        let signed_message = keypair.sign_with_defaults(message).expect("signing failed");
534
535        signed_message
536            .verify(&keypair.public_key)
537            .expect("verification failed");
538    }
539}