secp256k1/context/
mod.rs

1// SPDX-License-Identifier: CC0-1.0
2
3use core::marker::PhantomData;
4use core::mem::ManuallyDrop;
5use core::ptr::NonNull;
6
7#[cfg(feature = "alloc")]
8pub use self::alloc_only::{All, SignOnly, VerifyOnly};
9use crate::ffi::types::{c_uint, c_void, AlignedType};
10use crate::ffi::{self, CPtr};
11use crate::{Error, Secp256k1};
12
13#[cfg_attr(feature = "std", path = "internal_std.rs")]
14#[cfg_attr(not(feature = "std"), path = "internal_nostd.rs")]
15mod internal;
16
17#[cfg(not(feature = "std"))]
18mod spinlock;
19
20pub use internal::{rerandomize_global_context, with_global_context, with_raw_global_context};
21
22#[cfg(all(feature = "global-context", feature = "std"))]
23/// Module implementing a singleton pattern for a global `Secp256k1` context.
24pub mod global {
25
26    use std::ops::Deref;
27    use std::sync::Once;
28
29    use crate::{All, Secp256k1};
30
31    /// Proxy struct for global `SECP256K1` context.
32    #[derive(Debug, Copy, Clone)]
33    pub struct GlobalContext {
34        __private: (),
35    }
36
37    /// A global static context to avoid repeatedly creating contexts.
38    ///
39    /// If `rand` and `std` feature is enabled, context will have been randomized using
40    /// `rng`.
41    pub static SECP256K1: &GlobalContext = &GlobalContext { __private: () };
42
43    impl Deref for GlobalContext {
44        type Target = Secp256k1<All>;
45
46        #[allow(unused_mut)] // Unused when `rand` + `std` is not enabled.
47        #[allow(static_mut_refs)] // The "proper" way to do this is with OnceLock (MSRV 1.70) or LazyLock (MSRV 1.80)
48                                  // See https://doc.rust-lang.org/nightly/edition-guide/rust-2024/static-mut-references.html
49        fn deref(&self) -> &Self::Target {
50            static ONCE: Once = Once::new();
51            static mut CONTEXT: Option<Secp256k1<All>> = None;
52            ONCE.call_once(|| unsafe {
53                CONTEXT = Some(Secp256k1::new());
54            });
55            unsafe { CONTEXT.as_ref().unwrap() }
56        }
57    }
58}
59
60/// A trait for all kinds of contexts that lets you define the exact flags and a function to
61/// deallocate memory. It isn't possible to implement this for types outside this crate.
62///
63/// # Safety
64///
65/// This trait is marked unsafe to allow unsafe implementations of `deallocate`.
66pub unsafe trait Context: private::Sealed {
67    /// Flags for the ffi.
68    const FLAGS: c_uint;
69    /// A constant description of the context.
70    const DESCRIPTION: &'static str;
71    /// A function to deallocate the memory when the context is dropped.
72    ///
73    /// # Safety
74    ///
75    /// `ptr` must be valid. Further safety constraints may be imposed by [`std::alloc::dealloc`].
76    unsafe fn deallocate(ptr: *mut u8, size: usize);
77}
78
79/// Marker trait for indicating that an instance of [`Secp256k1`] can be used for signing.
80pub trait Signing: Context {}
81
82/// Marker trait for indicating that an instance of [`Secp256k1`] can be used for verification.
83pub trait Verification: Context {}
84
85/// Represents the set of capabilities needed for signing (preallocated memory).
86#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
87pub struct SignOnlyPreallocated<'buf> {
88    phantom: PhantomData<&'buf ()>,
89}
90
91/// Represents the set of capabilities needed for verification (preallocated memory).
92#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
93pub struct VerifyOnlyPreallocated<'buf> {
94    phantom: PhantomData<&'buf ()>,
95}
96
97/// Represents the set of all capabilities (preallocated memory).
98#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
99pub struct AllPreallocated<'buf> {
100    phantom: PhantomData<&'buf ()>,
101}
102
103mod private {
104    use super::*;
105    pub trait Sealed {}
106
107    impl Sealed for AllPreallocated<'_> {}
108    impl Sealed for VerifyOnlyPreallocated<'_> {}
109    impl Sealed for SignOnlyPreallocated<'_> {}
110}
111
112#[cfg(feature = "alloc")]
113mod alloc_only {
114    use core::marker::PhantomData;
115    use core::ptr::NonNull;
116
117    use super::private;
118    use crate::alloc::alloc;
119    use crate::ffi::types::{c_uint, c_void};
120    use crate::ffi::{self};
121    use crate::{AlignedType, Context, Secp256k1, Signing, Verification};
122
123    impl private::Sealed for SignOnly {}
124    impl private::Sealed for All {}
125    impl private::Sealed for VerifyOnly {}
126
127    const ALIGN_TO: usize = core::mem::align_of::<AlignedType>();
128
129    /// Represents the set of capabilities needed for signing.
130    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
131    pub enum SignOnly {}
132
133    /// Represents the set of capabilities needed for verification.
134    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
135    pub enum VerifyOnly {}
136
137    /// Represents the set of all capabilities.
138    #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
139    pub enum All {}
140
141    impl Signing for SignOnly {}
142    impl Signing for All {}
143
144    impl Verification for VerifyOnly {}
145    impl Verification for All {}
146
147    unsafe impl Context for SignOnly {
148        const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
149        const DESCRIPTION: &'static str = "signing only";
150
151        unsafe fn deallocate(ptr: *mut u8, size: usize) {
152            let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
153            alloc::dealloc(ptr, layout);
154        }
155    }
156
157    unsafe impl Context for VerifyOnly {
158        const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
159        const DESCRIPTION: &'static str = "verification only";
160
161        unsafe fn deallocate(ptr: *mut u8, size: usize) {
162            let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
163            alloc::dealloc(ptr, layout);
164        }
165    }
166
167    unsafe impl Context for All {
168        const FLAGS: c_uint = VerifyOnly::FLAGS | SignOnly::FLAGS;
169        const DESCRIPTION: &'static str = "all capabilities";
170
171        unsafe fn deallocate(ptr: *mut u8, size: usize) {
172            let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
173            alloc::dealloc(ptr, layout);
174        }
175    }
176
177    impl<C: Context> Secp256k1<C> {
178        /// Lets you create a context in a generic manner (sign/verify/all).
179        ///
180        /// If `rand` and `std` feature is enabled, context will have been randomized using
181        /// `rng`.
182        /// If `rand` or `std` feature is not enabled please consider randomizing the context as
183        /// follows:
184        /// ```
185        /// # #[cfg(all(feature = "rand", feature = "std"))] {
186        /// # use secp256k1::Secp256k1;
187        /// # use secp256k1::rand::{rng, RngCore};
188        /// let mut ctx = Secp256k1::new();
189        /// # let mut rng = rng();
190        /// # let mut seed = [0u8; 32];
191        /// # rng.fill_bytes(&mut seed);
192        /// // let seed = <32 bytes of random data>
193        /// ctx.seeded_randomize(&seed);
194        /// # }
195        /// ```
196        #[cfg_attr(
197            not(all(feature = "rand", feature = "std")),
198            allow(clippy::let_and_return, unused_mut)
199        )]
200        pub fn gen_new() -> Secp256k1<C> {
201            #[cfg(target_arch = "wasm32")]
202            ffi::types::sanity_checks_for_wasm();
203
204            let size = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) };
205            let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
206            let ptr = unsafe { alloc::alloc(layout) };
207            let ptr = NonNull::new(ptr as *mut c_void)
208                .unwrap_or_else(|| alloc::handle_alloc_error(layout));
209
210            #[allow(unused_mut)] // ctx is not mutated under some feature combinations.
211            let mut ctx = Secp256k1 {
212                ctx: unsafe { ffi::secp256k1_context_preallocated_create(ptr, C::FLAGS) },
213                phantom: PhantomData,
214            };
215
216            #[cfg(all(
217                not(target_arch = "wasm32"),
218                feature = "rand",
219                feature = "std",
220                not(feature = "global-context-less-secure")
221            ))]
222            {
223                ctx.randomize(&mut rand::rng());
224            }
225
226            #[allow(clippy::let_and_return)] // as for unused_mut
227            ctx
228        }
229    }
230
231    impl Secp256k1<All> {
232        /// Creates a new Secp256k1 context with all capabilities.
233        ///
234        /// If `rand` and `std` feature is enabled, context will have been randomized using
235        /// `rng`.
236        /// If `rand` or `std` feature is not enabled please consider randomizing the context (see
237        /// docs for `Secp256k1::gen_new()`).
238        pub fn new() -> Secp256k1<All> { Secp256k1::gen_new() }
239    }
240
241    impl Secp256k1<SignOnly> {
242        /// Creates a new Secp256k1 context that can only be used for signing.
243        ///
244        /// If `rand` and `std` feature is enabled, context will have been randomized using
245        /// `rng`.
246        /// If `rand` or `std` feature is not enabled please consider randomizing the context (see
247        /// docs for `Secp256k1::gen_new()`).
248        pub fn signing_only() -> Secp256k1<SignOnly> { Secp256k1::gen_new() }
249    }
250
251    impl Secp256k1<VerifyOnly> {
252        /// Creates a new Secp256k1 context that can only be used for verification.
253        ///
254        /// If `rand` and `std` feature is enabled, context will have been randomized using
255        /// `rng`.
256        /// If `rand` or `std` feature is not enabled please consider randomizing the context (see
257        /// docs for `Secp256k1::gen_new()`).
258        pub fn verification_only() -> Secp256k1<VerifyOnly> { Secp256k1::gen_new() }
259    }
260
261    impl Default for Secp256k1<All> {
262        fn default() -> Self { Self::new() }
263    }
264
265    impl<C: Context> Clone for Secp256k1<C> {
266        fn clone(&self) -> Secp256k1<C> {
267            let size = unsafe { ffi::secp256k1_context_preallocated_clone_size(self.ctx.as_ptr()) };
268            let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
269            let ptr = unsafe { alloc::alloc(layout) };
270            let ptr = NonNull::new(ptr as *mut c_void)
271                .unwrap_or_else(|| alloc::handle_alloc_error(layout));
272
273            Secp256k1 {
274                ctx: unsafe { ffi::secp256k1_context_preallocated_clone(self.ctx.as_ptr(), ptr) },
275                phantom: PhantomData,
276            }
277        }
278    }
279}
280
281impl Signing for SignOnlyPreallocated<'_> {}
282impl Signing for AllPreallocated<'_> {}
283
284impl Verification for VerifyOnlyPreallocated<'_> {}
285impl Verification for AllPreallocated<'_> {}
286
287unsafe impl Context for SignOnlyPreallocated<'_> {
288    const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
289    const DESCRIPTION: &'static str = "signing only";
290
291    unsafe fn deallocate(_ptr: *mut u8, _size: usize) {
292        // Allocated by the user
293    }
294}
295
296unsafe impl Context for VerifyOnlyPreallocated<'_> {
297    const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
298    const DESCRIPTION: &'static str = "verification only";
299
300    unsafe fn deallocate(_ptr: *mut u8, _size: usize) {
301        // Allocated by the user.
302    }
303}
304
305unsafe impl Context for AllPreallocated<'_> {
306    const FLAGS: c_uint = SignOnlyPreallocated::FLAGS | VerifyOnlyPreallocated::FLAGS;
307    const DESCRIPTION: &'static str = "all capabilities";
308
309    unsafe fn deallocate(_ptr: *mut u8, _size: usize) {
310        // Allocated by the user.
311    }
312}
313
314/// Trait marking that a particular context object internally points to
315/// memory that must outlive `'a`
316///
317/// # Safety
318///
319/// This trait is used internally to gate which context markers can safely
320/// be used with the `preallocated_gen_new` function. Do not implement it
321/// on your own structures.
322pub unsafe trait PreallocatedContext<'a> {}
323
324unsafe impl<'buf> PreallocatedContext<'buf> for AllPreallocated<'buf> {}
325unsafe impl<'buf> PreallocatedContext<'buf> for SignOnlyPreallocated<'buf> {}
326unsafe impl<'buf> PreallocatedContext<'buf> for VerifyOnlyPreallocated<'buf> {}
327
328impl<'buf, C: Context + PreallocatedContext<'buf>> Secp256k1<C> {
329    /// Lets you create a context with a preallocated buffer in a generic manner (sign/verify/all).
330    pub fn preallocated_gen_new(buf: &'buf mut [AlignedType]) -> Result<Secp256k1<C>, Error> {
331        #[cfg(target_arch = "wasm32")]
332        ffi::types::sanity_checks_for_wasm();
333
334        if buf.len() < Self::preallocate_size_gen() {
335            return Err(Error::NotEnoughMemory);
336        }
337        // Safe because buf is not null since it is not empty.
338        let buf = unsafe { NonNull::new_unchecked(buf.as_mut_c_ptr() as *mut c_void) };
339
340        Ok(Secp256k1 {
341            ctx: unsafe { ffi::secp256k1_context_preallocated_create(buf, AllPreallocated::FLAGS) },
342            phantom: PhantomData,
343        })
344    }
345}
346
347impl<'buf> Secp256k1<AllPreallocated<'buf>> {
348    /// Creates a new Secp256k1 context with all capabilities.
349    pub fn preallocated_new(
350        buf: &'buf mut [AlignedType],
351    ) -> Result<Secp256k1<AllPreallocated<'buf>>, Error> {
352        Secp256k1::preallocated_gen_new(buf)
353    }
354    /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for a context.
355    pub fn preallocate_size() -> usize { Self::preallocate_size_gen() }
356
357    /// Creates a context from a raw context.
358    ///
359    /// The returned [`core::mem::ManuallyDrop`] context will never deallocate the memory pointed to
360    /// by `raw_ctx` nor destroy the context. This may lead to memory leaks. `ManuallyDrop::drop`
361    /// (or [`core::ptr::drop_in_place`]) will only destroy the context; the caller is required to
362    /// free the memory.
363    ///
364    /// # Safety
365    ///
366    /// This is highly unsafe due to a number of conditions that aren't checked, specifically:
367    ///
368    /// * `raw_ctx` must be a valid pointer (live, aligned...) to memory that was initialized by
369    ///   `secp256k1_context_preallocated_create` (either called directly or from this library by
370    ///   one of the context creation methods - all of which call it internally).
371    /// * The version of `libsecp256k1` used to create `raw_ctx` must be **exactly the one linked
372    ///   into this library**.
373    /// * The lifetime of the `raw_ctx` pointer must outlive `'buf`.
374    /// * `raw_ctx` must point to writable memory (cannot be `ffi::secp256k1_context_no_precomp`),
375    ///   **or** the user must never attempt to rerandomize the context.
376    pub unsafe fn from_raw_all(
377        raw_ctx: NonNull<ffi::Context>,
378    ) -> ManuallyDrop<Secp256k1<AllPreallocated<'buf>>> {
379        ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData })
380    }
381}
382
383impl<'buf> Secp256k1<SignOnlyPreallocated<'buf>> {
384    /// Creates a new Secp256k1 context that can only be used for signing.
385    pub fn preallocated_signing_only(
386        buf: &'buf mut [AlignedType],
387    ) -> Result<Secp256k1<SignOnlyPreallocated<'buf>>, Error> {
388        Secp256k1::preallocated_gen_new(buf)
389    }
390
391    /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for the context.
392    #[inline]
393    pub fn preallocate_signing_size() -> usize { Self::preallocate_size_gen() }
394
395    /// Creates a context from a raw context that can only be used for signing.
396    ///
397    /// # Safety
398    ///
399    /// Please see [`Secp256k1::from_raw_all`] for full documentation and safety requirements.
400    pub unsafe fn from_raw_signing_only(
401        raw_ctx: NonNull<ffi::Context>,
402    ) -> ManuallyDrop<Secp256k1<SignOnlyPreallocated<'buf>>> {
403        ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData })
404    }
405}
406
407impl<'buf> Secp256k1<VerifyOnlyPreallocated<'buf>> {
408    /// Creates a new Secp256k1 context that can only be used for verification
409    pub fn preallocated_verification_only(
410        buf: &'buf mut [AlignedType],
411    ) -> Result<Secp256k1<VerifyOnlyPreallocated<'buf>>, Error> {
412        Secp256k1::preallocated_gen_new(buf)
413    }
414
415    /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for the context.
416    #[inline]
417    pub fn preallocate_verification_size() -> usize { Self::preallocate_size_gen() }
418
419    /// Creates a context from a raw context that can only be used for verification.
420    ///
421    /// # Safety
422    ///
423    /// Please see [`Secp256k1::from_raw_all`] for full documentation and safety requirements.
424    pub unsafe fn from_raw_verification_only(
425        raw_ctx: NonNull<ffi::Context>,
426    ) -> ManuallyDrop<Secp256k1<VerifyOnlyPreallocated<'buf>>> {
427        ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData })
428    }
429}