secp256k1/context/
internal_std.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use std::cell::RefCell;
4use std::marker::PhantomData;
5use std::mem::ManuallyDrop;
6use std::ptr::NonNull;
7
8use secp256k1_sys as ffi;
9
10use crate::{All, Context, Secp256k1};
11
12thread_local! {
13    static SECP256K1: RefCell<Secp256k1<All>> = RefCell::new(Secp256k1::new());
14}
15
16/// Borrows the global context and does some operation on it.
17///
18/// If `rerandomize_seed` is provided, then [`rerandomize_global_context`] is called on the context
19/// after the operation. This argument should be provided alongside any operation that uses secret
20/// data (e.g. signing, but not verification). If you have random data available, it should be
21/// provided here; it will be mixed with the current random state as well as the system RNG if it is
22/// available. If you do not have any random data, it is fine to provide all zeros, or a counter, or
23/// a weak source of entropy. This is a defense-in-depth measure to protect against side-channel
24/// attacks, and anything helps (and nothing will hurt).
25pub fn with_global_context<T, Ctx: Context, F: FnOnce(&Secp256k1<Ctx>) -> T>(
26    f: F,
27    rerandomize_seed: Option<&[u8; 32]>,
28) -> T {
29    with_raw_global_context(
30        |ctx| {
31            let secp = ManuallyDrop::new(Secp256k1 { ctx, phantom: PhantomData });
32            f(&*secp)
33        },
34        rerandomize_seed,
35    )
36}
37
38/// Borrows the global context as a raw pointer and does some operation on it.
39///
40/// If `rerandomize_seed` is provided, then [`rerandomize_global_context`] is called on the context
41/// after the operation. This argument should be provided alongside any operation that uses secret
42/// data (e.g. signing, but not verification). If you have random data available, it should be
43/// provided here; it will be mixed with the current random state as well as the system RNG if it is
44/// available. If you do not have any random data, it is fine to provide all zeros, or a counter, or
45/// a weak source of entropy. This is a defense-in-depth measure to protect against side-channel
46/// attacks, and anything helps (and nothing will hurt).
47pub fn with_raw_global_context<T, F: FnOnce(NonNull<ffi::Context>) -> T>(
48    f: F,
49    rerandomize_seed: Option<&[u8; 32]>,
50) -> T {
51    SECP256K1.with(|secp| {
52        let borrow = secp.borrow();
53        let ret = f(borrow.ctx);
54        drop(borrow);
55
56        if let Some(seed) = rerandomize_seed {
57            rerandomize_global_context(seed);
58        }
59        ret
60    })
61}
62
63/// Rerandomize the global context, using the given data as a seed.
64///
65/// The provided data will be mixed with the entropy from previous calls in a timing
66/// analysis resistant way. It is safe to directly pass secret data to this function.
67pub fn rerandomize_global_context(seed: &[u8; 32]) {
68    SECP256K1.with(|secp| {
69        let mut borrow = secp.borrow_mut();
70
71        // If we have access to the thread rng then use it as well.
72        #[cfg(feature = "rand")]
73        {
74            let mut new_seed: [u8; 32] = rand::random();
75            for (new, byte) in new_seed.iter_mut().zip(seed.iter()) {
76                *new ^= *byte;
77            }
78            borrow.seeded_randomize(&new_seed);
79        }
80        #[cfg(not(feature = "rand"))]
81        {
82            borrow.seeded_randomize(seed);
83        }
84    });
85}