Skip to content

Commit 0977949

Browse files
committed
context: introduce global rerandomizable context (std only)
This introduces the new global context API when std is enabled, using thread locals to allow rerandomizing the context after sensitive operations. As you can see, even the simple case involves some unsafe code and is a bit tricky to implement.
1 parent 6f24308 commit 0977949

File tree

3 files changed

+85
-0
lines changed

3 files changed

+85
-0
lines changed

src/context/internal_std.rs

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
// SPDX-License-Identifier: CC0-1.0
2+
3+
use std::cell::RefCell;
4+
use std::marker::PhantomData;
5+
use std::mem::ManuallyDrop;
6+
use std::ptr::NonNull;
7+
8+
use secp256k1_sys as ffi;
9+
10+
use crate::{All, Context, Secp256k1};
11+
12+
thread_local! {
13+
static SECP256K1: RefCell<Secp256k1<All>> = RefCell::new(Secp256k1::new());
14+
}
15+
16+
/// Borrows the global context and do some operation on it.
17+
///
18+
/// If provided, after the operation is complete, [`rerandomize_global_context`]
19+
/// is called on the context. If you have some random data available,
20+
pub fn with_global_context<T, Ctx: Context, F: FnOnce(&Secp256k1<Ctx>) -> T>(
21+
f: F,
22+
rerandomize_seed: Option<&[u8; 32]>,
23+
) -> T {
24+
with_raw_global_context(
25+
|ctx| {
26+
let secp = ManuallyDrop::new(Secp256k1 { ctx, phantom: PhantomData });
27+
f(&*secp)
28+
},
29+
rerandomize_seed,
30+
)
31+
}
32+
33+
/// Borrows the global context as a raw pointer and do some operation on it.
34+
///
35+
/// If provided, after the operation is complete, [`rerandomize_global_context`]
36+
/// is called on the context. If you have some random data available,
37+
pub fn with_raw_global_context<T, F: FnOnce(NonNull<ffi::Context>) -> T>(
38+
f: F,
39+
rerandomize_seed: Option<&[u8; 32]>,
40+
) -> T {
41+
SECP256K1.with(|secp| {
42+
let borrow = secp.borrow();
43+
let ret = f(borrow.ctx);
44+
drop(borrow);
45+
46+
if let Some(seed) = rerandomize_seed {
47+
rerandomize_global_context(seed);
48+
}
49+
ret
50+
})
51+
}
52+
53+
/// Rerandomize the global context, using the given data as a seed.
54+
///
55+
/// The provided data will be mixed with the entropy from previous calls in a timing
56+
/// analysis resistant way. It is safe to directly pass secret data to this function.
57+
pub fn rerandomize_global_context(seed: &[u8; 32]) {
58+
SECP256K1.with(|secp| {
59+
let mut borrow = secp.borrow_mut();
60+
61+
// If we have access to the thread rng then use it as well.
62+
#[cfg(feature = "rand")]
63+
{
64+
let mut new_seed: [u8; 32] = rand::random();
65+
for (new, byte) in mask.iter_mut().zip(seed.iter()) {
66+
*new ^= *byte;
67+
}
68+
borrow.seeded_randomize(&new_seed);
69+
}
70+
#[cfg(not(feature = "rand"))]
71+
{
72+
borrow.seeded_randomize(seed);
73+
}
74+
});
75+
}

src/context/mod.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,12 @@ use crate::ffi::types::{c_uint, c_void, AlignedType};
1010
use crate::ffi::{self, CPtr};
1111
use crate::{Error, Secp256k1};
1212

13+
#[cfg_attr(feature = "std", path = "internal_std.rs")]
14+
mod internal;
15+
16+
#[cfg(feature = "std")]
17+
pub use internal::{rerandomize_global_context, with_global_context, with_raw_global_context};
18+
1319
#[cfg(all(feature = "global-context", feature = "std"))]
1420
/// Module implementing a singleton pattern for a global `Secp256k1` context.
1521
pub mod global {

src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,10 @@ pub use secp256k1_sys as ffi;
184184
#[cfg(feature = "serde")]
185185
pub use serde;
186186

187+
#[cfg(feature = "std")]
188+
pub use crate::context::{
189+
rerandomize_global_context, with_global_context, with_raw_global_context,
190+
};
187191
#[cfg(feature = "alloc")]
188192
pub use crate::context::{All, SignOnly, VerifyOnly};
189193
pub use crate::context::{

0 commit comments

Comments
 (0)