From 93d824902865e4eb20f752a216b92095b2cbb30e Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 31 Jul 2018 15:55:58 +0000 Subject: [PATCH] improve documentation --- Cargo.toml | 8 ++++- src/key.rs | 2 +- src/lib.rs | 103 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 3 files changed, 109 insertions(+), 4 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f559b71..08b7eae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,8 +11,14 @@ documentation = "https://docs.rs/secp256k1/" description = "Rust bindings for Pieter Wuille's `libsecp256k1` library. Implements ECDSA for the SECG elliptic curve group secp256k1 and related utilities." keywords = [ "crypto", "ECDSA", "secp256k1", "libsecp256k1", "bitcoin" ] readme = "README.md" - build = "build.rs" + +# Should make docs.rs show all functions, even those behind non-default features +[package.metadata.docs.rs] +rustdoc-args = [ + "--features \"rand serde\"" +] + [build-dependencies] cc = "1.0" diff --git a/src/key.rs b/src/key.rs index 4810e05..29a774b 100644 --- a/src/key.rs +++ b/src/key.rs @@ -62,7 +62,7 @@ fn random_32_bytes(rng: &mut R) -> [u8; 32] { } impl SecretKey { - /// Creates a new random secret key + /// Creates a new random secret key. Requires compilation with the "rand" feature. #[inline] #[cfg(any(test, feature = "rand"))] pub fn new(secp: &Secp256k1, rng: &mut R) -> SecretKey { diff --git a/src/lib.rs b/src/lib.rs index c4bb8b1..6fd781c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,103 @@ //! curve. Such signatures are used extensively by the Bitcoin network //! and its derivatives. //! +//! To minimize dependencies, some functions are feature-gated. To generate +//! random keys or to re-randomize a context object, compile with the "rand" +//! feature. To de/serialize objects with serde, compile with "serde". +//! +//! Where possible, the bindings use the Rust type system to ensure that +//! API usage errors are impossible. For example, the library uses context +//! objects that contain precomputation tables which are created on object +//! construction. Since this is a slow operation (10+ milliseconds, vs ~50 +//! microseconds for typical crypto operations, on a 2.70 Ghz i7-6820HQ) +//! the tables are optional, giving a performance boost for users who only +//! care about signing, only care about verification, or only care about +//! parsing. In the upstream library, if you attempt to sign a message using +//! a context that does not support this, it will trigger an assertion +//! failure and terminate the program. In `rust-secp256k1`, this is caught +//! at compile-time; in fact, it is impossible to compile code that will +//! trigger any assertion failures in the upstream library. +//! +//! ```rust +//! extern crate secp256k1; +//! # #[cfg(feature="rand")] +//! extern crate rand; +//! +//! # +//! # fn main() { +//! # #[cfg(feature="rand")] { +//! use rand::OsRng; +//! use secp256k1::{Secp256k1, Message}; +//! +//! let secp = Secp256k1::new(); +//! let mut rng = OsRng::new().expect("OsRng"); +//! let (secret_key, public_key) = secp.generate_keypair(&mut rng); +//! let message = Message::from_slice(&[0xab; 32]).expect("32 bytes"); +//! +//! let sig = secp.sign(&message, &secret_key); +//! assert!(secp.verify(&message, &sig, &public_key).is_ok()); +//! # } } +//! ``` +//! +//! The above code requires `rust-secp256k1` to be compiled with the `rand` +//! feature enabled, to get access to [`generate_keypair`](struct.Secp256k1.html#method.generate_keypair) +//! Alternately, keys can be parsed from slices, like +//! +//! ```rust +//! # fn main() { +//! use self::secp256k1::{Secp256k1, Message, SecretKey, PublicKey}; +//! +//! let secp = Secp256k1::new(); +//! let secret_key = SecretKey::from_slice(&secp, &[0xcd; 32]).expect("32 bytes, within curve order"); +//! let public_key = PublicKey::from_secret_key(&secp, &secret_key); +//! let message = Message::from_slice(&[0xab; 32]).expect("32 bytes"); +//! +//! let sig = secp.sign(&message, &secret_key); +//! assert!(secp.verify(&message, &sig, &public_key).is_ok()); +//! # } +//! ``` +//! +//! Users who only want to verify signatures can use a cheaper context, like so: +//! +//! ```rust +//! # fn main() { +//! use secp256k1::{Secp256k1, Message, Signature, PublicKey}; +//! +//! let secp = Secp256k1::verification_only(); +//! +//! let public_key = PublicKey::from_slice(&secp, &[ +//! 0x02, +//! 0xc6, 0x6e, 0x7d, 0x89, 0x66, 0xb5, 0xc5, 0x55, +//! 0xaf, 0x58, 0x05, 0x98, 0x9d, 0xa9, 0xfb, 0xf8, +//! 0xdb, 0x95, 0xe1, 0x56, 0x31, 0xce, 0x35, 0x8c, +//! 0x3a, 0x17, 0x10, 0xc9, 0x62, 0x67, 0x90, 0x63, +//! ]).expect("public keys must be 33 or 65 bytes, serialized according to SEC 2"); +//! +//! let message = Message::from_slice(&[ +//! 0xaa, 0xdf, 0x7d, 0xe7, 0x82, 0x03, 0x4f, 0xbe, +//! 0x3d, 0x3d, 0xb2, 0xcb, 0x13, 0xc0, 0xcd, 0x91, +//! 0xbf, 0x41, 0xcb, 0x08, 0xfa, 0xc7, 0xbd, 0x61, +//! 0xd5, 0x44, 0x53, 0xcf, 0x6e, 0x82, 0xb4, 0x50, +//! ]).expect("messages must be 32 bytes and are expected to be hashes"); +//! +//! let sig = Signature::from_compact(&secp, &[ +//! 0xdc, 0x4d, 0xc2, 0x64, 0xa9, 0xfe, 0xf1, 0x7a, +//! 0x3f, 0x25, 0x34, 0x49, 0xcf, 0x8c, 0x39, 0x7a, +//! 0xb6, 0xf1, 0x6f, 0xb3, 0xd6, 0x3d, 0x86, 0x94, +//! 0x0b, 0x55, 0x86, 0x82, 0x3d, 0xfd, 0x02, 0xae, +//! 0x3b, 0x46, 0x1b, 0xb4, 0x33, 0x6b, 0x5e, 0xcb, +//! 0xae, 0xfd, 0x66, 0x27, 0xaa, 0x92, 0x2e, 0xfc, +//! 0x04, 0x8f, 0xec, 0x0c, 0x88, 0x1c, 0x10, 0xc4, +//! 0xc9, 0x42, 0x8f, 0xca, 0x69, 0xc1, 0x32, 0xa2, +//! ]).expect("compact signatures are 64 bytes; DER signatures are 68-72 bytes"); +//! +//! assert!(secp.verify(&message, &sig, &public_key).is_ok()); +//! # } +//! ``` +//! +//! Observe that the same code using, say [`signing_only`](struct.Secp256k1.html#method.signing_only) +//! to generate a context would simply not compile. +//! #![crate_type = "lib"] #![crate_type = "rlib"] @@ -480,7 +577,8 @@ impl Secp256k1 { impl Secp256k1 { /// (Re)randomizes the Secp256k1 context for cheap sidechannel resistance; - /// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell + /// see comment in libsecp256k1 commit d2275795f by Gregory Maxwell. Requires + /// compilation with "rand" feature. #[cfg(any(test, feature = "rand"))] pub fn randomize(&mut self, rng: &mut R) { let mut seed = [0; 32]; @@ -539,7 +637,8 @@ impl Secp256k1 { /// Generates a random keypair. Convenience function for `key::SecretKey::new` /// and `key::PublicKey::from_secret_key`; call those functions directly for - /// batch key generation. Requires a signing-capable context. + /// batch key generation. Requires a signing-capable context. Requires compilation + /// with the "rand" feature. #[inline] #[cfg(any(test, feature = "rand"))] pub fn generate_keypair(&self, rng: &mut R)