summaryrefslogtreecommitdiffstats
path: root/vendor/base64ct/src/alphabet.rs
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/base64ct/src/alphabet.rs')
-rw-r--r--vendor/base64ct/src/alphabet.rs124
1 files changed, 124 insertions, 0 deletions
diff --git a/vendor/base64ct/src/alphabet.rs b/vendor/base64ct/src/alphabet.rs
new file mode 100644
index 000000000..d888e72e7
--- /dev/null
+++ b/vendor/base64ct/src/alphabet.rs
@@ -0,0 +1,124 @@
+//! Base64 alphabets.
+
+// TODO(tarcieri): explicitly checked/wrapped arithmetic
+#![allow(clippy::integer_arithmetic)]
+
+use core::{fmt::Debug, ops::RangeInclusive};
+
+pub mod bcrypt;
+pub mod crypt;
+pub mod shacrypt;
+pub mod standard;
+pub mod url;
+
+/// Core encoder/decoder functions for a particular Base64 alphabet.
+pub trait Alphabet: 'static + Copy + Debug + Eq + Send + Sized + Sync {
+ /// First character in this Base64 alphabet.
+ const BASE: u8;
+
+ /// Decoder passes
+ const DECODER: &'static [DecodeStep];
+
+ /// Encoder passes
+ const ENCODER: &'static [EncodeStep];
+
+ /// Is this encoding padded?
+ const PADDED: bool;
+
+ /// Unpadded equivalent of this alphabet.
+ ///
+ /// For alphabets that are unpadded to begin with, this should be `Self`.
+ type Unpadded: Alphabet;
+
+ /// Decode 3 bytes of a Base64 message.
+ #[inline(always)]
+ fn decode_3bytes(src: &[u8], dst: &mut [u8]) -> i16 {
+ debug_assert_eq!(src.len(), 4);
+ debug_assert!(dst.len() >= 3, "dst too short: {}", dst.len());
+
+ let c0 = Self::decode_6bits(src[0]);
+ let c1 = Self::decode_6bits(src[1]);
+ let c2 = Self::decode_6bits(src[2]);
+ let c3 = Self::decode_6bits(src[3]);
+
+ dst[0] = ((c0 << 2) | (c1 >> 4)) as u8;
+ dst[1] = ((c1 << 4) | (c2 >> 2)) as u8;
+ dst[2] = ((c2 << 6) | c3) as u8;
+
+ ((c0 | c1 | c2 | c3) >> 8) & 1
+ }
+
+ /// Decode 6-bits of a Base64 message.
+ fn decode_6bits(src: u8) -> i16 {
+ let mut ret: i16 = -1;
+
+ for step in Self::DECODER {
+ ret += match step {
+ DecodeStep::Range(range, offset) => {
+ // Compute exclusive range from inclusive one
+ let start = *range.start() as i16 - 1;
+ let end = *range.end() as i16 + 1;
+ (((start - src as i16) & (src as i16 - end)) >> 8) & (src as i16 + *offset)
+ }
+ DecodeStep::Eq(value, offset) => {
+ let start = *value as i16 - 1;
+ let end = *value as i16 + 1;
+ (((start - src as i16) & (src as i16 - end)) >> 8) & *offset
+ }
+ };
+ }
+
+ ret
+ }
+
+ /// Encode 3-bytes of a Base64 message.
+ #[inline(always)]
+ fn encode_3bytes(src: &[u8], dst: &mut [u8]) {
+ debug_assert_eq!(src.len(), 3);
+ debug_assert!(dst.len() >= 4, "dst too short: {}", dst.len());
+
+ let b0 = src[0] as i16;
+ let b1 = src[1] as i16;
+ let b2 = src[2] as i16;
+
+ dst[0] = Self::encode_6bits(b0 >> 2);
+ dst[1] = Self::encode_6bits(((b0 << 4) | (b1 >> 4)) & 63);
+ dst[2] = Self::encode_6bits(((b1 << 2) | (b2 >> 6)) & 63);
+ dst[3] = Self::encode_6bits(b2 & 63);
+ }
+
+ /// Encode 6-bits of a Base64 message.
+ #[inline(always)]
+ fn encode_6bits(src: i16) -> u8 {
+ let mut diff = src + Self::BASE as i16;
+
+ for &step in Self::ENCODER {
+ diff += match step {
+ EncodeStep::Apply(threshold, offset) => ((threshold as i16 - diff) >> 8) & offset,
+ EncodeStep::Diff(threshold, offset) => ((threshold as i16 - src) >> 8) & offset,
+ };
+ }
+
+ diff as u8
+ }
+}
+
+/// Constant-time decoder step.
+#[derive(Debug)]
+pub enum DecodeStep {
+ /// Match the given range, offsetting the input on match.
+ Range(RangeInclusive<u8>, i16),
+
+ /// Match the given value, returning the associated offset on match.
+ Eq(u8, i16),
+}
+
+/// Constant-time encoder step.
+#[derive(Copy, Clone, Debug)]
+pub enum EncodeStep {
+ /// Apply the given offset to the cumulative result on match.
+ Apply(u8, i16),
+
+ /// Compute a difference using the given offset on match.
+ Diff(u8, i16),
+}