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