@@ -29,17 +29,18 @@ pub mod global {
2929 /// A global, static context to avoid repeatedly creating contexts where one can't be passed
3030 ///
3131 /// If the global-context feature is enabled (and not just the global-context-less-secure),
32- /// this will have been randomized.
32+ /// this will have been randomized for additional defense-in-depth side channel protection .
3333 pub static SECP256K1 : & GlobalContext = & GlobalContext { __private : ( ) } ;
3434
3535 impl Deref for GlobalContext {
3636 type Target = Secp256k1 < All > ;
3737
38+ #[ allow( unused_mut) ] // mut is unused when "global-context" is not enabled.
3839 fn deref ( & self ) -> & Self :: Target {
3940 static ONCE : Once = Once :: new ( ) ;
4041 static mut CONTEXT : Option < Secp256k1 < All > > = None ;
4142 ONCE . call_once ( || unsafe {
42- let mut ctx = Secp256k1 :: new ( ) ;
43+ let mut ctx = Secp256k1 :: new ( SideChannelProtection :: NoRandomize ) ;
4344 #[ cfg( feature = "global-context" ) ]
4445 {
4546 ctx. randomize ( & mut rand:: thread_rng ( ) ) ;
@@ -166,46 +167,57 @@ mod alloc_only {
166167 }
167168
168169 impl < C : Context > Secp256k1 < C > {
169- /// Lets you create a context in a generic manner(sign/verify/all)
170- pub fn gen_new ( ) -> Secp256k1 < C > {
170+ /// Lets you create a context in a generic manner(sign/verify/all).
171+ ///
172+ /// If the `rand` feature is enabled we randomize the context using `thread_rng`.
173+ pub fn gen_new ( opt : SideChannelProtection ) -> Secp256k1 < C > {
171174 #[ cfg( target_arch = "wasm32" ) ]
172175 ffi:: types:: sanity_checks_for_wasm ( ) ;
173176
174177 let size = unsafe { ffi:: secp256k1_context_preallocated_size ( C :: FLAGS ) } ;
175178 let layout = alloc:: Layout :: from_size_align ( size, ALIGN_TO ) . unwrap ( ) ;
176179 let ptr = unsafe { alloc:: alloc ( layout) } ;
177- Secp256k1 {
180+ let mut secp = Secp256k1 {
178181 ctx : unsafe { ffi:: secp256k1_context_preallocated_create ( ptr as * mut c_void , C :: FLAGS ) } ,
179182 phantom : PhantomData ,
180183 size,
184+ } ;
185+
186+ match opt {
187+ SideChannelProtection :: SeededRandomize ( seed) => secp. seeded_randomize ( seed) ,
188+ SideChannelProtection :: NoRandomize => { } ,
189+ #[ cfg( feature = "rand" ) ]
190+ SideChannelProtection :: Randomize => secp. randomize ( & mut rand:: thread_rng ( ) ) ,
181191 }
192+
193+ secp
182194 }
183195 }
184196
185197 impl Secp256k1 < All > {
186- /// Creates a new Secp256k1 context with all capabilities
187- pub fn new ( ) -> Secp256k1 < All > {
188- Secp256k1 :: gen_new ( )
198+ /// Creates a new Secp256k1 context with all capabilities.
199+ ///
200+ /// If the `rand` feature is enabled we randomize the context using `thread_rng`.
201+ pub fn new ( opt : SideChannelProtection ) -> Secp256k1 < All > {
202+ Secp256k1 :: gen_new ( opt)
189203 }
190204 }
191205
192206 impl Secp256k1 < SignOnly > {
193- /// Creates a new Secp256k1 context that can only be used for signing
194- pub fn signing_only ( ) -> Secp256k1 < SignOnly > {
195- Secp256k1 :: gen_new ( )
207+ /// Creates a new Secp256k1 context that can only be used for signing.
208+ ///
209+ /// If the `rand` feature is enabled we randomize the context using `thread_rng`.
210+ pub fn signing_only ( opt : SideChannelProtection ) -> Secp256k1 < SignOnly > {
211+ Secp256k1 :: gen_new ( opt)
196212 }
197213 }
198214
199215 impl Secp256k1 < VerifyOnly > {
200- /// Creates a new Secp256k1 context that can only be used for verification
201- pub fn verification_only ( ) -> Secp256k1 < VerifyOnly > {
202- Secp256k1 :: gen_new ( )
203- }
204- }
205-
206- impl Default for Secp256k1 < All > {
207- fn default ( ) -> Self {
208- Self :: new ( )
216+ /// Creates a new Secp256k1 context that can only be used for verification.
217+ ///
218+ /// If the `rand` feature is enabled we randomize the context using `thread_rng`.
219+ pub fn verification_only ( opt : SideChannelProtection ) -> Secp256k1 < VerifyOnly > {
220+ Secp256k1 :: gen_new ( opt)
209221 }
210222 }
211223
@@ -221,6 +233,40 @@ mod alloc_only {
221233 }
222234 }
223235 }
236+
237+ /// When initializing the context we support additional defense-in-depth side channel
238+ /// protection, which re-blinds certain operations on secret key data.
239+ ///
240+ /// # Examples
241+ ///
242+ /// If your application already depends on `rand` and/or you do not wish to use the re-exported
243+ /// secp2561 version of `rand` i.e., no transient dependency on `rand`.
244+ ///```
245+ /// use rand::thread_rng();
246+ /// use secp256k1::Secp256k1;
247+ ///
248+ /// let mut rng = thread_rng().unwrap();
249+ /// let mut seed = [0u8; 32];
250+ /// rng.fill_bytes(&mut seed);
251+ ///
252+ /// let _ = Secp256k1::new(SeededRandomize(&seed));
253+ /// ```
254+ /// If you are ok with adding the transient dependency on `rand` from secp256k1.
255+ /// ```
256+ /// use secp256k1::Secp256k1;
257+ ///
258+ /// let _ = Secp256k1::new(Randomize);
259+ /// ```
260+ #[ derive( Copy , Clone , PartialEq , Eq , Debug , PartialOrd , Ord , Hash ) ]
261+ pub enum SideChannelProtection < ' a > { // FIXME: Does this name overstate the side channel risk?
262+ /// Uses seed to randomize context (calls `seeded_randomize(seed)`).
263+ SeededRandomize ( & ' a [ u8 ; 32 ] ) ,
264+ /// Disables randomization (additional defense-in-depth sidechannel protection).
265+ NoRandomize ,
266+ /// Uses thread_rng to randomize context (calls `secp.randomize()`).
267+ #[ cfg( feature = "rand" ) ]
268+ Randomize ,
269+ }
224270}
225271
226272impl < ' buf > Signing for SignOnlyPreallocated < ' buf > { }
0 commit comments