Skip to content
Permalink
Browse files Browse the repository at this point in the history
fix
  • Loading branch information
dingelish committed Jan 18, 2021
1 parent b4fc913 commit a554b7a
Show file tree
Hide file tree
Showing 4 changed files with 91 additions and 6 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Expand Up @@ -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`
Expand Down
36 changes: 36 additions & 0 deletions src/decode.rs
Expand Up @@ -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.
///
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down
12 changes: 6 additions & 6 deletions src/lib.rs
Expand Up @@ -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,
}
}
}
Expand Down
48 changes: 48 additions & 0 deletions 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] = &[
Expand Down Expand Up @@ -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);
}

0 comments on commit a554b7a

Please sign in to comment.