Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 08c330f

Browse files
committedNov 8, 2023
Add PreallocatedBuffer
Add a wrapper type `PreallocatedBuffer` that maintains the invariant that the inner buffer is big enough. This allows us to take this as a parameter for preallocated context constructors and remove the error path.
1 parent ec02f3f commit 08c330f

File tree

2 files changed

+60
-16
lines changed

2 files changed

+60
-16
lines changed
 

‎src/context.rs

+52-13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
// SPDX-License-Identifier: CC0-1.0
22

3+
use core::fmt;
34
use core::marker::PhantomData;
45
use core::mem::ManuallyDrop;
56
use core::ptr::NonNull;
@@ -8,7 +9,7 @@ use core::ptr::NonNull;
89
pub use self::alloc_only::*;
910
use crate::ffi::types::{c_uint, c_void, AlignedType};
1011
use crate::ffi::{self, CPtr};
11-
use crate::{Error, Secp256k1};
12+
use crate::Secp256k1;
1213

1314
#[cfg(all(feature = "global-context", feature = "std"))]
1415
/// Module implementing a singleton pattern for a global `Secp256k1` context.
@@ -320,30 +321,51 @@ unsafe impl<'buf> PreallocatedContext<'buf> for AllPreallocated<'buf> {}
320321
unsafe impl<'buf> PreallocatedContext<'buf> for SignOnlyPreallocated<'buf> {}
321322
unsafe impl<'buf> PreallocatedContext<'buf> for VerifyOnlyPreallocated<'buf> {}
322323

324+
/// A preallocated buffer, enforces the invariant that the buffer is big enough.
325+
#[allow(missing_debug_implementations)]
326+
pub struct PreallocatedBuffer<'buf>(&'buf [AlignedType]);
327+
328+
impl<'buf> ffi::CPtr for PreallocatedBuffer<'buf> {
329+
type Target = AlignedType;
330+
fn as_c_ptr(&self) -> *const Self::Target { self.0.as_c_ptr() }
331+
fn as_mut_c_ptr(&mut self) -> *mut Self::Target { self.0.as_mut_c_ptr() }
332+
}
333+
323334
impl<'buf, C: Context + PreallocatedContext<'buf>> Secp256k1<C> {
335+
/// Wraps `buf` in a `PreallocatedBuffer`.
336+
///
337+
/// # Errors
338+
///
339+
/// Returns `NotEnoughMemoryError` if the buffer is too small.
340+
pub fn buffer(
341+
buf: &'buf mut [AlignedType],
342+
) -> Result<PreallocatedBuffer, NotEnoughMemoryError> {
343+
if buf.len() < Self::preallocate_size_gen() {
344+
return Err(NotEnoughMemoryError);
345+
}
346+
Ok(PreallocatedBuffer(buf))
347+
}
348+
324349
/// Lets you create a context with a preallocated buffer in a generic manner (sign/verify/all).
325-
pub fn preallocated_gen_new(buf: &'buf mut [AlignedType]) -> Result<Secp256k1<C>, Error> {
350+
pub fn preallocated_gen_new(buf: &'buf mut PreallocatedBuffer) -> Secp256k1<C> {
326351
#[cfg(target_arch = "wasm32")]
327352
ffi::types::sanity_checks_for_wasm();
328353

329-
if buf.len() < Self::preallocate_size_gen() {
330-
return Err(Error::NotEnoughMemory);
331-
}
332354
// Safe because buf is not null since it is not empty.
333355
let buf = unsafe { NonNull::new_unchecked(buf.as_mut_c_ptr() as *mut c_void) };
334356

335-
Ok(Secp256k1 {
357+
Secp256k1 {
336358
ctx: unsafe { ffi::secp256k1_context_preallocated_create(buf, AllPreallocated::FLAGS) },
337359
phantom: PhantomData,
338-
})
360+
}
339361
}
340362
}
341363

342364
impl<'buf> Secp256k1<AllPreallocated<'buf>> {
343365
/// Creates a new Secp256k1 context with all capabilities.
344366
pub fn preallocated_new(
345-
buf: &'buf mut [AlignedType],
346-
) -> Result<Secp256k1<AllPreallocated<'buf>>, Error> {
367+
buf: &'buf mut PreallocatedBuffer<'buf>,
368+
) -> Secp256k1<AllPreallocated<'buf>> {
347369
Secp256k1::preallocated_gen_new(buf)
348370
}
349371
/// Uses the ffi `secp256k1_context_preallocated_size` to check the memory size needed for a context.
@@ -377,8 +399,8 @@ impl<'buf> Secp256k1<AllPreallocated<'buf>> {
377399
impl<'buf> Secp256k1<SignOnlyPreallocated<'buf>> {
378400
/// Creates a new Secp256k1 context that can only be used for signing.
379401
pub fn preallocated_signing_only(
380-
buf: &'buf mut [AlignedType],
381-
) -> Result<Secp256k1<SignOnlyPreallocated<'buf>>, Error> {
402+
buf: &'buf mut PreallocatedBuffer<'buf>,
403+
) -> Secp256k1<SignOnlyPreallocated<'buf>> {
382404
Secp256k1::preallocated_gen_new(buf)
383405
}
384406

@@ -401,8 +423,8 @@ impl<'buf> Secp256k1<SignOnlyPreallocated<'buf>> {
401423
impl<'buf> Secp256k1<VerifyOnlyPreallocated<'buf>> {
402424
/// Creates a new Secp256k1 context that can only be used for verification
403425
pub fn preallocated_verification_only(
404-
buf: &'buf mut [AlignedType],
405-
) -> Result<Secp256k1<VerifyOnlyPreallocated<'buf>>, Error> {
426+
buf: &'buf mut PreallocatedBuffer<'buf>,
427+
) -> Secp256k1<VerifyOnlyPreallocated<'buf>> {
406428
Secp256k1::preallocated_gen_new(buf)
407429
}
408430

@@ -421,3 +443,20 @@ impl<'buf> Secp256k1<VerifyOnlyPreallocated<'buf>> {
421443
ManuallyDrop::new(Secp256k1 { ctx: raw_ctx, phantom: PhantomData })
422444
}
423445
}
446+
447+
/// Not enough memory for a preallocated buffer.
448+
#[derive(Debug, Clone, PartialEq, Eq)]
449+
#[non_exhaustive]
450+
#[allow(missing_copy_implementations)] // Don't implement Copy when we use non_exhaustive.
451+
pub struct NotEnoughMemoryError;
452+
453+
impl fmt::Display for NotEnoughMemoryError {
454+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
455+
f.write_str("not enough memory to use as a preallocated buffer")
456+
}
457+
}
458+
459+
#[cfg(feature = "std")]
460+
impl std::error::Error for NotEnoughMemoryError {
461+
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None }
462+
}

‎src/lib.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -586,12 +586,17 @@ mod tests {
586586
use crate::ffi::types::AlignedType;
587587

588588
let mut buf_ful = vec![AlignedType::zeroed(); Secp256k1::preallocate_size()];
589+
let mut buf_ful = Secp256k1::<AllPreallocated>::buffer(&mut buf_ful).unwrap();
590+
589591
let mut buf_sign = vec![AlignedType::zeroed(); Secp256k1::preallocate_signing_size()];
592+
let mut buf_sign = Secp256k1::<SignOnlyPreallocated>::buffer(&mut buf_sign).unwrap();
593+
590594
let mut buf_vfy = vec![AlignedType::zeroed(); Secp256k1::preallocate_verification_size()];
595+
let mut buf_vfy = Secp256k1::<VerifyOnlyPreallocated>::buffer(&mut buf_vfy).unwrap();
591596

592-
let full = Secp256k1::preallocated_new(&mut buf_ful).unwrap();
593-
let sign = Secp256k1::preallocated_signing_only(&mut buf_sign).unwrap();
594-
let vrfy = Secp256k1::preallocated_verification_only(&mut buf_vfy).unwrap();
597+
let full = Secp256k1::preallocated_new(&mut buf_ful);
598+
let sign = Secp256k1::preallocated_signing_only(&mut buf_sign);
599+
let vrfy = Secp256k1::preallocated_verification_only(&mut buf_vfy);
595600

596601
// drop(buf_vfy); // The buffer can't get dropped before the context.
597602
// println!("{:?}", buf_ful[5]); // Can't even read the data thanks to the borrow checker.

0 commit comments

Comments
 (0)
Please sign in to comment.