From a554b7ae880553db6dde8a387101a093911d5b2a Mon Sep 17 00:00:00 2001 From: Yu Ding Date: Sun, 17 Jan 2021 22:29:18 -0800 Subject: [PATCH 1/2] fix --- Cargo.toml | 1 + src/decode.rs | 36 ++++++++++++++++++++++++++++++++++++ src/lib.rs | 12 ++++++------ src/tables.rs | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 91 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 30e73eec..4b4385c3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -25,6 +25,7 @@ structopt = "0.3" default = ["std"] alloc = [] std = [] +slow_but_safe = [] [profile.bench] # Useful for better disassembly when using `perf record` and `perf annotate` diff --git a/src/decode.rs b/src/decode.rs index 4cc937d5..2762c4cf 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -444,6 +444,18 @@ fn write_u64(output: &mut [u8], value: u64) { output[..8].copy_from_slice(&value.to_be_bytes()); } +#[cfg(feature = "slow_but_safe")] +fn decode_aligned(b64ch: u8, decode_table: &[u8; 256]) -> u8 { + let mut result: u8 = 0x00; + let mut mask: u8; + let idx: [u8;2] = [ b64ch % 64, b64ch % 64 + 64]; + for i in 0..2 { + mask = 0xFF ^ (((idx[i] == b64ch) as i8 - 1) as u8); + result = result | (decode_table[idx[i] as usize] & mask); + } + result +} + /// Decode 8 bytes of input into 6 bytes of output. 8 bytes of output will be written, but only the /// first 6 of those contain meaningful data. /// @@ -463,13 +475,19 @@ fn decode_chunk( ) -> Result<(), DecodeError> { let mut accum: u64; + #[cfg(not(feature = "slow_but_safe"))] let morsel = decode_table[input[0] as usize]; + #[cfg(feature = "slow_but_safe")] + let morsel = decode_aligned(input[0], decode_table); if morsel == tables::INVALID_VALUE { return Err(DecodeError::InvalidByte(index_at_start_of_input, input[0])); } accum = (morsel as u64) << 58; + #[cfg(not(feature = "slow_but_safe"))] let morsel = decode_table[input[1] as usize]; + #[cfg(feature = "slow_but_safe")] + let morsel = decode_aligned(input[1], decode_table); if morsel == tables::INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 1, @@ -478,7 +496,10 @@ fn decode_chunk( } accum |= (morsel as u64) << 52; + #[cfg(not(feature = "slow_but_safe"))] let morsel = decode_table[input[2] as usize]; + #[cfg(feature = "slow_but_safe")] + let morsel = decode_aligned(input[2], decode_table); if morsel == tables::INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 2, @@ -487,7 +508,10 @@ fn decode_chunk( } accum |= (morsel as u64) << 46; + #[cfg(not(feature = "slow_but_safe"))] let morsel = decode_table[input[3] as usize]; + #[cfg(feature = "slow_but_safe")] + let morsel = decode_aligned(input[3], decode_table); if morsel == tables::INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 3, @@ -496,7 +520,10 @@ fn decode_chunk( } accum |= (morsel as u64) << 40; + #[cfg(not(feature = "slow_but_safe"))] let morsel = decode_table[input[4] as usize]; + #[cfg(feature = "slow_but_safe")] + let morsel = decode_aligned(input[4], decode_table); if morsel == tables::INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 4, @@ -505,7 +532,10 @@ fn decode_chunk( } accum |= (morsel as u64) << 34; + #[cfg(not(feature = "slow_but_safe"))] let morsel = decode_table[input[5] as usize]; + #[cfg(feature = "slow_but_safe")] + let morsel = decode_aligned(input[5], decode_table); if morsel == tables::INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 5, @@ -514,7 +544,10 @@ fn decode_chunk( } accum |= (morsel as u64) << 28; + #[cfg(not(feature = "slow_but_safe"))] let morsel = decode_table[input[6] as usize]; + #[cfg(feature = "slow_but_safe")] + let morsel = decode_aligned(input[6], decode_table); if morsel == tables::INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 6, @@ -523,7 +556,10 @@ fn decode_chunk( } accum |= (morsel as u64) << 22; + #[cfg(not(feature = "slow_but_safe"))] let morsel = decode_table[input[7] as usize]; + #[cfg(feature = "slow_but_safe")] + let morsel = decode_aligned(input[7], decode_table); if morsel == tables::INVALID_VALUE { return Err(DecodeError::InvalidByte( index_at_start_of_input + 7, diff --git a/src/lib.rs b/src/lib.rs index 6bded160..dbc55a3c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -138,12 +138,12 @@ impl CharacterSet { fn decode_table(self) -> &'static [u8; 256] { match self { - CharacterSet::Standard => tables::STANDARD_DECODE, - CharacterSet::UrlSafe => tables::URL_SAFE_DECODE, - CharacterSet::Crypt => tables::CRYPT_DECODE, - CharacterSet::Bcrypt => tables::BCRYPT_DECODE, - CharacterSet::ImapMutf7 => tables::IMAP_MUTF7_DECODE, - CharacterSet::BinHex => tables::BINHEX_DECODE, + CharacterSet::Standard => &tables::STANDARD_DECODE_HOLDER.data, + CharacterSet::UrlSafe => &tables::URL_SAFE_DECODE_HOLDER.data, + CharacterSet::Crypt => &tables::CRYPT_DECODE_HOLDER.data, + CharacterSet::Bcrypt => &tables::BCRYPT_DECODE_HOLDER.data, + CharacterSet::ImapMutf7 => &tables::IMAP_MUTF7_DECODE_HOLDER.data, + CharacterSet::BinHex => &tables::BINHEX_DECODE_HOLDER.data, } } } diff --git a/src/tables.rs b/src/tables.rs index a45851cd..7921bcd6 100644 --- a/src/tables.rs +++ b/src/tables.rs @@ -1,3 +1,35 @@ +//#[repr(align(64))] +//pub struct StructStandardEncode { pub data: [u8; 64] } +#[repr(align(64))] +pub struct StructStandardDecode { pub data: [u8; 256] } +//#[repr(align(64))] +//pub struct StructUrlSafeEncode { pub data: [u8; 64] } +#[repr(align(64))] +pub struct StructUrlSafeDecode { pub data: [u8; 256] } +//#[repr(align(64))] +//pub struct StructCryptEncode { pub data: [u8; 64] } +#[repr(align(64))] +pub struct StructCryptDecode { pub data: [u8; 256] } +//#[repr(align(64))] +//pub struct StructBcryptEncode { pub data: [u8; 64] } +#[repr(align(64))] +pub struct StructBcryptDecode { pub data: [u8; 256] } +//#[repr(align(64))] +//pub struct StructImapMutf7Encode { pub data: [u8; 64] } +#[repr(align(64))] +pub struct StructImapMutf7Decode { pub data: [u8; 256] } +//#[repr(align(64))] +//pub struct StructBinhexEncode { pub data: [u8; 64] } +#[repr(align(64))] +pub struct StructBinhexDecode { pub data: [u8; 256] } + +pub const STANDARD_DECODE_HOLDER: StructStandardDecode = StructStandardDecode { data: *STANDARD_DECODE }; +pub const URL_SAFE_DECODE_HOLDER: StructUrlSafeDecode = StructUrlSafeDecode { data: *URL_SAFE_DECODE }; +pub const CRYPT_DECODE_HOLDER: StructCryptDecode = StructCryptDecode { data: *CRYPT_DECODE }; +pub const BCRYPT_DECODE_HOLDER: StructBcryptDecode = StructBcryptDecode { data: *BCRYPT_DECODE }; +pub const IMAP_MUTF7_DECODE_HOLDER: StructImapMutf7Decode = StructImapMutf7Decode { data: *IMAP_MUTF7_DECODE }; +pub const BINHEX_DECODE_HOLDER: StructBinhexDecode = StructBinhexDecode { data: *BINHEX_DECODE }; + pub const INVALID_VALUE: u8 = 255; #[rustfmt::skip] pub const STANDARD_ENCODE: &[u8; 64] = &[ @@ -1955,3 +1987,19 @@ pub const BINHEX_DECODE: &[u8; 256] = &[ INVALID_VALUE, // input 254 (0xFE) INVALID_VALUE, // input 255 (0xFF) ]; + +#[test] +fn alignment_check() { + let p: *const u8 = STANDARD_DECODE_HOLDER.data.as_ptr(); + assert_eq!((p as u64) % 64, 0); + let p: *const u8 = URL_SAFE_DECODE_HOLDER.data.as_ptr(); + assert_eq!((p as u64) % 64, 0); + let p: *const u8 = CRYPT_DECODE_HOLDER.data.as_ptr(); + assert_eq!((p as u64) % 64, 0); + let p: *const u8 = BCRYPT_DECODE_HOLDER.data.as_ptr(); + assert_eq!((p as u64) % 64, 0); + let p: *const u8 = IMAP_MUTF7_DECODE_HOLDER.data.as_ptr(); + assert_eq!((p as u64) % 64, 0); + let p: *const u8 = BINHEX_DECODE_HOLDER.data.as_ptr(); + assert_eq!((p as u64) % 64, 0); +} From 48e6225ac1fb55b086bdb12e60df8bb86b9439e4 Mon Sep 17 00:00:00 2001 From: Yu Ding Date: Mon, 1 Feb 2021 11:16:39 -0800 Subject: [PATCH 2/2] Remove unnecessary types --- src/tables.rs | 50 +++++++++++++++++++++----------------------------- 1 file changed, 21 insertions(+), 29 deletions(-) diff --git a/src/tables.rs b/src/tables.rs index 7921bcd6..4632c3c2 100644 --- a/src/tables.rs +++ b/src/tables.rs @@ -1,34 +1,26 @@ -//#[repr(align(64))] -//pub struct StructStandardEncode { pub data: [u8; 64] } #[repr(align(64))] -pub struct StructStandardDecode { pub data: [u8; 256] } -//#[repr(align(64))] -//pub struct StructUrlSafeEncode { pub data: [u8; 64] } -#[repr(align(64))] -pub struct StructUrlSafeDecode { pub data: [u8; 256] } -//#[repr(align(64))] -//pub struct StructCryptEncode { pub data: [u8; 64] } -#[repr(align(64))] -pub struct StructCryptDecode { pub data: [u8; 256] } -//#[repr(align(64))] -//pub struct StructBcryptEncode { pub data: [u8; 64] } -#[repr(align(64))] -pub struct StructBcryptDecode { pub data: [u8; 256] } -//#[repr(align(64))] -//pub struct StructImapMutf7Encode { pub data: [u8; 64] } -#[repr(align(64))] -pub struct StructImapMutf7Decode { pub data: [u8; 256] } -//#[repr(align(64))] -//pub struct StructBinhexEncode { pub data: [u8; 64] } -#[repr(align(64))] -pub struct StructBinhexDecode { pub data: [u8; 256] } +pub struct DecodeTableHolder { + pub data: [u8; 256], +} -pub const STANDARD_DECODE_HOLDER: StructStandardDecode = StructStandardDecode { data: *STANDARD_DECODE }; -pub const URL_SAFE_DECODE_HOLDER: StructUrlSafeDecode = StructUrlSafeDecode { data: *URL_SAFE_DECODE }; -pub const CRYPT_DECODE_HOLDER: StructCryptDecode = StructCryptDecode { data: *CRYPT_DECODE }; -pub const BCRYPT_DECODE_HOLDER: StructBcryptDecode = StructBcryptDecode { data: *BCRYPT_DECODE }; -pub const IMAP_MUTF7_DECODE_HOLDER: StructImapMutf7Decode = StructImapMutf7Decode { data: *IMAP_MUTF7_DECODE }; -pub const BINHEX_DECODE_HOLDER: StructBinhexDecode = StructBinhexDecode { data: *BINHEX_DECODE }; +pub const STANDARD_DECODE_HOLDER: DecodeTableHolder = DecodeTableHolder { + data: *STANDARD_DECODE, +}; +pub const URL_SAFE_DECODE_HOLDER: DecodeTableHolder = DecodeTableHolder { + data: *URL_SAFE_DECODE, +}; +pub const CRYPT_DECODE_HOLDER: DecodeTableHolder = DecodeTableHolder { + data: *CRYPT_DECODE, +}; +pub const BCRYPT_DECODE_HOLDER: DecodeTableHolder = DecodeTableHolder { + data: *BCRYPT_DECODE, +}; +pub const IMAP_MUTF7_DECODE_HOLDER: DecodeTableHolder = DecodeTableHolder { + data: *IMAP_MUTF7_DECODE, +}; +pub const BINHEX_DECODE_HOLDER: DecodeTableHolder = DecodeTableHolder { + data: *BINHEX_DECODE, +}; pub const INVALID_VALUE: u8 = 255; #[rustfmt::skip]