Coverage Report

Created: 2026-02-26 06:40

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/rust/registry/src/index.crates.io-1949cf8c6b5b557f/base64ct-1.8.3/src/alphabet.rs
Line
Count
Source
1
//! Base64 alphabets.
2
3
// TODO(tarcieri): explicitly checked/wrapped arithmetic
4
#![allow(clippy::arithmetic_side_effects)]
5
6
use core::{fmt::Debug, ops::RangeInclusive};
7
8
pub mod bcrypt;
9
pub mod crypt;
10
pub mod pbkdf2;
11
pub mod shacrypt;
12
pub mod standard;
13
pub mod url;
14
15
/// Core encoder/decoder functions for a particular Base64 alphabet.
16
pub trait Alphabet: 'static + Copy + Debug + Eq + Send + Sized + Sync {
17
    /// First character in this Base64 alphabet.
18
    const BASE: u8;
19
20
    /// Decoder passes
21
    const DECODER: &'static [DecodeStep];
22
23
    /// Encoder passes
24
    const ENCODER: &'static [EncodeStep];
25
26
    /// Is this encoding padded?
27
    const PADDED: bool;
28
29
    /// Unpadded equivalent of this alphabet.
30
    ///
31
    /// For alphabets that are unpadded to begin with, this should be `Self`.
32
    type Unpadded: Alphabet;
33
34
    /// Decode 3 bytes of a Base64 message.
35
    #[inline(always)]
36
0
    fn decode_3bytes(src: &[u8], dst: &mut [u8]) -> i16 {
37
0
        debug_assert_eq!(src.len(), 4);
38
0
        debug_assert!(dst.len() >= 3, "dst too short: {}", dst.len());
39
40
0
        let c0 = Self::decode_6bits(src[0]);
41
0
        let c1 = Self::decode_6bits(src[1]);
42
0
        let c2 = Self::decode_6bits(src[2]);
43
0
        let c3 = Self::decode_6bits(src[3]);
44
45
0
        dst[0] = ((c0 << 2) | (c1 >> 4)) as u8;
46
0
        dst[1] = ((c1 << 4) | (c2 >> 2)) as u8;
47
0
        dst[2] = ((c2 << 6) | c3) as u8;
48
49
0
        ((c0 | c1 | c2 | c3) >> 8) & 1
50
0
    }
Unexecuted instantiation: <base64ct::alphabet::crypt::Base64Crypt as base64ct::alphabet::Alphabet>::decode_3bytes
Unexecuted instantiation: <base64ct::alphabet::bcrypt::Base64Bcrypt as base64ct::alphabet::Alphabet>::decode_3bytes
Unexecuted instantiation: <base64ct::alphabet::standard::Base64Unpadded as base64ct::alphabet::Alphabet>::decode_3bytes
Unexecuted instantiation: <_ as base64ct::alphabet::Alphabet>::decode_3bytes
51
52
    /// Decode 6-bits of a Base64 message.
53
0
    fn decode_6bits(src: u8) -> i16 {
54
0
        let mut ret: i16 = -1;
55
56
0
        for step in Self::DECODER {
57
0
            ret += match step {
58
0
                DecodeStep::Range(range, offset) => {
59
                    // Compute exclusive range from inclusive one
60
0
                    let start = *range.start() as i16 - 1;
61
0
                    let end = *range.end() as i16 + 1;
62
0
                    (((start - src as i16) & (src as i16 - end)) >> 8) & (src as i16 + *offset)
63
                }
64
0
                DecodeStep::Eq(value, offset) => {
65
0
                    let start = *value as i16 - 1;
66
0
                    let end = *value as i16 + 1;
67
0
                    (((start - src as i16) & (src as i16 - end)) >> 8) & *offset
68
                }
69
            };
70
        }
71
72
0
        ret
73
0
    }
Unexecuted instantiation: <base64ct::alphabet::crypt::Base64Crypt as base64ct::alphabet::Alphabet>::decode_6bits
Unexecuted instantiation: <base64ct::alphabet::bcrypt::Base64Bcrypt as base64ct::alphabet::Alphabet>::decode_6bits
Unexecuted instantiation: <base64ct::alphabet::standard::Base64Unpadded as base64ct::alphabet::Alphabet>::decode_6bits
Unexecuted instantiation: <_ as base64ct::alphabet::Alphabet>::decode_6bits
74
75
    /// Encode 3-bytes of a Base64 message.
76
    #[inline(always)]
77
0
    fn encode_3bytes(src: &[u8], dst: &mut [u8]) {
78
0
        debug_assert_eq!(src.len(), 3);
79
0
        debug_assert!(dst.len() >= 4, "dst too short: {}", dst.len());
80
81
0
        let b0 = src[0] as i16;
82
0
        let b1 = src[1] as i16;
83
0
        let b2 = src[2] as i16;
84
85
0
        dst[0] = Self::encode_6bits(b0 >> 2);
86
0
        dst[1] = Self::encode_6bits(((b0 << 4) | (b1 >> 4)) & 63);
87
0
        dst[2] = Self::encode_6bits(((b1 << 2) | (b2 >> 6)) & 63);
88
0
        dst[3] = Self::encode_6bits(b2 & 63);
89
0
    }
Unexecuted instantiation: <base64ct::alphabet::crypt::Base64Crypt as base64ct::alphabet::Alphabet>::encode_3bytes
Unexecuted instantiation: <base64ct::alphabet::bcrypt::Base64Bcrypt as base64ct::alphabet::Alphabet>::encode_3bytes
Unexecuted instantiation: <base64ct::alphabet::standard::Base64Unpadded as base64ct::alphabet::Alphabet>::encode_3bytes
Unexecuted instantiation: <_ as base64ct::alphabet::Alphabet>::encode_3bytes
90
91
    /// Encode 6-bits of a Base64 message.
92
    #[inline(always)]
93
0
    fn encode_6bits(src: i16) -> u8 {
94
0
        let mut diff = src + Self::BASE as i16;
95
96
0
        for &step in Self::ENCODER {
97
0
            diff += match step {
98
0
                EncodeStep::Apply(threshold, offset) => ((threshold as i16 - diff) >> 8) & offset,
99
0
                EncodeStep::Diff(threshold, offset) => ((threshold as i16 - src) >> 8) & offset,
100
            };
101
        }
102
103
0
        diff as u8
104
0
    }
Unexecuted instantiation: <base64ct::alphabet::crypt::Base64Crypt as base64ct::alphabet::Alphabet>::encode_6bits
Unexecuted instantiation: <base64ct::alphabet::bcrypt::Base64Bcrypt as base64ct::alphabet::Alphabet>::encode_6bits
Unexecuted instantiation: <base64ct::alphabet::standard::Base64Unpadded as base64ct::alphabet::Alphabet>::encode_6bits
Unexecuted instantiation: <_ as base64ct::alphabet::Alphabet>::encode_6bits
105
}
106
107
/// Constant-time decoder step.
108
#[derive(Debug)]
109
pub enum DecodeStep {
110
    /// Match the given range, offsetting the input on match.
111
    Range(RangeInclusive<u8>, i16),
112
113
    /// Match the given value, returning the associated offset on match.
114
    Eq(u8, i16),
115
}
116
117
/// Constant-time encoder step.
118
#[derive(Copy, Clone, Debug)]
119
pub enum EncodeStep {
120
    /// Apply the given offset to the cumulative result on match.
121
    Apply(u8, i16),
122
123
    /// Compute a difference using the given offset on match.
124
    Diff(u8, i16),
125
}