Skip to content

Commit

Permalink
condtype works well - can remove num_traits dependency and optimize t…
Browse files Browse the repository at this point in the history
…he comparison with MEC
  • Loading branch information
root committed Feb 17, 2024
1 parent e4d1c42 commit 1d2e16d
Show file tree
Hide file tree
Showing 7 changed files with 103 additions and 33 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ exclude = [
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
num-traits = "0.2.18"
typenum = "1.17.0"
zeroize = { version = "1.6.0", optional = true}

Expand Down
1 change: 1 addition & 0 deletions src/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
pub mod common;
pub mod error;
pub mod secret;
pub mod secret_sync;
Expand Down
32 changes: 32 additions & 0 deletions src/runtime/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
use crate::runtime::traits::MinimallyRepresentableUInt;
use core::ops::Sub;

use typenum::{Exp, U1, U16, U2, U256, U32, U4294967296, U64, U65536, U8};

impl MinimallyRepresentableUInt for U8 {
type Type = u8;
type UIntMaxValueAsType = <U256 as Sub<U1>>::Output;
const MIN: Self::Type = Self::Type::MIN;
const ONE: Self::Type = 1;
}

impl MinimallyRepresentableUInt for U16 {
type Type = u16;
type UIntMaxValueAsType = <U65536 as Sub<U1>>::Output;
const MIN: Self::Type = Self::Type::MIN;
const ONE: Self::Type = 1;
}

impl MinimallyRepresentableUInt for U32 {
type Type = u32;
type UIntMaxValueAsType = <U4294967296 as Sub<U1>>::Output;
const MIN: Self::Type = Self::Type::MIN;
const ONE: Self::Type = 1;
}

impl MinimallyRepresentableUInt for U64 {
type Type = u64;
type UIntMaxValueAsType = <Exp<U2, U64> as Sub<U1>>::Output;
const MIN: Self::Type = Self::Type::MIN;
const ONE: Self::Type = 1;
}
16 changes: 10 additions & 6 deletions src/runtime/error.rs
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
use crate::runtime::traits::MinimallyRepresentableUInt;

#[derive(Debug)]
#[non_exhaustive]
pub enum ExposeSecretError {
ExposeMoreThanMaximallyAllow(ExposeMoreThanMaximallyAllowError),
pub enum ExposeSecretError<SIZE: MinimallyRepresentableUInt> {
ExposeMoreThanMaximallyAllow(ExposeMoreThanMaximallyAllowError<SIZE>),
}

#[derive(Debug)]
pub struct ExposeMoreThanMaximallyAllowError {
pub struct ExposeMoreThanMaximallyAllowError<SIZE: MinimallyRepresentableUInt> {
pub mec: usize,
pub ec: usize,
pub ec: SIZE::Type,
}

impl core::fmt::Display for ExposeMoreThanMaximallyAllowError {
impl<SIZE: MinimallyRepresentableUInt> core::fmt::Display
for ExposeMoreThanMaximallyAllowError<SIZE>
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "`Secret` is exposed more than what it is maximally allowed to; it is exposed for {} times and it is only allowed to be exposed for {} times", self.ec, self.mec)
}
}

impl core::fmt::Display for ExposeSecretError {
impl<SIZE: MinimallyRepresentableUInt> core::fmt::Display for ExposeSecretError<SIZE> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::ExposeMoreThanMaximallyAllow(err) => err.fmt(f),
Expand Down
51 changes: 33 additions & 18 deletions src/runtime/secret.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
use core::{cell::UnsafeCell, marker::PhantomData, ops::Deref};

use crate::runtime::{error, traits};
pub struct RTSecret<T, const MEC: usize>(T, UnsafeCell<usize>);
use num_traits::{AsPrimitive, ConstOne};
use typenum::{IsLessOrEqual, True, Unsigned, U64};

pub struct RTSecret<T, MEC: Unsigned, SIZE: traits::MinimallyRepresentableUInt = U64>(
T,
UnsafeCell<<SIZE as traits::MinimallyRepresentableUInt>::Type>,
PhantomData<MEC>,
);

pub struct RTExposedSecret<'brand, T>(T, PhantomData<fn(&'brand ()) -> &'brand ()>);

impl<'brand, T> Deref for RTExposedSecret<'brand, &'brand T> {
Expand All @@ -11,25 +19,31 @@ impl<'brand, T> Deref for RTExposedSecret<'brand, &'brand T> {
}
}

impl<T, const MEC: usize> RTSecret<T, MEC> {
pub const fn new(value: T) -> Self {
Self(value, UnsafeCell::new(0))
impl<T, MEC: Unsigned, SIZE: traits::MinimallyRepresentableUInt> RTSecret<T, MEC, SIZE> {
pub const fn new(t: T) -> Self
where
MEC: IsLessOrEqual<SIZE::UIntMaxValueAsType, Output = True>,
{
Self(t, UnsafeCell::new(SIZE::MIN), PhantomData)
}

pub fn new_with(f: impl FnOnce() -> T) -> Self {
Self(f(), UnsafeCell::new(0))
pub fn new_with(f: impl FnOnce() -> T) -> Self
where
MEC: IsLessOrEqual<SIZE::UIntMaxValueAsType, Output = True>,
{
Self(f(), UnsafeCell::new(SIZE::MIN), PhantomData)
}

pub fn exposure_count(&self) -> &usize {
pub fn exposure_count(&self) -> &SIZE::Type {
// SAFETY: The function only returns a shared reference (&usize) to the exposure count.
// It does not allow mutable access to the exposure count directly.
// This means that while external code can observe the exposure count, it cannot modify it directly.
unsafe { &*self.1.get() }
}
}

impl<'secret, T, const MEC: usize> traits::RTExposeSecret<'secret, &'secret T>
for RTSecret<T, MEC>
impl<'secret, T, MEC: Unsigned, SIZE: traits::MinimallyRepresentableUInt>
traits::RTExposeSecret<'secret, &'secret T, SIZE> for RTSecret<T, MEC, SIZE>
{
type Exposed<'brand> = RTExposedSecret<'brand, &'brand T>
where
Expand All @@ -50,22 +64,23 @@ impl<'secret, T, const MEC: usize> traits::RTExposeSecret<'secret, &'secret T>
fn try_expose_secret<ReturnType, ClosureType>(
&self,
scope: ClosureType,
) -> Result<ReturnType, error::ExposeSecretError>
) -> Result<ReturnType, error::ExposeSecretError<SIZE>>
where
for<'brand> ClosureType: FnOnce(RTExposedSecret<'brand, &'brand T>) -> ReturnType,
{
// SAFETY: All tuple fields of `RTSecret` are private, there are no setter to them.
// `RTSecret` is also not `Sync` so it is not possible to have multithreading race condition.
let ec_mut = unsafe { &mut *self.1.get() };
if *ec_mut >= MEC {
let ec_mut_usize: usize = ec_mut.as_();
if ec_mut_usize >= MEC::USIZE {
return Err(error::ExposeSecretError::ExposeMoreThanMaximallyAllow(
error::ExposeMoreThanMaximallyAllowError {
mec: MEC,
mec: MEC::USIZE,
ec: *ec_mut,
},
));
};
*ec_mut += 1;
*ec_mut += SIZE::ONE;
Ok(scope(RTExposedSecret(&self.0, PhantomData)))
}
}
Expand All @@ -77,17 +92,17 @@ mod tests {

#[test]
#[should_panic(
expected = "`RTSecret` has already been exposed 18446744073709551615 times, which is also the maximum number it is allowed to be exposed for."
expected = "`RTSecret` has already been exposed 2 times, which is also the maximum number it is allowed to be exposed for."
)]
fn test_usize_max_expose_secret() {
extern crate std;
let mut secret_one = RTSecret::<isize, { usize::MAX }>::new(69);
*secret_one.1.get_mut() = usize::MAX - 1;
use typenum::{U2, U8};
let mut secret_one = RTSecret::<isize, U2, U8>::new(69);
*secret_one.1.get_mut() = u8::MAX - 1;
#[allow(unused_assignments)]
let mut usize_max_reached = false;

for _ in 0..=2 {
if secret_one.exposure_count() == &usize::MAX {
if secret_one.exposure_count() == &u8::MAX {
usize_max_reached = true;
assert!(usize_max_reached);
};
Expand Down
18 changes: 16 additions & 2 deletions src/runtime/traits.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,13 @@
use core::{
fmt::{Debug, Display},
ops::AddAssign,
};

pub use crate::runtime::error;
use num_traits::AsPrimitive;
use typenum::Unsigned;

pub trait RTExposeSecret<'secret, T> {
pub trait RTExposeSecret<'secret, T, SIZE: MinimallyRepresentableUInt> {
type Exposed<'brand>
where
'secret: 'brand;
Expand All @@ -12,7 +19,14 @@ pub trait RTExposeSecret<'secret, T> {
fn try_expose_secret<ReturnType, ClosureType>(
&self,
scope: ClosureType,
) -> Result<ReturnType, error::ExposeSecretError>
) -> Result<ReturnType, error::ExposeSecretError<SIZE>>
where
for<'brand> ClosureType: FnOnce(Self::Exposed<'brand>) -> ReturnType;
}

pub(crate) trait MinimallyRepresentableUInt: Unsigned {
type Type: AddAssign + AsPrimitive<usize> + Debug + Display;
type UIntMaxValueAsType;
const MIN: Self::Type;
const ONE: Self::Type;
}
17 changes: 10 additions & 7 deletions tests/extern_bin_rt.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
use sosecrets_rs::runtime::{
secret::{RTExposedSecret, RTSecret},
traits::RTExposeSecret,
use sosecrets_rs::{
prelude::typenum::{U0, U1, U2},
runtime::{
secret::{RTExposedSecret, RTSecret},
traits::RTExposeSecret,
},
};

#[test]
Expand All @@ -11,8 +14,8 @@ fn test_bounds() {
// This has to take a value, since the async fn's return type is unnameable.
// fn check_send_sync_val<T: Send + Sync>(_t: T) {}
// fn check_send_sync<T: Send + Sync>() {}
check_unpin::<RTSecret<i32, 2>>();
check_send::<RTSecret<i32, 2>>();
check_unpin::<RTSecret<i32, U1>>();
check_send::<RTSecret<i32, U1>>();
check_unpin::<RTExposedSecret<'_, PhantomData<fn(&()) -> &()>>>();
check_send::<RTExposedSecret<'_, PhantomData<fn(&()) -> &()>>>();

Expand All @@ -26,7 +29,7 @@ fn test_bounds() {

#[test]
fn test_expose_secret_runtime() {
let secret_one = RTSecret::<isize, 2>::new(69);
let secret_one = RTSecret::<isize, U2>::new(69);

let _ = secret_one.expose_secret(|exposed_secret| {
assert_eq!(*exposed_secret, 69);
Expand All @@ -40,7 +43,7 @@ fn test_expose_secret_runtime() {
#[test]
#[should_panic = "`RTSecret` has already been exposed 2 times, which is also the maximum number it is allowed to be exposed for."]
fn test_expose_secret_runtime_should_panic() {
let secret_one = RTSecret::<isize, 2>::new(69);
let secret_one = RTSecret::<isize, U2>::new(69);

let _ = secret_one.expose_secret(|exposed_secret| {
assert_eq!(*exposed_secret, 69);
Expand Down

0 comments on commit 1d2e16d

Please sign in to comment.