cashweb_secp256k1/
context.rs

1use core::marker::PhantomData;
2use core::mem::{self, ManuallyDrop};
3use ffi::types::{c_uint, c_void};
4use ffi::{self, types::AlignedType, CPtr};
5use Error;
6use Secp256k1;
7
8#[cfg(feature = "std")]
9pub use self::std_only::*;
10
11#[cfg(feature = "global-context")]
12/// Module implementing a singleton pattern for a global `Secp256k1` context
13pub mod global {
14    use rand;
15    use std::ops::Deref;
16    use std::sync::Once;
17    use {All, Secp256k1};
18
19    /// Proxy struct for global `SECP256K1` context
20    pub struct GlobalContext {
21        __private: (),
22    }
23
24    /// A global, static context to avoid repeatedly creating contexts where one can't be passed
25    pub static SECP256K1: &GlobalContext = &GlobalContext { __private: () };
26
27    impl Deref for GlobalContext {
28        type Target = Secp256k1<All>;
29
30        fn deref(&self) -> &Self::Target {
31            static ONCE: Once = Once::new();
32            static mut CONTEXT: Option<Secp256k1<All>> = None;
33            ONCE.call_once(|| unsafe {
34                let mut ctx = Secp256k1::new();
35                ctx.randomize(&mut rand::thread_rng());
36                CONTEXT = Some(ctx);
37            });
38            unsafe { CONTEXT.as_ref().unwrap() }
39        }
40    }
41}
42
43/// A trait for all kinds of Context's that Lets you define the exact flags and a function to deallocate memory.
44/// It shouldn't be possible to implement this for types outside this crate.
45pub unsafe trait Context: private::Sealed {
46    /// Flags for the ffi.
47    const FLAGS: c_uint;
48    /// A constant description of the context.
49    const DESCRIPTION: &'static str;
50    /// A function to deallocate the memory when the context is dropped.
51    unsafe fn deallocate(ptr: *mut u8, size: usize);
52}
53
54/// Marker trait for indicating that an instance of `Secp256k1` can be used for signing.
55pub trait Signing: Context {}
56
57/// Marker trait for indicating that an instance of `Secp256k1` can be used for verification.
58pub trait Verification: Context {}
59
60/// Represents the set of capabilities needed for signing with a user preallocated memory.
61pub struct SignOnlyPreallocated<'buf> {
62    phantom: PhantomData<&'buf ()>,
63}
64
65/// Represents the set of capabilities needed for verification with a user preallocated memory.
66pub struct VerifyOnlyPreallocated<'buf> {
67    phantom: PhantomData<&'buf ()>,
68}
69
70/// Represents the set of all capabilities with a user preallocated memory.
71pub struct AllPreallocated<'buf> {
72    phantom: PhantomData<&'buf ()>,
73}
74
75mod private {
76    use super::*;
77    // A trick to prevent users from implementing a trait.
78    // on one hand this trait is public, on the other it's in a private module
79    // so it's not visible to anyone besides it's parent (the context module)
80    pub trait Sealed {}
81
82    impl<'buf> Sealed for AllPreallocated<'buf> {}
83    impl<'buf> Sealed for VerifyOnlyPreallocated<'buf> {}
84    impl<'buf> Sealed for SignOnlyPreallocated<'buf> {}
85}
86
87#[cfg(feature = "std")]
88mod std_only {
89    impl private::Sealed for SignOnly {}
90    impl private::Sealed for All {}
91    impl private::Sealed for VerifyOnly {}
92
93    use super::*;
94    use std::alloc;
95    const ALIGN_TO: usize = mem::align_of::<AlignedType>();
96
97    /// Represents the set of capabilities needed for signing.
98    pub enum SignOnly {}
99
100    /// Represents the set of capabilities needed for verification.
101    pub enum VerifyOnly {}
102
103    /// Represents the set of all capabilities.
104    pub enum All {}
105
106    impl Signing for SignOnly {}
107    impl Signing for All {}
108
109    impl Verification for VerifyOnly {}
110    impl Verification for All {}
111
112    unsafe impl Context for SignOnly {
113        const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
114        const DESCRIPTION: &'static str = "signing only";
115
116        unsafe fn deallocate(ptr: *mut u8, size: usize) {
117            let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
118            alloc::dealloc(ptr, layout);
119        }
120    }
121
122    unsafe impl Context for VerifyOnly {
123        const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
124        const DESCRIPTION: &'static str = "verification only";
125
126        unsafe fn deallocate(ptr: *mut u8, size: usize) {
127            let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
128            alloc::dealloc(ptr, layout);
129        }
130    }
131
132    unsafe impl Context for All {
133        const FLAGS: c_uint = VerifyOnly::FLAGS | SignOnly::FLAGS;
134        const DESCRIPTION: &'static str = "all capabilities";
135
136        unsafe fn deallocate(ptr: *mut u8, size: usize) {
137            let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
138            alloc::dealloc(ptr, layout);
139        }
140    }
141
142    impl<C: Context> Secp256k1<C> {
143        /// Lets you create a context in a generic manner(sign/verify/all)
144        pub fn gen_new() -> Secp256k1<C> {
145            #[cfg(target_arch = "wasm32")]
146            ffi::types::sanity_checks_for_wasm();
147
148            let size = unsafe { ffi::secp256k1_context_preallocated_size(C::FLAGS) };
149            let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
150            let ptr = unsafe { alloc::alloc(layout) };
151            Secp256k1 {
152                ctx: unsafe {
153                    ffi::secp256k1_context_preallocated_create(ptr as *mut c_void, C::FLAGS)
154                },
155                phantom: PhantomData,
156                size,
157            }
158        }
159    }
160
161    impl Secp256k1<All> {
162        /// Creates a new Secp256k1 context with all capabilities
163        pub fn new() -> Secp256k1<All> {
164            Secp256k1::gen_new()
165        }
166    }
167
168    impl Secp256k1<SignOnly> {
169        /// Creates a new Secp256k1 context that can only be used for signing
170        pub fn signing_only() -> Secp256k1<SignOnly> {
171            Secp256k1::gen_new()
172        }
173    }
174
175    impl Secp256k1<VerifyOnly> {
176        /// Creates a new Secp256k1 context that can only be used for verification
177        pub fn verification_only() -> Secp256k1<VerifyOnly> {
178            Secp256k1::gen_new()
179        }
180    }
181
182    impl Default for Secp256k1<All> {
183        fn default() -> Self {
184            Self::new()
185        }
186    }
187
188    impl<C: Context> Clone for Secp256k1<C> {
189        fn clone(&self) -> Secp256k1<C> {
190            let size = unsafe { ffi::secp256k1_context_preallocated_clone_size(self.ctx as _) };
191            let layout = alloc::Layout::from_size_align(size, ALIGN_TO).unwrap();
192            let ptr = unsafe { alloc::alloc(layout) };
193            Secp256k1 {
194                ctx: unsafe {
195                    ffi::secp256k1_context_preallocated_clone(self.ctx, ptr as *mut c_void)
196                },
197                phantom: PhantomData,
198                size,
199            }
200        }
201    }
202}
203
204impl<'buf> Signing for SignOnlyPreallocated<'buf> {}
205impl<'buf> Signing for AllPreallocated<'buf> {}
206
207impl<'buf> Verification for VerifyOnlyPreallocated<'buf> {}
208impl<'buf> Verification for AllPreallocated<'buf> {}
209
210unsafe impl<'buf> Context for SignOnlyPreallocated<'buf> {
211    const FLAGS: c_uint = ffi::SECP256K1_START_SIGN;
212    const DESCRIPTION: &'static str = "signing only";
213
214    unsafe fn deallocate(_ptr: *mut u8, _size: usize) {
215        // Allocated by the user
216    }
217}
218
219unsafe impl<'buf> Context for VerifyOnlyPreallocated<'buf> {
220    const FLAGS: c_uint = ffi::SECP256K1_START_VERIFY;
221    const DESCRIPTION: &'static str = "verification only";
222
223    unsafe fn deallocate(_ptr: *mut u8, _size: usize) {
224        // Allocated by the user
225    }
226}
227
228unsafe impl<'buf> Context for AllPreallocated<'buf> {
229    const FLAGS: c_uint = SignOnlyPreallocated::FLAGS | VerifyOnlyPreallocated::FLAGS;
230    const DESCRIPTION: &'static str = "all capabilities";
231
232    unsafe fn deallocate(_ptr: *mut u8, _size: usize) {
233        // Allocated by the user
234    }
235}
236
237impl<'buf, C: Context + 'buf> Secp256k1<C> {
238    /// Lets you create a context with preallocated buffer in a generic manner(sign/verify/all)
239    pub fn preallocated_gen_new(buf: &'buf mut [AlignedType]) -> Result<Secp256k1<C>, Error> {
240        #[cfg(target_arch = "wasm32")]
241        ffi::types::sanity_checks_for_wasm();
242
243        if buf.len() < Self::preallocate_size_gen() {
244            return Err(Error::NotEnoughMemory);
245        }
246        Ok(Secp256k1 {
247            ctx: unsafe {
248                ffi::secp256k1_context_preallocated_create(
249                    buf.as_mut_c_ptr() as *mut c_void,
250                    C::FLAGS,
251                )
252            },
253            phantom: PhantomData,
254            size: 0, // We don't care about the size because it's the caller responsibility to deallocate.
255        })
256    }
257}
258
259impl<'buf> Secp256k1<AllPreallocated<'buf>> {
260    /// Creates a new Secp256k1 context with all capabilities
261    pub fn preallocated_new(
262        buf: &'buf mut [AlignedType],
263    ) -> Result<Secp256k1<AllPreallocated<'buf>>, Error> {
264        Secp256k1::preallocated_gen_new(buf)
265    }
266    /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for a context
267    pub fn preallocate_size() -> usize {
268        Self::preallocate_size_gen()
269    }
270
271    /// Create a context from a raw context.
272    ///
273    /// # Safety
274    /// This is highly unsafe, due to the number of conditions that aren't checked.
275    /// * `raw_ctx` needs to be a valid Secp256k1 context pointer.
276    /// that was generated by *exactly* the same code/version of the libsecp256k1 used here.
277    /// * The capabilities (All/SignOnly/VerifyOnly) of the context *must* match the flags passed to libsecp256k1
278    /// when generating the context.
279    /// * The user must handle the freeing of the context(using the correct functions) by himself.
280    /// * Violating these may lead to Undefined Behavior.
281    ///
282    pub unsafe fn from_raw_all(
283        raw_ctx: *mut ffi::Context,
284    ) -> ManuallyDrop<Secp256k1<AllPreallocated<'buf>>> {
285        ManuallyDrop::new(Secp256k1 {
286            ctx: raw_ctx,
287            phantom: PhantomData,
288            size: 0, // We don't care about the size because it's the caller responsibility to deallocate.
289        })
290    }
291}
292
293impl<'buf> Secp256k1<SignOnlyPreallocated<'buf>> {
294    /// Creates a new Secp256k1 context that can only be used for signing
295    pub fn preallocated_signing_only(
296        buf: &'buf mut [AlignedType],
297    ) -> Result<Secp256k1<SignOnlyPreallocated<'buf>>, Error> {
298        Secp256k1::preallocated_gen_new(buf)
299    }
300
301    /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for the context
302    #[inline]
303    pub fn preallocate_signing_size() -> usize {
304        Self::preallocate_size_gen()
305    }
306
307    /// Create a context from a raw context.
308    ///
309    /// # Safety
310    /// This is highly unsafe, due to the number of conditions that aren't checked.
311    /// * `raw_ctx` needs to be a valid Secp256k1 context pointer.
312    /// that was generated by *exactly* the same code/version of the libsecp256k1 used here.
313    /// * The capabilities (All/SignOnly/VerifyOnly) of the context *must* match the flags passed to libsecp256k1
314    /// when generating the context.
315    /// * The user must handle the freeing of the context(using the correct functions) by himself.
316    /// * This list *is not* exhaustive, and any violation may lead to Undefined Behavior.,
317    ///
318    pub unsafe fn from_raw_signining_only(
319        raw_ctx: *mut ffi::Context,
320    ) -> ManuallyDrop<Secp256k1<SignOnlyPreallocated<'buf>>> {
321        ManuallyDrop::new(Secp256k1 {
322            ctx: raw_ctx,
323            phantom: PhantomData,
324            size: 0, // We don't care about the size because it's the caller responsibility to deallocate.
325        })
326    }
327}
328
329impl<'buf> Secp256k1<VerifyOnlyPreallocated<'buf>> {
330    /// Creates a new Secp256k1 context that can only be used for verification
331    pub fn preallocated_verification_only(
332        buf: &'buf mut [AlignedType],
333    ) -> Result<Secp256k1<VerifyOnlyPreallocated<'buf>>, Error> {
334        Secp256k1::preallocated_gen_new(buf)
335    }
336
337    /// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for the context
338    #[inline]
339    pub fn preallocate_verification_size() -> usize {
340        Self::preallocate_size_gen()
341    }
342
343    /// Create a context from a raw context.
344    ///
345    /// # Safety
346    /// This is highly unsafe, due to the number of conditions that aren't checked.
347    /// * `raw_ctx` needs to be a valid Secp256k1 context pointer.
348    /// that was generated by *exactly* the same code/version of the libsecp256k1 used here.
349    /// * The capabilities (All/SignOnly/VerifyOnly) of the context *must* match the flags passed to libsecp256k1
350    /// when generating the context.
351    /// * The user must handle the freeing of the context(using the correct functions) by himself.
352    /// * This list *is not* exhaustive, and any violation may lead to Undefined Behavior.,
353    ///
354    pub unsafe fn from_raw_verification_only(
355        raw_ctx: *mut ffi::Context,
356    ) -> ManuallyDrop<Secp256k1<VerifyOnlyPreallocated<'buf>>> {
357        ManuallyDrop::new(Secp256k1 {
358            ctx: raw_ctx,
359            phantom: PhantomData,
360            size: 0, // We don't care about the size because it's the caller responsibility to deallocate.
361        })
362    }
363}