diff --git a/examples/generate_keys.rs b/examples/generate_keys.rs index ae1ec2b84..34a34e8b6 100644 --- a/examples/generate_keys.rs +++ b/examples/generate_keys.rs @@ -4,7 +4,7 @@ use secp256k1::rand::rngs::OsRng; use secp256k1::{PublicKey, Secp256k1, SecretKey}; fn main() { - let secp = Secp256k1::new(); + let secp = Secp256k1::new(SideChannelProtection::Randomize); let mut rng = OsRng::new().unwrap(); // First option: let (seckey, pubkey) = secp.generate_keypair(&mut rng); diff --git a/src/context.rs b/src/context.rs index f89bbe96d..e37695102 100644 --- a/src/context.rs +++ b/src/context.rs @@ -29,17 +29,18 @@ pub mod global { /// A global, static context to avoid repeatedly creating contexts where one can't be passed /// /// If the global-context feature is enabled (and not just the global-context-less-secure), - /// this will have been randomized. + /// this will have been randomized for additional defense-in-depth side channel protection. pub static SECP256K1: &GlobalContext = &GlobalContext { __private: () }; impl Deref for GlobalContext { type Target = Secp256k1; + #[allow(unused_mut)] // mut is unused when "global-context" is not enabled. fn deref(&self) -> &Self::Target { static ONCE: Once = Once::new(); static mut CONTEXT: Option> = None; ONCE.call_once(|| unsafe { - let mut ctx = Secp256k1::new(); + let mut ctx = Secp256k1::new(SideChannelProtection::NoRandomize); #[cfg(feature = "global-context")] { ctx.randomize(&mut rand::thread_rng()); @@ -166,46 +167,57 @@ mod alloc_only { } impl Secp256k1 { - /// Lets you create a context in a generic manner(sign/verify/all) - pub fn gen_new() -> Secp256k1 { + /// Lets you create a context in a generic manner(sign/verify/all). + /// + /// If the `rand` feature is enabled we randomize the context using `thread_rng`. + pub fn gen_new(opt: SideChannelProtection) -> Secp256k1 { #[cfg(target_arch = "wasm32")] ffi::types::sanity_checks_for_wasm(); let size = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) }; let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap(); let ptr = unsafe {alloc::alloc(layout)}; - Secp256k1 { + let mut secp = Secp256k1 { ctx: unsafe { ffi::secp256k1_context_preallocated_create(ptr as *mut c_void, C::FLAGS) }, phantom: PhantomData, size, + }; + + match opt { + SideChannelProtection::SeededRandomize(seed) => secp.seeded_randomize(seed), + SideChannelProtection::NoRandomize => {}, + #[cfg(feature = "rand")] + SideChannelProtection::Randomize => secp.randomize(&mut rand::thread_rng()), } + + secp } } impl Secp256k1 { - /// Creates a new Secp256k1 context with all capabilities - pub fn new() -> Secp256k1 { - Secp256k1::gen_new() + /// Creates a new Secp256k1 context with all capabilities. + /// + /// If the `rand` feature is enabled we randomize the context using `thread_rng`. + pub fn new(opt: SideChannelProtection) -> Secp256k1 { + Secp256k1::gen_new(opt) } } impl Secp256k1 { - /// Creates a new Secp256k1 context that can only be used for signing - pub fn signing_only() -> Secp256k1 { - Secp256k1::gen_new() + /// Creates a new Secp256k1 context that can only be used for signing. + /// + /// If the `rand` feature is enabled we randomize the context using `thread_rng`. + pub fn signing_only(opt: SideChannelProtection) -> Secp256k1 { + Secp256k1::gen_new(opt) } } impl Secp256k1 { - /// Creates a new Secp256k1 context that can only be used for verification - pub fn verification_only() -> Secp256k1 { - Secp256k1::gen_new() - } - } - - impl Default for Secp256k1 { - fn default() -> Self { - Self::new() + /// Creates a new Secp256k1 context that can only be used for verification. + /// + /// If the `rand` feature is enabled we randomize the context using `thread_rng`. + pub fn verification_only(opt: SideChannelProtection) -> Secp256k1 { + Secp256k1::gen_new(opt) } } @@ -221,6 +233,40 @@ mod alloc_only { } } } + + /// When initializing the context we support additional defense-in-depth side channel + /// protection, which re-blinds certain operations on secret key data. + /// + /// # Examples + /// + /// If your application already depends on `rand` and/or you do not wish to use the re-exported + /// secp2561 version of `rand` i.e., no transient dependency on `rand`. + ///``` + /// use rand::thread_rng(); + /// use secp256k1::Secp256k1; + /// + /// let mut rng = thread_rng().unwrap(); + /// let mut seed = [0u8; 32]; + /// rng.fill_bytes(&mut seed); + /// + /// let _ = Secp256k1::new(SeededRandomize(&seed)); + /// ``` + /// If you are ok with adding the transient dependency on `rand` from secp256k1. + /// ``` + /// use secp256k1::Secp256k1; + /// + /// let _ = Secp256k1::new(Randomize); + /// ``` + #[derive(Copy, Clone, PartialEq, Eq, Debug, PartialOrd, Ord, Hash)] + pub enum SideChannelProtection<'a> { // FIXME: Does this name overstate the side channel risk? + /// Uses seed to randomize context (calls `seeded_randomize(seed)`). + SeededRandomize(&'a [u8; 32]), + /// Disables randomization (additional defense-in-depth sidechannel protection). + NoRandomize, + /// Uses thread_rng to randomize context (calls `secp.randomize()`). + #[cfg(feature = "rand")] + Randomize, + } } impl<'buf> Signing for SignOnlyPreallocated<'buf> {} diff --git a/src/lib.rs b/src/lib.rs index de38e3970..4f0dab9fc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -20,9 +20,12 @@ //! 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". -//! **Important**: `serde` encoding is **not** the same as consensus encoding! +//! random keys or to re-randomize a context object, compile with the `rand` +//! feature. If you are willing to use the `rand` dependency, we have enabled an +//! additional defense-in-depth side channel protection for our context objects, +//! which re-blinds certain operations on secret key data. To de/serialize +//! objects with serde, compile with "serde". **Important**: `serde` encoding is +//! **not** the same as consensus encoding! //! //! Where possible, the bindings use the Rust type system to ensure that //! API usage errors are impossible. For example, the library uses context @@ -117,7 +120,7 @@ //! //! * `std` - use standard Rust library, enabled by default. //! * `alloc` - use the `alloc` standard Rust library to provide heap allocations. -//! * `rand` - use `rand` library to provide random generator (e.g. to generate keys). +//! * `rand` - use `rand` library to provide randomness (e.g. to randomize contexts). //! * `rand-std` - use `rand` library with its `std` feature enabled. (Implies `rand`.) //! * `recovery` - enable functions that can compute the public key from signature. //! * `lowmemory` - optimize the library for low-memory environments.