mirror of
https://github.com/kristoferssolo/cipher-workshop.git
synced 2025-12-31 13:52:29 +00:00
refactor(cipher-core): unify secret_block! and secret_key! macros
Move duplicated macro definitions from aes and des crates into
cipher-core for shared use. Both macros now:
- Support u8 through u128 integer types
- Include Zeroize derive for secure memory handling
- Generate consistent formatting and conversion methods
This commit is contained in:
parent
451986d702
commit
aacb836e77
@ -2,7 +2,7 @@ use crate::{
|
|||||||
block::{Block32, secret_block},
|
block::{Block32, secret_block},
|
||||||
sbox::SboxLookup,
|
sbox::SboxLookup,
|
||||||
};
|
};
|
||||||
use cipher_core::{parse_block_int, BlockError, InputBlock};
|
use cipher_core::{BlockError, InputBlock, parse_block_int};
|
||||||
use std::{
|
use std::{
|
||||||
ops::BitXor,
|
ops::BitXor,
|
||||||
slice::{from_raw_parts, from_raw_parts_mut},
|
slice::{from_raw_parts, from_raw_parts_mut},
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
mod block128;
|
mod block128;
|
||||||
mod block32;
|
mod block32;
|
||||||
mod secret_block;
|
|
||||||
|
|
||||||
use crate::secret_block;
|
use cipher_core::secret_block;
|
||||||
pub use {block32::Block32, block128::Block128};
|
pub use {block32::Block32, block128::Block128};
|
||||||
|
|||||||
@ -1,190 +0,0 @@
|
|||||||
/// Macro to generate a masked, zeroizable integer wrapper type.
|
|
||||||
///
|
|
||||||
/// Usage:
|
|
||||||
/// ```
|
|
||||||
/// use des::secret_block;
|
|
||||||
/// secret_block! {
|
|
||||||
/// /// docs...
|
|
||||||
/// pub struct Block48(u64, 48, 0x0000_FFFF_FFFF_FFFFu64);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! secret_block {
|
|
||||||
(
|
|
||||||
$(#[$meta:meta])*
|
|
||||||
$vis:vis struct $name:ident ( $int:tt, $bits:expr, $mask:expr );
|
|
||||||
) => {
|
|
||||||
$(#[$meta])*
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
$vis struct $name($int);
|
|
||||||
|
|
||||||
impl $name {
|
|
||||||
/// Mask to restrict the underlying integer to valid bits.
|
|
||||||
pub const MASK: $int = $mask;
|
|
||||||
|
|
||||||
/// Calculate the number of hex digits needed for the bit width
|
|
||||||
const fn hex_width() -> usize {
|
|
||||||
($bits as usize).div_ceil(4)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the number of octal digits needed for the bit width
|
|
||||||
const fn octal_width() -> usize {
|
|
||||||
($bits as usize).div_ceil(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn new(value: $int) -> Self {
|
|
||||||
Self(value & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_as $int);
|
|
||||||
secret_block!(@conversions_from $int $int);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$int> for $name {
|
|
||||||
fn from(v: $int) -> Self {
|
|
||||||
Self(v & Self::MASK)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$name> for $int {
|
|
||||||
fn from(value: $name) -> $int {
|
|
||||||
value.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::UpperHex for $name {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:0width$X}", self.0, width = Self::hex_width())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::LowerHex for $name {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:0width$x}", self.0, width = Self::hex_width())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Octal for $name {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:0width$o}", self.0, width = Self::octal_width())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Binary for $name {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:0width$b}", self.0, width = $bits)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
// Helper: generate conversions_as based on type
|
|
||||||
(@conversions_as u8) => {
|
|
||||||
/// Return value as u8
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u8(&self) -> u8 {
|
|
||||||
self.0 as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_as u16);
|
|
||||||
};
|
|
||||||
(@conversions_as u16) => {
|
|
||||||
/// Return value as u16
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u16(&self) -> u16 {
|
|
||||||
self.0 as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_as u32);
|
|
||||||
};
|
|
||||||
(@conversions_as u32) => {
|
|
||||||
/// Return value as u32
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u32(&self) -> u32 {
|
|
||||||
self.0 as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_as u64);
|
|
||||||
};
|
|
||||||
(@conversions_as u64) => {
|
|
||||||
/// Return value as u64
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u64(&self) -> u64 {
|
|
||||||
self.0 as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_as u128);
|
|
||||||
};
|
|
||||||
(@conversions_as u128) => {
|
|
||||||
/// Return value as u129
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u128(&self) -> u128 {
|
|
||||||
self.0 as u128
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Helper: generate conversions_from based on type
|
|
||||||
(@conversions_from u8 $int:tt) => {
|
|
||||||
/// Create value from u8
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u8(key: u8) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(@conversions_from u16 $int:tt) => {
|
|
||||||
/// Create value from u16
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u16(key: u16) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_from u8 $int);
|
|
||||||
};
|
|
||||||
(@conversions_from u32 $int:tt) => {
|
|
||||||
/// Create value from u32
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u32(key: u32) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_from u16 $int);
|
|
||||||
};
|
|
||||||
(@conversions_from u64 $int:tt) => {
|
|
||||||
/// Create value from u64
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u64(key: u64) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_from u32 $int);
|
|
||||||
};
|
|
||||||
(@conversions_from u128 $int:tt) => {
|
|
||||||
/// Create value from u128
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u128(key: u128) -> Self {
|
|
||||||
Self(key & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_from u64 $int);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +0,0 @@
|
|||||||
use crate::secret_key;
|
|
||||||
|
|
||||||
secret_key! {
|
|
||||||
pub struct ExpandedKey(u32, 32, 0xFFFF_FFFF);
|
|
||||||
}
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
mod aes_key;
|
mod aes_key;
|
||||||
mod secret_key;
|
|
||||||
mod subkey;
|
mod subkey;
|
||||||
mod subkeys;
|
mod subkeys;
|
||||||
|
|
||||||
use crate::secret_key;
|
use cipher_core::secret_key;
|
||||||
pub use {aes_key::Key, subkey::Subkey, subkeys::Subkeys};
|
pub use {aes_key::Key, subkey::Subkey, subkeys::Subkeys};
|
||||||
|
|||||||
@ -1,149 +0,0 @@
|
|||||||
/// Macro to generate a masked, zeroizable integer wrapper type.
|
|
||||||
///
|
|
||||||
/// Usage:
|
|
||||||
/// ```
|
|
||||||
/// use des::secret_key;
|
|
||||||
/// secret_key! {
|
|
||||||
/// /// docs...
|
|
||||||
/// pub struct Subkey(u64, 48, 0x0000_FFFF_FFFF_FFFFu64);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! secret_key {
|
|
||||||
(
|
|
||||||
$(#[$meta:meta])*
|
|
||||||
$vis:vis struct $name:ident ( $int:tt, $bits:expr, $mask:expr );
|
|
||||||
) => {
|
|
||||||
$(#[$meta])*
|
|
||||||
#[derive(Default, Clone, Copy)]
|
|
||||||
$vis struct $name($int);
|
|
||||||
|
|
||||||
impl $name {
|
|
||||||
/// Mask to restrict the underlying integer to valid bits.
|
|
||||||
pub const MASK: $int = $mask;
|
|
||||||
|
|
||||||
secret_key!(@conversions_as $int);
|
|
||||||
secret_key!(@conversions_from $int $int);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::fmt::Debug for $name {
|
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
|
||||||
f.write_str(concat!(stringify!($name), "[REDACTED]"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$int> for $name {
|
|
||||||
fn from(v: $int) -> Self {
|
|
||||||
Self(v & Self::MASK)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Helper: generate conversions_as based on type
|
|
||||||
(@conversions_as u8) => {
|
|
||||||
/// Return value as u8
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u8(&self) -> u8 {
|
|
||||||
self.0 as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_as u16);
|
|
||||||
};
|
|
||||||
(@conversions_as u16) => {
|
|
||||||
/// Return value as u16
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u16(&self) -> u16 {
|
|
||||||
self.0 as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_as u32);
|
|
||||||
};
|
|
||||||
(@conversions_as u32) => {
|
|
||||||
/// Return value as u32
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u32(&self) -> u32 {
|
|
||||||
self.0 as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_as u64);
|
|
||||||
};
|
|
||||||
(@conversions_as u64) => {
|
|
||||||
/// Return value as u64
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u64(&self) -> u64 {
|
|
||||||
self.0 as u64
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_as u128);
|
|
||||||
};
|
|
||||||
(@conversions_as u128) => {
|
|
||||||
/// Return value as u128
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u128(&self) -> u128 {
|
|
||||||
self.0 as u128
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Helper: generate conversions_from based on type
|
|
||||||
(@conversions_from u8 $int:tt) => {
|
|
||||||
/// Create value from u8
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u8(key: u8) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(@conversions_from u16 $int:tt) => {
|
|
||||||
/// Create value from u16
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u16(key: u16) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_from u8 $int);
|
|
||||||
};
|
|
||||||
(@conversions_from u32 $int:tt) => {
|
|
||||||
/// Create value from u32
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u32(key: u32) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_from u16 $int);
|
|
||||||
};
|
|
||||||
(@conversions_from u64 $int:tt) => {
|
|
||||||
/// Create value from u64
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u64(key: u64) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_from u32 $int);
|
|
||||||
};
|
|
||||||
(@conversions_from u128 $int:tt) => {
|
|
||||||
/// Create value from u128
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u128(key: u128) -> Self {
|
|
||||||
Self(key & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_from u64 $int);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -6,6 +6,7 @@ edition.workspace = true
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
thiserror.workspace = true
|
thiserror.workspace = true
|
||||||
|
zeroize.workspace = true
|
||||||
|
|
||||||
[lints]
|
[lints]
|
||||||
workspace = true
|
workspace = true
|
||||||
|
|||||||
@ -1,11 +1,12 @@
|
|||||||
mod error;
|
mod error;
|
||||||
|
mod macros;
|
||||||
mod parsing;
|
mod parsing;
|
||||||
mod traits;
|
mod traits;
|
||||||
mod types;
|
mod types;
|
||||||
|
|
||||||
pub use {
|
pub use {
|
||||||
error::{BlockError, CipherError, CipherResult},
|
error::{BlockError, CipherError, CipherResult},
|
||||||
parsing::{parse_block_int, BlockInt},
|
parsing::{BlockInt, parse_block_int},
|
||||||
traits::{BlockCipher, BlockParser, InputBlock},
|
traits::{BlockCipher, BlockParser, InputBlock},
|
||||||
types::{CipherAction, Output},
|
types::{CipherAction, Output},
|
||||||
};
|
};
|
||||||
|
|||||||
265
cipher-core/src/macros.rs
Normal file
265
cipher-core/src/macros.rs
Normal file
@ -0,0 +1,265 @@
|
|||||||
|
/// Macro to generate a masked integer wrapper type for cipher blocks.
|
||||||
|
///
|
||||||
|
/// Generates a type with formatting traits, conversions, and security features.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```ignore
|
||||||
|
/// secret_block! {
|
||||||
|
/// pub struct Block64(u64, 64, 0xFFFF_FFFF_FFFF_FFFF);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! secret_block {
|
||||||
|
(
|
||||||
|
$(#[$meta:meta])*
|
||||||
|
$vis:vis struct $name:ident ( $int:tt, $bits:expr, $mask:expr );
|
||||||
|
) => {
|
||||||
|
$(#[$meta])*
|
||||||
|
#[derive(Debug, Clone, Copy, PartialEq, Eq, ::zeroize::Zeroize)]
|
||||||
|
$vis struct $name($int);
|
||||||
|
|
||||||
|
impl $name {
|
||||||
|
/// Mask to restrict the underlying integer to valid bits.
|
||||||
|
pub const MASK: $int = $mask;
|
||||||
|
|
||||||
|
const fn hex_width() -> usize {
|
||||||
|
($bits as usize).div_ceil(4)
|
||||||
|
}
|
||||||
|
|
||||||
|
const fn octal_width() -> usize {
|
||||||
|
($bits as usize).div_ceil(3)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn new(value: $int) -> Self {
|
||||||
|
Self(value & Self::MASK)
|
||||||
|
}
|
||||||
|
|
||||||
|
$crate::secret_block!(@conversions_as $int);
|
||||||
|
$crate::secret_block!(@conversions_from $int $int);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$int> for $name {
|
||||||
|
fn from(v: $int) -> Self {
|
||||||
|
Self(v & Self::MASK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$name> for $int {
|
||||||
|
fn from(value: $name) -> $int {
|
||||||
|
value.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::UpperHex for $name {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
write!(f, "{:0width$X}", self.0, width = Self::hex_width())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::LowerHex for $name {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
write!(f, "{:0width$x}", self.0, width = Self::hex_width())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Octal for $name {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
write!(f, "{:0width$o}", self.0, width = Self::octal_width())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Binary for $name {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
write!(f, "{:0width$b}", self.0, width = $bits)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Conversion chain: as_u8 -> as_u16 -> as_u32 -> as_u64 -> as_u128
|
||||||
|
(@conversions_as u8) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_u8(&self) -> u8 { self.0 as u8 }
|
||||||
|
$crate::secret_block!(@conversions_as u16);
|
||||||
|
};
|
||||||
|
(@conversions_as u16) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_u16(&self) -> u16 { self.0 as u16 }
|
||||||
|
$crate::secret_block!(@conversions_as u32);
|
||||||
|
};
|
||||||
|
(@conversions_as u32) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_u32(&self) -> u32 { self.0 as u32 }
|
||||||
|
$crate::secret_block!(@conversions_as u64);
|
||||||
|
};
|
||||||
|
(@conversions_as u64) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_u64(&self) -> u64 { self.0 as u64 }
|
||||||
|
$crate::secret_block!(@conversions_as u128);
|
||||||
|
};
|
||||||
|
(@conversions_as u128) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_u128(&self) -> u128 { self.0 as u128 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Conversion chain: from_u128 -> from_u64 -> from_u32 -> from_u16 -> from_u8
|
||||||
|
(@conversions_from u8 $int:tt) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_u8(v: u8) -> Self { Self(v as $int & Self::MASK) }
|
||||||
|
};
|
||||||
|
(@conversions_from u16 $int:tt) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_u16(v: u16) -> Self { Self(v as $int & Self::MASK) }
|
||||||
|
$crate::secret_block!(@conversions_from u8 $int);
|
||||||
|
};
|
||||||
|
(@conversions_from u32 $int:tt) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_u32(v: u32) -> Self { Self(v as $int & Self::MASK) }
|
||||||
|
$crate::secret_block!(@conversions_from u16 $int);
|
||||||
|
};
|
||||||
|
(@conversions_from u64 $int:tt) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_u64(v: u64) -> Self { Self(v as $int & Self::MASK) }
|
||||||
|
$crate::secret_block!(@conversions_from u32 $int);
|
||||||
|
};
|
||||||
|
(@conversions_from u128 $int:tt) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_u128(v: u128) -> Self { Self(v as $int & Self::MASK) }
|
||||||
|
$crate::secret_block!(@conversions_from u64 $int);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Macro to generate a masked integer wrapper type for cipher keys.
|
||||||
|
///
|
||||||
|
/// Keys have redacted Debug output and are zeroized on drop for security.
|
||||||
|
///
|
||||||
|
/// # Example
|
||||||
|
/// ```ignore
|
||||||
|
/// secret_key! {
|
||||||
|
/// pub struct Key(u64, 64, 0xFFFF_FFFF_FFFF_FFFF);
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! secret_key {
|
||||||
|
(
|
||||||
|
$(#[$meta:meta])*
|
||||||
|
$vis:vis struct $name:ident ( $int:tt, $bits:expr, $mask:expr );
|
||||||
|
) => {
|
||||||
|
$(#[$meta])*
|
||||||
|
#[derive(Default, Clone, Copy, ::zeroize::Zeroize)]
|
||||||
|
$vis struct $name($int);
|
||||||
|
|
||||||
|
impl $name {
|
||||||
|
/// Mask to restrict the underlying integer to valid bits.
|
||||||
|
pub const MASK: $int = $mask;
|
||||||
|
|
||||||
|
$crate::secret_key!(@conversions_as $int);
|
||||||
|
$crate::secret_key!(@conversions_from $int $int);
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ::std::fmt::Debug for $name {
|
||||||
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
|
f.write_str(concat!(stringify!($name), "[REDACTED]"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<$int> for $name {
|
||||||
|
fn from(v: $int) -> Self {
|
||||||
|
Self(v & Self::MASK)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Conversion chain: as_u8 -> as_u16 -> as_u32 -> as_u64 -> as_u128
|
||||||
|
(@conversions_as u8) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_u8(&self) -> u8 { self.0 as u8 }
|
||||||
|
$crate::secret_key!(@conversions_as u16);
|
||||||
|
};
|
||||||
|
(@conversions_as u16) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_u16(&self) -> u16 { self.0 as u16 }
|
||||||
|
$crate::secret_key!(@conversions_as u32);
|
||||||
|
};
|
||||||
|
(@conversions_as u32) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_u32(&self) -> u32 { self.0 as u32 }
|
||||||
|
$crate::secret_key!(@conversions_as u64);
|
||||||
|
};
|
||||||
|
(@conversions_as u64) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_u64(&self) -> u64 { self.0 as u64 }
|
||||||
|
$crate::secret_key!(@conversions_as u128);
|
||||||
|
};
|
||||||
|
(@conversions_as u128) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn as_u128(&self) -> u128 { self.0 as u128 }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Conversion chain: from_u128 -> from_u64 -> from_u32 -> from_u16 -> from_u8
|
||||||
|
(@conversions_from u8 $int:tt) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_u8(v: u8) -> Self { Self(v as $int & Self::MASK) }
|
||||||
|
};
|
||||||
|
(@conversions_from u16 $int:tt) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_u16(v: u16) -> Self { Self(v as $int & Self::MASK) }
|
||||||
|
$crate::secret_key!(@conversions_from u8 $int);
|
||||||
|
};
|
||||||
|
(@conversions_from u32 $int:tt) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_u32(v: u32) -> Self { Self(v as $int & Self::MASK) }
|
||||||
|
$crate::secret_key!(@conversions_from u16 $int);
|
||||||
|
};
|
||||||
|
(@conversions_from u64 $int:tt) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_u64(v: u64) -> Self { Self(v as $int & Self::MASK) }
|
||||||
|
$crate::secret_key!(@conversions_from u32 $int);
|
||||||
|
};
|
||||||
|
(@conversions_from u128 $int:tt) => {
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub const fn from_u128(v: u128) -> Self { Self(v as $int & Self::MASK) }
|
||||||
|
$crate::secret_key!(@conversions_from u64 $int);
|
||||||
|
};
|
||||||
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
use std::ops::BitXor;
|
use std::ops::BitXor;
|
||||||
|
|
||||||
use crate::secret_block;
|
use super::secret_block;
|
||||||
|
|
||||||
secret_block! {
|
secret_block! {
|
||||||
pub struct Block32(u32, 32, 0xFFFF_FFFF);
|
pub struct Block32(u32, 32, 0xFFFF_FFFF);
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
use crate::{block::Block6, key::Subkey, secret_block};
|
use super::{Block6, secret_block};
|
||||||
|
use crate::key::Subkey;
|
||||||
use std::{array, ops::BitXor};
|
use std::{array, ops::BitXor};
|
||||||
|
|
||||||
secret_block! {
|
secret_block! {
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
use crate::secret_block;
|
use super::secret_block;
|
||||||
|
|
||||||
secret_block! {
|
secret_block! {
|
||||||
pub struct Block6(u8, 6, 0x3F);
|
pub struct Block6(u8, 6, 0x3F);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
use crate::block::{lr::LR, secret_block};
|
use crate::block::{lr::LR, secret_block};
|
||||||
use cipher_core::{parse_block_int, BlockError, InputBlock};
|
use cipher_core::{BlockError, InputBlock, parse_block_int};
|
||||||
use std::{
|
use std::{
|
||||||
slice::{from_raw_parts, from_raw_parts_mut},
|
slice::{from_raw_parts, from_raw_parts_mut},
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
|
|||||||
@ -3,7 +3,6 @@ mod block48;
|
|||||||
mod block6;
|
mod block6;
|
||||||
mod block64;
|
mod block64;
|
||||||
mod lr;
|
mod lr;
|
||||||
mod secret_block;
|
|
||||||
|
|
||||||
use crate::secret_block;
|
use cipher_core::secret_block;
|
||||||
pub use {block6::Block6, block32::Block32, block48::Block48, block64::Block64, lr::LR};
|
pub use {block6::Block6, block32::Block32, block48::Block48, block64::Block64, lr::LR};
|
||||||
|
|||||||
@ -1,168 +0,0 @@
|
|||||||
/// Macro to generate a masked, zeroizable integer wrapper type.
|
|
||||||
///
|
|
||||||
/// Usage:
|
|
||||||
/// ```
|
|
||||||
/// use des::secret_block;
|
|
||||||
/// secret_block! {
|
|
||||||
/// /// docs...
|
|
||||||
/// pub struct Block48(u64, 48, 0x0000_FFFF_FFFF_FFFFu64);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! secret_block {
|
|
||||||
(
|
|
||||||
$(#[$meta:meta])*
|
|
||||||
$vis:vis struct $name:ident ( $int:tt, $bits:expr, $mask:expr );
|
|
||||||
) => {
|
|
||||||
$(#[$meta])*
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, ::zeroize::Zeroize)]
|
|
||||||
$vis struct $name($int);
|
|
||||||
|
|
||||||
impl $name {
|
|
||||||
/// Mask to restrict the underlying integer to valid bits.
|
|
||||||
pub const MASK: $int = $mask;
|
|
||||||
|
|
||||||
/// Calculate the number of hex digits needed for the bit width
|
|
||||||
const fn hex_width() -> usize {
|
|
||||||
($bits as usize).div_ceil(4)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Calculate the number of octal digits needed for the bit width
|
|
||||||
const fn octal_width() -> usize {
|
|
||||||
($bits as usize).div_ceil(3)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn new(value: $int) -> Self {
|
|
||||||
Self(value & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_as $int);
|
|
||||||
secret_block!(@conversions_from $int $int);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$int> for $name {
|
|
||||||
fn from(v: $int) -> Self {
|
|
||||||
Self(v & Self::MASK)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$name> for $int {
|
|
||||||
fn from(value: $name) -> $int {
|
|
||||||
value.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::UpperHex for $name {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:0width$X}", self.0, width = Self::hex_width())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::LowerHex for $name {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:0width$x}", self.0, width = Self::hex_width())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Octal for $name {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:0width$o}", self.0, width = Self::octal_width())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Binary for $name {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
write!(f, "{:0width$b}", self.0, width = $bits)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
|
||||||
// Helper: generate conversions_as based on type
|
|
||||||
(@conversions_as u8) => {
|
|
||||||
/// Return value as u8
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u8(&self) -> u8 {
|
|
||||||
self.0 as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_as u16);
|
|
||||||
};
|
|
||||||
(@conversions_as u16) => {
|
|
||||||
/// Return value as u16
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u16(&self) -> u16 {
|
|
||||||
self.0 as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_as u32);
|
|
||||||
};
|
|
||||||
(@conversions_as u32) => {
|
|
||||||
/// Return value as u32
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u32(&self) -> u32 {
|
|
||||||
self.0 as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_as u64);
|
|
||||||
};
|
|
||||||
(@conversions_as u64) => {
|
|
||||||
/// Return value as u64
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u64(&self) -> u64 {
|
|
||||||
self.0 as u64
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Helper: generate conversions_from based on type
|
|
||||||
(@conversions_from u8 $int:tt) => {
|
|
||||||
/// Create value from u8
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u8(key: u8) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(@conversions_from u16 $int:tt) => {
|
|
||||||
/// Create value from u16
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u16(key: u16) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_from u8 $int);
|
|
||||||
};
|
|
||||||
(@conversions_from u32 $int:tt) => {
|
|
||||||
/// Create value from u32
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u32(key: u32) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_from u16 $int);
|
|
||||||
};
|
|
||||||
(@conversions_from u64 $int:tt) => {
|
|
||||||
/// Create value from u64
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u64(key: u64) -> Self {
|
|
||||||
Self(key & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_block!(@conversions_from u32 $int);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -81,21 +81,21 @@ where
|
|||||||
{
|
{
|
||||||
let mut lr = LR::from(block);
|
let mut lr = LR::from(block);
|
||||||
|
|
||||||
for subkey in subkeys {
|
for &subkey in subkeys {
|
||||||
feistel(&mut lr, subkey);
|
feistel(&mut lr, subkey);
|
||||||
}
|
}
|
||||||
lr.swap();
|
lr.swap();
|
||||||
lr.into()
|
lr.into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn feistel(lr: &mut LR, subkey: &Subkey) {
|
fn feistel(lr: &mut LR, subkey: Subkey) {
|
||||||
let tmp = lr.right;
|
let tmp = lr.right;
|
||||||
lr.right = lr.left ^ f_function(lr.right, subkey);
|
lr.right = lr.left ^ f_function(lr.right, subkey);
|
||||||
lr.left = tmp;
|
lr.left = tmp;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn f_function(right: Block32, subkey: &Subkey) -> Block32 {
|
fn f_function(right: Block32, subkey: Subkey) -> Block32 {
|
||||||
let expanded = expansion_permutation(right);
|
let expanded = expansion_permutation(right);
|
||||||
let xored = expanded ^ subkey;
|
let xored = expanded ^ subkey;
|
||||||
let sboxed = s_box_substitution(xored);
|
let sboxed = s_box_substitution(xored);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
use crate::key::{half28::Half28, key56::Key56};
|
use crate::key::{half28::Half28, key56::Key56};
|
||||||
use zeroize::ZeroizeOnDrop;
|
use zeroize::ZeroizeOnDrop;
|
||||||
|
|
||||||
#[derive(ZeroizeOnDrop)]
|
#[derive(Clone, ZeroizeOnDrop)]
|
||||||
pub struct CD56 {
|
pub struct CD56 {
|
||||||
pub c: Half28,
|
pub c: Half28,
|
||||||
pub d: Half28,
|
pub d: Half28,
|
||||||
@ -14,7 +14,7 @@ impl CD56 {
|
|||||||
Self { c, d }
|
Self { c, d }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn rotate_left(&mut self, amount: u8) {
|
pub const fn rotate_left(&mut self, amount: u8) {
|
||||||
self.c = self.c.rotate_left(amount);
|
self.c = self.c.rotate_left(amount);
|
||||||
self.d = self.d.rotate_left(amount);
|
self.d = self.d.rotate_left(amount);
|
||||||
}
|
}
|
||||||
@ -22,12 +22,12 @@ impl CD56 {
|
|||||||
|
|
||||||
impl From<CD56> for Key56 {
|
impl From<CD56> for Key56 {
|
||||||
fn from(value: CD56) -> Self {
|
fn from(value: CD56) -> Self {
|
||||||
Self::from_half28(&value.c, &value.d)
|
Self::from_half28(value.c, value.d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<&CD56> for Key56 {
|
impl From<&CD56> for Key56 {
|
||||||
fn from(value: &CD56) -> Self {
|
fn from(value: &CD56) -> Self {
|
||||||
Self::from_half28(&value.c, &value.d)
|
Self::from_half28(value.c, value.d)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,7 +7,7 @@ secret_key! {
|
|||||||
|
|
||||||
impl Half28 {
|
impl Half28 {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn rotate_left(&self, amount: u8) -> Self {
|
pub const fn rotate_left(self, amount: u8) -> Self {
|
||||||
let value = self.0;
|
let value = self.0;
|
||||||
let main_shifted = (value << amount) & Self::MASK;
|
let main_shifted = (value << amount) & Self::MASK;
|
||||||
let wrapped_bits = (value >> (28 - amount)) & ((1 << amount) - 1);
|
let wrapped_bits = (value >> (28 - amount)) & ((1 << amount) - 1);
|
||||||
|
|||||||
@ -1,7 +1,4 @@
|
|||||||
use crate::{
|
use super::{cd56::CD56, half28::Half28, secret_key};
|
||||||
key::{cd56::CD56, half28::Half28},
|
|
||||||
secret_key,
|
|
||||||
};
|
|
||||||
|
|
||||||
secret_key! {
|
secret_key! {
|
||||||
/// 56-bit key after PC-1 (lower 56 bits used).
|
/// 56-bit key after PC-1 (lower 56 bits used).
|
||||||
@ -10,14 +7,14 @@ secret_key! {
|
|||||||
|
|
||||||
impl Key56 {
|
impl Key56 {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn split(&self) -> CD56 {
|
pub const fn split(self) -> CD56 {
|
||||||
let c = ((self.0 >> 28) & 0x0FFF_FFFF) as u32;
|
let c = ((self.0 >> 28) & 0x0FFF_FFFF) as u32;
|
||||||
let d = (self.0 & 0x0FFF_FFFF) as u32;
|
let d = (self.0 & 0x0FFF_FFFF) as u32;
|
||||||
CD56::new(Half28::from_u32(c), Half28::from_u32(d))
|
CD56::new(Half28::from_u32(c), Half28::from_u32(d))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn from_half28(left: &Half28, right: &Half28) -> Self {
|
pub const fn from_half28(left: Half28, right: Half28) -> Self {
|
||||||
let left = left.as_u64();
|
let left = left.as_u64();
|
||||||
let right = right.as_u64();
|
let right = right.as_u64();
|
||||||
Self::from_u64((left << 28) | right)
|
Self::from_u64((left << 28) | right)
|
||||||
|
|||||||
@ -2,9 +2,8 @@ mod cd56;
|
|||||||
mod des_key;
|
mod des_key;
|
||||||
mod half28;
|
mod half28;
|
||||||
mod key56;
|
mod key56;
|
||||||
mod secret_key;
|
|
||||||
mod subkey;
|
mod subkey;
|
||||||
mod subkeys;
|
mod subkeys;
|
||||||
|
|
||||||
use crate::secret_key;
|
use cipher_core::secret_key;
|
||||||
pub use {des_key::Key, subkey::Subkey, subkeys::Subkeys};
|
pub use {des_key::Key, subkey::Subkey, subkeys::Subkeys};
|
||||||
|
|||||||
@ -1,127 +0,0 @@
|
|||||||
/// Macro to generate a masked, zeroizable integer wrapper type.
|
|
||||||
///
|
|
||||||
/// Usage:
|
|
||||||
/// ```
|
|
||||||
/// use des::secret_key;
|
|
||||||
/// secret_key! {
|
|
||||||
/// /// docs...
|
|
||||||
/// pub struct Subkey(u64, 48, 0x0000_FFFF_FFFF_FFFFu64);
|
|
||||||
/// }
|
|
||||||
/// ```
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! secret_key {
|
|
||||||
(
|
|
||||||
$(#[$meta:meta])*
|
|
||||||
$vis:vis struct $name:ident ( $int:tt, $bits:expr, $mask:expr );
|
|
||||||
) => {
|
|
||||||
$(#[$meta])*
|
|
||||||
#[derive(::zeroize::ZeroizeOnDrop, Default)]
|
|
||||||
$vis struct $name($int);
|
|
||||||
|
|
||||||
impl $name {
|
|
||||||
/// Mask to restrict the underlying integer to valid bits.
|
|
||||||
pub const MASK: $int = $mask;
|
|
||||||
|
|
||||||
secret_key!(@conversions_as $int);
|
|
||||||
secret_key!(@conversions_from $int $int);
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ::std::fmt::Debug for $name {
|
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
|
||||||
f.write_str(concat!(stringify!($name), "[REDACTED]"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<$int> for $name {
|
|
||||||
fn from(v: $int) -> Self {
|
|
||||||
Self(v & Self::MASK)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Helper: generate conversions_as based on type
|
|
||||||
(@conversions_as u8) => {
|
|
||||||
/// Return value as u8
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u8(&self) -> u8 {
|
|
||||||
self.0 as u8
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_as u16);
|
|
||||||
};
|
|
||||||
(@conversions_as u16) => {
|
|
||||||
/// Return value as u16
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u16(&self) -> u16 {
|
|
||||||
self.0 as u16
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_as u32);
|
|
||||||
};
|
|
||||||
(@conversions_as u32) => {
|
|
||||||
/// Return value as u32
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u32(&self) -> u32 {
|
|
||||||
self.0 as u32
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_as u64);
|
|
||||||
};
|
|
||||||
(@conversions_as u64) => {
|
|
||||||
/// Return value as u64
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn as_u64(&self) -> u64 {
|
|
||||||
self.0 as u64
|
|
||||||
}
|
|
||||||
};
|
|
||||||
// Helper: generate conversions_from based on type
|
|
||||||
(@conversions_from u8 $int:tt) => {
|
|
||||||
/// Create value from u8
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u8(key: u8) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
(@conversions_from u16 $int:tt) => {
|
|
||||||
/// Create value from u16
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u16(key: u16) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_from u8 $int);
|
|
||||||
};
|
|
||||||
(@conversions_from u32 $int:tt) => {
|
|
||||||
/// Create value from u32
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u32(key: u32) -> Self {
|
|
||||||
Self(key as $int & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_from u16 $int);
|
|
||||||
};
|
|
||||||
(@conversions_from u64 $int:tt) => {
|
|
||||||
/// Create value from u64
|
|
||||||
#[allow(dead_code)]
|
|
||||||
#[inline]
|
|
||||||
#[must_use]
|
|
||||||
pub const fn from_u64(key: u64) -> Self {
|
|
||||||
Self(key & Self::MASK)
|
|
||||||
}
|
|
||||||
|
|
||||||
secret_key!(@conversions_from u32 $int);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user