schnorrkel/
lib.rs

1// -*- mode: rust; -*-
2//
3// This file is part of schnorrkel.
4// Copyright (c) 2017-2019 Isis Lovecruft and Web 3 Foundation
5// See LICENSE for licensing information.
6//
7// Authors:
8// - Isis Agora Lovecruft <isis@patternsinthevoid.net>
9// - Jeffrey Burdges <jeff@web3.foundation>
10
11//! Schnorr signature variants using Ristretto point compression.
12//!
13//! # Example
14//!
15//! Creating a signature on a message is simple.
16//!
17//! First, we need to generate a `Keypair`, which includes both public and
18//! secret halves of an asymmetric key.  To do so, we need a cryptographically
19//! secure pseudorandom number generator (CSPRNG).
20//!
21//! ```
22//! # #[cfg(all(feature = "std"))]
23//! # fn main() {
24//! use rand::{Rng, rngs::OsRng};
25//! use schnorrkel::{Keypair,Signature};
26//!
27//! let keypair: Keypair = Keypair::generate_with(OsRng);
28//! # }
29//! #
30//! # #[cfg(any(not(feature = "std")))]
31//! # fn main() { }
32//! ```
33//!
34//! We can now use this `keypair` to sign a message:
35//!
36//! ```
37//! # fn main() {
38//! # use rand::{SeedableRng}; // Rng
39//! # use rand_chacha::ChaChaRng;
40//! # use schnorrkel::{Keypair,Signature,signing_context};
41//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]);
42//! # let keypair: Keypair = Keypair::generate_with(&mut csprng);
43//! let context = signing_context(b"this signature does this thing");
44//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
45//! # #[cfg(feature = "getrandom")]
46//! let signature: Signature = keypair.sign(context.bytes(message));
47//! # }
48//! ```
49//!
50//! As well as to verify that this is, indeed, a valid signature on
51//! that `message`:
52//!
53//! ```
54//! # fn main() {
55//! # use rand::{SeedableRng}; // Rng
56//! # use rand_chacha::ChaChaRng;
57//! # use schnorrkel::{Keypair,Signature,signing_context};
58//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]);
59//! # let keypair: Keypair = Keypair::generate_with(&mut csprng);
60//! # let context = signing_context(b"this signature does this thing");
61//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
62//! # #[cfg(feature = "getrandom")]
63//! # let signature: Signature = keypair.sign(context.bytes(message));
64//! # #[cfg(feature = "getrandom")]
65//! assert!(keypair.verify(context.bytes(message), &signature).is_ok());
66//! # }
67//! ```
68//!
69//! Anyone else, given the `public` half of the `keypair` can also easily
70//! verify this signature:
71//!
72//! ```
73//! # fn main() {
74//! # use rand::{SeedableRng}; // Rng
75//! # use rand_chacha::ChaChaRng;
76//! # use schnorrkel::{Keypair,Signature,signing_context};
77//! use schnorrkel::PublicKey;
78//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]);
79//! # let keypair: Keypair = Keypair::generate_with(&mut csprng);
80//! # let context = signing_context(b"this signature does this thing");
81//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
82//! # #[cfg(feature = "getrandom")]
83//! # let signature: Signature = keypair.sign(context.bytes(message));
84//! let public_key: PublicKey = keypair.public;
85//! # #[cfg(feature = "getrandom")]
86//! assert!(public_key.verify(context.bytes(message), &signature).is_ok());
87//! # }
88//! ```
89//!
90//! ## Serialisation
91//!
92//! `PublicKey`s, `MiniSecretKey`s, `Keypair`s, and `Signature`s can be serialised
93//! into byte-arrays by calling `.to_bytes()`.  It's perfectly acceptable and
94//! safe to transfer and/or store those bytes.  (Of course, never transfer your
95//! secret key to anyone else, since they will only need the public key to
96//! verify your signatures!)
97//!
98//! ```
99//! # #[cfg(feature = "getrandom")]
100//! # fn main() {
101//! # use rand::{Rng, SeedableRng};
102//! # use rand_chacha::ChaChaRng;
103//! # use schnorrkel::{Keypair, Signature, PublicKey, signing_context};
104//! use schnorrkel::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
105//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]);
106//! # let keypair: Keypair = Keypair::generate_with(&mut csprng);
107//! # let context = signing_context(b"this signature does this thing");
108//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
109//! # let signature: Signature = keypair.sign(context.bytes(message));
110//! # let public_key: PublicKey = keypair.public;
111//!
112//! let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = public_key.to_bytes();
113//! let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair.secret.to_bytes();
114//! let keypair_bytes:    [u8; KEYPAIR_LENGTH]    = keypair.to_bytes();
115//! let signature_bytes:  [u8; SIGNATURE_LENGTH]  = signature.to_bytes();
116//! # }
117//! # #[cfg(not(feature = "getrandom"))]
118//! # fn main() { }
119//! ```
120//!
121//! And similarly, decoded from bytes with `::from_bytes()`:
122//!
123//! ```
124//! # use rand::{Rng, SeedableRng};
125//! # use rand_chacha::ChaChaRng;
126//! # use schnorrkel::{SecretKey, Keypair, Signature, PublicKey, SignatureError, signing_context};
127//! # use schnorrkel::{PUBLIC_KEY_LENGTH, SECRET_KEY_LENGTH, KEYPAIR_LENGTH, SIGNATURE_LENGTH};
128//! # #[cfg(feature = "getrandom")]
129//! # fn do_test() -> Result<(SecretKey, PublicKey, Keypair, Signature), SignatureError> {
130//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]);
131//! # let keypair_orig: Keypair = Keypair::generate_with(&mut csprng);
132//! # let context = signing_context(b"this signature does this thing");
133//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
134//! # let signature_orig: Signature = keypair_orig.sign(context.bytes(message));
135//! # let public_key_bytes: [u8; PUBLIC_KEY_LENGTH] = keypair_orig.public.to_bytes();
136//! # let secret_key_bytes: [u8; SECRET_KEY_LENGTH] = keypair_orig.secret.to_bytes();
137//! # let keypair_bytes:    [u8; KEYPAIR_LENGTH]    = keypair_orig.to_bytes();
138//! # let signature_bytes:  [u8; SIGNATURE_LENGTH]  = signature_orig.to_bytes();
139//! #
140//! let public_key: PublicKey = PublicKey::from_bytes(&public_key_bytes)?;
141//! let secret_key: SecretKey = SecretKey::from_bytes(&secret_key_bytes)?;
142//! let keypair:    Keypair   = Keypair::from_bytes(&keypair_bytes)?;
143//! let signature:  Signature = Signature::from_bytes(&signature_bytes)?;
144//! #
145//! # Ok((secret_key, public_key, keypair, signature))
146//! # }
147//! # fn main() {
148//! #     #[cfg(feature = "getrandom")]
149//! #     do_test();
150//! # }
151//! ```
152//!
153//! ### Using Serde
154//!
155//! If you prefer the bytes to be wrapped in another serialisation format, all
156//! types additionally come with built-in [serde](https://serde.rs) support by
157//! building `schnorrkell` via:
158//!
159//! ```bash
160//! $ cargo build --features="serde"
161//! ```
162//!
163//! They can be then serialised into any of the wire formats which serde supports.
164//! For example, using [bincode](https://github.com/TyOverby/bincode):
165//!
166//! ```
167//! # #[cfg(feature = "serde")]
168//! # fn main() {
169//! # use rand::{Rng, SeedableRng};
170//! # use rand_chacha::ChaChaRng;
171//! # use schnorrkel::{Keypair, Signature, PublicKey, signing_context};
172//! use bincode::{serialize};
173//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]);
174//! # let keypair: Keypair = Keypair::generate_with(&mut csprng);
175//! # let context = signing_context(b"this signature does this thing");
176//! # let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
177//! # let signature: Signature = keypair.sign(context.bytes(message));
178//! # let public_key: PublicKey = keypair.public;
179//! # assert!( public_key.verify(context.bytes(message), &signature).is_ok() );
180//!
181//! let encoded_public_key: Vec<u8> = serialize(&public_key).unwrap();
182//! let encoded_signature: Vec<u8> = serialize(&signature).unwrap();
183//! # }
184//! # #[cfg(not(feature = "serde"))]
185//! # fn main() {}
186//! ```
187//!
188//! After sending the `encoded_public_key` and `encoded_signature`, the
189//! recipient may deserialise them and verify:
190//!
191//! ```
192//! # #[cfg(feature = "serde")]
193//! # fn main() {
194//! # use rand::{Rng, SeedableRng};
195//! # use rand_chacha::ChaChaRng;
196//! # use schnorrkel::{Keypair, Signature, PublicKey, signing_context};
197//! # use bincode::{serialize};
198//! use bincode::{deserialize};
199//!
200//! # let mut csprng: ChaChaRng = ChaChaRng::from_seed([0u8; 32]);
201//! # let keypair: Keypair = Keypair::generate_with(&mut csprng);
202//! let message: &[u8] = "This is a test of the tsunami alert system.".as_bytes();
203//! # let context = signing_context(b"this signature does this thing");
204//! # let signature: Signature = keypair.sign(context.bytes(message));
205//! # let public_key: PublicKey = keypair.public;
206//! # let encoded_public_key: Vec<u8> = serialize(&public_key).unwrap();
207//! # let encoded_signature: Vec<u8> = serialize(&signature).unwrap();
208//! let decoded_public_key: PublicKey = deserialize(&encoded_public_key).unwrap();
209//! let decoded_signature: Signature = deserialize(&encoded_signature).unwrap();
210//!
211//! # assert_eq!(public_key, decoded_public_key);
212//! # assert_eq!(signature, decoded_signature);
213//! #
214//! assert!( public_key.verify(context.bytes(message), &signature).is_ok() );
215//! # }
216//! # #[cfg(not(feature = "serde"))]
217//! # fn main() {}
218//! ```
219
220#![no_std]
221#![warn(future_incompatible)]
222#![warn(rust_2018_compatibility)]
223#![warn(rust_2018_idioms)]
224#![deny(missing_docs)] // refuse to compile if documentation is missing
225#![allow(clippy::needless_lifetimes)]
226
227#[cfg(feature = "std")]
228#[macro_use]
229extern crate std;
230
231#[cfg(feature = "alloc")]
232extern crate alloc;
233
234use getrandom_or_panic::{RngCore,CryptoRng,getrandom_or_panic};
235use curve25519_dalek::scalar::Scalar;
236
237#[macro_use]
238mod serdey;
239
240pub mod points;
241mod scalars;
242pub mod keys;
243
244pub mod context;
245pub mod sign;
246pub mod vrf;
247pub mod derive;
248pub mod cert;
249pub mod errors;
250
251#[cfg(all(feature = "aead", feature = "getrandom"))]
252pub mod aead;
253
254#[cfg(feature = "alloc")]
255mod batch;
256
257// Not safe because need randomness
258
259#[cfg_attr(not(test), deprecated(since = "0.11.0", note = "This module will be replaced in the future"))]
260#[cfg(feature = "std")]
261pub mod musig;
262
263pub use crate::keys::*; // {MiniSecretKey,SecretKey,PublicKey,Keypair,ExpansionMode}; + *_LENGTH
264pub use crate::context::{signing_context}; // SigningContext,SigningTranscript
265pub use crate::sign::{Signature,SIGNATURE_LENGTH};
266pub use crate::errors::{SignatureError,SignatureResult};
267
268#[cfg(feature = "alloc")]
269pub use crate::batch::{verify_batch,verify_batch_rng,verify_batch_deterministic,PreparedBatch};
270
271pub(crate) fn scalar_from_canonical_bytes(bytes: [u8; 32]) -> Option<Scalar> {
272    let key = Scalar::from_canonical_bytes(bytes);
273
274    // Note: this is a `CtOption` so we have to do this to extract the value.
275    if bool::from(key.is_none()) {
276        return None;
277    }
278
279    Some(key.unwrap())
280}