Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Randomize context on creation #385

Merged
merged 4 commits into from
Feb 4, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,7 @@ alloc = []
rand-std = ["rand/std"]
recovery = ["secp256k1-sys/recovery"]
lowmemory = ["secp256k1-sys/lowmemory"]
global-context = ["std", "rand-std", "global-context-less-secure"]
global-context-less-secure = []
global-context = ["std"]

[dependencies]
secp256k1-sys = { version = "0.4.2", default-features = false, path = "./secp256k1-sys" }
Expand Down
71 changes: 58 additions & 13 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ use Secp256k1;
#[cfg_attr(docsrs, doc(cfg(any(feature = "std", feature = "alloc"))))]
pub use self::alloc_only::*;

#[cfg(all(feature = "global-context-less-secure", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(any(feature = "global-context", feature = "global-context-less-secure"))))]
#[cfg(all(feature = "global-context", feature = "std"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "global-context", feature = "std"))))]
/// Module implementing a singleton pattern for a global `Secp256k1` context
pub mod global {
#[cfg(feature = "global-context")]
#[cfg(feature = "rand-std")]
use rand;

use std::ops::Deref;
Expand All @@ -26,22 +26,29 @@ pub mod global {
__private: (),
}

/// A global, static context to avoid repeatedly creating contexts where one can't be passed
/// A global static context to avoid repeatedly creating contexts.
///
/// If the global-context feature is enabled (and not just the global-context-less-secure),
/// this will have been randomized.
/// If `rand-std` feature is enabled, context will have been randomized using `thread_rng`.
///
/// ```
/// # #[cfg(all(feature = "global-context", feature = "rand-std"))] {
/// use secp256k1::{PublicKey, SECP256K1};
/// use secp256k1::rand::thread_rng;
/// let _ = SECP256K1.generate_keypair(&mut thread_rng());
/// # }
/// ```
pub static SECP256K1: &GlobalContext = &GlobalContext { __private: () };

impl Deref for GlobalContext {
type Target = Secp256k1<All>;

#[allow(unused_mut)] // Unused when "global-context" is not enabled.
#[allow(unused_mut)] // Unused when `rand-std` is not enabled.
fn deref(&self) -> &Self::Target {
static ONCE: Once = Once::new();
static mut CONTEXT: Option<Secp256k1<All>> = None;
ONCE.call_once(|| unsafe {
let mut ctx = Secp256k1::new();
#[cfg(feature = "global-context")]
#[cfg(feature = "rand-std")]
{
ctx.randomize(&mut rand::thread_rng());
}
Expand Down Expand Up @@ -108,6 +115,9 @@ mod alloc_only {
#[cfg(not(feature = "std"))]
use alloc::alloc;

#[cfg(feature = "rand-std")]
use rand;

impl private::Sealed for SignOnly {}
impl private::Sealed for All {}
impl private::Sealed for VerifyOnly {}
Expand Down Expand Up @@ -167,38 +177,73 @@ mod alloc_only {
}

impl<C: Context> Secp256k1<C> {
/// Lets you create a context in a generic manner(sign/verify/all)
/// Lets you create a context in a generic manner (sign/verify/all).
///
/// If `rand-std` feature is enabled, context will have been randomized using `thread_rng`.
/// If `rand-std` feature is not enabled please consider randomizing the context as follows:
/// ```
/// # #[cfg(all(feature = "rand-std", any(feature = "alloc", feature = "std")))] {
/// # use secp256k1::Secp256k1;
/// # use secp256k1::rand::{thread_rng, RngCore};
/// let mut ctx = Secp256k1::new();
/// # let mut rng = thread_rng();
/// # let mut seed = [0u8; 32];
/// # rng.fill_bytes(&mut seed);
/// // let seed = <32 bytes of random data>
/// ctx.seeded_randomize(&seed);
/// # }
/// ```
#[allow(unused_mut)] // Unused when `rand-std` is not enabled.
pub fn gen_new() -> Secp256k1<C> {
#[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 ctx = Secp256k1 {
ctx: unsafe { ffi::secp256k1_context_preallocated_create(ptr as *mut c_void, C::FLAGS) },
phantom: PhantomData,
size,
};

#[cfg(feature = "rand-std")]
{
ctx.randomize(&mut rand::thread_rng());
}

ctx
}
}

impl Secp256k1<All> {
/// Creates a new Secp256k1 context with all capabilities
/// Creates a new Secp256k1 context with all capabilities.
///
/// If `rand-std` feature is enabled, context will have been randomized using `thread_rng`.
/// If `rand-std` feature is not enabled please consider randomizing the context (see docs
/// for `Secp256k1::gen_new()`).
pub fn new() -> Secp256k1<All> {
Secp256k1::gen_new()
}
}

impl Secp256k1<SignOnly> {
/// Creates a new Secp256k1 context that can only be used for signing
/// Creates a new Secp256k1 context that can only be used for signing.
///
/// If `rand-std` feature is enabled, context will have been randomized using `thread_rng`.
/// If `rand-std` feature is not enabled please consider randomizing the context (see docs
/// for `Secp256k1::gen_new()`).
pub fn signing_only() -> Secp256k1<SignOnly> {
Secp256k1::gen_new()
}
}

impl Secp256k1<VerifyOnly> {
/// Creates a new Secp256k1 context that can only be used for verification
/// Creates a new Secp256k1 context that can only be used for verification.
///
/// If `rand-std` feature is enabled, context will have been randomized using `thread_rng`.
/// If `rand-std` feature is not enabled please consider randomizing the context (see docs
/// for `Secp256k1::gen_new()`).
pub fn verification_only() -> Secp256k1<VerifyOnly> {
Secp256k1::gen_new()
}
Expand Down
6 changes: 3 additions & 3 deletions src/key.rs
Original file line number Diff line number Diff line change
Expand Up @@ -641,7 +641,7 @@ impl Ord for PublicKey {
/// feature active. This is due to security considerations, see the [`serde_keypair`] documentation
/// for details.
///
/// If the `serde` and `global-context[-less-secure]` features are active `KeyPair`s can be serialized and
/// If the `serde` and `global-context` features are active `KeyPair`s can be serialized and
/// deserialized by annotating them with `#[serde(with = "secp256k1::serde_keypair")]`
/// inside structs or enums for which [`Serialize`] and [`Deserialize`] are being derived.
///
Expand Down Expand Up @@ -1320,7 +1320,7 @@ impl<'de> ::serde::Deserialize<'de> for XOnlyPublicKey {
///
/// [`SecretKey`]: crate::SecretKey
/// [global context]: crate::SECP256K1
#[cfg(all(feature = "global-context-less-secure", feature = "serde"))]
#[cfg(all(feature = "global-context", feature = "serde"))]
pub mod serde_keypair {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use key::KeyPair;
Expand Down Expand Up @@ -1924,7 +1924,7 @@ mod test {
}

#[test]
#[cfg(all(feature = "global-context-less-secure", feature = "serde"))]
#[cfg(all(feature = "global-context", feature = "serde"))]
fn test_serde_keypair() {
use serde::{Deserialize, Deserializer, Serialize, Serializer};
use serde_test::{Configure, Token, assert_tokens};
Expand Down
20 changes: 11 additions & 9 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,13 @@
//! 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-std` feature. If you are willing to use the `rand-std` feature, we
//! have enabled an additional defense-in-depth sidechannel 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
Expand Down Expand Up @@ -125,9 +129,7 @@
//! * `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.
//! * `global-context` - enable use of global secp256k1 context. (Implies `std`, `rand-std` and
//! `global-context-less-secure`.)
//! * `global-context-less-secure` - enables global context without extra sidechannel protection.
//! * `global-context` - enable use of global secp256k1 context (implies `std`).
//! * `serde` - implements serialization and deserialization for types in this crate using `serde`.
//! **Important**: `serde` encoding is **not** the same as consensus encoding!
//! * `bitcoin_hashes` - enables interaction with the `bitcoin-hashes` crate (e.g. conversions).
Expand Down Expand Up @@ -195,8 +197,8 @@ use core::marker::PhantomData;
use core::{mem, fmt, str};
use ffi::{CPtr, types::AlignedType};

#[cfg(feature = "global-context-less-secure")]
#[cfg_attr(docsrs, doc(cfg(any(feature = "global-context", feature = "global-context-less-secure"))))]
#[cfg(feature = "global-context")]
#[cfg_attr(docsrs, doc(cfg(any(feature = "global-context", feature = "global-context"))))]
pub use context::global::SECP256K1;

#[cfg(feature = "bitcoin_hashes")]
Expand Down Expand Up @@ -955,7 +957,7 @@ mod tests {

}

#[cfg(feature = "global-context-less-secure")]
#[cfg(feature = "global-context")]
#[test]
fn test_global_context() {
use super::SECP256K1;
Expand Down