@@ -10,6 +10,108 @@ use crate::ffi::types::{c_uint, c_void, AlignedType};
1010use crate :: ffi:: { self , CPtr } ;
1111use crate :: { Error , Secp256k1 } ;
1212
13+ #[ cfg( feature = "std" ) ]
14+ mod internal {
15+ use std:: cell:: RefCell ;
16+ use std:: marker:: PhantomData ;
17+ use std:: mem:: ManuallyDrop ;
18+ use std:: ptr:: NonNull ;
19+
20+ use secp256k1_sys as ffi;
21+
22+ use crate :: { All , Context , Secp256k1 } ;
23+
24+ thread_local ! {
25+ static SECP256K1 : RefCell <Secp256k1 <All >> = RefCell :: new( Secp256k1 :: new( ) ) ;
26+ static RAND_SEED : RefCell <[ u8 ; 32 ] > = const { RefCell :: new( [ 0 ; 32 ] ) } ;
27+ }
28+
29+ /// Borrows the global context and do some operation on it.
30+ ///
31+ /// If provided, after the operation is complete, [`rerandomize_global_context`]
32+ /// is called on the context. If you have some random data available,
33+ pub fn with_global_context < T , Ctx : Context , F : FnOnce ( & Secp256k1 < Ctx > ) -> T > (
34+ f : F ,
35+ rerandomize_seed : Option < & [ u8 ; 32 ] > ,
36+ ) -> T {
37+ with_raw_global_context (
38+ |ctx| {
39+ let secp = ManuallyDrop :: new ( Secp256k1 { ctx, phantom : PhantomData } ) ;
40+ f ( & * secp)
41+ } ,
42+ rerandomize_seed,
43+ )
44+ }
45+
46+ /// Borrows the global context as a raw pointer and do some operation on it.
47+ ///
48+ /// If provided, after the operation is complete, [`rerandomize_global_context`]
49+ /// is called on the context. If you have some random data available,
50+ pub fn with_raw_global_context < T , F : FnOnce ( NonNull < ffi:: Context > ) -> T > (
51+ f : F ,
52+ rerandomize_seed : Option < & [ u8 ; 32 ] > ,
53+ ) -> T {
54+ SECP256K1 . with ( |secp| {
55+ let borrow = secp. borrow ( ) ;
56+ let ret = f ( borrow. ctx ) ;
57+ drop ( borrow) ;
58+
59+ if let Some ( seed) = rerandomize_seed {
60+ rerandomize_global_context ( seed) ;
61+ }
62+ ret
63+ } )
64+ }
65+
66+ /// Rerandomize the global context, using the given data as a seed.
67+ ///
68+ /// The provided data will be mixed with the entropy from previous calls in a timing
69+ /// analysis resistant way. It is safe to directly pass secret data to this function.
70+ pub fn rerandomize_global_context ( seed : & [ u8 ; 32 ] ) {
71+ SECP256K1 . with ( |secp| {
72+ RAND_SEED . with ( |rand_seed| {
73+ let mut old_seed = rand_seed. borrow_mut ( ) ;
74+ let mut new_seed = [ 0 ; 32 ] ;
75+ // We don't have direct access to sha256 except through the default nonce
76+ // functions. The ECDSA one uses RFC6979 which is absurdly slow, but the
77+ // Schnorr one is not too bad.
78+ unsafe {
79+ assert_eq ! (
80+ ( ffi:: secp256k1_nonce_function_bip340. unwrap( ) ) (
81+ new_seed. as_mut_ptr( ) ,
82+ seed. as_ptr( ) , // msg
83+ seed. len( ) , // msg len
84+ old_seed. as_ptr( ) , // key32
85+ old_seed. as_ptr( ) , // xonly_pk32
86+ b"rust-secp-randomize" . as_ptr( ) ,
87+ b"rust-secp-randomize" . len( ) ,
88+ core:: ptr:: null_mut( ) ,
89+ ) ,
90+ 1 ,
91+ "calling bip340 nonce function failed" ,
92+ ) ;
93+ }
94+
95+ // If we have access to the thread rng then use it as well.
96+ #[ cfg( feature = "rand" ) ]
97+ {
98+ let mask: [ u8 ; 32 ] = rand:: random ( ) ;
99+ for ( byte, mask) in new_seed. iter_mut ( ) . zip ( mask. iter ( ) ) {
100+ * byte ^= * mask;
101+ }
102+ }
103+
104+ // Actual rerandomization
105+ let mut borrow = secp. borrow_mut ( ) ;
106+ borrow. seeded_randomize ( & new_seed) ;
107+ old_seed. copy_from_slice ( & new_seed) ;
108+ } ) ;
109+ } ) ;
110+ }
111+ }
112+ #[ cfg( feature = "std" ) ]
113+ pub use internal:: { rerandomize_global_context, with_global_context, with_raw_global_context} ;
114+
13115#[ cfg( all( feature = "global-context" , feature = "std" ) ) ]
14116/// Module implementing a singleton pattern for a global `Secp256k1` context.
15117pub mod global {
0 commit comments