Skip to main content

ed25519_dalek/
lib.rs

1// -*- mode: rust; -*-
2//
3// This file is part of ed25519-dalek.
4// Copyright (c) 2017-2019 isis lovecruft
5// See LICENSE for licensing information.
6//
7// Authors:
8// - isis agora lovecruft <[email protected]>
9
10//! A Rust implementation of ed25519 key generation, signing, and verification.
11//!
12//! # Example
13//!
14//! Creating an ed25519 signature on a message is simple.
15//!
16//! First, we need to generate a `SigningKey`, which includes both public and
17//! secret halves of an asymmetric key.  To do so, we need a cryptographically
18//! secure pseudorandom number generator (CSPRNG). For this example, we'll use
19//! the operating system's builtin PRNG:
20//!
21#![cfg_attr(feature = "rand_core", doc = "```")]
22#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")]
23//! # fn main() {
24//! // $ cargo add ed25519_dalek --features rand_core
25//! use getrandom::{SysRng, rand_core::UnwrapErr};
26//! use rand_core::TryRng;
27//! use ed25519_dalek::SigningKey;
28//! use ed25519_dalek::Signature;
29//!
30//! let mut csprng = UnwrapErr(SysRng);
31//! let signing_key: SigningKey = SigningKey::generate(&mut csprng);
32//! # }
33//! ```
34//!
35//! We can now use this `signing_key` to sign a message:
36//!
37#![cfg_attr(feature = "rand_core", doc = "```")]
38#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")]
39//! # fn main() {
40//! # use getrandom::{SysRng, rand_core::{TryRng, UnwrapErr}};
41//! # use ed25519_dalek::SigningKey;
42//! # let mut csprng = UnwrapErr(SysRng);
43//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng);
44//! use ed25519_dalek::{Signature, Signer};
45//! let message: &[u8] = b"This is a test of the tsunami alert system.";
46//! let signature: Signature = signing_key.sign(message);
47//! # }
48//! ```
49//!
50//! As well as to verify that this is, indeed, a valid signature on
51//! that `message`:
52//!
53#![cfg_attr(feature = "rand_core", doc = "```")]
54#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")]
55//! # fn main() {
56//! # use getrandom::{SysRng, rand_core::{TryRng, UnwrapErr}};
57//! # use ed25519_dalek::{SigningKey, Signature, Signer};
58//! # let mut csprng = UnwrapErr(SysRng);
59//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng);
60//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
61//! # let signature: Signature = signing_key.sign(message);
62//! use ed25519_dalek::Verifier;
63//! assert!(signing_key.verify(message, &signature).is_ok());
64//! # }
65//! ```
66//!
67//! Anyone else, given the `public` half of the `signing_key` can also easily
68//! verify this signature:
69//!
70#![cfg_attr(feature = "rand_core", doc = "```")]
71#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")]
72//! # fn main() {
73//! # use getrandom::{SysRng, rand_core::{TryRng, UnwrapErr}};
74//! # use ed25519_dalek::SigningKey;
75//! # use ed25519_dalek::Signature;
76//! # use ed25519_dalek::Signer;
77//! use ed25519_dalek::{VerifyingKey, Verifier};
78//! # let mut csprng = UnwrapErr(SysRng);
79//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng);
80//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
81//! # let signature: Signature = signing_key.sign(message);
82//!
83//! let verifying_key: VerifyingKey = signing_key.verifying_key();
84//! assert!(verifying_key.verify(message, &signature).is_ok());
85//! # }
86//! ```
87//!
88//! ## Serialisation
89//!
90//! `VerifyingKey`s, `SecretKey`s, `SigningKey`s, and `Signature`s can be serialised
91//! into byte-arrays by calling `.to_bytes()`.  It's perfectly acceptable and
92//! safe to transfer and/or store those bytes.  (Of course, never transfer your
93//! secret key to anyone else, since they will only need the public key to
94//! verify your signatures!)
95//!
96#![cfg_attr(feature = "rand_core", doc = "```")]
97#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")]
98//! # fn main() {
99//! # use getrandom::{SysRng, rand_core::{TryRng, UnwrapErr}};
100//! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey};
101//! use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
102//! # let mut csprng = UnwrapErr(SysRng);
103//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng);
104//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
105//! # let signature: Signature = signing_key.sign(message);
106//!
107//! let verifying_key_bytes: [u8; PUBLIC_KEY_LENGTH] = signing_key.verifying_key().to_bytes();
108//! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = signing_key.to_bytes();
109//! let signing_key_bytes:    [u8; KEYPAIR_LENGTH]    = signing_key.to_keypair_bytes();
110//! let signature_bytes:  [u8; SIGNATURE_LENGTH]  = signature.to_bytes();
111//! # }
112//! ```
113//!
114//! And similarly, decoded from bytes with `::from_bytes()`:
115//!
116#![cfg_attr(feature = "rand_core", doc = "```")]
117#![cfg_attr(not(feature = "rand_core"), doc = "```ignore")]
118//! # use core::convert::{TryFrom, TryInto};
119//! # use getrandom::{SysRng, rand_core::{TryRng, UnwrapErr}};
120//! # use ed25519_dalek::{SigningKey, Signature, Signer, VerifyingKey, SecretKey, SignatureError};
121//! # use ed25519_dalek::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
122//! # fn do_test() -> Result<(SigningKey, VerifyingKey, Signature), SignatureError> {
123//! # let mut csprng = UnwrapErr(SysRng);
124//! # let signing_key_orig: SigningKey = SigningKey::generate(&mut csprng);
125//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
126//! # let signature_orig: Signature = signing_key_orig.sign(message);
127//! # let verifying_key_bytes: [u8; PUBLIC_KEY_LENGTH] = signing_key_orig.verifying_key().to_bytes();
128//! # let signing_key_bytes: [u8; SECRET_KEY_LENGTH] = signing_key_orig.to_bytes();
129//! # let signature_bytes:  [u8; SIGNATURE_LENGTH]  = signature_orig.to_bytes();
130//! #
131//! let verifying_key: VerifyingKey = VerifyingKey::from_bytes(&verifying_key_bytes)?;
132//! let signing_key: SigningKey = SigningKey::from_bytes(&signing_key_bytes);
133//! let signature: Signature = Signature::try_from(&signature_bytes[..])?;
134//! #
135//! # Ok((signing_key, verifying_key, signature))
136//! # }
137//! # fn main() {
138//! #     do_test();
139//! # }
140//! ```
141//!
142//! ### PKCS#8 Key Encoding
143//!
144//! PKCS#8 is a private key format with support for multiple algorithms.
145//! It can be encoded as binary (DER) or text (PEM).
146//!
147//! You can recognize PEM-encoded PKCS#8 keys by the following:
148//!
149//! ```text
150//! -----BEGIN PRIVATE KEY-----
151//! ```
152//!
153//! To use PKCS#8, you need to enable the `pkcs8` crate feature.
154//!
155//! The following traits can be used to decode/encode [`SigningKey`] and
156//! [`VerifyingKey`] as PKCS#8. Note that [`pkcs8`] is re-exported from the
157//! toplevel of the crate:
158//!
159//! - [`pkcs8::DecodePrivateKey`]: decode private keys from PKCS#8
160//! - [`pkcs8::EncodePrivateKey`]: encode private keys to PKCS#8
161//! - [`pkcs8::DecodePublicKey`]: decode public keys from PKCS#8
162//! - [`pkcs8::EncodePublicKey`]: encode public keys to PKCS#8
163//!
164//! #### Example
165//!
166//! NOTE: this requires the `pem` crate feature.
167//!
168#![cfg_attr(feature = "pem", doc = "```")]
169#![cfg_attr(not(feature = "pem"), doc = "```ignore")]
170//! use ed25519_dalek::{VerifyingKey, pkcs8::DecodePublicKey};
171//!
172//! let pem = "-----BEGIN PUBLIC KEY-----
173//! MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=
174//! -----END PUBLIC KEY-----";
175//!
176//! let verifying_key = VerifyingKey::from_public_key_pem(pem)
177//!     .expect("invalid public key PEM");
178//! ```
179//!
180//! ### Using Serde
181//!
182//! If you prefer the bytes to be wrapped in another serialisation format, all
183//! types additionally come with built-in [serde](https://serde.rs) support by
184//! building `ed25519-dalek` via:
185//!
186//! ```bash
187//! $ cargo build --features="serde"
188//! ```
189//!
190//! They can be then serialised into any of the wire formats which serde supports.
191//! For example, using [postcard](https://docs.rs/postcard):
192//!
193#![cfg_attr(all(feature = "rand_core", feature = "serde"), doc = "```")]
194#![cfg_attr(not(all(feature = "rand_core", feature = "serde")), doc = "```ignore")]
195//! # fn main() {
196//! # use getrandom::{SysRng, rand_core::{TryRng, UnwrapErr}};
197//! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey};
198//! use postcard::to_allocvec;
199//! # let mut csprng = UnwrapErr(SysRng);
200//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng);
201//! # let message: &[u8] = b"This is a test of the tsunami alert system.";
202//! # let signature: Signature = signing_key.sign(message);
203//! # let verifying_key: VerifyingKey = signing_key.verifying_key();
204//! # let verified: bool = verifying_key.verify(message, &signature).is_ok();
205//!
206//! let encoded_verifying_key: Vec<u8> = to_allocvec(&verifying_key).unwrap();
207//! let encoded_signature: Vec<u8> = to_allocvec(&signature).unwrap();
208//! # }
209//! ```
210//!
211//! After sending the `encoded_verifying_key` and `encoded_signature`, the
212//! recipient may deserialise them and verify:
213//!
214#![cfg_attr(all(feature = "rand_core", feature = "serde"), doc = "```")]
215#![cfg_attr(not(all(feature = "rand_core", feature = "serde")), doc = "```ignore")]
216//! # fn main() {
217//! # use getrandom::{SysRng, rand_core::{TryRng, UnwrapErr}};
218//! # use ed25519_dalek::{SigningKey, Signature, Signer, Verifier, VerifyingKey};
219//! # use postcard::to_allocvec;
220//! use postcard::from_bytes;
221//!
222//! # let mut csprng = UnwrapErr(SysRng);
223//! # let signing_key: SigningKey = SigningKey::generate(&mut csprng);
224//! let message: &[u8] = b"This is a test of the tsunami alert system.";
225//! # let signature: Signature = signing_key.sign(message);
226//! # let verifying_key: VerifyingKey = signing_key.verifying_key();
227//! # let verified: bool = verifying_key.verify(message, &signature).is_ok();
228//! # let encoded_verifying_key: Vec<u8> = to_allocvec(&verifying_key).unwrap();
229//! # let encoded_signature: Vec<u8> = to_allocvec(&signature).unwrap();
230//! let decoded_verifying_key: VerifyingKey = from_bytes(&encoded_verifying_key).unwrap();
231//! let decoded_signature: Signature = from_bytes(&encoded_signature).unwrap();
232//!
233//! # assert_eq!(verifying_key, decoded_verifying_key);
234//! # assert_eq!(signature, decoded_signature);
235//! #
236//! let verified: bool = decoded_verifying_key.verify(&message, &decoded_signature).is_ok();
237//!
238//! assert!(verified);
239//! # }
240//! ```
241
242#![no_std]
243#![warn(future_incompatible, rust_2018_idioms)]
244#![deny(missing_docs)] // refuse to compile if documentation is missing
245#![deny(clippy::unwrap_used)] // don't allow unwrap
246#![cfg_attr(not(any(test, feature = "batch")), forbid(unsafe_code))]
247#![cfg_attr(docsrs, feature(doc_cfg))]
248
249#[cfg(feature = "batch")]
250extern crate alloc;
251
252#[cfg(test)]
253#[macro_use]
254extern crate std;
255
256#[cfg(feature = "rand_core")]
257pub use rand_core;
258
259pub use ed25519;
260
261#[cfg(feature = "batch")]
262mod batch;
263mod constants;
264#[cfg(feature = "digest")]
265mod context;
266mod errors;
267mod signature;
268mod signing;
269mod verifying;
270
271#[cfg(feature = "hazmat")]
272pub mod hazmat;
273#[cfg(not(feature = "hazmat"))]
274mod hazmat;
275
276#[cfg(feature = "digest")]
277pub use curve25519_dalek::digest::Digest;
278#[cfg(feature = "digest")]
279pub use sha2::Sha512;
280
281#[cfg(feature = "batch")]
282pub use crate::batch::*;
283pub use crate::constants::*;
284#[cfg(feature = "digest")]
285pub use crate::context::Context;
286pub use crate::errors::*;
287pub use crate::signing::*;
288pub use crate::verifying::*;
289
290// Re-export the `Signer` and `Verifier` traits from the `signature` crate
291#[cfg(feature = "digest")]
292pub use ::signature::{DigestSigner, DigestVerifier};
293pub use ed25519::Signature;
294pub use ed25519::signature::{Signer, Verifier};
295
296#[cfg(feature = "pkcs8")]
297pub use ed25519::pkcs8;