1#![cfg_attr(not(feature = "std"), no_std)]
2#![deny(unsafe_code)]
3#![deny(missing_docs)]
4#![deny(clippy::all)]
5#![deny(clippy::pedantic)]
6#![allow(clippy::missing_errors_doc)]
7
8#[cfg(feature = "alloc")]
47extern crate alloc;
48
49#[cfg(feature = "simd")]
50mod simd;
51
52pub mod runtime {
58 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
60 #[non_exhaustive]
61 pub enum Backend {
62 Scalar,
64 Avx512Vbmi,
66 Avx2,
68 Ssse3Sse41,
70 Neon,
72 WasmSimd128,
74 }
75
76 impl Backend {
77 #[must_use]
83 pub const fn as_str(self) -> &'static str {
84 match self {
85 Self::Scalar => "scalar",
86 Self::Avx512Vbmi => "avx512-vbmi",
87 Self::Avx2 => "avx2",
88 Self::Ssse3Sse41 => "ssse3-sse4.1",
89 Self::Neon => "neon",
90 Self::WasmSimd128 => "wasm-simd128",
91 }
92 }
93
94 #[must_use]
107 pub const fn required_cpu_features(self) -> &'static [&'static str] {
108 match self {
109 Self::Scalar => &[],
110 Self::Avx512Vbmi => &["avx512f", "avx512bw", "avx512vl", "avx512vbmi"],
111 Self::Avx2 => &["avx2"],
112 Self::Ssse3Sse41 => &["ssse3", "sse4.1"],
113 Self::Neon => &["neon"],
114 Self::WasmSimd128 => &["simd128"],
115 }
116 }
117 }
118
119 impl core::fmt::Display for Backend {
120 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
121 formatter.write_str(self.as_str())
122 }
123 }
124
125 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
127 #[non_exhaustive]
128 pub enum SecurityPosture {
129 ScalarOnly,
131 SimdCandidateScalarActive,
133 Accelerated,
135 }
136
137 impl SecurityPosture {
138 #[must_use]
147 pub const fn as_str(self) -> &'static str {
148 match self {
149 Self::ScalarOnly => "scalar-only",
150 Self::SimdCandidateScalarActive => "simd-candidate-scalar-active",
151 Self::Accelerated => "accelerated",
152 }
153 }
154 }
155
156 impl core::fmt::Display for SecurityPosture {
157 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
158 formatter.write_str(self.as_str())
159 }
160 }
161
162 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
164 #[non_exhaustive]
165 pub enum BackendPolicy {
166 ScalarExecutionOnly,
168 SimdFeatureDisabled,
170 NoDetectedSimdCandidate,
172 HighAssuranceScalarOnly,
175 }
176
177 impl BackendPolicy {
178 #[must_use]
187 pub const fn as_str(self) -> &'static str {
188 match self {
189 Self::ScalarExecutionOnly => "scalar-execution-only",
190 Self::SimdFeatureDisabled => "simd-feature-disabled",
191 Self::NoDetectedSimdCandidate => "no-detected-simd-candidate",
192 Self::HighAssuranceScalarOnly => "high-assurance-scalar-only",
193 }
194 }
195 }
196
197 impl core::fmt::Display for BackendPolicy {
198 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
199 formatter.write_str(self.as_str())
200 }
201 }
202
203 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
205 pub struct BackendPolicyError {
206 pub policy: BackendPolicy,
208 pub report: BackendReport,
210 }
211
212 impl core::fmt::Display for BackendPolicyError {
213 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
214 write!(
215 formatter,
216 "runtime backend policy `{}` was not satisfied ({})",
217 self.policy, self.report,
218 )
219 }
220 }
221
222 #[cfg(feature = "std")]
223 impl std::error::Error for BackendPolicyError {}
224
225 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
227 pub struct BackendReport {
228 pub active: Backend,
230 pub candidate: Backend,
232 pub simd_feature_enabled: bool,
234 pub accelerated_backend_active: bool,
236 pub unsafe_boundary_enforced: bool,
238 pub security_posture: SecurityPosture,
240 }
241
242 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
244 pub struct BackendSnapshot {
245 pub active: &'static str,
247 pub candidate: &'static str,
249 pub candidate_required_cpu_features: &'static [&'static str],
251 pub simd_feature_enabled: bool,
253 pub accelerated_backend_active: bool,
255 pub unsafe_boundary_enforced: bool,
257 pub security_posture: &'static str,
259 }
260
261 impl core::fmt::Display for BackendReport {
262 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
263 write!(
264 formatter,
265 "active={} candidate={} candidate_required_cpu_features=",
266 self.active, self.candidate,
267 )?;
268 write_feature_list(formatter, self.candidate_required_cpu_features())?;
269 write!(
270 formatter,
271 " simd_feature_enabled={} accelerated_backend_active={} unsafe_boundary_enforced={} security_posture={}",
272 self.simd_feature_enabled,
273 self.accelerated_backend_active,
274 self.unsafe_boundary_enforced,
275 self.security_posture,
276 )
277 }
278 }
279
280 impl BackendReport {
281 #[must_use]
291 pub const fn satisfies(self, policy: BackendPolicy) -> bool {
292 match policy {
293 BackendPolicy::ScalarExecutionOnly => {
294 matches!(self.active, Backend::Scalar) && !self.accelerated_backend_active
295 }
296 BackendPolicy::SimdFeatureDisabled => !self.simd_feature_enabled,
297 BackendPolicy::NoDetectedSimdCandidate => matches!(self.candidate, Backend::Scalar),
298 BackendPolicy::HighAssuranceScalarOnly => {
299 matches!(self.active, Backend::Scalar)
300 && matches!(self.candidate, Backend::Scalar)
301 && !self.simd_feature_enabled
302 && !self.accelerated_backend_active
303 && self.unsafe_boundary_enforced
304 }
305 }
306 }
307
308 #[must_use]
319 pub const fn candidate_required_cpu_features(self) -> &'static [&'static str] {
320 self.candidate.required_cpu_features()
321 }
322
323 #[must_use]
332 pub const fn snapshot(self) -> BackendSnapshot {
333 BackendSnapshot {
334 active: self.active.as_str(),
335 candidate: self.candidate.as_str(),
336 candidate_required_cpu_features: self.candidate_required_cpu_features(),
337 simd_feature_enabled: self.simd_feature_enabled,
338 accelerated_backend_active: self.accelerated_backend_active,
339 unsafe_boundary_enforced: self.unsafe_boundary_enforced,
340 security_posture: self.security_posture.as_str(),
341 }
342 }
343 }
344
345 #[must_use]
354 pub fn backend_report() -> BackendReport {
355 let active = active_backend();
356 let candidate = detected_candidate();
357 let accelerated_backend_active = active != Backend::Scalar;
358 let security_posture = if accelerated_backend_active {
359 SecurityPosture::Accelerated
360 } else if candidate != Backend::Scalar {
361 SecurityPosture::SimdCandidateScalarActive
362 } else {
363 SecurityPosture::ScalarOnly
364 };
365
366 BackendReport {
367 active,
368 candidate,
369 simd_feature_enabled: cfg!(feature = "simd"),
370 accelerated_backend_active,
371 unsafe_boundary_enforced: true,
372 security_posture,
373 }
374 }
375
376 pub fn require_backend_policy(policy: BackendPolicy) -> Result<(), BackendPolicyError> {
385 let report = backend_report();
386 if report.satisfies(policy) {
387 Ok(())
388 } else {
389 Err(BackendPolicyError { policy, report })
390 }
391 }
392
393 fn write_feature_list(
394 formatter: &mut core::fmt::Formatter<'_>,
395 features: &[&str],
396 ) -> core::fmt::Result {
397 formatter.write_str("[")?;
398 let mut index = 0;
399 while index < features.len() {
400 if index != 0 {
401 formatter.write_str(",")?;
402 }
403 formatter.write_str(features[index])?;
404 index += 1;
405 }
406 formatter.write_str("]")
407 }
408
409 #[cfg(feature = "simd")]
410 fn active_backend() -> Backend {
411 match super::simd::active_backend() {
412 super::simd::ActiveBackend::Scalar => Backend::Scalar,
413 }
414 }
415
416 #[cfg(not(feature = "simd"))]
417 const fn active_backend() -> Backend {
418 Backend::Scalar
419 }
420
421 #[cfg(feature = "simd")]
422 fn detected_candidate() -> Backend {
423 match super::simd::detected_candidate() {
424 super::simd::Candidate::Scalar => Backend::Scalar,
425 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
426 super::simd::Candidate::Avx512Vbmi => Backend::Avx512Vbmi,
427 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
428 super::simd::Candidate::Avx2 => Backend::Avx2,
429 #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
430 super::simd::Candidate::Ssse3Sse41 => Backend::Ssse3Sse41,
431 #[cfg(any(target_arch = "aarch64", target_arch = "arm"))]
432 super::simd::Candidate::Neon => Backend::Neon,
433 #[cfg(target_arch = "wasm32")]
434 super::simd::Candidate::WasmSimd128 => Backend::WasmSimd128,
435 }
436 }
437
438 #[cfg(not(feature = "simd"))]
439 const fn detected_candidate() -> Backend {
440 Backend::Scalar
441 }
442}
443
444#[cfg(feature = "stream")]
445pub mod stream {
446 use super::{Alphabet, DecodeError, EncodeError, Engine};
481 use std::io::{self, Read, Write};
482
483 struct OutputQueue<const CAP: usize> {
484 buffer: [u8; CAP],
485 start: usize,
486 len: usize,
487 }
488
489 impl<const CAP: usize> OutputQueue<CAP> {
490 const fn new() -> Self {
491 Self {
492 buffer: [0; CAP],
493 start: 0,
494 len: 0,
495 }
496 }
497
498 const fn is_empty(&self) -> bool {
499 self.len == 0
500 }
501
502 const fn len(&self) -> usize {
503 self.len
504 }
505
506 const fn capacity(&self) -> usize {
507 self.len + self.available_capacity()
508 }
509
510 fn push_slice(&mut self, input: &[u8]) -> io::Result<()> {
511 if input.len() > self.available_capacity() {
512 return Err(io::Error::other(
513 "base64 stream output queue capacity exceeded",
514 ));
515 }
516
517 let mut read = 0;
518 while read < input.len() {
519 let write = (self.start + self.len) % CAP;
520 self.buffer[write] = input[read];
521 self.len += 1;
522 read += 1;
523 }
524
525 Ok(())
526 }
527
528 fn copy_front(&self, output: &mut [u8]) -> usize {
529 let count = core::cmp::min(self.len, output.len());
530 let first = core::cmp::min(count, CAP - self.start);
531 output[..first].copy_from_slice(&self.buffer[self.start..self.start + first]);
532
533 let second = count - first;
534 if second > 0 {
535 output[first..first + second].copy_from_slice(&self.buffer[..second]);
536 }
537
538 count
539 }
540
541 fn discard_front(&mut self, count: usize) {
542 let count = core::cmp::min(count, self.len);
543 let first = core::cmp::min(count, CAP - self.start);
544 crate::wipe_bytes(&mut self.buffer[self.start..self.start + first]);
545
546 let second = count - first;
547 if second > 0 {
548 crate::wipe_bytes(&mut self.buffer[..second]);
549 }
550
551 self.start = (self.start + count) % CAP;
552 self.len -= count;
553 if self.len == 0 {
554 self.start = 0;
555 }
556 }
557
558 fn pop_slice(&mut self, output: &mut [u8]) -> usize {
559 let count = self.copy_front(output);
560 self.discard_front(count);
561 count
562 }
563
564 fn clear_all(&mut self) {
565 crate::wipe_bytes(&mut self.buffer);
566 self.start = 0;
567 self.len = 0;
568 }
569
570 const fn available_capacity(&self) -> usize {
571 CAP - self.len
572 }
573 }
574
575 pub struct Encoder<W, A, const PAD: bool>
583 where
584 A: Alphabet,
585 {
586 inner: Option<W>,
587 engine: Engine<A, PAD>,
588 pending: [u8; 2],
589 pending_len: usize,
590 output: OutputQueue<1024>,
591 finalized: bool,
592 }
593
594 impl<W, A, const PAD: bool> Encoder<W, A, PAD>
595 where
596 A: Alphabet,
597 {
598 #[must_use]
600 pub const fn new(inner: W, engine: Engine<A, PAD>) -> Self {
601 Self {
602 inner: Some(inner),
603 engine,
604 pending: [0; 2],
605 pending_len: 0,
606 output: OutputQueue::new(),
607 finalized: false,
608 }
609 }
610
611 #[must_use]
613 pub fn get_ref(&self) -> &W {
614 self.inner_ref()
615 }
616
617 pub fn get_mut(&mut self) -> &mut W {
619 self.inner_mut()
620 }
621
622 #[must_use]
624 pub const fn engine(&self) -> Engine<A, PAD> {
625 self.engine
626 }
627
628 #[must_use]
630 pub const fn is_padded(&self) -> bool {
631 PAD
632 }
633
634 #[must_use]
637 pub const fn pending_len(&self) -> usize {
638 self.pending_len
639 }
640
641 #[must_use]
644 pub const fn has_pending_input(&self) -> bool {
645 self.pending_len != 0
646 }
647
648 #[must_use]
653 pub const fn pending_input_needed_len(&self) -> usize {
654 if self.has_pending_input() {
655 3 - self.pending_len
656 } else {
657 0
658 }
659 }
660
661 #[must_use]
664 pub const fn buffered_output_len(&self) -> usize {
665 self.output.len()
666 }
667
668 #[must_use]
671 pub const fn buffered_output_capacity(&self) -> usize {
672 self.output.capacity()
673 }
674
675 #[must_use]
678 pub const fn buffered_output_remaining_capacity(&self) -> usize {
679 self.output.available_capacity()
680 }
681
682 #[must_use]
685 pub const fn has_buffered_output(&self) -> bool {
686 !self.output.is_empty()
687 }
688
689 #[must_use]
693 pub const fn is_finalized(&self) -> bool {
694 self.finalized
695 }
696
697 #[must_use]
700 pub const fn can_into_inner(&self) -> bool {
701 !self.has_pending_input() && !self.has_buffered_output()
702 }
703
704 #[must_use]
708 pub fn into_inner(mut self) -> W {
709 self.take_inner()
710 }
711
712 #[allow(clippy::result_large_err)]
718 pub fn try_into_inner(mut self) -> Result<W, Self> {
719 if !self.can_into_inner() {
720 return Err(self);
721 }
722 Ok(self.take_inner())
723 }
724
725 fn inner_ref(&self) -> &W {
726 match &self.inner {
727 Some(inner) => inner,
728 None => unreachable!("stream encoder inner writer was already taken"),
729 }
730 }
731
732 fn inner_mut(&mut self) -> &mut W {
733 match &mut self.inner {
734 Some(inner) => inner,
735 None => unreachable!("stream encoder inner writer was already taken"),
736 }
737 }
738
739 fn take_inner(&mut self) -> W {
740 match self.inner.take() {
741 Some(inner) => inner,
742 None => unreachable!("stream encoder inner writer was already taken"),
743 }
744 }
745
746 fn clear_pending(&mut self) {
747 crate::wipe_bytes(&mut self.pending);
748 self.pending_len = 0;
749 }
750
751 fn clear_output(&mut self) {
752 self.output.clear_all();
753 }
754 }
755
756 impl<W, A, const PAD: bool> Drop for Encoder<W, A, PAD>
757 where
758 A: Alphabet,
759 {
760 fn drop(&mut self) {
761 self.clear_pending();
762 self.clear_output();
763 }
764 }
765
766 impl<W, A, const PAD: bool> core::fmt::Debug for Encoder<W, A, PAD>
767 where
768 A: Alphabet,
769 {
770 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
771 formatter
772 .debug_struct("Encoder")
773 .field("inner", &redacted_inner_state(self.inner.is_some()))
774 .field("engine", &self.engine)
775 .field("pending", &"<redacted>")
776 .field("pending_len", &self.pending_len)
777 .field("pending_input_needed_len", &self.pending_input_needed_len())
778 .field("buffered_output_len", &self.output.len())
779 .field("buffered_output_capacity", &self.output.capacity())
780 .field(
781 "buffered_output_remaining_capacity",
782 &self.output.available_capacity(),
783 )
784 .field("can_into_inner", &self.can_into_inner())
785 .field("finalized", &self.finalized)
786 .finish()
787 }
788 }
789
790 impl<W, A, const PAD: bool> Encoder<W, A, PAD>
791 where
792 W: Write,
793 A: Alphabet,
794 {
795 pub fn try_finish(&mut self) -> io::Result<()> {
805 if !self.finalized {
806 self.queue_pending_final()?;
807 self.finalized = true;
808 }
809 self.flush()
810 }
811
812 pub fn finish(mut self) -> io::Result<W> {
814 self.try_finish()?;
815 Ok(self.take_inner())
816 }
817
818 fn queue_pending_final(&mut self) -> io::Result<()> {
819 if self.pending_len == 0 {
820 return Ok(());
821 }
822
823 let mut pending = [0u8; 2];
824 pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
825 let pending_len = self.pending_len;
826 let mut encoded = [0u8; 4];
827 let result = self.queue_encoded_temp(&pending[..pending_len], &mut encoded);
828 crate::wipe_bytes(&mut pending);
829 result?;
830 self.clear_pending();
831 Ok(())
832 }
833
834 fn queue_encoded_temp(&mut self, input: &[u8], encoded: &mut [u8]) -> io::Result<()> {
835 let written = match self.engine.encode_slice(input, encoded) {
836 Ok(written) => written,
837 Err(err) => {
838 crate::wipe_bytes(encoded);
839 return Err(encode_error_to_io(err));
840 }
841 };
842
843 let result = self.output.push_slice(&encoded[..written]);
844 crate::wipe_bytes(encoded);
845 result
846 }
847
848 fn drain_output(&mut self) -> io::Result<()> {
849 let mut chunk = [0u8; 1024];
850 while !self.output.is_empty() {
851 let pending = self.output.copy_front(&mut chunk);
852 let result = self.inner_mut().write(&chunk[..pending]);
853 crate::wipe_bytes(&mut chunk[..pending]);
854 match result {
855 Ok(0) => {
856 return Err(io::Error::new(
857 io::ErrorKind::WriteZero,
858 "base64 stream encoder could not drain buffered output",
859 ));
860 }
861 Ok(written) => {
862 if written > pending {
863 return Err(io::Error::new(
864 io::ErrorKind::InvalidData,
865 "wrapped writer reported more bytes than provided",
866 ));
867 }
868 self.output.discard_front(written);
869 }
870 Err(err) => return Err(err),
871 }
872 }
873
874 Ok(())
875 }
876 }
877
878 impl<W, A, const PAD: bool> Write for Encoder<W, A, PAD>
879 where
880 W: Write,
881 A: Alphabet,
882 {
883 fn write(&mut self, input: &[u8]) -> io::Result<usize> {
884 if input.is_empty() {
885 self.drain_output()?;
886 return Ok(0);
887 }
888 self.drain_output()?;
889 if self.finalized {
890 return Err(io::Error::new(
891 io::ErrorKind::InvalidInput,
892 "base64 stream encoder received input after finalization",
893 ));
894 }
895
896 let mut consumed = 0;
897 if self.pending_len > 0 {
898 let needed = 3 - self.pending_len;
899 if input.len() < needed {
900 self.pending[self.pending_len..self.pending_len + input.len()]
901 .copy_from_slice(input);
902 self.pending_len += input.len();
903 return Ok(input.len());
904 }
905
906 let mut chunk = [0u8; 3];
907 chunk[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
908 chunk[self.pending_len..].copy_from_slice(&input[..needed]);
909
910 let mut encoded = [0u8; 4];
911 let result = self.queue_encoded_temp(&chunk, &mut encoded);
912 crate::wipe_bytes(&mut chunk);
913 result?;
914 self.clear_pending();
915 consumed += needed;
916 return Ok(consumed);
917 }
918
919 let remaining = &input[consumed..];
920 let full_len = remaining.len() / 3 * 3;
921 if full_len > 0 {
922 let mut take = core::cmp::min(full_len, 768);
923 take -= take % 3;
924 debug_assert!(take > 0);
925
926 let mut encoded = [0u8; 1024];
927 self.queue_encoded_temp(&remaining[..take], &mut encoded)?;
928 return Ok(consumed + take);
929 }
930
931 let tail = &remaining[full_len..];
932 self.pending[..tail.len()].copy_from_slice(tail);
933 self.pending_len = tail.len();
934
935 Ok(input.len())
936 }
937
938 fn flush(&mut self) -> io::Result<()> {
939 self.drain_output()?;
940 self.inner_mut().flush()
941 }
942 }
943
944 fn encode_error_to_io(err: EncodeError) -> io::Error {
945 io::Error::new(io::ErrorKind::InvalidInput, err)
946 }
947
948 pub struct Decoder<W, A, const PAD: bool>
956 where
957 A: Alphabet,
958 {
959 inner: Option<W>,
960 engine: Engine<A, PAD>,
961 pending: [u8; 4],
962 pending_len: usize,
963 output: OutputQueue<1024>,
964 finished: bool,
965 finalized: bool,
966 failed: bool,
967 }
968
969 impl<W, A, const PAD: bool> Decoder<W, A, PAD>
970 where
971 A: Alphabet,
972 {
973 #[must_use]
975 pub const fn new(inner: W, engine: Engine<A, PAD>) -> Self {
976 Self {
977 inner: Some(inner),
978 engine,
979 pending: [0; 4],
980 pending_len: 0,
981 output: OutputQueue::new(),
982 finished: false,
983 finalized: false,
984 failed: false,
985 }
986 }
987
988 #[must_use]
990 pub fn get_ref(&self) -> &W {
991 self.inner_ref()
992 }
993
994 pub fn get_mut(&mut self) -> &mut W {
996 self.inner_mut()
997 }
998
999 #[must_use]
1001 pub const fn engine(&self) -> Engine<A, PAD> {
1002 self.engine
1003 }
1004
1005 #[must_use]
1007 pub const fn is_padded(&self) -> bool {
1008 PAD
1009 }
1010
1011 #[must_use]
1014 pub const fn pending_len(&self) -> usize {
1015 self.pending_len
1016 }
1017
1018 #[must_use]
1021 pub const fn has_pending_input(&self) -> bool {
1022 self.pending_len != 0
1023 }
1024
1025 #[must_use]
1030 pub const fn pending_input_needed_len(&self) -> usize {
1031 if self.has_pending_input() {
1032 4 - self.pending_len
1033 } else {
1034 0
1035 }
1036 }
1037
1038 #[must_use]
1041 pub const fn buffered_output_len(&self) -> usize {
1042 self.output.len()
1043 }
1044
1045 #[must_use]
1048 pub const fn buffered_output_capacity(&self) -> usize {
1049 self.output.capacity()
1050 }
1051
1052 #[must_use]
1055 pub const fn buffered_output_remaining_capacity(&self) -> usize {
1056 self.output.available_capacity()
1057 }
1058
1059 #[must_use]
1062 pub const fn has_buffered_output(&self) -> bool {
1063 !self.output.is_empty()
1064 }
1065
1066 #[must_use]
1072 pub const fn has_terminal_padding(&self) -> bool {
1073 self.finished
1074 }
1075
1076 #[must_use]
1080 pub const fn is_finalized(&self) -> bool {
1081 self.finalized
1082 }
1083
1084 #[must_use]
1090 pub const fn is_failed(&self) -> bool {
1091 self.failed
1092 }
1093
1094 #[must_use]
1097 pub const fn can_into_inner(&self) -> bool {
1098 !self.is_failed() && !self.has_pending_input() && !self.has_buffered_output()
1099 }
1100
1101 #[must_use]
1105 pub fn into_inner(mut self) -> W {
1106 self.take_inner()
1107 }
1108
1109 #[allow(clippy::result_large_err)]
1115 pub fn try_into_inner(mut self) -> Result<W, Self> {
1116 if !self.can_into_inner() {
1117 return Err(self);
1118 }
1119 Ok(self.take_inner())
1120 }
1121
1122 fn inner_ref(&self) -> &W {
1123 match &self.inner {
1124 Some(inner) => inner,
1125 None => unreachable!("stream decoder inner writer was already taken"),
1126 }
1127 }
1128
1129 fn inner_mut(&mut self) -> &mut W {
1130 match &mut self.inner {
1131 Some(inner) => inner,
1132 None => unreachable!("stream decoder inner writer was already taken"),
1133 }
1134 }
1135
1136 fn take_inner(&mut self) -> W {
1137 match self.inner.take() {
1138 Some(inner) => inner,
1139 None => unreachable!("stream decoder inner writer was already taken"),
1140 }
1141 }
1142
1143 fn clear_pending(&mut self) {
1144 crate::wipe_bytes(&mut self.pending);
1145 self.pending_len = 0;
1146 }
1147
1148 fn clear_output(&mut self) {
1149 self.output.clear_all();
1150 }
1151 }
1152
1153 impl<W, A, const PAD: bool> Drop for Decoder<W, A, PAD>
1154 where
1155 A: Alphabet,
1156 {
1157 fn drop(&mut self) {
1158 self.clear_pending();
1159 self.clear_output();
1160 }
1161 }
1162
1163 impl<W, A, const PAD: bool> core::fmt::Debug for Decoder<W, A, PAD>
1164 where
1165 A: Alphabet,
1166 {
1167 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1168 formatter
1169 .debug_struct("Decoder")
1170 .field("inner", &redacted_inner_state(self.inner.is_some()))
1171 .field("engine", &self.engine)
1172 .field("pending", &"<redacted>")
1173 .field("pending_len", &self.pending_len)
1174 .field("pending_input_needed_len", &self.pending_input_needed_len())
1175 .field("buffered_output_len", &self.output.len())
1176 .field("buffered_output_capacity", &self.output.capacity())
1177 .field(
1178 "buffered_output_remaining_capacity",
1179 &self.output.available_capacity(),
1180 )
1181 .field("can_into_inner", &self.can_into_inner())
1182 .field("terminal_padding", &self.finished)
1183 .field("finalized", &self.finalized)
1184 .field("failed", &self.failed)
1185 .finish()
1186 }
1187 }
1188
1189 impl<W, A, const PAD: bool> Decoder<W, A, PAD>
1190 where
1191 W: Write,
1192 A: Alphabet,
1193 {
1194 pub fn try_finish(&mut self) -> io::Result<()> {
1204 if self.failed {
1205 return Err(stream_decoder_failed_error());
1206 }
1207 if !self.finalized {
1208 self.queue_pending_final()?;
1209 self.finalized = true;
1210 }
1211 self.flush()
1212 }
1213
1214 pub fn finish(mut self) -> io::Result<W> {
1216 self.try_finish()?;
1217 Ok(self.take_inner())
1218 }
1219
1220 fn queue_pending_final(&mut self) -> io::Result<()> {
1221 if self.pending_len == 0 {
1222 return Ok(());
1223 }
1224
1225 let mut pending = [0u8; 4];
1226 pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
1227 let pending_len = self.pending_len;
1228 let mut decoded = [0u8; 3];
1229 let result = self.queue_decoded_temp(&pending[..pending_len], &mut decoded);
1230 crate::wipe_bytes(&mut pending);
1231 if let Err(err) = result {
1232 self.clear_pending();
1233 return Err(err);
1234 }
1235 self.clear_pending();
1236 Ok(())
1237 }
1238
1239 fn queue_full_quad(&mut self, mut input: [u8; 4]) -> io::Result<()> {
1240 let mut decoded = [0u8; 3];
1241 let result = self.queue_decoded_temp(&input, &mut decoded);
1242 crate::wipe_bytes(&mut input);
1243 let written = result?;
1244 if written < 3 {
1245 self.finished = true;
1246 }
1247 Ok(())
1248 }
1249
1250 fn queue_decoded_temp(&mut self, input: &[u8], decoded: &mut [u8]) -> io::Result<usize> {
1251 let written = match self.engine.decode_slice(input, decoded) {
1252 Ok(written) => written,
1253 Err(err) => {
1254 crate::wipe_bytes(decoded);
1255 self.failed = true;
1256 return Err(decode_error_to_io(err));
1257 }
1258 };
1259
1260 let result = self.output.push_slice(&decoded[..written]);
1261 crate::wipe_bytes(decoded);
1262 result?;
1263 Ok(written)
1264 }
1265
1266 fn drain_output(&mut self) -> io::Result<()> {
1267 let mut chunk = [0u8; 1024];
1268 while !self.output.is_empty() {
1269 let pending = self.output.copy_front(&mut chunk);
1270 let result = self.inner_mut().write(&chunk[..pending]);
1271 crate::wipe_bytes(&mut chunk[..pending]);
1272 match result {
1273 Ok(0) => {
1274 return Err(io::Error::new(
1275 io::ErrorKind::WriteZero,
1276 "base64 stream decoder could not drain buffered output",
1277 ));
1278 }
1279 Ok(written) => {
1280 if written > pending {
1281 return Err(io::Error::new(
1282 io::ErrorKind::InvalidData,
1283 "wrapped writer reported more bytes than provided",
1284 ));
1285 }
1286 self.output.discard_front(written);
1287 }
1288 Err(err) => return Err(err),
1289 }
1290 }
1291
1292 Ok(())
1293 }
1294 }
1295
1296 impl<W, A, const PAD: bool> Write for Decoder<W, A, PAD>
1297 where
1298 W: Write,
1299 A: Alphabet,
1300 {
1301 fn write(&mut self, input: &[u8]) -> io::Result<usize> {
1302 if self.failed {
1303 return Err(stream_decoder_failed_error());
1304 }
1305 if input.is_empty() {
1306 self.drain_output()?;
1307 return Ok(0);
1308 }
1309 self.drain_output()?;
1310 if self.finalized {
1311 return Err(io::Error::new(
1312 io::ErrorKind::InvalidInput,
1313 "base64 stream decoder received input after finalization",
1314 ));
1315 }
1316 if self.finished {
1317 self.failed = true;
1318 return Err(trailing_input_after_padding_error());
1319 }
1320
1321 let mut consumed = 0;
1322 if self.pending_len > 0 {
1323 let needed = 4 - self.pending_len;
1324 if input.len() < needed {
1325 self.pending[self.pending_len..self.pending_len + input.len()]
1326 .copy_from_slice(input);
1327 self.pending_len += input.len();
1328 return Ok(input.len());
1329 }
1330
1331 let mut quad = [0u8; 4];
1332 quad[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
1333 quad[self.pending_len..].copy_from_slice(&input[..needed]);
1334 let result = self.queue_full_quad(quad);
1335 crate::wipe_bytes(&mut quad);
1336 if let Err(err) = result {
1337 self.clear_pending();
1338 return Err(err);
1339 }
1340 self.clear_pending();
1341 consumed += needed;
1342 return Ok(consumed);
1343 }
1344
1345 let remaining = &input[consumed..];
1346 let full_len = remaining.len() / 4 * 4;
1347 if full_len > 0 {
1348 let quad = [remaining[0], remaining[1], remaining[2], remaining[3]];
1349 let mut quad = quad;
1350 let result = self.queue_full_quad(quad);
1351 crate::wipe_bytes(&mut quad);
1352 result?;
1353 return Ok(consumed + 4);
1354 }
1355
1356 let tail = &remaining[full_len..];
1357 self.pending[..tail.len()].copy_from_slice(tail);
1358 self.pending_len = tail.len();
1359
1360 Ok(input.len())
1361 }
1362
1363 fn flush(&mut self) -> io::Result<()> {
1364 if self.failed {
1365 return Err(stream_decoder_failed_error());
1366 }
1367 self.drain_output()?;
1368 self.inner_mut().flush()
1369 }
1370 }
1371
1372 fn decode_error_to_io(err: DecodeError) -> io::Error {
1373 io::Error::new(io::ErrorKind::InvalidInput, err)
1374 }
1375
1376 fn trailing_input_after_padding_error() -> io::Error {
1377 io::Error::new(
1378 io::ErrorKind::InvalidInput,
1379 "base64 decoder received trailing input after padding",
1380 )
1381 }
1382
1383 fn stream_decoder_failed_error() -> io::Error {
1384 io::Error::new(
1385 io::ErrorKind::InvalidInput,
1386 "base64 stream decoder is failed after malformed input",
1387 )
1388 }
1389
1390 pub struct DecoderReader<R, A, const PAD: bool>
1397 where
1398 A: Alphabet,
1399 {
1400 inner: Option<R>,
1401 engine: Engine<A, PAD>,
1402 pending: [u8; 4],
1403 pending_len: usize,
1404 output: OutputQueue<3>,
1405 finished: bool,
1406 terminal_seen: bool,
1407 failed: bool,
1408 }
1409
1410 impl<R, A, const PAD: bool> DecoderReader<R, A, PAD>
1411 where
1412 A: Alphabet,
1413 {
1414 #[must_use]
1416 pub fn new(inner: R, engine: Engine<A, PAD>) -> Self {
1417 Self {
1418 inner: Some(inner),
1419 engine,
1420 pending: [0; 4],
1421 pending_len: 0,
1422 output: OutputQueue::new(),
1423 finished: false,
1424 terminal_seen: false,
1425 failed: false,
1426 }
1427 }
1428
1429 #[must_use]
1431 pub fn get_ref(&self) -> &R {
1432 self.inner_ref()
1433 }
1434
1435 pub fn get_mut(&mut self) -> &mut R {
1437 self.inner_mut()
1438 }
1439
1440 #[must_use]
1442 pub const fn engine(&self) -> Engine<A, PAD> {
1443 self.engine
1444 }
1445
1446 #[must_use]
1448 pub const fn is_padded(&self) -> bool {
1449 PAD
1450 }
1451
1452 #[must_use]
1455 pub const fn pending_len(&self) -> usize {
1456 self.pending_len
1457 }
1458
1459 #[must_use]
1462 pub const fn has_pending_input(&self) -> bool {
1463 self.pending_len != 0
1464 }
1465
1466 #[must_use]
1471 pub const fn pending_input_needed_len(&self) -> usize {
1472 if self.has_pending_input() {
1473 4 - self.pending_len
1474 } else {
1475 0
1476 }
1477 }
1478
1479 #[must_use]
1482 pub const fn buffered_output_len(&self) -> usize {
1483 self.output.len()
1484 }
1485
1486 #[must_use]
1489 pub const fn buffered_output_capacity(&self) -> usize {
1490 self.output.capacity()
1491 }
1492
1493 #[must_use]
1496 pub const fn buffered_output_remaining_capacity(&self) -> usize {
1497 self.output.available_capacity()
1498 }
1499
1500 #[must_use]
1503 pub const fn has_buffered_output(&self) -> bool {
1504 !self.output.is_empty()
1505 }
1506
1507 #[must_use]
1514 pub const fn has_terminal_padding(&self) -> bool {
1515 self.terminal_seen
1516 }
1517
1518 #[must_use]
1524 pub const fn has_finished_input(&self) -> bool {
1525 self.finished
1526 }
1527
1528 #[must_use]
1531 pub const fn is_finished(&self) -> bool {
1532 self.finished && self.output.is_empty()
1533 }
1534
1535 #[must_use]
1542 pub const fn is_failed(&self) -> bool {
1543 self.failed
1544 }
1545
1546 #[must_use]
1549 pub const fn can_into_inner(&self) -> bool {
1550 !self.is_failed() && self.is_finished()
1551 }
1552
1553 #[must_use]
1555 pub fn into_inner(mut self) -> R {
1556 self.take_inner()
1557 }
1558
1559 #[allow(clippy::result_large_err)]
1567 pub fn try_into_inner(mut self) -> Result<R, Self> {
1568 if !self.can_into_inner() {
1569 return Err(self);
1570 }
1571 Ok(self.take_inner())
1572 }
1573
1574 fn inner_ref(&self) -> &R {
1575 match &self.inner {
1576 Some(inner) => inner,
1577 None => unreachable!("stream decoder reader inner reader was already taken"),
1578 }
1579 }
1580
1581 fn inner_mut(&mut self) -> &mut R {
1582 match &mut self.inner {
1583 Some(inner) => inner,
1584 None => unreachable!("stream decoder reader inner reader was already taken"),
1585 }
1586 }
1587
1588 fn take_inner(&mut self) -> R {
1589 match self.inner.take() {
1590 Some(inner) => inner,
1591 None => unreachable!("stream decoder reader inner reader was already taken"),
1592 }
1593 }
1594
1595 fn clear_pending(&mut self) {
1596 crate::wipe_bytes(&mut self.pending);
1597 self.pending_len = 0;
1598 }
1599 }
1600
1601 impl<R, A, const PAD: bool> Drop for DecoderReader<R, A, PAD>
1602 where
1603 A: Alphabet,
1604 {
1605 fn drop(&mut self) {
1606 self.clear_pending();
1607 self.output.clear_all();
1608 }
1609 }
1610
1611 impl<R, A, const PAD: bool> core::fmt::Debug for DecoderReader<R, A, PAD>
1612 where
1613 A: Alphabet,
1614 {
1615 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1616 formatter
1617 .debug_struct("DecoderReader")
1618 .field("inner", &redacted_inner_state(self.inner.is_some()))
1619 .field("engine", &self.engine)
1620 .field("pending", &"<redacted>")
1621 .field("pending_len", &self.pending_len)
1622 .field("pending_input_needed_len", &self.pending_input_needed_len())
1623 .field("buffered_output_len", &self.output.len())
1624 .field("buffered_output_capacity", &self.output.capacity())
1625 .field(
1626 "buffered_output_remaining_capacity",
1627 &self.output.available_capacity(),
1628 )
1629 .field("can_into_inner", &self.can_into_inner())
1630 .field("finished", &self.finished)
1631 .field("terminal_padding", &self.terminal_seen)
1632 .field("failed", &self.failed)
1633 .finish()
1634 }
1635 }
1636
1637 impl<R, A, const PAD: bool> Read for DecoderReader<R, A, PAD>
1638 where
1639 R: Read,
1640 A: Alphabet,
1641 {
1642 fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
1643 if output.is_empty() {
1644 return Ok(0);
1645 }
1646 if self.failed {
1647 return Err(stream_decoder_failed_error());
1648 }
1649
1650 while self.output.is_empty() && !self.finished {
1651 self.fill_output()?;
1652 }
1653
1654 Ok(self.output.pop_slice(output))
1655 }
1656 }
1657
1658 impl<R, A, const PAD: bool> DecoderReader<R, A, PAD>
1659 where
1660 R: Read,
1661 A: Alphabet,
1662 {
1663 fn fill_output(&mut self) -> io::Result<()> {
1664 if self.failed {
1665 return Err(stream_decoder_failed_error());
1666 }
1667 if self.terminal_seen {
1668 self.finished = true;
1669 return Ok(());
1670 }
1671
1672 let mut input = [0u8; 4];
1673 let available = 4 - self.pending_len;
1674 let read = self.inner_mut().read(&mut input[..available])?;
1675 if read == 0 {
1676 crate::wipe_bytes(&mut input);
1677 self.finished = true;
1678 self.push_final_pending()?;
1679 return Ok(());
1680 }
1681
1682 self.pending[self.pending_len..self.pending_len + read].copy_from_slice(&input[..read]);
1683 crate::wipe_bytes(&mut input);
1684 self.pending_len += read;
1685 if self.pending_len < 4 {
1686 return Ok(());
1687 }
1688
1689 let mut quad = self.pending;
1690 self.clear_pending();
1691 let result = self.push_decoded(&quad);
1692 crate::wipe_bytes(&mut quad);
1693 result?;
1694 if self.terminal_seen {
1695 self.finished = true;
1696 }
1697 Ok(())
1698 }
1699
1700 fn push_final_pending(&mut self) -> io::Result<()> {
1701 if self.pending_len == 0 {
1702 return Ok(());
1703 }
1704
1705 let mut pending = [0u8; 4];
1706 pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
1707 let pending_len = self.pending_len;
1708 self.clear_pending();
1709 let result = self.push_decoded(&pending[..pending_len]);
1710 crate::wipe_bytes(&mut pending);
1711 result
1712 }
1713
1714 fn push_decoded(&mut self, input: &[u8]) -> io::Result<()> {
1715 let mut decoded = [0u8; 3];
1716 let written = match self.engine.decode_slice(input, &mut decoded) {
1717 Ok(written) => written,
1718 Err(err) => {
1719 crate::wipe_bytes(&mut decoded);
1720 self.failed = true;
1721 return Err(decode_error_to_io(err));
1722 }
1723 };
1724 let result = self.output.push_slice(&decoded[..written]);
1725 crate::wipe_bytes(&mut decoded);
1726 result?;
1727 if input.len() == 4 && written < 3 {
1728 self.terminal_seen = true;
1729 }
1730 Ok(())
1731 }
1732 }
1733
1734 pub struct EncoderReader<R, A, const PAD: bool>
1736 where
1737 A: Alphabet,
1738 {
1739 inner: Option<R>,
1740 engine: Engine<A, PAD>,
1741 pending: [u8; 2],
1742 pending_len: usize,
1743 output: OutputQueue<1024>,
1744 finished: bool,
1745 }
1746
1747 impl<R, A, const PAD: bool> EncoderReader<R, A, PAD>
1748 where
1749 A: Alphabet,
1750 {
1751 #[must_use]
1753 pub fn new(inner: R, engine: Engine<A, PAD>) -> Self {
1754 Self {
1755 inner: Some(inner),
1756 engine,
1757 pending: [0; 2],
1758 pending_len: 0,
1759 output: OutputQueue::new(),
1760 finished: false,
1761 }
1762 }
1763
1764 #[must_use]
1766 pub fn get_ref(&self) -> &R {
1767 self.inner_ref()
1768 }
1769
1770 pub fn get_mut(&mut self) -> &mut R {
1772 self.inner_mut()
1773 }
1774
1775 #[must_use]
1777 pub const fn engine(&self) -> Engine<A, PAD> {
1778 self.engine
1779 }
1780
1781 #[must_use]
1783 pub const fn is_padded(&self) -> bool {
1784 PAD
1785 }
1786
1787 #[must_use]
1790 pub const fn pending_len(&self) -> usize {
1791 self.pending_len
1792 }
1793
1794 #[must_use]
1797 pub const fn has_pending_input(&self) -> bool {
1798 self.pending_len != 0
1799 }
1800
1801 #[must_use]
1806 pub const fn pending_input_needed_len(&self) -> usize {
1807 if self.has_pending_input() {
1808 3 - self.pending_len
1809 } else {
1810 0
1811 }
1812 }
1813
1814 #[must_use]
1817 pub const fn buffered_output_len(&self) -> usize {
1818 self.output.len()
1819 }
1820
1821 #[must_use]
1824 pub const fn buffered_output_capacity(&self) -> usize {
1825 self.output.capacity()
1826 }
1827
1828 #[must_use]
1831 pub const fn buffered_output_remaining_capacity(&self) -> usize {
1832 self.output.available_capacity()
1833 }
1834
1835 #[must_use]
1838 pub const fn has_buffered_output(&self) -> bool {
1839 !self.output.is_empty()
1840 }
1841
1842 #[must_use]
1848 pub const fn has_finished_input(&self) -> bool {
1849 self.finished
1850 }
1851
1852 #[must_use]
1855 pub const fn is_finished(&self) -> bool {
1856 self.finished && self.output.is_empty()
1857 }
1858
1859 #[must_use]
1862 pub const fn can_into_inner(&self) -> bool {
1863 self.is_finished()
1864 }
1865
1866 #[must_use]
1868 pub fn into_inner(mut self) -> R {
1869 self.take_inner()
1870 }
1871
1872 #[allow(clippy::result_large_err)]
1879 pub fn try_into_inner(mut self) -> Result<R, Self> {
1880 if !self.can_into_inner() {
1881 return Err(self);
1882 }
1883 Ok(self.take_inner())
1884 }
1885
1886 fn inner_ref(&self) -> &R {
1887 match &self.inner {
1888 Some(inner) => inner,
1889 None => unreachable!("stream encoder reader inner reader was already taken"),
1890 }
1891 }
1892
1893 fn inner_mut(&mut self) -> &mut R {
1894 match &mut self.inner {
1895 Some(inner) => inner,
1896 None => unreachable!("stream encoder reader inner reader was already taken"),
1897 }
1898 }
1899
1900 fn take_inner(&mut self) -> R {
1901 match self.inner.take() {
1902 Some(inner) => inner,
1903 None => unreachable!("stream encoder reader inner reader was already taken"),
1904 }
1905 }
1906
1907 fn clear_pending(&mut self) {
1908 crate::wipe_bytes(&mut self.pending);
1909 self.pending_len = 0;
1910 }
1911 }
1912
1913 impl<R, A, const PAD: bool> Drop for EncoderReader<R, A, PAD>
1914 where
1915 A: Alphabet,
1916 {
1917 fn drop(&mut self) {
1918 self.clear_pending();
1919 self.output.clear_all();
1920 }
1921 }
1922
1923 impl<R, A, const PAD: bool> core::fmt::Debug for EncoderReader<R, A, PAD>
1924 where
1925 A: Alphabet,
1926 {
1927 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1928 formatter
1929 .debug_struct("EncoderReader")
1930 .field("inner", &redacted_inner_state(self.inner.is_some()))
1931 .field("engine", &self.engine)
1932 .field("pending", &"<redacted>")
1933 .field("pending_len", &self.pending_len)
1934 .field("pending_input_needed_len", &self.pending_input_needed_len())
1935 .field("buffered_output_len", &self.output.len())
1936 .field("buffered_output_capacity", &self.output.capacity())
1937 .field(
1938 "buffered_output_remaining_capacity",
1939 &self.output.available_capacity(),
1940 )
1941 .field("can_into_inner", &self.can_into_inner())
1942 .field("finished", &self.finished)
1943 .finish()
1944 }
1945 }
1946
1947 impl<R, A, const PAD: bool> Read for EncoderReader<R, A, PAD>
1948 where
1949 R: Read,
1950 A: Alphabet,
1951 {
1952 fn read(&mut self, output: &mut [u8]) -> io::Result<usize> {
1953 if output.is_empty() {
1954 return Ok(0);
1955 }
1956
1957 while self.output.is_empty() && !self.finished {
1958 self.fill_output()?;
1959 }
1960
1961 Ok(self.output.pop_slice(output))
1962 }
1963 }
1964
1965 impl<R, A, const PAD: bool> EncoderReader<R, A, PAD>
1966 where
1967 R: Read,
1968 A: Alphabet,
1969 {
1970 fn fill_output(&mut self) -> io::Result<()> {
1971 let mut input = [0u8; 768];
1972 let read = self.inner_mut().read(&mut input)?;
1973 if read == 0 {
1974 crate::wipe_bytes(&mut input);
1975 self.finished = true;
1976 self.push_final_pending()?;
1977 return Ok(());
1978 }
1979
1980 let mut consumed = 0;
1981 if self.pending_len > 0 {
1982 let needed = 3 - self.pending_len;
1983 if read < needed {
1984 self.pending[self.pending_len..self.pending_len + read]
1985 .copy_from_slice(&input[..read]);
1986 self.pending_len += read;
1987 crate::wipe_bytes(&mut input);
1988 return Ok(());
1989 }
1990
1991 let mut chunk = [0u8; 3];
1992 chunk[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
1993 chunk[self.pending_len..].copy_from_slice(&input[..needed]);
1994 let result = self.push_encoded(&chunk);
1995 crate::wipe_bytes(&mut chunk);
1996 if let Err(err) = result {
1997 crate::wipe_bytes(&mut input);
1998 return Err(err);
1999 }
2000 self.clear_pending();
2001 consumed += needed;
2002 }
2003
2004 let remaining = &input[consumed..read];
2005 let full_len = remaining.len() / 3 * 3;
2006 let tail_len = remaining.len() - full_len;
2007 let mut tail = [0u8; 2];
2008 tail[..tail_len].copy_from_slice(&remaining[full_len..]);
2009 let result = if full_len > 0 {
2010 self.push_encoded(&remaining[..full_len])
2011 } else {
2012 Ok(())
2013 };
2014 crate::wipe_bytes(&mut input);
2015 if let Err(err) = result {
2016 crate::wipe_bytes(&mut tail);
2017 return Err(err);
2018 }
2019 self.pending[..tail_len].copy_from_slice(&tail[..tail_len]);
2020 crate::wipe_bytes(&mut tail);
2021 self.pending_len = tail_len;
2022 Ok(())
2023 }
2024
2025 fn push_final_pending(&mut self) -> io::Result<()> {
2026 if self.pending_len == 0 {
2027 return Ok(());
2028 }
2029
2030 let mut pending = [0u8; 2];
2031 pending[..self.pending_len].copy_from_slice(&self.pending[..self.pending_len]);
2032 let pending_len = self.pending_len;
2033 self.clear_pending();
2034 let result = self.push_encoded(&pending[..pending_len]);
2035 crate::wipe_bytes(&mut pending);
2036 result
2037 }
2038
2039 fn push_encoded(&mut self, input: &[u8]) -> io::Result<()> {
2040 let mut encoded = [0u8; 1024];
2041 let written = match self.engine.encode_slice(input, &mut encoded) {
2042 Ok(written) => written,
2043 Err(err) => {
2044 crate::wipe_bytes(&mut encoded);
2045 return Err(encode_error_to_io(err));
2046 }
2047 };
2048 let result = self.output.push_slice(&encoded[..written]);
2049 crate::wipe_bytes(&mut encoded);
2050 result
2051 }
2052 }
2053
2054 const fn redacted_inner_state(present: bool) -> &'static str {
2055 if present { "<present>" } else { "<taken>" }
2056 }
2057}
2058
2059pub mod ct {
2067 use super::{
2068 Alphabet, DecodeError, DecodedBuffer, Standard, UrlSafe, ct_decode_in_place,
2069 ct_decode_slice, ct_decoded_len, ct_validate_decode,
2070 };
2071 use core::marker::PhantomData;
2072
2073 pub const STANDARD: CtEngine<Standard, true> = CtEngine::new();
2075
2076 pub const STANDARD_NO_PAD: CtEngine<Standard, false> = CtEngine::new();
2078
2079 pub const URL_SAFE: CtEngine<UrlSafe, true> = CtEngine::new();
2081
2082 pub const URL_SAFE_NO_PAD: CtEngine<UrlSafe, false> = CtEngine::new();
2084
2085 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
2087 pub struct CtEngine<A, const PAD: bool> {
2088 alphabet: PhantomData<A>,
2089 }
2090
2091 impl<A, const PAD: bool> CtEngine<A, PAD>
2092 where
2093 A: Alphabet,
2094 {
2095 #[must_use]
2097 pub const fn new() -> Self {
2098 Self {
2099 alphabet: PhantomData,
2100 }
2101 }
2102
2103 #[must_use]
2106 pub const fn is_padded(&self) -> bool {
2107 PAD
2108 }
2109
2110 pub fn validate_result(&self, input: &[u8]) -> Result<(), DecodeError> {
2125 ct_validate_decode::<A, PAD>(input)
2126 }
2127
2128 #[must_use]
2142 pub fn validate(&self, input: &[u8]) -> bool {
2143 self.validate_result(input).is_ok()
2144 }
2145
2146 pub fn decoded_len(&self, input: &[u8]) -> Result<usize, DecodeError> {
2152 ct_decoded_len::<A, PAD>(input)
2153 }
2154
2155 pub fn decode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
2177 ct_decode_slice::<A, PAD>(input, output)
2178 }
2179
2180 pub fn decode_slice_clear_tail(
2202 &self,
2203 input: &[u8],
2204 output: &mut [u8],
2205 ) -> Result<usize, DecodeError> {
2206 let written = match self.decode_slice(input, output) {
2207 Ok(written) => written,
2208 Err(err) => {
2209 crate::wipe_bytes(output);
2210 return Err(err);
2211 }
2212 };
2213 crate::wipe_tail(output, written);
2214 Ok(written)
2215 }
2216
2217 pub fn decode_buffer<const CAP: usize>(
2233 &self,
2234 input: &[u8],
2235 ) -> Result<DecodedBuffer<CAP>, DecodeError> {
2236 let mut output = DecodedBuffer::new();
2237 let written = match self.decode_slice_clear_tail(input, &mut output.bytes) {
2238 Ok(written) => written,
2239 Err(err) => {
2240 output.clear();
2241 return Err(err);
2242 }
2243 };
2244 output.len = written;
2245 Ok(output)
2246 }
2247
2248 pub fn decode_in_place<'a>(
2265 &self,
2266 buffer: &'a mut [u8],
2267 ) -> Result<&'a mut [u8], DecodeError> {
2268 let len = ct_decode_in_place::<A, PAD>(buffer)?;
2269 Ok(&mut buffer[..len])
2270 }
2271
2272 pub fn decode_in_place_clear_tail<'a>(
2289 &self,
2290 buffer: &'a mut [u8],
2291 ) -> Result<&'a mut [u8], DecodeError> {
2292 let len = match ct_decode_in_place::<A, PAD>(buffer) {
2293 Ok(len) => len,
2294 Err(err) => {
2295 crate::wipe_bytes(buffer);
2296 return Err(err);
2297 }
2298 };
2299 crate::wipe_tail(buffer, len);
2300 Ok(&mut buffer[..len])
2301 }
2302 }
2303
2304 impl<A, const PAD: bool> core::fmt::Display for CtEngine<A, PAD> {
2305 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2306 write!(formatter, "ct padded={PAD}")
2307 }
2308 }
2309}
2310
2311pub const STANDARD: Engine<Standard, true> = Engine::new();
2313
2314pub const STANDARD_NO_PAD: Engine<Standard, false> = Engine::new();
2316
2317pub const URL_SAFE: Engine<UrlSafe, true> = Engine::new();
2319
2320pub const URL_SAFE_NO_PAD: Engine<UrlSafe, false> = Engine::new();
2322
2323pub const BCRYPT_NO_PAD: Engine<Bcrypt, false> = Engine::new();
2328
2329pub const CRYPT_NO_PAD: Engine<Crypt, false> = Engine::new();
2334
2335#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2337pub enum LineEnding {
2338 Lf,
2340 CrLf,
2342}
2343
2344impl LineEnding {
2345 #[must_use]
2347 pub const fn name(self) -> &'static str {
2348 match self {
2349 Self::Lf => "LF",
2350 Self::CrLf => "CRLF",
2351 }
2352 }
2353
2354 #[must_use]
2356 pub const fn as_str(self) -> &'static str {
2357 match self {
2358 Self::Lf => "\n",
2359 Self::CrLf => "\r\n",
2360 }
2361 }
2362
2363 #[must_use]
2365 pub const fn as_bytes(self) -> &'static [u8] {
2366 self.as_str().as_bytes()
2367 }
2368
2369 #[must_use]
2371 pub const fn byte_len(self) -> usize {
2372 match self {
2373 Self::Lf => 1,
2374 Self::CrLf => 2,
2375 }
2376 }
2377}
2378
2379impl core::fmt::Display for LineEnding {
2380 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2381 formatter.write_str(self.name())
2382 }
2383}
2384
2385#[derive(Clone, Copy, Debug, Eq, PartialEq)]
2391pub struct LineWrap {
2392 pub line_len: usize,
2394 pub line_ending: LineEnding,
2396}
2397
2398impl LineWrap {
2399 pub const MIME: Self = Self::new(76, LineEnding::CrLf);
2401 pub const PEM: Self = Self::new(64, LineEnding::Lf);
2403 pub const PEM_CRLF: Self = Self::new(64, LineEnding::CrLf);
2405
2406 #[must_use]
2408 pub const fn new(line_len: usize, line_ending: LineEnding) -> Self {
2409 Self {
2410 line_len,
2411 line_ending,
2412 }
2413 }
2414
2415 #[must_use]
2422 pub const fn checked_new(line_len: usize, line_ending: LineEnding) -> Option<Self> {
2423 if line_len == 0 {
2424 None
2425 } else {
2426 Some(Self::new(line_len, line_ending))
2427 }
2428 }
2429
2430 #[must_use]
2432 pub const fn line_len(self) -> usize {
2433 self.line_len
2434 }
2435
2436 #[must_use]
2438 pub const fn line_ending(self) -> LineEnding {
2439 self.line_ending
2440 }
2441
2442 #[must_use]
2444 pub const fn is_valid(self) -> bool {
2445 self.line_len != 0
2446 }
2447}
2448
2449impl core::fmt::Display for LineWrap {
2450 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2451 write!(formatter, "{}:{}", self.line_len, self.line_ending.name())
2452 }
2453}
2454
2455#[allow(unsafe_code)]
2456fn wipe_bytes(bytes: &mut [u8]) {
2457 for byte in bytes {
2458 unsafe {
2462 core::ptr::write_volatile(byte, 0);
2463 }
2464 }
2465 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
2466}
2467
2468fn wipe_tail(bytes: &mut [u8], start: usize) {
2469 wipe_bytes(&mut bytes[start..]);
2470}
2471
2472#[cfg(feature = "alloc")]
2473#[allow(unsafe_code)]
2474fn wipe_vec_spare_capacity(bytes: &mut alloc::vec::Vec<u8>) {
2475 let ptr = bytes.as_mut_ptr();
2476 let mut offset = bytes.len();
2477 while offset < bytes.capacity() {
2478 unsafe {
2482 core::ptr::write_volatile(ptr.add(offset), 0);
2483 }
2484 offset += 1;
2485 }
2486 core::sync::atomic::compiler_fence(core::sync::atomic::Ordering::SeqCst);
2487}
2488
2489#[cfg(feature = "alloc")]
2490fn wipe_vec_all(bytes: &mut alloc::vec::Vec<u8>) {
2491 wipe_bytes(bytes);
2492 wipe_vec_spare_capacity(bytes);
2493}
2494
2495pub struct EncodedBuffer<const CAP: usize> {
2505 bytes: [u8; CAP],
2506 len: usize,
2507}
2508
2509impl<const CAP: usize> EncodedBuffer<CAP> {
2510 #[must_use]
2512 pub const fn new() -> Self {
2513 Self {
2514 bytes: [0u8; CAP],
2515 len: 0,
2516 }
2517 }
2518
2519 #[must_use]
2521 pub const fn len(&self) -> usize {
2522 self.len
2523 }
2524
2525 #[must_use]
2527 pub const fn is_empty(&self) -> bool {
2528 self.len == 0
2529 }
2530
2531 #[must_use]
2533 pub const fn is_full(&self) -> bool {
2534 self.len == CAP
2535 }
2536
2537 #[must_use]
2539 pub const fn capacity(&self) -> usize {
2540 CAP
2541 }
2542
2543 #[must_use]
2545 pub const fn remaining_capacity(&self) -> usize {
2546 CAP - self.len
2547 }
2548
2549 #[must_use]
2551 pub fn as_bytes(&self) -> &[u8] {
2552 &self.bytes[..self.len]
2553 }
2554
2555 pub fn as_utf8(&self) -> Result<&str, core::str::Utf8Error> {
2562 core::str::from_utf8(self.as_bytes())
2563 }
2564
2565 #[must_use]
2572 pub fn as_str(&self) -> &str {
2573 match self.as_utf8() {
2574 Ok(output) => output,
2575 Err(_) => unreachable!("base64 encoder produced non-UTF-8 output"),
2576 }
2577 }
2578
2579 #[must_use]
2587 pub fn constant_time_eq(&self, other: &[u8]) -> bool {
2588 constant_time_eq_public_len(self.as_bytes(), other)
2589 }
2590
2591 #[must_use]
2599 pub fn into_exposed_array(mut self) -> ([u8; CAP], usize) {
2600 let len = self.len;
2601 self.len = 0;
2602 (core::mem::replace(&mut self.bytes, [0u8; CAP]), len)
2603 }
2604
2605 pub fn clear(&mut self) {
2607 wipe_bytes(&mut self.bytes);
2608 self.len = 0;
2609 }
2610
2611 pub fn clear_tail(&mut self) {
2613 wipe_tail(&mut self.bytes, self.len);
2614 }
2615}
2616
2617impl<const CAP: usize> AsRef<[u8]> for EncodedBuffer<CAP> {
2618 fn as_ref(&self) -> &[u8] {
2619 self.as_bytes()
2620 }
2621}
2622
2623impl<const CAP: usize> Clone for EncodedBuffer<CAP> {
2624 fn clone(&self) -> Self {
2625 let mut output = Self::new();
2626 output.bytes[..self.len].copy_from_slice(self.as_bytes());
2627 output.len = self.len;
2628 output
2629 }
2630}
2631
2632impl<const CAP: usize> core::fmt::Debug for EncodedBuffer<CAP> {
2633 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2634 formatter
2635 .debug_struct("EncodedBuffer")
2636 .field("bytes", &"<redacted>")
2637 .field("len", &self.len)
2638 .field("capacity", &CAP)
2639 .finish()
2640 }
2641}
2642
2643impl<const CAP: usize> core::fmt::Display for EncodedBuffer<CAP> {
2644 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2645 formatter.write_str(self.as_str())
2646 }
2647}
2648
2649impl<const CAP: usize> Default for EncodedBuffer<CAP> {
2650 fn default() -> Self {
2651 Self::new()
2652 }
2653}
2654
2655impl<const CAP: usize> Drop for EncodedBuffer<CAP> {
2656 fn drop(&mut self) {
2657 self.clear();
2658 }
2659}
2660
2661impl<const CAP: usize> Eq for EncodedBuffer<CAP> {}
2662
2663impl<const CAP: usize> PartialEq for EncodedBuffer<CAP> {
2664 fn eq(&self, other: &Self) -> bool {
2665 self.constant_time_eq(other.as_bytes())
2666 }
2667}
2668
2669impl<const CAP: usize> PartialEq<&[u8]> for EncodedBuffer<CAP> {
2670 fn eq(&self, other: &&[u8]) -> bool {
2671 self.constant_time_eq(other)
2672 }
2673}
2674
2675impl<const CAP: usize, const N: usize> PartialEq<&[u8; N]> for EncodedBuffer<CAP> {
2676 fn eq(&self, other: &&[u8; N]) -> bool {
2677 self.constant_time_eq(&other[..])
2678 }
2679}
2680
2681impl<const CAP: usize> PartialEq<&str> for EncodedBuffer<CAP> {
2682 fn eq(&self, other: &&str) -> bool {
2683 self.constant_time_eq(other.as_bytes())
2684 }
2685}
2686
2687#[cfg(feature = "alloc")]
2688impl<const CAP: usize> PartialEq<alloc::string::String> for EncodedBuffer<CAP> {
2689 fn eq(&self, other: &alloc::string::String) -> bool {
2690 self.constant_time_eq(other.as_bytes())
2691 }
2692}
2693
2694impl<const CAP: usize> PartialEq<EncodedBuffer<CAP>> for &[u8] {
2695 fn eq(&self, other: &EncodedBuffer<CAP>) -> bool {
2696 other.constant_time_eq(self)
2697 }
2698}
2699
2700impl<const CAP: usize, const N: usize> PartialEq<EncodedBuffer<CAP>> for &[u8; N] {
2701 fn eq(&self, other: &EncodedBuffer<CAP>) -> bool {
2702 other.constant_time_eq(&self[..])
2703 }
2704}
2705
2706impl<const CAP: usize> PartialEq<EncodedBuffer<CAP>> for &str {
2707 fn eq(&self, other: &EncodedBuffer<CAP>) -> bool {
2708 other.constant_time_eq(self.as_bytes())
2709 }
2710}
2711
2712#[cfg(feature = "alloc")]
2713impl<const CAP: usize> PartialEq<EncodedBuffer<CAP>> for alloc::string::String {
2714 fn eq(&self, other: &EncodedBuffer<CAP>) -> bool {
2715 other.constant_time_eq(self.as_bytes())
2716 }
2717}
2718
2719impl<const CAP: usize> TryFrom<&[u8]> for EncodedBuffer<CAP> {
2720 type Error = EncodeError;
2721
2722 fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
2728 STANDARD.encode_buffer(input)
2729 }
2730}
2731
2732impl<const CAP: usize, const N: usize> TryFrom<&[u8; N]> for EncodedBuffer<CAP> {
2733 type Error = EncodeError;
2734
2735 fn try_from(input: &[u8; N]) -> Result<Self, Self::Error> {
2741 Self::try_from(&input[..])
2742 }
2743}
2744
2745impl<const CAP: usize> TryFrom<&str> for EncodedBuffer<CAP> {
2746 type Error = EncodeError;
2747
2748 fn try_from(input: &str) -> Result<Self, Self::Error> {
2755 Self::try_from(input.as_bytes())
2756 }
2757}
2758
2759pub struct DecodedBuffer<const CAP: usize> {
2769 bytes: [u8; CAP],
2770 len: usize,
2771}
2772
2773impl<const CAP: usize> DecodedBuffer<CAP> {
2774 #[must_use]
2776 pub const fn new() -> Self {
2777 Self {
2778 bytes: [0u8; CAP],
2779 len: 0,
2780 }
2781 }
2782
2783 #[must_use]
2785 pub const fn len(&self) -> usize {
2786 self.len
2787 }
2788
2789 #[must_use]
2791 pub const fn is_empty(&self) -> bool {
2792 self.len == 0
2793 }
2794
2795 #[must_use]
2797 pub const fn is_full(&self) -> bool {
2798 self.len == CAP
2799 }
2800
2801 #[must_use]
2803 pub const fn capacity(&self) -> usize {
2804 CAP
2805 }
2806
2807 #[must_use]
2809 pub const fn remaining_capacity(&self) -> usize {
2810 CAP - self.len
2811 }
2812
2813 #[must_use]
2815 pub fn as_bytes(&self) -> &[u8] {
2816 &self.bytes[..self.len]
2817 }
2818
2819 pub fn as_utf8(&self) -> Result<&str, core::str::Utf8Error> {
2825 core::str::from_utf8(self.as_bytes())
2826 }
2827
2828 #[must_use]
2836 pub fn constant_time_eq(&self, other: &[u8]) -> bool {
2837 constant_time_eq_public_len(self.as_bytes(), other)
2838 }
2839
2840 #[must_use]
2848 pub fn into_exposed_array(mut self) -> ([u8; CAP], usize) {
2849 let len = self.len;
2850 self.len = 0;
2851 (core::mem::replace(&mut self.bytes, [0u8; CAP]), len)
2852 }
2853
2854 pub fn clear(&mut self) {
2856 wipe_bytes(&mut self.bytes);
2857 self.len = 0;
2858 }
2859
2860 pub fn clear_tail(&mut self) {
2862 wipe_tail(&mut self.bytes, self.len);
2863 }
2864}
2865
2866impl<const CAP: usize> AsRef<[u8]> for DecodedBuffer<CAP> {
2867 fn as_ref(&self) -> &[u8] {
2868 self.as_bytes()
2869 }
2870}
2871
2872impl<const CAP: usize> Clone for DecodedBuffer<CAP> {
2873 fn clone(&self) -> Self {
2874 let mut output = Self::new();
2875 output.bytes[..self.len].copy_from_slice(self.as_bytes());
2876 output.len = self.len;
2877 output
2878 }
2879}
2880
2881impl<const CAP: usize> core::fmt::Debug for DecodedBuffer<CAP> {
2882 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
2883 formatter
2884 .debug_struct("DecodedBuffer")
2885 .field("bytes", &"<redacted>")
2886 .field("len", &self.len)
2887 .field("capacity", &CAP)
2888 .finish()
2889 }
2890}
2891
2892impl<const CAP: usize> Default for DecodedBuffer<CAP> {
2893 fn default() -> Self {
2894 Self::new()
2895 }
2896}
2897
2898impl<const CAP: usize> Drop for DecodedBuffer<CAP> {
2899 fn drop(&mut self) {
2900 self.clear();
2901 }
2902}
2903
2904impl<const CAP: usize> Eq for DecodedBuffer<CAP> {}
2905
2906impl<const CAP: usize> PartialEq for DecodedBuffer<CAP> {
2907 fn eq(&self, other: &Self) -> bool {
2908 self.constant_time_eq(other.as_bytes())
2909 }
2910}
2911
2912impl<const CAP: usize> PartialEq<&[u8]> for DecodedBuffer<CAP> {
2913 fn eq(&self, other: &&[u8]) -> bool {
2914 self.constant_time_eq(other)
2915 }
2916}
2917
2918impl<const CAP: usize, const N: usize> PartialEq<&[u8; N]> for DecodedBuffer<CAP> {
2919 fn eq(&self, other: &&[u8; N]) -> bool {
2920 self.constant_time_eq(&other[..])
2921 }
2922}
2923
2924impl<const CAP: usize> PartialEq<&str> for DecodedBuffer<CAP> {
2925 fn eq(&self, other: &&str) -> bool {
2926 self.constant_time_eq(other.as_bytes())
2927 }
2928}
2929
2930#[cfg(feature = "alloc")]
2931impl<const CAP: usize> PartialEq<alloc::string::String> for DecodedBuffer<CAP> {
2932 fn eq(&self, other: &alloc::string::String) -> bool {
2933 self.constant_time_eq(other.as_bytes())
2934 }
2935}
2936
2937impl<const CAP: usize> PartialEq<DecodedBuffer<CAP>> for &[u8] {
2938 fn eq(&self, other: &DecodedBuffer<CAP>) -> bool {
2939 other.constant_time_eq(self)
2940 }
2941}
2942
2943impl<const CAP: usize, const N: usize> PartialEq<DecodedBuffer<CAP>> for &[u8; N] {
2944 fn eq(&self, other: &DecodedBuffer<CAP>) -> bool {
2945 other.constant_time_eq(&self[..])
2946 }
2947}
2948
2949impl<const CAP: usize> PartialEq<DecodedBuffer<CAP>> for &str {
2950 fn eq(&self, other: &DecodedBuffer<CAP>) -> bool {
2951 other.constant_time_eq(self.as_bytes())
2952 }
2953}
2954
2955#[cfg(feature = "alloc")]
2956impl<const CAP: usize> PartialEq<DecodedBuffer<CAP>> for alloc::string::String {
2957 fn eq(&self, other: &DecodedBuffer<CAP>) -> bool {
2958 other.constant_time_eq(self.as_bytes())
2959 }
2960}
2961
2962impl<const CAP: usize> TryFrom<&[u8]> for DecodedBuffer<CAP> {
2963 type Error = DecodeError;
2964
2965 fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
2970 STANDARD.decode_buffer(input)
2971 }
2972}
2973
2974impl<const CAP: usize, const N: usize> TryFrom<&[u8; N]> for DecodedBuffer<CAP> {
2975 type Error = DecodeError;
2976
2977 fn try_from(input: &[u8; N]) -> Result<Self, Self::Error> {
2983 Self::try_from(&input[..])
2984 }
2985}
2986
2987impl<const CAP: usize> TryFrom<&str> for DecodedBuffer<CAP> {
2988 type Error = DecodeError;
2989
2990 fn try_from(input: &str) -> Result<Self, Self::Error> {
2995 Self::try_from(input.as_bytes())
2996 }
2997}
2998
2999impl<const CAP: usize> core::str::FromStr for DecodedBuffer<CAP> {
3000 type Err = DecodeError;
3001
3002 fn from_str(input: &str) -> Result<Self, Self::Err> {
3007 Self::try_from(input)
3008 }
3009}
3010
3011#[cfg(feature = "alloc")]
3023pub struct SecretBuffer {
3024 bytes: alloc::vec::Vec<u8>,
3025}
3026
3027#[cfg(feature = "alloc")]
3028impl SecretBuffer {
3029 #[must_use]
3031 pub fn from_vec(mut bytes: alloc::vec::Vec<u8>) -> Self {
3032 wipe_vec_spare_capacity(&mut bytes);
3033 Self { bytes }
3034 }
3035
3036 #[must_use]
3038 pub fn from_slice(bytes: &[u8]) -> Self {
3039 Self::from_vec(bytes.to_vec())
3040 }
3041
3042 #[must_use]
3044 pub fn len(&self) -> usize {
3045 self.bytes.len()
3046 }
3047
3048 #[must_use]
3050 pub fn is_empty(&self) -> bool {
3051 self.bytes.is_empty()
3052 }
3053
3054 #[must_use]
3059 pub fn expose_secret(&self) -> &[u8] {
3060 &self.bytes
3061 }
3062
3063 pub fn expose_secret_utf8(&self) -> Result<&str, core::str::Utf8Error> {
3069 core::str::from_utf8(self.expose_secret())
3070 }
3071
3072 #[must_use]
3077 pub fn expose_secret_mut(&mut self) -> &mut [u8] {
3078 &mut self.bytes
3079 }
3080
3081 #[must_use]
3088 pub fn into_exposed_vec(mut self) -> alloc::vec::Vec<u8> {
3089 core::mem::take(&mut self.bytes)
3090 }
3091
3092 pub fn try_into_exposed_string(self) -> Result<alloc::string::String, Self> {
3102 if core::str::from_utf8(self.expose_secret()).is_err() {
3103 return Err(self);
3104 }
3105
3106 match alloc::string::String::from_utf8(self.into_exposed_vec()) {
3107 Ok(text) => Ok(text),
3108 Err(error) => Err(Self::from_vec(error.into_bytes())),
3109 }
3110 }
3111
3112 #[must_use]
3120 pub fn constant_time_eq(&self, other: &[u8]) -> bool {
3121 constant_time_eq_public_len(self.expose_secret(), other)
3122 }
3123
3124 pub fn clear(&mut self) {
3126 wipe_vec_all(&mut self.bytes);
3127 self.bytes.clear();
3128 }
3129}
3130
3131#[cfg(feature = "alloc")]
3132impl Clone for SecretBuffer {
3133 fn clone(&self) -> Self {
3134 Self::from_slice(self.expose_secret())
3135 }
3136}
3137
3138#[cfg(feature = "alloc")]
3139impl core::fmt::Debug for SecretBuffer {
3140 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
3141 formatter
3142 .debug_struct("SecretBuffer")
3143 .field("bytes", &"<redacted>")
3144 .field("len", &self.len())
3145 .finish()
3146 }
3147}
3148
3149#[cfg(feature = "alloc")]
3150impl core::fmt::Display for SecretBuffer {
3151 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
3152 formatter.write_str("<redacted>")
3153 }
3154}
3155
3156#[cfg(feature = "alloc")]
3157impl Drop for SecretBuffer {
3158 fn drop(&mut self) {
3159 wipe_vec_all(&mut self.bytes);
3160 }
3161}
3162
3163#[cfg(feature = "alloc")]
3164impl Eq for SecretBuffer {}
3165
3166#[cfg(feature = "alloc")]
3167impl PartialEq for SecretBuffer {
3168 fn eq(&self, other: &Self) -> bool {
3169 self.constant_time_eq(other.expose_secret())
3170 }
3171}
3172
3173#[cfg(feature = "alloc")]
3174impl PartialEq<&[u8]> for SecretBuffer {
3175 fn eq(&self, other: &&[u8]) -> bool {
3176 self.constant_time_eq(other)
3177 }
3178}
3179
3180#[cfg(feature = "alloc")]
3181impl<const N: usize> PartialEq<&[u8; N]> for SecretBuffer {
3182 fn eq(&self, other: &&[u8; N]) -> bool {
3183 self.constant_time_eq(&other[..])
3184 }
3185}
3186
3187#[cfg(feature = "alloc")]
3188impl PartialEq<&str> for SecretBuffer {
3189 fn eq(&self, other: &&str) -> bool {
3190 self.constant_time_eq(other.as_bytes())
3191 }
3192}
3193
3194#[cfg(feature = "alloc")]
3195impl PartialEq<alloc::string::String> for SecretBuffer {
3196 fn eq(&self, other: &alloc::string::String) -> bool {
3197 self.constant_time_eq(other.as_bytes())
3198 }
3199}
3200
3201#[cfg(feature = "alloc")]
3202impl PartialEq<SecretBuffer> for &[u8] {
3203 fn eq(&self, other: &SecretBuffer) -> bool {
3204 other.constant_time_eq(self)
3205 }
3206}
3207
3208#[cfg(feature = "alloc")]
3209impl<const N: usize> PartialEq<SecretBuffer> for &[u8; N] {
3210 fn eq(&self, other: &SecretBuffer) -> bool {
3211 other.constant_time_eq(&self[..])
3212 }
3213}
3214
3215#[cfg(feature = "alloc")]
3216impl PartialEq<SecretBuffer> for &str {
3217 fn eq(&self, other: &SecretBuffer) -> bool {
3218 other.constant_time_eq(self.as_bytes())
3219 }
3220}
3221
3222#[cfg(feature = "alloc")]
3223impl PartialEq<SecretBuffer> for alloc::string::String {
3224 fn eq(&self, other: &SecretBuffer) -> bool {
3225 other.constant_time_eq(self.as_bytes())
3226 }
3227}
3228
3229#[cfg(feature = "alloc")]
3230impl From<alloc::vec::Vec<u8>> for SecretBuffer {
3231 fn from(bytes: alloc::vec::Vec<u8>) -> Self {
3236 Self::from_vec(bytes)
3237 }
3238}
3239
3240#[cfg(feature = "alloc")]
3241impl From<alloc::string::String> for SecretBuffer {
3242 fn from(text: alloc::string::String) -> Self {
3247 Self::from_vec(text.into_bytes())
3248 }
3249}
3250
3251#[cfg(feature = "alloc")]
3252impl<const CAP: usize> From<EncodedBuffer<CAP>> for SecretBuffer {
3253 fn from(buffer: EncodedBuffer<CAP>) -> Self {
3259 Self::from_slice(buffer.as_bytes())
3260 }
3261}
3262
3263#[cfg(feature = "alloc")]
3264impl<const CAP: usize> From<DecodedBuffer<CAP>> for SecretBuffer {
3265 fn from(buffer: DecodedBuffer<CAP>) -> Self {
3271 Self::from_slice(buffer.as_bytes())
3272 }
3273}
3274
3275#[cfg(feature = "alloc")]
3276impl TryFrom<&[u8]> for SecretBuffer {
3277 type Error = DecodeError;
3278
3279 fn try_from(input: &[u8]) -> Result<Self, Self::Error> {
3284 STANDARD.decode_secret(input)
3285 }
3286}
3287
3288#[cfg(feature = "alloc")]
3289impl<const N: usize> TryFrom<&[u8; N]> for SecretBuffer {
3290 type Error = DecodeError;
3291
3292 fn try_from(input: &[u8; N]) -> Result<Self, Self::Error> {
3298 Self::try_from(&input[..])
3299 }
3300}
3301
3302#[cfg(feature = "alloc")]
3303impl TryFrom<&str> for SecretBuffer {
3304 type Error = DecodeError;
3305
3306 fn try_from(input: &str) -> Result<Self, Self::Error> {
3311 Self::try_from(input.as_bytes())
3312 }
3313}
3314
3315#[cfg(feature = "alloc")]
3316impl core::str::FromStr for SecretBuffer {
3317 type Err = DecodeError;
3318
3319 fn from_str(input: &str) -> Result<Self, Self::Err> {
3324 Self::try_from(input)
3325 }
3326}
3327
3328#[derive(Clone, Copy, Debug, Eq, PartialEq)]
3334pub struct Profile<A, const PAD: bool> {
3335 engine: Engine<A, PAD>,
3336 wrap: Option<LineWrap>,
3337}
3338
3339impl<A, const PAD: bool> Profile<A, PAD>
3340where
3341 A: Alphabet,
3342{
3343 #[must_use]
3345 pub const fn new(engine: Engine<A, PAD>, wrap: Option<LineWrap>) -> Self {
3346 Self { engine, wrap }
3347 }
3348
3349 #[must_use]
3355 pub const fn checked_new(engine: Engine<A, PAD>, wrap: Option<LineWrap>) -> Option<Self> {
3356 match wrap {
3357 Some(wrap) if !wrap.is_valid() => None,
3358 _ => Some(Self::new(engine, wrap)),
3359 }
3360 }
3361
3362 #[must_use]
3364 pub const fn is_valid(&self) -> bool {
3365 match self.wrap {
3366 Some(wrap) => wrap.is_valid(),
3367 None => true,
3368 }
3369 }
3370
3371 #[must_use]
3373 pub const fn engine(&self) -> Engine<A, PAD> {
3374 self.engine
3375 }
3376
3377 #[must_use]
3379 pub const fn is_padded(&self) -> bool {
3380 PAD
3381 }
3382
3383 #[must_use]
3385 pub const fn is_wrapped(&self) -> bool {
3386 self.wrap.is_some()
3387 }
3388
3389 #[must_use]
3391 pub const fn line_wrap(&self) -> Option<LineWrap> {
3392 self.wrap
3393 }
3394
3395 #[must_use]
3397 pub const fn line_len(&self) -> Option<usize> {
3398 match self.wrap {
3399 Some(wrap) => Some(wrap.line_len()),
3400 None => None,
3401 }
3402 }
3403
3404 #[must_use]
3406 pub const fn line_ending(&self) -> Option<LineEnding> {
3407 match self.wrap {
3408 Some(wrap) => Some(wrap.line_ending()),
3409 None => None,
3410 }
3411 }
3412
3413 pub const fn encoded_len(&self, input_len: usize) -> Result<usize, EncodeError> {
3415 match self.wrap {
3416 Some(wrap) => wrapped_encoded_len(input_len, PAD, wrap),
3417 None => encoded_len(input_len, PAD),
3418 }
3419 }
3420
3421 #[must_use]
3424 pub const fn checked_encoded_len(&self, input_len: usize) -> Option<usize> {
3425 match self.wrap {
3426 Some(wrap) => checked_wrapped_encoded_len(input_len, PAD, wrap),
3427 None => checked_encoded_len(input_len, PAD),
3428 }
3429 }
3430
3431 pub fn decoded_len(&self, input: &[u8]) -> Result<usize, DecodeError> {
3433 match self.wrap {
3434 Some(wrap) => self.engine.decoded_len_wrapped(input, wrap),
3435 None => self.engine.decoded_len(input),
3436 }
3437 }
3438
3439 pub fn validate_result(&self, input: &[u8]) -> Result<(), DecodeError> {
3441 match self.wrap {
3442 Some(wrap) => self.engine.validate_wrapped_result(input, wrap),
3443 None => self.engine.validate_result(input),
3444 }
3445 }
3446
3447 #[must_use]
3449 pub fn validate(&self, input: &[u8]) -> bool {
3450 self.validate_result(input).is_ok()
3451 }
3452
3453 pub fn encode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, EncodeError> {
3455 match self.wrap {
3456 Some(wrap) => self.engine.encode_slice_wrapped(input, output, wrap),
3457 None => self.engine.encode_slice(input, output),
3458 }
3459 }
3460
3461 pub fn encode_slice_clear_tail(
3464 &self,
3465 input: &[u8],
3466 output: &mut [u8],
3467 ) -> Result<usize, EncodeError> {
3468 match self.wrap {
3469 Some(wrap) => self
3470 .engine
3471 .encode_slice_wrapped_clear_tail(input, output, wrap),
3472 None => self.engine.encode_slice_clear_tail(input, output),
3473 }
3474 }
3475
3476 pub fn encode_buffer<const CAP: usize>(
3482 &self,
3483 input: &[u8],
3484 ) -> Result<EncodedBuffer<CAP>, EncodeError> {
3485 let mut output = EncodedBuffer::new();
3486 let written = match self.encode_slice_clear_tail(input, &mut output.bytes) {
3487 Ok(written) => written,
3488 Err(err) => {
3489 output.clear();
3490 return Err(err);
3491 }
3492 };
3493 output.len = written;
3494 Ok(output)
3495 }
3496
3497 pub fn decode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
3499 match self.wrap {
3500 Some(wrap) => self.engine.decode_slice_wrapped(input, output, wrap),
3501 None => self.engine.decode_slice(input, output),
3502 }
3503 }
3504
3505 pub fn decode_slice_clear_tail(
3508 &self,
3509 input: &[u8],
3510 output: &mut [u8],
3511 ) -> Result<usize, DecodeError> {
3512 match self.wrap {
3513 Some(wrap) => self
3514 .engine
3515 .decode_slice_wrapped_clear_tail(input, output, wrap),
3516 None => self.engine.decode_slice_clear_tail(input, output),
3517 }
3518 }
3519
3520 pub fn decode_buffer<const CAP: usize>(
3526 &self,
3527 input: &[u8],
3528 ) -> Result<DecodedBuffer<CAP>, DecodeError> {
3529 let mut output = DecodedBuffer::new();
3530 let written = match self.decode_slice_clear_tail(input, &mut output.bytes) {
3531 Ok(written) => written,
3532 Err(err) => {
3533 output.clear();
3534 return Err(err);
3535 }
3536 };
3537 output.len = written;
3538 Ok(output)
3539 }
3540
3541 pub fn decode_in_place<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], DecodeError> {
3558 match self.wrap {
3559 Some(wrap) => self.engine.decode_in_place_wrapped(buffer, wrap),
3560 None => self.engine.decode_in_place(buffer),
3561 }
3562 }
3563
3564 pub fn decode_in_place_clear_tail<'a>(
3583 &self,
3584 buffer: &'a mut [u8],
3585 ) -> Result<&'a mut [u8], DecodeError> {
3586 match self.wrap {
3587 Some(wrap) => self.engine.decode_in_place_wrapped_clear_tail(buffer, wrap),
3588 None => self.engine.decode_in_place_clear_tail(buffer),
3589 }
3590 }
3591
3592 #[cfg(feature = "alloc")]
3594 pub fn encode_vec(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, EncodeError> {
3595 match self.wrap {
3596 Some(wrap) => self.engine.encode_wrapped_vec(input, wrap),
3597 None => self.engine.encode_vec(input),
3598 }
3599 }
3600
3601 #[cfg(feature = "alloc")]
3603 pub fn encode_secret(&self, input: &[u8]) -> Result<SecretBuffer, EncodeError> {
3604 self.encode_vec(input).map(SecretBuffer::from_vec)
3605 }
3606
3607 #[cfg(feature = "alloc")]
3609 pub fn encode_string(&self, input: &[u8]) -> Result<alloc::string::String, EncodeError> {
3610 match self.wrap {
3611 Some(wrap) => self.engine.encode_wrapped_string(input, wrap),
3612 None => self.engine.encode_string(input),
3613 }
3614 }
3615
3616 #[cfg(feature = "alloc")]
3618 pub fn decode_vec(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> {
3619 match self.wrap {
3620 Some(wrap) => self.engine.decode_wrapped_vec(input, wrap),
3621 None => self.engine.decode_vec(input),
3622 }
3623 }
3624
3625 #[cfg(feature = "alloc")]
3627 pub fn decode_secret(&self, input: &[u8]) -> Result<SecretBuffer, DecodeError> {
3628 self.decode_vec(input).map(SecretBuffer::from_vec)
3629 }
3630}
3631
3632impl<A, const PAD: bool> Default for Profile<A, PAD>
3633where
3634 A: Alphabet,
3635{
3636 fn default() -> Self {
3637 Self::new(Engine::new(), None)
3638 }
3639}
3640
3641impl<A, const PAD: bool> core::fmt::Display for Profile<A, PAD>
3642where
3643 A: Alphabet,
3644{
3645 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
3646 match self.wrap {
3647 Some(wrap) => write!(formatter, "padded={PAD} wrap={wrap}"),
3648 None => write!(formatter, "padded={PAD} wrap=none"),
3649 }
3650 }
3651}
3652
3653impl<A, const PAD: bool> From<Engine<A, PAD>> for Profile<A, PAD>
3654where
3655 A: Alphabet,
3656{
3657 fn from(engine: Engine<A, PAD>) -> Self {
3658 Self::new(engine, None)
3659 }
3660}
3661
3662pub const MIME: Profile<Standard, true> = Profile::new(STANDARD, Some(LineWrap::MIME));
3664
3665pub const PEM: Profile<Standard, true> = Profile::new(STANDARD, Some(LineWrap::PEM));
3667
3668pub const PEM_CRLF: Profile<Standard, true> = Profile::new(STANDARD, Some(LineWrap::PEM_CRLF));
3670
3671pub const BCRYPT: Profile<Bcrypt, false> = Profile::new(BCRYPT_NO_PAD, None);
3676
3677pub const CRYPT: Profile<Crypt, false> = Profile::new(CRYPT_NO_PAD, None);
3682
3683pub const fn encoded_len(input_len: usize, padded: bool) -> Result<usize, EncodeError> {
3698 match checked_encoded_len(input_len, padded) {
3699 Some(len) => Ok(len),
3700 None => Err(EncodeError::LengthOverflow),
3701 }
3702}
3703
3704pub const fn wrapped_encoded_len(
3718 input_len: usize,
3719 padded: bool,
3720 wrap: LineWrap,
3721) -> Result<usize, EncodeError> {
3722 if wrap.line_len == 0 {
3723 return Err(EncodeError::InvalidLineWrap { line_len: 0 });
3724 }
3725
3726 let Some(encoded) = checked_encoded_len(input_len, padded) else {
3727 return Err(EncodeError::LengthOverflow);
3728 };
3729 if encoded == 0 {
3730 return Ok(0);
3731 }
3732
3733 let breaks = (encoded - 1) / wrap.line_len;
3734 let Some(line_ending_bytes) = breaks.checked_mul(wrap.line_ending.byte_len()) else {
3735 return Err(EncodeError::LengthOverflow);
3736 };
3737 match encoded.checked_add(line_ending_bytes) {
3738 Some(len) => Ok(len),
3739 None => Err(EncodeError::LengthOverflow),
3740 }
3741}
3742
3743#[must_use]
3759pub const fn checked_wrapped_encoded_len(
3760 input_len: usize,
3761 padded: bool,
3762 wrap: LineWrap,
3763) -> Option<usize> {
3764 if wrap.line_len == 0 {
3765 return None;
3766 }
3767
3768 let Some(encoded) = checked_encoded_len(input_len, padded) else {
3769 return None;
3770 };
3771 if encoded == 0 {
3772 return Some(0);
3773 }
3774
3775 let breaks = (encoded - 1) / wrap.line_len;
3776 let Some(line_ending_bytes) = breaks.checked_mul(wrap.line_ending.byte_len()) else {
3777 return None;
3778 };
3779 encoded.checked_add(line_ending_bytes)
3780}
3781
3782#[must_use]
3793pub const fn checked_encoded_len(input_len: usize, padded: bool) -> Option<usize> {
3794 let groups = input_len / 3;
3795 if groups > usize::MAX / 4 {
3796 return None;
3797 }
3798 let full = groups * 4;
3799 let rem = input_len % 3;
3800 if rem == 0 {
3801 Some(full)
3802 } else if padded {
3803 full.checked_add(4)
3804 } else {
3805 full.checked_add(rem + 1)
3806 }
3807}
3808
3809#[must_use]
3820pub const fn decoded_capacity(encoded_len: usize) -> usize {
3821 let rem = encoded_len % 4;
3822 encoded_len / 4 * 3
3823 + if rem == 2 {
3824 1
3825 } else if rem == 3 {
3826 2
3827 } else {
3828 0
3829 }
3830}
3831
3832pub fn decoded_len(input: &[u8], padded: bool) -> Result<usize, DecodeError> {
3846 if padded {
3847 decoded_len_padded(input)
3848 } else {
3849 decoded_len_unpadded(input)
3850 }
3851}
3852
3853#[macro_export]
3885macro_rules! define_alphabet {
3886 ($(#[$meta:meta])* $vis:vis struct $name:ident = $encode:expr;) => {
3887 $(#[$meta])*
3888 #[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
3889 $vis struct $name;
3890
3891 impl $crate::Alphabet for $name {
3892 const ENCODE: [u8; 64] = *$encode;
3893
3894 #[inline]
3895 fn decode(byte: u8) -> Option<u8> {
3896 $crate::decode_alphabet_byte(byte, &Self::ENCODE)
3897 }
3898 }
3899
3900 const _: [(); 1] = [(); match $crate::validate_alphabet(
3901 &<$name as $crate::Alphabet>::ENCODE,
3902 ) {
3903 Ok(()) => 1,
3904 Err(_) => 0,
3905 }];
3906 };
3907}
3908
3909pub const fn validate_alphabet(encode: &[u8; 64]) -> Result<(), AlphabetError> {
3922 let mut index = 0;
3923 while index < encode.len() {
3924 let byte = encode[index];
3925 if !is_visible_ascii(byte) {
3926 return Err(AlphabetError::InvalidByte { index, byte });
3927 }
3928 if byte == b'=' {
3929 return Err(AlphabetError::PaddingByte { index });
3930 }
3931
3932 let mut duplicate = index + 1;
3933 while duplicate < encode.len() {
3934 if encode[duplicate] == byte {
3935 return Err(AlphabetError::DuplicateByte {
3936 first: index,
3937 second: duplicate,
3938 byte,
3939 });
3940 }
3941 duplicate += 1;
3942 }
3943
3944 index += 1;
3945 }
3946
3947 Ok(())
3948}
3949
3950#[must_use]
3978pub const fn decode_alphabet_byte(byte: u8, encode: &[u8; 64]) -> Option<u8> {
3979 let mut index = 0;
3980 let mut candidate = 0;
3981 let mut decoded = 0;
3982 let mut valid = 0;
3983 while index < encode.len() {
3984 let matches = ct_mask_eq_u8(byte, encode[index]);
3985 decoded |= candidate & matches;
3986 valid |= matches;
3987 index += 1;
3988 candidate += 1;
3989 }
3990
3991 if valid == 0 { None } else { Some(decoded) }
3992}
3993
3994pub trait Alphabet {
3996 const ENCODE: [u8; 64];
3998
3999 #[must_use]
4010 fn encode(value: u8) -> u8 {
4011 encode_alphabet_value(value, &Self::ENCODE)
4012 }
4013
4014 fn decode(byte: u8) -> Option<u8>;
4016}
4017
4018const fn is_visible_ascii(byte: u8) -> bool {
4019 byte >= 0x21 && byte <= 0x7e
4020}
4021
4022#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
4024pub struct Standard;
4025
4026impl Alphabet for Standard {
4027 const ENCODE: [u8; 64] = *b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
4028
4029 #[inline]
4030 fn encode(value: u8) -> u8 {
4031 encode_ascii_base64(value, Self::ENCODE[62], Self::ENCODE[63])
4032 }
4033
4034 #[inline]
4035 fn decode(byte: u8) -> Option<u8> {
4036 decode_ascii_base64(byte, Self::ENCODE[62], Self::ENCODE[63])
4037 }
4038}
4039
4040#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
4042pub struct UrlSafe;
4043
4044impl Alphabet for UrlSafe {
4045 const ENCODE: [u8; 64] = *b"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
4046
4047 #[inline]
4048 fn encode(value: u8) -> u8 {
4049 encode_ascii_base64(value, Self::ENCODE[62], Self::ENCODE[63])
4050 }
4051
4052 #[inline]
4053 fn decode(byte: u8) -> Option<u8> {
4054 decode_ascii_base64(byte, Self::ENCODE[62], Self::ENCODE[63])
4055 }
4056}
4057
4058#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
4064pub struct Bcrypt;
4065
4066impl Alphabet for Bcrypt {
4067 const ENCODE: [u8; 64] = *b"./ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
4068
4069 #[inline]
4070 fn decode(byte: u8) -> Option<u8> {
4071 decode_alphabet_byte(byte, &Self::ENCODE)
4072 }
4073}
4074
4075#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
4080pub struct Crypt;
4081
4082impl Alphabet for Crypt {
4083 const ENCODE: [u8; 64] = *b"./0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
4084
4085 #[inline]
4086 fn decode(byte: u8) -> Option<u8> {
4087 decode_alphabet_byte(byte, &Self::ENCODE)
4088 }
4089}
4090
4091#[inline]
4092const fn encode_base64_value<A: Alphabet>(value: u8) -> u8 {
4093 encode_alphabet_value(value, &A::ENCODE)
4094}
4095
4096#[inline]
4097fn encode_base64_value_runtime<A: Alphabet>(value: u8) -> u8 {
4098 A::encode(value)
4099}
4100
4101#[inline]
4102const fn encode_alphabet_value(value: u8, encode: &[u8; 64]) -> u8 {
4103 let mut output = 0;
4104 let mut index = 0;
4105 let mut candidate = 0;
4106 while index < encode.len() {
4107 output |= encode[index] & ct_mask_eq_u8(value, candidate);
4108 index += 1;
4109 candidate += 1;
4110 }
4111 output
4112}
4113
4114#[inline]
4115const fn encode_ascii_base64(value: u8, value_62_byte: u8, value_63_byte: u8) -> u8 {
4116 let upper = ct_mask_lt_u8(value, 26);
4117 let lower = ct_mask_lt_u8(value.wrapping_sub(26), 26);
4118 let digit = ct_mask_lt_u8(value.wrapping_sub(52), 10);
4119 let value_62 = ct_mask_eq_u8(value, 0x3e);
4120 let value_63 = ct_mask_eq_u8(value, 0x3f);
4121
4122 (value.wrapping_add(b'A') & upper)
4123 | (value.wrapping_sub(26).wrapping_add(b'a') & lower)
4124 | (value.wrapping_sub(52).wrapping_add(b'0') & digit)
4125 | (value_62_byte & value_62)
4126 | (value_63_byte & value_63)
4127}
4128
4129#[inline]
4130fn decode_ascii_base64(byte: u8, value_62_byte: u8, value_63_byte: u8) -> Option<u8> {
4131 let upper = ct_mask_lt_u8(byte.wrapping_sub(b'A'), 26);
4132 let lower = ct_mask_lt_u8(byte.wrapping_sub(b'a'), 26);
4133 let digit = ct_mask_lt_u8(byte.wrapping_sub(b'0'), 10);
4134 let value_62 = ct_mask_eq_u8(byte, value_62_byte);
4135 let value_63 = ct_mask_eq_u8(byte, value_63_byte);
4136 let valid = upper | lower | digit | value_62 | value_63;
4137
4138 let decoded = (byte.wrapping_sub(b'A') & upper)
4139 | (byte.wrapping_sub(b'a').wrapping_add(26) & lower)
4140 | (byte.wrapping_sub(b'0').wrapping_add(52) & digit)
4141 | (0x3e & value_62)
4142 | (0x3f & value_63);
4143
4144 if valid == 0 { None } else { Some(decoded) }
4145}
4146
4147#[inline]
4148const fn ct_mask_bit(bit: u8) -> u8 {
4149 0u8.wrapping_sub(bit & 1)
4150}
4151
4152#[inline]
4153const fn ct_mask_nonzero_u8(value: u8) -> u8 {
4154 let wide = value as u16;
4155 let negative = 0u16.wrapping_sub(wide);
4156 let nonzero = ((wide | negative) >> 8) as u8;
4157 ct_mask_bit(nonzero)
4158}
4159
4160#[inline]
4161const fn ct_mask_eq_u8(left: u8, right: u8) -> u8 {
4162 !ct_mask_nonzero_u8(left ^ right)
4163}
4164
4165#[inline]
4166const fn ct_mask_lt_u8(left: u8, right: u8) -> u8 {
4167 let diff = (left as u16).wrapping_sub(right as u16);
4168 ct_mask_bit((diff >> 8) as u8)
4169}
4170
4171fn constant_time_eq_public_len(left: &[u8], right: &[u8]) -> bool {
4172 if left.len() != right.len() {
4173 return false;
4174 }
4175
4176 let diff = left.iter().zip(right).fold(0u8, |diff, (left, right)| {
4177 diff | core::hint::black_box(*left ^ *right)
4178 });
4179 diff == 0
4180}
4181
4182mod backend {
4183 use super::{
4184 Alphabet, DecodeError, EncodeError, checked_encoded_len, decode_padded, decode_unpadded,
4185 encode_base64_value_runtime,
4186 };
4187
4188 pub(super) fn encode_slice<A, const PAD: bool>(
4189 input: &[u8],
4190 output: &mut [u8],
4191 ) -> Result<usize, EncodeError>
4192 where
4193 A: Alphabet,
4194 {
4195 #[cfg(feature = "simd")]
4196 match super::simd::active_backend() {
4197 super::simd::ActiveBackend::Scalar => {}
4198 }
4199
4200 scalar_encode_slice::<A, PAD>(input, output)
4201 }
4202
4203 pub(super) fn decode_slice<A, const PAD: bool>(
4204 input: &[u8],
4205 output: &mut [u8],
4206 ) -> Result<usize, DecodeError>
4207 where
4208 A: Alphabet,
4209 {
4210 #[cfg(feature = "simd")]
4211 match super::simd::active_backend() {
4212 super::simd::ActiveBackend::Scalar => {}
4213 }
4214
4215 scalar_decode_slice::<A, PAD>(input, output)
4216 }
4217
4218 #[cfg(test)]
4219 pub(super) fn scalar_reference_encode_slice<A, const PAD: bool>(
4220 input: &[u8],
4221 output: &mut [u8],
4222 ) -> Result<usize, EncodeError>
4223 where
4224 A: Alphabet,
4225 {
4226 scalar_encode_slice::<A, PAD>(input, output)
4227 }
4228
4229 #[cfg(test)]
4230 pub(super) fn scalar_reference_decode_slice<A, const PAD: bool>(
4231 input: &[u8],
4232 output: &mut [u8],
4233 ) -> Result<usize, DecodeError>
4234 where
4235 A: Alphabet,
4236 {
4237 scalar_decode_slice::<A, PAD>(input, output)
4238 }
4239
4240 fn scalar_encode_slice<A, const PAD: bool>(
4241 input: &[u8],
4242 output: &mut [u8],
4243 ) -> Result<usize, EncodeError>
4244 where
4245 A: Alphabet,
4246 {
4247 let required = checked_encoded_len(input.len(), PAD).ok_or(EncodeError::LengthOverflow)?;
4248 if output.len() < required {
4249 return Err(EncodeError::OutputTooSmall {
4250 required,
4251 available: output.len(),
4252 });
4253 }
4254
4255 let mut read = 0;
4256 let mut write = 0;
4257 while read + 3 <= input.len() {
4258 let b0 = input[read];
4259 let b1 = input[read + 1];
4260 let b2 = input[read + 2];
4261
4262 output[write] = encode_base64_value_runtime::<A>(b0 >> 2);
4263 output[write + 1] =
4264 encode_base64_value_runtime::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
4265 output[write + 2] =
4266 encode_base64_value_runtime::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
4267 output[write + 3] = encode_base64_value_runtime::<A>(b2 & 0b0011_1111);
4268
4269 read += 3;
4270 write += 4;
4271 }
4272
4273 match input.len() - read {
4274 0 => {}
4275 1 => {
4276 let b0 = input[read];
4277 output[write] = encode_base64_value_runtime::<A>(b0 >> 2);
4278 output[write + 1] = encode_base64_value_runtime::<A>((b0 & 0b0000_0011) << 4);
4279 write += 2;
4280 if PAD {
4281 output[write] = b'=';
4282 output[write + 1] = b'=';
4283 write += 2;
4284 }
4285 }
4286 2 => {
4287 let b0 = input[read];
4288 let b1 = input[read + 1];
4289 output[write] = encode_base64_value_runtime::<A>(b0 >> 2);
4290 output[write + 1] =
4291 encode_base64_value_runtime::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
4292 output[write + 2] = encode_base64_value_runtime::<A>((b1 & 0b0000_1111) << 2);
4293 write += 3;
4294 if PAD {
4295 output[write] = b'=';
4296 write += 1;
4297 }
4298 }
4299 _ => unreachable!(),
4300 }
4301
4302 Ok(write)
4303 }
4304
4305 fn scalar_decode_slice<A, const PAD: bool>(
4306 input: &[u8],
4307 output: &mut [u8],
4308 ) -> Result<usize, DecodeError>
4309 where
4310 A: Alphabet,
4311 {
4312 if input.is_empty() {
4313 return Ok(0);
4314 }
4315
4316 if PAD {
4317 decode_padded::<A>(input, output)
4318 } else {
4319 decode_unpadded::<A>(input, output)
4320 }
4321 }
4322}
4323
4324pub struct Engine<A, const PAD: bool> {
4326 alphabet: core::marker::PhantomData<A>,
4327}
4328
4329impl<A, const PAD: bool> Clone for Engine<A, PAD> {
4330 fn clone(&self) -> Self {
4331 *self
4332 }
4333}
4334
4335impl<A, const PAD: bool> Copy for Engine<A, PAD> {}
4336
4337impl<A, const PAD: bool> core::fmt::Debug for Engine<A, PAD> {
4338 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
4339 formatter
4340 .debug_struct("Engine")
4341 .field("padded", &PAD)
4342 .finish()
4343 }
4344}
4345
4346impl<A, const PAD: bool> core::fmt::Display for Engine<A, PAD> {
4347 fn fmt(&self, formatter: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
4348 write!(formatter, "padded={PAD}")
4349 }
4350}
4351
4352impl<A, const PAD: bool> Default for Engine<A, PAD> {
4353 fn default() -> Self {
4354 Self {
4355 alphabet: core::marker::PhantomData,
4356 }
4357 }
4358}
4359
4360impl<A, const PAD: bool> Eq for Engine<A, PAD> {}
4361
4362impl<A, const PAD: bool> PartialEq for Engine<A, PAD> {
4363 fn eq(&self, _other: &Self) -> bool {
4364 true
4365 }
4366}
4367
4368impl<A, const PAD: bool> Engine<A, PAD>
4369where
4370 A: Alphabet,
4371{
4372 #[must_use]
4374 pub const fn new() -> Self {
4375 Self {
4376 alphabet: core::marker::PhantomData,
4377 }
4378 }
4379
4380 #[must_use]
4382 pub const fn is_padded(&self) -> bool {
4383 PAD
4384 }
4385
4386 #[must_use]
4391 pub const fn profile(&self) -> Profile<A, PAD> {
4392 Profile::new(*self, None)
4393 }
4394
4395 #[must_use]
4401 pub const fn ct_decoder(&self) -> ct::CtEngine<A, PAD> {
4402 ct::CtEngine::new()
4403 }
4404
4405 #[cfg(feature = "stream")]
4419 #[must_use]
4420 pub fn encoder_writer<W>(&self, inner: W) -> stream::Encoder<W, A, PAD> {
4421 stream::Encoder::new(inner, *self)
4422 }
4423
4424 #[cfg(feature = "stream")]
4438 #[must_use]
4439 pub fn decoder_writer<W>(&self, inner: W) -> stream::Decoder<W, A, PAD> {
4440 stream::Decoder::new(inner, *self)
4441 }
4442
4443 #[cfg(feature = "stream")]
4458 #[must_use]
4459 pub fn encoder_reader<R>(&self, inner: R) -> stream::EncoderReader<R, A, PAD> {
4460 stream::EncoderReader::new(inner, *self)
4461 }
4462
4463 #[cfg(feature = "stream")]
4478 #[must_use]
4479 pub fn decoder_reader<R>(&self, inner: R) -> stream::DecoderReader<R, A, PAD> {
4480 stream::DecoderReader::new(inner, *self)
4481 }
4482
4483 pub const fn encoded_len(&self, input_len: usize) -> Result<usize, EncodeError> {
4485 encoded_len(input_len, PAD)
4486 }
4487
4488 #[must_use]
4490 pub const fn checked_encoded_len(&self, input_len: usize) -> Option<usize> {
4491 checked_encoded_len(input_len, PAD)
4492 }
4493
4494 pub const fn wrapped_encoded_len(
4499 &self,
4500 input_len: usize,
4501 wrap: LineWrap,
4502 ) -> Result<usize, EncodeError> {
4503 wrapped_encoded_len(input_len, PAD, wrap)
4504 }
4505
4506 #[must_use]
4509 pub const fn checked_wrapped_encoded_len(
4510 &self,
4511 input_len: usize,
4512 wrap: LineWrap,
4513 ) -> Option<usize> {
4514 checked_wrapped_encoded_len(input_len, PAD, wrap)
4515 }
4516
4517 pub fn decoded_len(&self, input: &[u8]) -> Result<usize, DecodeError> {
4522 decoded_len(input, PAD)
4523 }
4524
4525 pub fn decoded_len_legacy(&self, input: &[u8]) -> Result<usize, DecodeError> {
4531 validate_legacy_decode::<A, PAD>(input)
4532 }
4533
4534 pub fn decoded_len_wrapped(&self, input: &[u8], wrap: LineWrap) -> Result<usize, DecodeError> {
4541 validate_wrapped_decode::<A, PAD>(input, wrap)
4542 }
4543
4544 pub fn validate_result(&self, input: &[u8]) -> Result<(), DecodeError> {
4559 validate_decode::<A, PAD>(input).map(|_| ())
4560 }
4561
4562 #[must_use]
4575 pub fn validate(&self, input: &[u8]) -> bool {
4576 self.validate_result(input).is_ok()
4577 }
4578
4579 pub fn validate_legacy_result(&self, input: &[u8]) -> Result<(), DecodeError> {
4594 validate_legacy_decode::<A, PAD>(input).map(|_| ())
4595 }
4596
4597 #[must_use]
4611 pub fn validate_legacy(&self, input: &[u8]) -> bool {
4612 self.validate_legacy_result(input).is_ok()
4613 }
4614
4615 pub fn validate_wrapped_result(&self, input: &[u8], wrap: LineWrap) -> Result<(), DecodeError> {
4631 validate_wrapped_decode::<A, PAD>(input, wrap).map(|_| ())
4632 }
4633
4634 #[must_use]
4648 pub fn validate_wrapped(&self, input: &[u8], wrap: LineWrap) -> bool {
4649 self.validate_wrapped_result(input, wrap).is_ok()
4650 }
4651
4652 #[must_use]
4684 pub const fn encode_array<const INPUT_LEN: usize, const OUTPUT_LEN: usize>(
4685 &self,
4686 input: &[u8; INPUT_LEN],
4687 ) -> [u8; OUTPUT_LEN] {
4688 let Some(required) = checked_encoded_len(INPUT_LEN, PAD) else {
4689 panic!("encoded base64 length overflows usize");
4690 };
4691 assert!(
4692 required == OUTPUT_LEN,
4693 "base64 output array has incorrect length"
4694 );
4695
4696 let mut output = [0u8; OUTPUT_LEN];
4697 let mut read = 0;
4698 let mut write = 0;
4699 while INPUT_LEN - read >= 3 {
4700 let b0 = input[read];
4701 let b1 = input[read + 1];
4702 let b2 = input[read + 2];
4703
4704 output[write] = encode_base64_value::<A>(b0 >> 2);
4705 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
4706 output[write + 2] = encode_base64_value::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
4707 output[write + 3] = encode_base64_value::<A>(b2 & 0b0011_1111);
4708
4709 read += 3;
4710 write += 4;
4711 }
4712
4713 match INPUT_LEN - read {
4714 0 => {}
4715 1 => {
4716 let b0 = input[read];
4717 output[write] = encode_base64_value::<A>(b0 >> 2);
4718 output[write + 1] = encode_base64_value::<A>((b0 & 0b0000_0011) << 4);
4719 write += 2;
4720 if PAD {
4721 output[write] = b'=';
4722 output[write + 1] = b'=';
4723 }
4724 }
4725 2 => {
4726 let b0 = input[read];
4727 let b1 = input[read + 1];
4728 output[write] = encode_base64_value::<A>(b0 >> 2);
4729 output[write + 1] = encode_base64_value::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
4730 output[write + 2] = encode_base64_value::<A>((b1 & 0b0000_1111) << 2);
4731 if PAD {
4732 output[write + 3] = b'=';
4733 }
4734 }
4735 _ => unreachable!(),
4736 }
4737
4738 output
4739 }
4740
4741 pub fn encode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, EncodeError> {
4743 backend::encode_slice::<A, PAD>(input, output)
4744 }
4745
4746 pub fn encode_slice_wrapped(
4765 &self,
4766 input: &[u8],
4767 output: &mut [u8],
4768 wrap: LineWrap,
4769 ) -> Result<usize, EncodeError> {
4770 let required = self.wrapped_encoded_len(input.len(), wrap)?;
4771 if output.len() < required {
4772 return Err(EncodeError::OutputTooSmall {
4773 required,
4774 available: output.len(),
4775 });
4776 }
4777
4778 let encoded_len =
4779 checked_encoded_len(input.len(), PAD).ok_or(EncodeError::LengthOverflow)?;
4780 if encoded_len == 0 {
4781 return Ok(0);
4782 }
4783
4784 if output.len() < required.saturating_add(encoded_len) {
4785 let mut scratch = [0u8; 1024];
4786 let mut input_offset = 0;
4787 let mut output_offset = 0;
4788 let mut column = 0;
4789
4790 while input_offset < input.len() {
4791 let remaining = input.len() - input_offset;
4792 let mut take = remaining.min(768);
4793 if remaining > take {
4794 take -= take % 3;
4795 }
4796 if take == 0 {
4797 take = remaining;
4798 }
4799
4800 let encoded =
4801 self.encode_slice(&input[input_offset..input_offset + take], &mut scratch)?;
4802 write_wrapped_bytes(
4803 &scratch[..encoded],
4804 output,
4805 &mut output_offset,
4806 &mut column,
4807 wrap,
4808 );
4809 wipe_bytes(&mut scratch[..encoded]);
4810 input_offset += take;
4811 }
4812
4813 Ok(output_offset)
4814 } else {
4815 let encoded =
4816 self.encode_slice(input, &mut output[required..required + encoded_len])?;
4817 let mut output_offset = 0;
4818 let mut column = 0;
4819 let mut read = required;
4820 while read < required + encoded {
4821 let byte = output[read];
4822 write_wrapped_byte(byte, output, &mut output_offset, &mut column, wrap);
4823 read += 1;
4824 }
4825 wipe_bytes(&mut output[required..required + encoded]);
4826 Ok(output_offset)
4827 }
4828 }
4829
4830 pub fn encode_slice_wrapped_clear_tail(
4836 &self,
4837 input: &[u8],
4838 output: &mut [u8],
4839 wrap: LineWrap,
4840 ) -> Result<usize, EncodeError> {
4841 let written = match self.encode_slice_wrapped(input, output, wrap) {
4842 Ok(written) => written,
4843 Err(err) => {
4844 wipe_bytes(output);
4845 return Err(err);
4846 }
4847 };
4848 wipe_tail(output, written);
4849 Ok(written)
4850 }
4851
4852 pub fn encode_wrapped_buffer<const CAP: usize>(
4858 &self,
4859 input: &[u8],
4860 wrap: LineWrap,
4861 ) -> Result<EncodedBuffer<CAP>, EncodeError> {
4862 let mut output = EncodedBuffer::new();
4863 let written = match self.encode_slice_wrapped_clear_tail(input, &mut output.bytes, wrap) {
4864 Ok(written) => written,
4865 Err(err) => {
4866 output.clear();
4867 return Err(err);
4868 }
4869 };
4870 output.len = written;
4871 Ok(output)
4872 }
4873
4874 #[cfg(feature = "alloc")]
4876 pub fn encode_wrapped_vec(
4877 &self,
4878 input: &[u8],
4879 wrap: LineWrap,
4880 ) -> Result<alloc::vec::Vec<u8>, EncodeError> {
4881 let required = self.wrapped_encoded_len(input.len(), wrap)?;
4882 let mut output = alloc::vec![0; required];
4883 let written = self.encode_slice_wrapped(input, &mut output, wrap)?;
4884 output.truncate(written);
4885 Ok(output)
4886 }
4887
4888 #[cfg(feature = "alloc")]
4890 pub fn encode_wrapped_string(
4891 &self,
4892 input: &[u8],
4893 wrap: LineWrap,
4894 ) -> Result<alloc::string::String, EncodeError> {
4895 let output = self.encode_wrapped_vec(input, wrap)?;
4896 match alloc::string::String::from_utf8(output) {
4897 Ok(output) => Ok(output),
4898 Err(_) => unreachable!("base64 encoder produced non-UTF-8 output"),
4899 }
4900 }
4901
4902 #[cfg(feature = "alloc")]
4907 pub fn encode_wrapped_secret(
4908 &self,
4909 input: &[u8],
4910 wrap: LineWrap,
4911 ) -> Result<SecretBuffer, EncodeError> {
4912 self.encode_wrapped_vec(input, wrap)
4913 .map(SecretBuffer::from_vec)
4914 }
4915
4916 pub fn encode_slice_clear_tail(
4936 &self,
4937 input: &[u8],
4938 output: &mut [u8],
4939 ) -> Result<usize, EncodeError> {
4940 let written = match self.encode_slice(input, output) {
4941 Ok(written) => written,
4942 Err(err) => {
4943 wipe_bytes(output);
4944 return Err(err);
4945 }
4946 };
4947 wipe_tail(output, written);
4948 Ok(written)
4949 }
4950
4951 pub fn encode_buffer<const CAP: usize>(
4966 &self,
4967 input: &[u8],
4968 ) -> Result<EncodedBuffer<CAP>, EncodeError> {
4969 let mut output = EncodedBuffer::new();
4970 let written = match self.encode_slice_clear_tail(input, &mut output.bytes) {
4971 Ok(written) => written,
4972 Err(err) => {
4973 output.clear();
4974 return Err(err);
4975 }
4976 };
4977 output.len = written;
4978 Ok(output)
4979 }
4980
4981 #[cfg(feature = "alloc")]
4983 pub fn encode_vec(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, EncodeError> {
4984 let required = checked_encoded_len(input.len(), PAD).ok_or(EncodeError::LengthOverflow)?;
4985 let mut output = alloc::vec![0; required];
4986 let written = self.encode_slice(input, &mut output)?;
4987 output.truncate(written);
4988 Ok(output)
4989 }
4990
4991 #[cfg(feature = "alloc")]
4996 pub fn encode_secret(&self, input: &[u8]) -> Result<SecretBuffer, EncodeError> {
4997 self.encode_vec(input).map(SecretBuffer::from_vec)
4998 }
4999
5000 #[cfg(feature = "alloc")]
5015 pub fn encode_string(&self, input: &[u8]) -> Result<alloc::string::String, EncodeError> {
5016 let output = self.encode_vec(input)?;
5017 match alloc::string::String::from_utf8(output) {
5018 Ok(output) => Ok(output),
5019 Err(_) => unreachable!("base64 encoder produced non-UTF-8 output"),
5020 }
5021 }
5022
5023 pub fn encode_in_place<'a>(
5040 &self,
5041 buffer: &'a mut [u8],
5042 input_len: usize,
5043 ) -> Result<&'a mut [u8], EncodeError> {
5044 if input_len > buffer.len() {
5045 return Err(EncodeError::InputTooLarge {
5046 input_len,
5047 buffer_len: buffer.len(),
5048 });
5049 }
5050
5051 let required = checked_encoded_len(input_len, PAD).ok_or(EncodeError::LengthOverflow)?;
5052 if buffer.len() < required {
5053 return Err(EncodeError::OutputTooSmall {
5054 required,
5055 available: buffer.len(),
5056 });
5057 }
5058
5059 let mut read = input_len;
5060 let mut write = required;
5061
5062 match input_len % 3 {
5063 0 => {}
5064 1 => {
5065 read -= 1;
5066 let b0 = buffer[read];
5067 if PAD {
5068 write -= 4;
5069 buffer[write] = encode_base64_value_runtime::<A>(b0 >> 2);
5070 buffer[write + 1] = encode_base64_value_runtime::<A>((b0 & 0b0000_0011) << 4);
5071 buffer[write + 2] = b'=';
5072 buffer[write + 3] = b'=';
5073 } else {
5074 write -= 2;
5075 buffer[write] = encode_base64_value_runtime::<A>(b0 >> 2);
5076 buffer[write + 1] = encode_base64_value_runtime::<A>((b0 & 0b0000_0011) << 4);
5077 }
5078 }
5079 2 => {
5080 read -= 2;
5081 let b0 = buffer[read];
5082 let b1 = buffer[read + 1];
5083 if PAD {
5084 write -= 4;
5085 buffer[write] = encode_base64_value_runtime::<A>(b0 >> 2);
5086 buffer[write + 1] =
5087 encode_base64_value_runtime::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
5088 buffer[write + 2] = encode_base64_value_runtime::<A>((b1 & 0b0000_1111) << 2);
5089 buffer[write + 3] = b'=';
5090 } else {
5091 write -= 3;
5092 buffer[write] = encode_base64_value_runtime::<A>(b0 >> 2);
5093 buffer[write + 1] =
5094 encode_base64_value_runtime::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
5095 buffer[write + 2] = encode_base64_value_runtime::<A>((b1 & 0b0000_1111) << 2);
5096 }
5097 }
5098 _ => unreachable!(),
5099 }
5100
5101 while read > 0 {
5102 read -= 3;
5103 write -= 4;
5104 let b0 = buffer[read];
5105 let b1 = buffer[read + 1];
5106 let b2 = buffer[read + 2];
5107
5108 buffer[write] = encode_base64_value_runtime::<A>(b0 >> 2);
5109 buffer[write + 1] =
5110 encode_base64_value_runtime::<A>(((b0 & 0b0000_0011) << 4) | (b1 >> 4));
5111 buffer[write + 2] =
5112 encode_base64_value_runtime::<A>(((b1 & 0b0000_1111) << 2) | (b2 >> 6));
5113 buffer[write + 3] = encode_base64_value_runtime::<A>(b2 & 0b0011_1111);
5114 }
5115
5116 debug_assert_eq!(write, 0);
5117 Ok(&mut buffer[..required])
5118 }
5119
5120 pub fn encode_in_place_clear_tail<'a>(
5138 &self,
5139 buffer: &'a mut [u8],
5140 input_len: usize,
5141 ) -> Result<&'a mut [u8], EncodeError> {
5142 let len = match self.encode_in_place(buffer, input_len) {
5143 Ok(encoded) => encoded.len(),
5144 Err(err) => {
5145 wipe_bytes(buffer);
5146 return Err(err);
5147 }
5148 };
5149 wipe_tail(buffer, len);
5150 Ok(&mut buffer[..len])
5151 }
5152
5153 pub fn decode_slice(&self, input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
5164 backend::decode_slice::<A, PAD>(input, output)
5165 }
5166
5167 pub fn decode_slice_clear_tail(
5187 &self,
5188 input: &[u8],
5189 output: &mut [u8],
5190 ) -> Result<usize, DecodeError> {
5191 let written = match self.decode_slice(input, output) {
5192 Ok(written) => written,
5193 Err(err) => {
5194 wipe_bytes(output);
5195 return Err(err);
5196 }
5197 };
5198 wipe_tail(output, written);
5199 Ok(written)
5200 }
5201
5202 pub fn decode_buffer<const CAP: usize>(
5217 &self,
5218 input: &[u8],
5219 ) -> Result<DecodedBuffer<CAP>, DecodeError> {
5220 let mut output = DecodedBuffer::new();
5221 let written = match self.decode_slice_clear_tail(input, &mut output.bytes) {
5222 Ok(written) => written,
5223 Err(err) => {
5224 output.clear();
5225 return Err(err);
5226 }
5227 };
5228 output.len = written;
5229 Ok(output)
5230 }
5231
5232 pub fn decode_slice_legacy(
5238 &self,
5239 input: &[u8],
5240 output: &mut [u8],
5241 ) -> Result<usize, DecodeError> {
5242 let required = validate_legacy_decode::<A, PAD>(input)?;
5243 if output.len() < required {
5244 return Err(DecodeError::OutputTooSmall {
5245 required,
5246 available: output.len(),
5247 });
5248 }
5249 decode_legacy_to_slice::<A, PAD>(input, output)
5250 }
5251
5252 pub fn decode_slice_legacy_clear_tail(
5272 &self,
5273 input: &[u8],
5274 output: &mut [u8],
5275 ) -> Result<usize, DecodeError> {
5276 let written = match self.decode_slice_legacy(input, output) {
5277 Ok(written) => written,
5278 Err(err) => {
5279 wipe_bytes(output);
5280 return Err(err);
5281 }
5282 };
5283 wipe_tail(output, written);
5284 Ok(written)
5285 }
5286
5287 pub fn decode_buffer_legacy<const CAP: usize>(
5295 &self,
5296 input: &[u8],
5297 ) -> Result<DecodedBuffer<CAP>, DecodeError> {
5298 let mut output = DecodedBuffer::new();
5299 let written = match self.decode_slice_legacy_clear_tail(input, &mut output.bytes) {
5300 Ok(written) => written,
5301 Err(err) => {
5302 output.clear();
5303 return Err(err);
5304 }
5305 };
5306 output.len = written;
5307 Ok(output)
5308 }
5309
5310 pub fn decode_slice_wrapped(
5317 &self,
5318 input: &[u8],
5319 output: &mut [u8],
5320 wrap: LineWrap,
5321 ) -> Result<usize, DecodeError> {
5322 let required = validate_wrapped_decode::<A, PAD>(input, wrap)?;
5323 if output.len() < required {
5324 return Err(DecodeError::OutputTooSmall {
5325 required,
5326 available: output.len(),
5327 });
5328 }
5329 decode_wrapped_to_slice::<A, PAD>(input, output, wrap)
5330 }
5331
5332 pub fn decode_slice_wrapped_clear_tail(
5338 &self,
5339 input: &[u8],
5340 output: &mut [u8],
5341 wrap: LineWrap,
5342 ) -> Result<usize, DecodeError> {
5343 let written = match self.decode_slice_wrapped(input, output, wrap) {
5344 Ok(written) => written,
5345 Err(err) => {
5346 wipe_bytes(output);
5347 return Err(err);
5348 }
5349 };
5350 wipe_tail(output, written);
5351 Ok(written)
5352 }
5353
5354 pub fn decode_wrapped_buffer<const CAP: usize>(
5363 &self,
5364 input: &[u8],
5365 wrap: LineWrap,
5366 ) -> Result<DecodedBuffer<CAP>, DecodeError> {
5367 let mut output = DecodedBuffer::new();
5368 let written = match self.decode_slice_wrapped_clear_tail(input, &mut output.bytes, wrap) {
5369 Ok(written) => written,
5370 Err(err) => {
5371 output.clear();
5372 return Err(err);
5373 }
5374 };
5375 output.len = written;
5376 Ok(output)
5377 }
5378
5379 #[cfg(feature = "alloc")]
5383 pub fn decode_vec(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> {
5384 let required = validate_decode::<A, PAD>(input)?;
5385 let mut output = alloc::vec![0; required];
5386 let written = match self.decode_slice(input, &mut output) {
5387 Ok(written) => written,
5388 Err(err) => {
5389 wipe_bytes(&mut output);
5390 return Err(err);
5391 }
5392 };
5393 output.truncate(written);
5394 Ok(output)
5395 }
5396
5397 #[cfg(feature = "alloc")]
5402 pub fn decode_secret(&self, input: &[u8]) -> Result<SecretBuffer, DecodeError> {
5403 self.decode_vec(input).map(SecretBuffer::from_vec)
5404 }
5405
5406 #[cfg(feature = "alloc")]
5409 pub fn decode_vec_legacy(&self, input: &[u8]) -> Result<alloc::vec::Vec<u8>, DecodeError> {
5410 let required = validate_legacy_decode::<A, PAD>(input)?;
5411 let mut output = alloc::vec![0; required];
5412 let written = match self.decode_slice_legacy(input, &mut output) {
5413 Ok(written) => written,
5414 Err(err) => {
5415 wipe_bytes(&mut output);
5416 return Err(err);
5417 }
5418 };
5419 output.truncate(written);
5420 Ok(output)
5421 }
5422
5423 #[cfg(feature = "alloc")]
5430 pub fn decode_secret_legacy(&self, input: &[u8]) -> Result<SecretBuffer, DecodeError> {
5431 self.decode_vec_legacy(input).map(SecretBuffer::from_vec)
5432 }
5433
5434 #[cfg(feature = "alloc")]
5436 pub fn decode_wrapped_vec(
5437 &self,
5438 input: &[u8],
5439 wrap: LineWrap,
5440 ) -> Result<alloc::vec::Vec<u8>, DecodeError> {
5441 let required = validate_wrapped_decode::<A, PAD>(input, wrap)?;
5442 let mut output = alloc::vec![0; required];
5443 let written = match self.decode_slice_wrapped(input, &mut output, wrap) {
5444 Ok(written) => written,
5445 Err(err) => {
5446 wipe_bytes(&mut output);
5447 return Err(err);
5448 }
5449 };
5450 output.truncate(written);
5451 Ok(output)
5452 }
5453
5454 #[cfg(feature = "alloc")]
5461 pub fn decode_wrapped_secret(
5462 &self,
5463 input: &[u8],
5464 wrap: LineWrap,
5465 ) -> Result<SecretBuffer, DecodeError> {
5466 self.decode_wrapped_vec(input, wrap)
5467 .map(SecretBuffer::from_vec)
5468 }
5469
5470 pub fn decode_in_place_wrapped<'a>(
5490 &self,
5491 buffer: &'a mut [u8],
5492 wrap: LineWrap,
5493 ) -> Result<&'a mut [u8], DecodeError> {
5494 let _required = validate_wrapped_decode::<A, PAD>(buffer, wrap)?;
5495 let compacted = compact_wrapped_input(buffer, wrap)?;
5496 let len = Self::decode_slice_to_start(&mut buffer[..compacted])?;
5497 Ok(&mut buffer[..len])
5498 }
5499
5500 pub fn decode_in_place_wrapped_clear_tail<'a>(
5521 &self,
5522 buffer: &'a mut [u8],
5523 wrap: LineWrap,
5524 ) -> Result<&'a mut [u8], DecodeError> {
5525 if let Err(err) = validate_wrapped_decode::<A, PAD>(buffer, wrap) {
5526 wipe_bytes(buffer);
5527 return Err(err);
5528 }
5529
5530 let compacted = match compact_wrapped_input(buffer, wrap) {
5531 Ok(compacted) => compacted,
5532 Err(err) => {
5533 wipe_bytes(buffer);
5534 return Err(err);
5535 }
5536 };
5537
5538 let len = match Self::decode_slice_to_start(&mut buffer[..compacted]) {
5539 Ok(len) => len,
5540 Err(err) => {
5541 wipe_bytes(buffer);
5542 return Err(err);
5543 }
5544 };
5545 wipe_tail(buffer, len);
5546 Ok(&mut buffer[..len])
5547 }
5548
5549 pub fn decode_in_place<'a>(&self, buffer: &'a mut [u8]) -> Result<&'a mut [u8], DecodeError> {
5561 let len = Self::decode_slice_to_start(buffer)?;
5562 Ok(&mut buffer[..len])
5563 }
5564
5565 pub fn decode_in_place_clear_tail<'a>(
5582 &self,
5583 buffer: &'a mut [u8],
5584 ) -> Result<&'a mut [u8], DecodeError> {
5585 let len = match Self::decode_slice_to_start(buffer) {
5586 Ok(len) => len,
5587 Err(err) => {
5588 wipe_bytes(buffer);
5589 return Err(err);
5590 }
5591 };
5592 wipe_tail(buffer, len);
5593 Ok(&mut buffer[..len])
5594 }
5595
5596 pub fn decode_in_place_legacy<'a>(
5601 &self,
5602 buffer: &'a mut [u8],
5603 ) -> Result<&'a mut [u8], DecodeError> {
5604 let _required = validate_legacy_decode::<A, PAD>(buffer)?;
5605 let mut write = 0;
5606 let mut read = 0;
5607 while read < buffer.len() {
5608 let byte = buffer[read];
5609 if !is_legacy_whitespace(byte) {
5610 buffer[write] = byte;
5611 write += 1;
5612 }
5613 read += 1;
5614 }
5615 let len = Self::decode_slice_to_start(&mut buffer[..write])?;
5616 Ok(&mut buffer[..len])
5617 }
5618
5619 pub fn decode_in_place_legacy_clear_tail<'a>(
5625 &self,
5626 buffer: &'a mut [u8],
5627 ) -> Result<&'a mut [u8], DecodeError> {
5628 if let Err(err) = validate_legacy_decode::<A, PAD>(buffer) {
5629 wipe_bytes(buffer);
5630 return Err(err);
5631 }
5632
5633 let mut write = 0;
5634 let mut read = 0;
5635 while read < buffer.len() {
5636 let byte = buffer[read];
5637 if !is_legacy_whitespace(byte) {
5638 buffer[write] = byte;
5639 write += 1;
5640 }
5641 read += 1;
5642 }
5643
5644 let len = match Self::decode_slice_to_start(&mut buffer[..write]) {
5645 Ok(len) => len,
5646 Err(err) => {
5647 wipe_bytes(buffer);
5648 return Err(err);
5649 }
5650 };
5651 wipe_tail(buffer, len);
5652 Ok(&mut buffer[..len])
5653 }
5654
5655 fn decode_slice_to_start(buffer: &mut [u8]) -> Result<usize, DecodeError> {
5656 let _required = validate_decode::<A, PAD>(buffer)?;
5657 let input_len = buffer.len();
5658 let mut read = 0;
5659 let mut write = 0;
5660 while read + 4 <= input_len {
5661 let chunk = read_quad(buffer, read)?;
5662 let available = buffer.len();
5663 let output_tail = buffer.get_mut(write..).ok_or(DecodeError::OutputTooSmall {
5664 required: write,
5665 available,
5666 })?;
5667 let written = decode_chunk::<A, PAD>(chunk, output_tail)
5668 .map_err(|err| err.with_index_offset(read))?;
5669 read += 4;
5670 write += written;
5671 if written < 3 {
5672 if read != input_len {
5673 return Err(DecodeError::InvalidPadding { index: read - 4 });
5674 }
5675 return Ok(write);
5676 }
5677 }
5678
5679 let rem = input_len - read;
5680 if rem == 0 {
5681 return Ok(write);
5682 }
5683 if PAD {
5684 return Err(DecodeError::InvalidLength);
5685 }
5686 let mut tail = [0u8; 3];
5687 tail[..rem].copy_from_slice(&buffer[read..input_len]);
5688 decode_tail_unpadded::<A>(&tail[..rem], &mut buffer[write..])
5689 .map_err(|err| err.with_index_offset(read))
5690 .map(|n| write + n)
5691 }
5692}
5693
5694fn write_wrapped_bytes(
5695 input: &[u8],
5696 output: &mut [u8],
5697 output_offset: &mut usize,
5698 column: &mut usize,
5699 wrap: LineWrap,
5700) {
5701 for byte in input {
5702 write_wrapped_byte(*byte, output, output_offset, column, wrap);
5703 }
5704}
5705
5706fn write_wrapped_byte(
5707 byte: u8,
5708 output: &mut [u8],
5709 output_offset: &mut usize,
5710 column: &mut usize,
5711 wrap: LineWrap,
5712) {
5713 if *column == wrap.line_len {
5714 let line_ending = wrap.line_ending.as_bytes();
5715 let mut index = 0;
5716 while index < line_ending.len() {
5717 output[*output_offset] = line_ending[index];
5718 *output_offset += 1;
5719 index += 1;
5720 }
5721 *column = 0;
5722 }
5723
5724 output[*output_offset] = byte;
5725 *output_offset += 1;
5726 *column += 1;
5727}
5728
5729#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5731pub enum EncodeError {
5732 LengthOverflow,
5734 InvalidLineWrap {
5736 line_len: usize,
5738 },
5739 InputTooLarge {
5741 input_len: usize,
5743 buffer_len: usize,
5745 },
5746 OutputTooSmall {
5748 required: usize,
5750 available: usize,
5752 },
5753}
5754
5755impl core::fmt::Display for EncodeError {
5756 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
5757 match self {
5758 Self::LengthOverflow => f.write_str("base64 output length overflows usize"),
5759 Self::InvalidLineWrap { line_len } => {
5760 write!(f, "base64 line wrap length {line_len} is invalid")
5761 }
5762 Self::InputTooLarge {
5763 input_len,
5764 buffer_len,
5765 } => write!(
5766 f,
5767 "base64 input length {input_len} exceeds buffer length {buffer_len}"
5768 ),
5769 Self::OutputTooSmall {
5770 required,
5771 available,
5772 } => write!(
5773 f,
5774 "base64 output buffer too small: required {required}, available {available}"
5775 ),
5776 }
5777 }
5778}
5779
5780#[cfg(feature = "std")]
5781impl std::error::Error for EncodeError {}
5782
5783#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5785pub enum AlphabetError {
5786 InvalidByte {
5788 index: usize,
5790 byte: u8,
5792 },
5793 PaddingByte {
5795 index: usize,
5797 },
5798 DuplicateByte {
5800 first: usize,
5802 second: usize,
5804 byte: u8,
5806 },
5807}
5808
5809impl core::fmt::Display for AlphabetError {
5810 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
5811 match self {
5812 Self::InvalidByte { index, byte } => {
5813 write!(
5814 f,
5815 "invalid base64 alphabet byte 0x{byte:02x} at index {index}"
5816 )
5817 }
5818 Self::PaddingByte { index } => {
5819 write!(f, "base64 alphabet contains padding byte at index {index}")
5820 }
5821 Self::DuplicateByte {
5822 first,
5823 second,
5824 byte,
5825 } => write!(
5826 f,
5827 "base64 alphabet byte 0x{byte:02x} is duplicated at indexes {first} and {second}"
5828 ),
5829 }
5830 }
5831}
5832
5833#[cfg(feature = "std")]
5834impl std::error::Error for AlphabetError {}
5835
5836#[derive(Clone, Copy, Debug, Eq, PartialEq)]
5838pub enum DecodeError {
5839 InvalidInput,
5842 InvalidLength,
5844 InvalidByte {
5846 index: usize,
5848 byte: u8,
5850 },
5851 InvalidPadding {
5853 index: usize,
5855 },
5856 InvalidLineWrap {
5858 index: usize,
5860 },
5861 OutputTooSmall {
5863 required: usize,
5865 available: usize,
5867 },
5868}
5869
5870impl core::fmt::Display for DecodeError {
5871 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
5872 match self {
5873 Self::InvalidInput => f.write_str("malformed base64 input"),
5874 Self::InvalidLength => f.write_str("invalid base64 input length"),
5875 Self::InvalidByte { index, byte } => {
5876 write!(f, "invalid base64 byte 0x{byte:02x} at index {index}")
5877 }
5878 Self::InvalidPadding { index } => write!(f, "invalid base64 padding at index {index}"),
5879 Self::InvalidLineWrap { index } => {
5880 write!(f, "invalid base64 line wrapping at index {index}")
5881 }
5882 Self::OutputTooSmall {
5883 required,
5884 available,
5885 } => write!(
5886 f,
5887 "base64 decode output buffer too small: required {required}, available {available}"
5888 ),
5889 }
5890 }
5891}
5892
5893impl DecodeError {
5894 fn with_index_offset(self, offset: usize) -> Self {
5895 match self {
5896 Self::InvalidByte { index, byte } => Self::InvalidByte {
5897 index: index + offset,
5898 byte,
5899 },
5900 Self::InvalidPadding { index } => Self::InvalidPadding {
5901 index: index + offset,
5902 },
5903 Self::InvalidLineWrap { index } => Self::InvalidLineWrap {
5904 index: index + offset,
5905 },
5906 Self::InvalidInput | Self::InvalidLength | Self::OutputTooSmall { .. } => self,
5907 }
5908 }
5909}
5910
5911#[cfg(feature = "std")]
5912impl std::error::Error for DecodeError {}
5913
5914fn validate_legacy_decode<A: Alphabet, const PAD: bool>(
5915 input: &[u8],
5916) -> Result<usize, DecodeError> {
5917 let mut chunk = [0u8; 4];
5918 let mut indexes = [0usize; 4];
5919 let mut chunk_len = 0;
5920 let mut required = 0;
5921 let mut terminal_seen = false;
5922
5923 for (index, byte) in input.iter().copied().enumerate() {
5924 if is_legacy_whitespace(byte) {
5925 continue;
5926 }
5927 if terminal_seen {
5928 return Err(DecodeError::InvalidPadding { index });
5929 }
5930
5931 chunk[chunk_len] = byte;
5932 indexes[chunk_len] = index;
5933 chunk_len += 1;
5934
5935 if chunk_len == 4 {
5936 let written =
5937 validate_chunk::<A, PAD>(chunk).map_err(|err| map_chunk_error(err, &indexes))?;
5938 required += written;
5939 terminal_seen = written < 3;
5940 chunk_len = 0;
5941 }
5942 }
5943
5944 if chunk_len == 0 {
5945 return Ok(required);
5946 }
5947 if PAD {
5948 return Err(DecodeError::InvalidLength);
5949 }
5950
5951 validate_tail_unpadded::<A>(&chunk[..chunk_len])
5952 .map_err(|err| map_partial_chunk_error(err, &indexes, chunk_len))?;
5953 Ok(required + decoded_capacity(chunk_len))
5954}
5955
5956fn decode_legacy_to_slice<A: Alphabet, const PAD: bool>(
5957 input: &[u8],
5958 output: &mut [u8],
5959) -> Result<usize, DecodeError> {
5960 let mut chunk = [0u8; 4];
5961 let mut indexes = [0usize; 4];
5962 let mut chunk_len = 0;
5963 let mut write = 0;
5964 let mut terminal_seen = false;
5965
5966 for (index, byte) in input.iter().copied().enumerate() {
5967 if is_legacy_whitespace(byte) {
5968 continue;
5969 }
5970 if terminal_seen {
5971 return Err(DecodeError::InvalidPadding { index });
5972 }
5973
5974 chunk[chunk_len] = byte;
5975 indexes[chunk_len] = index;
5976 chunk_len += 1;
5977
5978 if chunk_len == 4 {
5979 let available = output.len();
5980 let output_tail = output.get_mut(write..).ok_or(DecodeError::OutputTooSmall {
5981 required: write,
5982 available,
5983 })?;
5984 let written = decode_chunk::<A, PAD>(chunk, output_tail)
5985 .map_err(|err| map_chunk_error(err, &indexes))?;
5986 write += written;
5987 terminal_seen = written < 3;
5988 chunk_len = 0;
5989 }
5990 }
5991
5992 if chunk_len == 0 {
5993 return Ok(write);
5994 }
5995 if PAD {
5996 return Err(DecodeError::InvalidLength);
5997 }
5998
5999 decode_tail_unpadded::<A>(&chunk[..chunk_len], &mut output[write..])
6000 .map_err(|err| map_partial_chunk_error(err, &indexes, chunk_len))
6001 .map(|n| write + n)
6002}
6003
6004struct WrappedBytes<'a> {
6005 input: &'a [u8],
6006 wrap: LineWrap,
6007 index: usize,
6008 line_len: usize,
6009}
6010
6011impl<'a> WrappedBytes<'a> {
6012 const fn new(input: &'a [u8], wrap: LineWrap) -> Result<Self, DecodeError> {
6013 if wrap.line_len == 0 {
6014 return Err(DecodeError::InvalidLineWrap { index: 0 });
6015 }
6016 Ok(Self {
6017 input,
6018 wrap,
6019 index: 0,
6020 line_len: 0,
6021 })
6022 }
6023
6024 fn next_byte(&mut self) -> Result<Option<(usize, u8)>, DecodeError> {
6025 loop {
6026 if self.index == self.input.len() {
6027 return Ok(None);
6028 }
6029
6030 if self.starts_with_line_ending() {
6031 let line_end_index = self.index;
6032 if self.line_len == 0 {
6033 return Err(DecodeError::InvalidLineWrap {
6034 index: line_end_index,
6035 });
6036 }
6037
6038 self.index += self.wrap.line_ending.byte_len();
6039 if self.index == self.input.len() {
6040 self.line_len = 0;
6041 return Ok(None);
6042 }
6043
6044 if self.line_len != self.wrap.line_len {
6045 return Err(DecodeError::InvalidLineWrap {
6046 index: line_end_index,
6047 });
6048 }
6049 self.line_len = 0;
6050 continue;
6051 }
6052
6053 let byte = self.input[self.index];
6054 if matches!(byte, b'\r' | b'\n') {
6055 return Err(DecodeError::InvalidLineWrap { index: self.index });
6056 }
6057
6058 self.line_len += 1;
6059 if self.line_len > self.wrap.line_len {
6060 return Err(DecodeError::InvalidLineWrap { index: self.index });
6061 }
6062
6063 let index = self.index;
6064 self.index += 1;
6065 return Ok(Some((index, byte)));
6066 }
6067 }
6068
6069 fn starts_with_line_ending(&self) -> bool {
6070 let line_ending = self.wrap.line_ending.as_bytes();
6071 let end = self.index + line_ending.len();
6072 end <= self.input.len() && &self.input[self.index..end] == line_ending
6073 }
6074}
6075
6076fn validate_wrapped_decode<A: Alphabet, const PAD: bool>(
6077 input: &[u8],
6078 wrap: LineWrap,
6079) -> Result<usize, DecodeError> {
6080 let mut bytes = WrappedBytes::new(input, wrap)?;
6081 let mut chunk = [0u8; 4];
6082 let mut indexes = [0usize; 4];
6083 let mut chunk_len = 0;
6084 let mut required = 0;
6085 let mut terminal_seen = false;
6086
6087 while let Some((index, byte)) = bytes.next_byte()? {
6088 if terminal_seen {
6089 return Err(DecodeError::InvalidPadding { index });
6090 }
6091
6092 chunk[chunk_len] = byte;
6093 indexes[chunk_len] = index;
6094 chunk_len += 1;
6095
6096 if chunk_len == 4 {
6097 let written =
6098 validate_chunk::<A, PAD>(chunk).map_err(|err| map_chunk_error(err, &indexes))?;
6099 required += written;
6100 terminal_seen = written < 3;
6101 chunk_len = 0;
6102 }
6103 }
6104
6105 if chunk_len == 0 {
6106 return Ok(required);
6107 }
6108 if PAD {
6109 return Err(DecodeError::InvalidLength);
6110 }
6111
6112 validate_tail_unpadded::<A>(&chunk[..chunk_len])
6113 .map_err(|err| map_partial_chunk_error(err, &indexes, chunk_len))?;
6114 Ok(required + decoded_capacity(chunk_len))
6115}
6116
6117fn decode_wrapped_to_slice<A: Alphabet, const PAD: bool>(
6118 input: &[u8],
6119 output: &mut [u8],
6120 wrap: LineWrap,
6121) -> Result<usize, DecodeError> {
6122 let mut bytes = WrappedBytes::new(input, wrap)?;
6123 let mut chunk = [0u8; 4];
6124 let mut indexes = [0usize; 4];
6125 let mut chunk_len = 0;
6126 let mut write = 0;
6127 let mut terminal_seen = false;
6128
6129 while let Some((index, byte)) = bytes.next_byte()? {
6130 if terminal_seen {
6131 return Err(DecodeError::InvalidPadding { index });
6132 }
6133
6134 chunk[chunk_len] = byte;
6135 indexes[chunk_len] = index;
6136 chunk_len += 1;
6137
6138 if chunk_len == 4 {
6139 let available = output.len();
6140 let output_tail = output.get_mut(write..).ok_or(DecodeError::OutputTooSmall {
6141 required: write,
6142 available,
6143 })?;
6144 let written = decode_chunk::<A, PAD>(chunk, output_tail)
6145 .map_err(|err| map_chunk_error(err, &indexes))?;
6146 write += written;
6147 terminal_seen = written < 3;
6148 chunk_len = 0;
6149 }
6150 }
6151
6152 if chunk_len == 0 {
6153 return Ok(write);
6154 }
6155 if PAD {
6156 return Err(DecodeError::InvalidLength);
6157 }
6158
6159 decode_tail_unpadded::<A>(&chunk[..chunk_len], &mut output[write..])
6160 .map_err(|err| map_partial_chunk_error(err, &indexes, chunk_len))
6161 .map(|n| write + n)
6162}
6163
6164fn compact_wrapped_input(buffer: &mut [u8], wrap: LineWrap) -> Result<usize, DecodeError> {
6165 if !wrap.is_valid() {
6166 return Err(DecodeError::InvalidLineWrap { index: 0 });
6167 }
6168
6169 let line_ending = wrap.line_ending.as_bytes();
6170 let line_ending_len = line_ending.len();
6171 let mut read = 0;
6172 let mut write = 0;
6173
6174 while read < buffer.len() {
6175 let line_end = read + line_ending_len;
6176 if buffer.get(read..line_end) == Some(line_ending) {
6177 read = line_end;
6178 continue;
6179 }
6180
6181 buffer[write] = buffer[read];
6182 write += 1;
6183 read += 1;
6184 }
6185
6186 Ok(write)
6187}
6188
6189#[inline]
6190const fn is_legacy_whitespace(byte: u8) -> bool {
6191 matches!(byte, b' ' | b'\t' | b'\r' | b'\n')
6192}
6193
6194fn map_chunk_error(err: DecodeError, indexes: &[usize; 4]) -> DecodeError {
6195 match err {
6196 DecodeError::InvalidByte { index, byte } => DecodeError::InvalidByte {
6197 index: indexes[index],
6198 byte,
6199 },
6200 DecodeError::InvalidPadding { index } => DecodeError::InvalidPadding {
6201 index: indexes[index],
6202 },
6203 DecodeError::InvalidInput
6204 | DecodeError::InvalidLineWrap { .. }
6205 | DecodeError::InvalidLength
6206 | DecodeError::OutputTooSmall { .. } => err,
6207 }
6208}
6209
6210fn map_partial_chunk_error(err: DecodeError, indexes: &[usize; 4], len: usize) -> DecodeError {
6211 match err {
6212 DecodeError::InvalidByte { index, byte } if index < len => DecodeError::InvalidByte {
6213 index: indexes[index],
6214 byte,
6215 },
6216 DecodeError::InvalidPadding { index } if index < len => DecodeError::InvalidPadding {
6217 index: indexes[index],
6218 },
6219 DecodeError::InvalidByte { .. }
6220 | DecodeError::InvalidPadding { .. }
6221 | DecodeError::InvalidLineWrap { .. }
6222 | DecodeError::InvalidInput
6223 | DecodeError::InvalidLength
6224 | DecodeError::OutputTooSmall { .. } => err,
6225 }
6226}
6227
6228fn decode_padded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
6229 if !input.len().is_multiple_of(4) {
6230 return Err(DecodeError::InvalidLength);
6231 }
6232 let required = decoded_len_padded(input)?;
6233 if output.len() < required {
6234 return Err(DecodeError::OutputTooSmall {
6235 required,
6236 available: output.len(),
6237 });
6238 }
6239
6240 let mut read = 0;
6241 let mut write = 0;
6242 while read < input.len() {
6243 let chunk = read_quad(input, read)?;
6244 let available = output.len();
6245 let output_tail = output.get_mut(write..).ok_or(DecodeError::OutputTooSmall {
6246 required: write,
6247 available,
6248 })?;
6249 let written = decode_chunk::<A, true>(chunk, output_tail)
6250 .map_err(|err| err.with_index_offset(read))?;
6251 read += 4;
6252 write += written;
6253 if written < 3 && read != input.len() {
6254 return Err(DecodeError::InvalidPadding { index: read - 4 });
6255 }
6256 }
6257 Ok(write)
6258}
6259
6260fn validate_decode<A: Alphabet, const PAD: bool>(input: &[u8]) -> Result<usize, DecodeError> {
6261 if input.is_empty() {
6262 return Ok(0);
6263 }
6264
6265 if PAD {
6266 validate_padded::<A>(input)
6267 } else {
6268 validate_unpadded::<A>(input)
6269 }
6270}
6271
6272fn validate_padded<A: Alphabet>(input: &[u8]) -> Result<usize, DecodeError> {
6273 if !input.len().is_multiple_of(4) {
6274 return Err(DecodeError::InvalidLength);
6275 }
6276 let required = decoded_len_padded(input)?;
6277
6278 let mut read = 0;
6279 while read < input.len() {
6280 let chunk = read_quad(input, read)?;
6281 let written =
6282 validate_chunk::<A, true>(chunk).map_err(|err| err.with_index_offset(read))?;
6283 read += 4;
6284 if written < 3 && read != input.len() {
6285 return Err(DecodeError::InvalidPadding { index: read - 4 });
6286 }
6287 }
6288
6289 Ok(required)
6290}
6291
6292fn validate_unpadded<A: Alphabet>(input: &[u8]) -> Result<usize, DecodeError> {
6293 let required = decoded_len_unpadded(input)?;
6294
6295 let mut read = 0;
6296 while read + 4 <= input.len() {
6297 let chunk = read_quad(input, read)?;
6298 validate_chunk::<A, false>(chunk).map_err(|err| err.with_index_offset(read))?;
6299 read += 4;
6300 }
6301 validate_tail_unpadded::<A>(&input[read..]).map_err(|err| err.with_index_offset(read))?;
6302
6303 Ok(required)
6304}
6305
6306fn decode_unpadded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
6307 let required = decoded_len_unpadded(input)?;
6308 if output.len() < required {
6309 return Err(DecodeError::OutputTooSmall {
6310 required,
6311 available: output.len(),
6312 });
6313 }
6314
6315 let mut read = 0;
6316 let mut write = 0;
6317 while read + 4 <= input.len() {
6318 let chunk = read_quad(input, read)?;
6319 let available = output.len();
6320 let output_tail = output.get_mut(write..).ok_or(DecodeError::OutputTooSmall {
6321 required: write,
6322 available,
6323 })?;
6324 let written = decode_chunk::<A, false>(chunk, output_tail)
6325 .map_err(|err| err.with_index_offset(read))?;
6326 read += 4;
6327 write += written;
6328 }
6329 decode_tail_unpadded::<A>(&input[read..], &mut output[write..])
6330 .map_err(|err| err.with_index_offset(read))
6331 .map(|n| write + n)
6332}
6333
6334fn decoded_len_padded(input: &[u8]) -> Result<usize, DecodeError> {
6335 if input.is_empty() {
6336 return Ok(0);
6337 }
6338 if !input.len().is_multiple_of(4) {
6339 return Err(DecodeError::InvalidLength);
6340 }
6341
6342 let Some((&last, before_last_prefix)) = input.split_last() else {
6343 return Ok(0);
6344 };
6345 let Some(&before_last) = before_last_prefix.last() else {
6346 return Err(DecodeError::InvalidLength);
6347 };
6348
6349 let mut padding = 0;
6350 if last == b'=' {
6351 padding += 1;
6352 }
6353 if before_last == b'=' {
6354 padding += 1;
6355 }
6356 if padding == 0
6357 && let Some(index) = input.iter().position(|byte| *byte == b'=')
6358 {
6359 return Err(DecodeError::InvalidPadding { index });
6360 }
6361 if padding > 0 {
6362 let first_pad = input.len() - padding;
6363 if let Some(index) = input[..first_pad].iter().position(|byte| *byte == b'=') {
6364 return Err(DecodeError::InvalidPadding { index });
6365 }
6366 }
6367 Ok(input.len() / 4 * 3 - padding)
6368}
6369
6370fn decoded_len_unpadded(input: &[u8]) -> Result<usize, DecodeError> {
6371 if input.len() % 4 == 1 {
6372 return Err(DecodeError::InvalidLength);
6373 }
6374 if let Some(index) = input.iter().position(|byte| *byte == b'=') {
6375 return Err(DecodeError::InvalidPadding { index });
6376 }
6377 Ok(decoded_capacity(input.len()))
6378}
6379
6380fn read_quad(input: &[u8], offset: usize) -> Result<[u8; 4], DecodeError> {
6381 let end = offset.checked_add(4).ok_or(DecodeError::InvalidLength)?;
6382 match input.get(offset..end) {
6383 Some([b0, b1, b2, b3]) => Ok([*b0, *b1, *b2, *b3]),
6384 _ => Err(DecodeError::InvalidLength),
6385 }
6386}
6387
6388fn first_padding_index(input: [u8; 4]) -> usize {
6389 let [b0, b1, b2, b3] = input;
6390 if b0 == b'=' {
6391 0
6392 } else if b1 == b'=' {
6393 1
6394 } else if b2 == b'=' {
6395 2
6396 } else if b3 == b'=' {
6397 3
6398 } else {
6399 0
6400 }
6401}
6402
6403fn validate_chunk<A: Alphabet, const PAD: bool>(input: [u8; 4]) -> Result<usize, DecodeError> {
6404 let [b0, b1, b2, b3] = input;
6405 let _v0 = decode_byte::<A>(b0, 0)?;
6406 let v1 = decode_byte::<A>(b1, 1)?;
6407
6408 match (b2, b3) {
6409 (b'=', b'=') if PAD => {
6410 if v1 & 0b0000_1111 != 0 {
6411 return Err(DecodeError::InvalidPadding { index: 1 });
6412 }
6413 Ok(1)
6414 }
6415 (b'=', _) if PAD => Err(DecodeError::InvalidPadding { index: 2 }),
6416 (_, b'=') if PAD => {
6417 let v2 = decode_byte::<A>(b2, 2)?;
6418 if v2 & 0b0000_0011 != 0 {
6419 return Err(DecodeError::InvalidPadding { index: 2 });
6420 }
6421 Ok(2)
6422 }
6423 (b'=', _) | (_, b'=') => Err(DecodeError::InvalidPadding {
6424 index: first_padding_index(input),
6425 }),
6426 _ => {
6427 decode_byte::<A>(b2, 2)?;
6428 decode_byte::<A>(b3, 3)?;
6429 Ok(3)
6430 }
6431 }
6432}
6433
6434fn decode_chunk<A: Alphabet, const PAD: bool>(
6435 input: [u8; 4],
6436 output: &mut [u8],
6437) -> Result<usize, DecodeError> {
6438 let [b0, b1, b2, b3] = input;
6439 let v0 = decode_byte::<A>(b0, 0)?;
6440 let v1 = decode_byte::<A>(b1, 1)?;
6441
6442 match (b2, b3) {
6443 (b'=', b'=') if PAD => {
6444 if output.is_empty() {
6445 return Err(DecodeError::OutputTooSmall {
6446 required: 1,
6447 available: output.len(),
6448 });
6449 }
6450 if v1 & 0b0000_1111 != 0 {
6451 return Err(DecodeError::InvalidPadding { index: 1 });
6452 }
6453 output[0] = (v0 << 2) | (v1 >> 4);
6454 Ok(1)
6455 }
6456 (b'=', _) if PAD => Err(DecodeError::InvalidPadding { index: 2 }),
6457 (_, b'=') if PAD => {
6458 if output.len() < 2 {
6459 return Err(DecodeError::OutputTooSmall {
6460 required: 2,
6461 available: output.len(),
6462 });
6463 }
6464 let v2 = decode_byte::<A>(b2, 2)?;
6465 if v2 & 0b0000_0011 != 0 {
6466 return Err(DecodeError::InvalidPadding { index: 2 });
6467 }
6468 output[0] = (v0 << 2) | (v1 >> 4);
6469 output[1] = (v1 << 4) | (v2 >> 2);
6470 Ok(2)
6471 }
6472 (b'=', _) | (_, b'=') => Err(DecodeError::InvalidPadding {
6473 index: first_padding_index(input),
6474 }),
6475 _ => {
6476 if output.len() < 3 {
6477 return Err(DecodeError::OutputTooSmall {
6478 required: 3,
6479 available: output.len(),
6480 });
6481 }
6482 let v2 = decode_byte::<A>(b2, 2)?;
6483 let v3 = decode_byte::<A>(b3, 3)?;
6484 output[0] = (v0 << 2) | (v1 >> 4);
6485 output[1] = (v1 << 4) | (v2 >> 2);
6486 output[2] = (v2 << 6) | v3;
6487 Ok(3)
6488 }
6489 }
6490}
6491
6492fn validate_tail_unpadded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
6493 match input {
6494 [] => Ok(()),
6495 [b0, b1] => {
6496 decode_byte::<A>(*b0, 0)?;
6497 let v1 = decode_byte::<A>(*b1, 1)?;
6498 if v1 & 0b0000_1111 != 0 {
6499 return Err(DecodeError::InvalidPadding { index: 1 });
6500 }
6501 Ok(())
6502 }
6503 [b0, b1, b2] => {
6504 decode_byte::<A>(*b0, 0)?;
6505 decode_byte::<A>(*b1, 1)?;
6506 let v2 = decode_byte::<A>(*b2, 2)?;
6507 if v2 & 0b0000_0011 != 0 {
6508 return Err(DecodeError::InvalidPadding { index: 2 });
6509 }
6510 Ok(())
6511 }
6512 _ => Err(DecodeError::InvalidLength),
6513 }
6514}
6515
6516fn decode_tail_unpadded<A: Alphabet>(
6517 input: &[u8],
6518 output: &mut [u8],
6519) -> Result<usize, DecodeError> {
6520 match input {
6521 [] => Ok(0),
6522 [b0, b1] => {
6523 let Some(out0) = output.first_mut() else {
6524 return Err(DecodeError::OutputTooSmall {
6525 required: 1,
6526 available: output.len(),
6527 });
6528 };
6529 let v0 = decode_byte::<A>(*b0, 0)?;
6530 let v1 = decode_byte::<A>(*b1, 1)?;
6531 if v1 & 0b0000_1111 != 0 {
6532 return Err(DecodeError::InvalidPadding { index: 1 });
6533 }
6534 *out0 = (v0 << 2) | (v1 >> 4);
6535 Ok(1)
6536 }
6537 [b0, b1, b2] => {
6538 let available = output.len();
6539 let Some([out0, out1]) = output.get_mut(..2) else {
6540 return Err(DecodeError::OutputTooSmall {
6541 required: 2,
6542 available,
6543 });
6544 };
6545 let v0 = decode_byte::<A>(*b0, 0)?;
6546 let v1 = decode_byte::<A>(*b1, 1)?;
6547 let v2 = decode_byte::<A>(*b2, 2)?;
6548 if v2 & 0b0000_0011 != 0 {
6549 return Err(DecodeError::InvalidPadding { index: 2 });
6550 }
6551 *out0 = (v0 << 2) | (v1 >> 4);
6552 *out1 = (v1 << 4) | (v2 >> 2);
6553 Ok(2)
6554 }
6555 _ => Err(DecodeError::InvalidLength),
6556 }
6557}
6558
6559fn decode_byte<A: Alphabet>(byte: u8, index: usize) -> Result<u8, DecodeError> {
6560 A::decode(byte).ok_or(DecodeError::InvalidByte { index, byte })
6561}
6562
6563fn ct_decode_slice<A: Alphabet, const PAD: bool>(
6564 input: &[u8],
6565 output: &mut [u8],
6566) -> Result<usize, DecodeError> {
6567 if input.is_empty() {
6568 return Ok(0);
6569 }
6570
6571 if PAD {
6572 ct_decode_padded::<A>(input, output)
6573 } else {
6574 ct_decode_unpadded::<A>(input, output)
6575 }
6576}
6577
6578fn ct_decode_in_place<A: Alphabet, const PAD: bool>(
6579 buffer: &mut [u8],
6580) -> Result<usize, DecodeError> {
6581 if buffer.is_empty() {
6582 return Ok(0);
6583 }
6584
6585 if PAD {
6586 ct_decode_padded_in_place::<A>(buffer)
6587 } else {
6588 ct_decode_unpadded_in_place::<A>(buffer)
6589 }
6590}
6591
6592fn ct_validate_decode<A: Alphabet, const PAD: bool>(input: &[u8]) -> Result<(), DecodeError> {
6593 if input.is_empty() {
6594 return Ok(());
6595 }
6596
6597 if PAD {
6598 ct_validate_padded::<A>(input)
6599 } else {
6600 ct_validate_unpadded::<A>(input)
6601 }
6602}
6603
6604fn ct_decoded_len<A: Alphabet, const PAD: bool>(input: &[u8]) -> Result<usize, DecodeError> {
6605 ct_validate_decode::<A, PAD>(input)?;
6606 if input.is_empty() {
6607 return Ok(0);
6608 }
6609
6610 if PAD {
6611 Ok(input.len() / 4 * 3 - ct_padding_len(input))
6612 } else {
6613 let full_quads = input.len() / 4 * 3;
6614 match input.len() % 4 {
6615 0 => Ok(full_quads),
6616 2 => Ok(full_quads + 1),
6617 3 => Ok(full_quads + 2),
6618 _ => Err(DecodeError::InvalidLength),
6619 }
6620 }
6621}
6622
6623fn ct_validate_padded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
6624 if !input.len().is_multiple_of(4) {
6625 return Err(DecodeError::InvalidLength);
6626 }
6627
6628 let padding = ct_padding_len(input);
6629 let mut invalid_byte = 0u8;
6630 let mut invalid_padding = 0u8;
6631 let mut read = 0;
6632
6633 while read + 4 < input.len() {
6634 let [b0, b1, b2, b3] = read_quad(input, read)?;
6635 let (_, valid0) = ct_decode_alphabet_byte::<A>(b0);
6636 let (_, valid1) = ct_decode_alphabet_byte::<A>(b1);
6637 let (_, valid2) = ct_decode_alphabet_byte::<A>(b2);
6638 let (_, valid3) = ct_decode_alphabet_byte::<A>(b3);
6639
6640 invalid_byte |= !valid0;
6641 invalid_byte |= !valid1;
6642 invalid_byte |= !valid2;
6643 invalid_byte |= !valid3;
6644 invalid_padding |= ct_mask_eq_u8(b2, b'=');
6645 invalid_padding |= ct_mask_eq_u8(b3, b'=');
6646 read += 4;
6647 }
6648
6649 let final_chunk = read_quad(input, read)?;
6650 let (_, final_invalid_byte, final_invalid_padding, _) =
6651 ct_padded_final_quantum::<A>(final_chunk, padding);
6652 invalid_byte |= final_invalid_byte;
6653 invalid_padding |= final_invalid_padding;
6654
6655 report_ct_error(invalid_byte, invalid_padding)
6656}
6657
6658fn ct_validate_unpadded<A: Alphabet>(input: &[u8]) -> Result<(), DecodeError> {
6659 if input.len() % 4 == 1 {
6660 return Err(DecodeError::InvalidLength);
6661 }
6662
6663 let mut invalid_byte = 0u8;
6664 let mut invalid_padding = 0u8;
6665 let mut read = 0;
6666
6667 while read + 4 <= input.len() {
6668 let [b0, b1, b2, b3] = read_quad(input, read)?;
6669 let (_, valid0) = ct_decode_alphabet_byte::<A>(b0);
6670 let (_, valid1) = ct_decode_alphabet_byte::<A>(b1);
6671 let (_, valid2) = ct_decode_alphabet_byte::<A>(b2);
6672 let (_, valid3) = ct_decode_alphabet_byte::<A>(b3);
6673
6674 invalid_byte |= !valid0;
6675 invalid_byte |= !valid1;
6676 invalid_byte |= !valid2;
6677 invalid_byte |= !valid3;
6678 invalid_padding |= ct_mask_eq_u8(b0, b'=');
6679 invalid_padding |= ct_mask_eq_u8(b1, b'=');
6680 invalid_padding |= ct_mask_eq_u8(b2, b'=');
6681 invalid_padding |= ct_mask_eq_u8(b3, b'=');
6682
6683 read += 4;
6684 }
6685
6686 match input.get(read..) {
6687 Some([]) => {}
6688 Some([b0, b1]) => {
6689 let (_, valid0) = ct_decode_alphabet_byte::<A>(*b0);
6690 let (v1, valid1) = ct_decode_alphabet_byte::<A>(*b1);
6691 invalid_byte |= !valid0;
6692 invalid_byte |= !valid1;
6693 invalid_padding |= ct_mask_eq_u8(*b0, b'=');
6694 invalid_padding |= ct_mask_eq_u8(*b1, b'=');
6695 invalid_padding |= ct_mask_nonzero_u8(v1 & 0b0000_1111);
6696 }
6697 Some([b0, b1, b2]) => {
6698 let (_, valid0) = ct_decode_alphabet_byte::<A>(*b0);
6699 let (_, valid1) = ct_decode_alphabet_byte::<A>(*b1);
6700 let (v2, valid2) = ct_decode_alphabet_byte::<A>(*b2);
6701 invalid_byte |= !valid0;
6702 invalid_byte |= !valid1;
6703 invalid_byte |= !valid2;
6704 invalid_padding |= ct_mask_eq_u8(*b0, b'=');
6705 invalid_padding |= ct_mask_eq_u8(*b1, b'=');
6706 invalid_padding |= ct_mask_eq_u8(*b2, b'=');
6707 invalid_padding |= ct_mask_nonzero_u8(v2 & 0b0000_0011);
6708 }
6709 _ => return Err(DecodeError::InvalidLength),
6710 }
6711
6712 report_ct_error(invalid_byte, invalid_padding)
6713}
6714
6715fn ct_padded_final_quantum<A: Alphabet>(
6716 input: [u8; 4],
6717 padding: usize,
6718) -> ([u8; 3], u8, u8, usize) {
6719 let [b0, b1, b2, b3] = input;
6720 let (v0, valid0) = ct_decode_alphabet_byte::<A>(b0);
6721 let (v1, valid1) = ct_decode_alphabet_byte::<A>(b1);
6722 let (v2, valid2) = ct_decode_alphabet_byte::<A>(b2);
6723 let (v3, valid3) = ct_decode_alphabet_byte::<A>(b3);
6724
6725 let padding_byte = padding.to_le_bytes()[0];
6726 let no_padding = ct_mask_eq_u8(padding_byte, 0);
6727 let one_padding = ct_mask_eq_u8(padding_byte, 1);
6728 let two_padding = ct_mask_eq_u8(padding_byte, 2);
6729 let require_v2 = no_padding | one_padding;
6730 let require_v3 = no_padding;
6731
6732 let invalid_byte = !valid0 | !valid1 | (!valid2 & require_v2) | (!valid3 & require_v3);
6733 let invalid_padding = (ct_mask_nonzero_u8(v1 & 0b0000_1111) & two_padding)
6734 | ((ct_mask_eq_u8(b2, b'=') | ct_mask_nonzero_u8(v2 & 0b0000_0011)) & one_padding)
6735 | ((ct_mask_eq_u8(b2, b'=') | ct_mask_eq_u8(b3, b'=')) & no_padding);
6736
6737 (
6738 [(v0 << 2) | (v1 >> 4), (v1 << 4) | (v2 >> 2), (v2 << 6) | v3],
6739 invalid_byte,
6740 invalid_padding,
6741 3 - padding,
6742 )
6743}
6744
6745fn ct_decode_padded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
6746 if !input.len().is_multiple_of(4) {
6747 return Err(DecodeError::InvalidLength);
6748 }
6749
6750 let padding = ct_padding_len(input);
6751 let required = input.len() / 4 * 3 - padding;
6752 if output.len() < required {
6753 return Err(DecodeError::OutputTooSmall {
6754 required,
6755 available: output.len(),
6756 });
6757 }
6758
6759 let mut invalid_byte = 0u8;
6760 let mut invalid_padding = 0u8;
6761 let mut write = 0;
6762 let mut read = 0;
6763
6764 while read + 4 < input.len() {
6765 let [b0, b1, b2, b3] = read_quad(input, read)?;
6766 let (v0, valid0) = ct_decode_alphabet_byte::<A>(b0);
6767 let (v1, valid1) = ct_decode_alphabet_byte::<A>(b1);
6768 let (v2, valid2) = ct_decode_alphabet_byte::<A>(b2);
6769 let (v3, valid3) = ct_decode_alphabet_byte::<A>(b3);
6770
6771 invalid_byte |= !valid0;
6772 invalid_byte |= !valid1;
6773 invalid_byte |= !valid2;
6774 invalid_byte |= !valid3;
6775 invalid_padding |= ct_mask_eq_u8(b2, b'=');
6776 invalid_padding |= ct_mask_eq_u8(b3, b'=');
6777 output[write] = (v0 << 2) | (v1 >> 4);
6778 output[write + 1] = (v1 << 4) | (v2 >> 2);
6779 output[write + 2] = (v2 << 6) | v3;
6780 write += 3;
6781 read += 4;
6782 }
6783
6784 let final_chunk = read_quad(input, read)?;
6785 let (final_bytes, final_invalid_byte, final_invalid_padding, final_written) =
6786 ct_padded_final_quantum::<A>(final_chunk, padding);
6787 invalid_byte |= final_invalid_byte;
6788 invalid_padding |= final_invalid_padding;
6789 output[write..write + final_written].copy_from_slice(&final_bytes[..final_written]);
6790 write += final_written;
6791
6792 report_ct_error(invalid_byte, invalid_padding)?;
6793 Ok(write)
6794}
6795
6796fn ct_decode_padded_in_place<A: Alphabet>(buffer: &mut [u8]) -> Result<usize, DecodeError> {
6797 if !buffer.len().is_multiple_of(4) {
6798 return Err(DecodeError::InvalidLength);
6799 }
6800
6801 let padding = ct_padding_len(buffer);
6802 let required = buffer.len() / 4 * 3 - padding;
6803 debug_assert!(required <= buffer.len());
6804
6805 let mut invalid_byte = 0u8;
6806 let mut invalid_padding = 0u8;
6807 let mut write = 0;
6808 let mut read = 0;
6809
6810 while read + 4 < buffer.len() {
6811 let [b0, b1, b2, b3] = read_quad(buffer, read)?;
6812 let (v0, valid0) = ct_decode_alphabet_byte::<A>(b0);
6813 let (v1, valid1) = ct_decode_alphabet_byte::<A>(b1);
6814 let (v2, valid2) = ct_decode_alphabet_byte::<A>(b2);
6815 let (v3, valid3) = ct_decode_alphabet_byte::<A>(b3);
6816
6817 invalid_byte |= !valid0;
6818 invalid_byte |= !valid1;
6819 invalid_byte |= !valid2;
6820 invalid_byte |= !valid3;
6821 invalid_padding |= ct_mask_eq_u8(b2, b'=');
6822 invalid_padding |= ct_mask_eq_u8(b3, b'=');
6823 buffer[write] = (v0 << 2) | (v1 >> 4);
6824 buffer[write + 1] = (v1 << 4) | (v2 >> 2);
6825 buffer[write + 2] = (v2 << 6) | v3;
6826 write += 3;
6827 read += 4;
6828 }
6829
6830 let final_chunk = read_quad(buffer, read)?;
6831 let (final_bytes, final_invalid_byte, final_invalid_padding, final_written) =
6832 ct_padded_final_quantum::<A>(final_chunk, padding);
6833 invalid_byte |= final_invalid_byte;
6834 invalid_padding |= final_invalid_padding;
6835 buffer[write..write + final_written].copy_from_slice(&final_bytes[..final_written]);
6836 write += final_written;
6837
6838 debug_assert_eq!(write, required);
6839 report_ct_error(invalid_byte, invalid_padding)?;
6840 Ok(write)
6841}
6842
6843fn ct_decode_unpadded<A: Alphabet>(input: &[u8], output: &mut [u8]) -> Result<usize, DecodeError> {
6844 if input.len() % 4 == 1 {
6845 return Err(DecodeError::InvalidLength);
6846 }
6847
6848 let required = decoded_capacity(input.len());
6849 if output.len() < required {
6850 return Err(DecodeError::OutputTooSmall {
6851 required,
6852 available: output.len(),
6853 });
6854 }
6855
6856 let mut invalid_byte = 0u8;
6857 let mut invalid_padding = 0u8;
6858 let mut write = 0;
6859 let mut read = 0;
6860
6861 while read + 4 <= input.len() {
6862 let [b0, b1, b2, b3] = read_quad(input, read)?;
6863 let (v0, valid0) = ct_decode_alphabet_byte::<A>(b0);
6864 let (v1, valid1) = ct_decode_alphabet_byte::<A>(b1);
6865 let (v2, valid2) = ct_decode_alphabet_byte::<A>(b2);
6866 let (v3, valid3) = ct_decode_alphabet_byte::<A>(b3);
6867
6868 invalid_byte |= !valid0;
6869 invalid_byte |= !valid1;
6870 invalid_byte |= !valid2;
6871 invalid_byte |= !valid3;
6872 invalid_padding |= ct_mask_eq_u8(b0, b'=');
6873 invalid_padding |= ct_mask_eq_u8(b1, b'=');
6874 invalid_padding |= ct_mask_eq_u8(b2, b'=');
6875 invalid_padding |= ct_mask_eq_u8(b3, b'=');
6876
6877 output[write] = (v0 << 2) | (v1 >> 4);
6878 output[write + 1] = (v1 << 4) | (v2 >> 2);
6879 output[write + 2] = (v2 << 6) | v3;
6880 read += 4;
6881 write += 3;
6882 }
6883
6884 match input.get(read..) {
6885 Some([]) => {}
6886 Some([b0, b1]) => {
6887 let (v0, valid0) = ct_decode_alphabet_byte::<A>(*b0);
6888 let (v1, valid1) = ct_decode_alphabet_byte::<A>(*b1);
6889 invalid_byte |= !valid0;
6890 invalid_byte |= !valid1;
6891 invalid_padding |= ct_mask_eq_u8(*b0, b'=');
6892 invalid_padding |= ct_mask_eq_u8(*b1, b'=');
6893 invalid_padding |= ct_mask_nonzero_u8(v1 & 0b0000_1111);
6894 output[write] = (v0 << 2) | (v1 >> 4);
6895 write += 1;
6896 }
6897 Some([b0, b1, b2]) => {
6898 let (v0, valid0) = ct_decode_alphabet_byte::<A>(*b0);
6899 let (v1, valid1) = ct_decode_alphabet_byte::<A>(*b1);
6900 let (v2, valid2) = ct_decode_alphabet_byte::<A>(*b2);
6901 invalid_byte |= !valid0;
6902 invalid_byte |= !valid1;
6903 invalid_byte |= !valid2;
6904 invalid_padding |= ct_mask_eq_u8(*b0, b'=');
6905 invalid_padding |= ct_mask_eq_u8(*b1, b'=');
6906 invalid_padding |= ct_mask_eq_u8(*b2, b'=');
6907 invalid_padding |= ct_mask_nonzero_u8(v2 & 0b0000_0011);
6908 output[write] = (v0 << 2) | (v1 >> 4);
6909 output[write + 1] = (v1 << 4) | (v2 >> 2);
6910 write += 2;
6911 }
6912 _ => return Err(DecodeError::InvalidLength),
6913 }
6914
6915 report_ct_error(invalid_byte, invalid_padding)?;
6916 Ok(write)
6917}
6918
6919fn ct_decode_unpadded_in_place<A: Alphabet>(buffer: &mut [u8]) -> Result<usize, DecodeError> {
6920 if buffer.len() % 4 == 1 {
6921 return Err(DecodeError::InvalidLength);
6922 }
6923
6924 let required = decoded_capacity(buffer.len());
6925 debug_assert!(required <= buffer.len());
6926
6927 let mut invalid_byte = 0u8;
6928 let mut invalid_padding = 0u8;
6929 let mut write = 0;
6930 let mut read = 0;
6931
6932 while read + 4 <= buffer.len() {
6933 let [b0, b1, b2, b3] = read_quad(buffer, read)?;
6934 let (v0, valid0) = ct_decode_alphabet_byte::<A>(b0);
6935 let (v1, valid1) = ct_decode_alphabet_byte::<A>(b1);
6936 let (v2, valid2) = ct_decode_alphabet_byte::<A>(b2);
6937 let (v3, valid3) = ct_decode_alphabet_byte::<A>(b3);
6938
6939 invalid_byte |= !valid0;
6940 invalid_byte |= !valid1;
6941 invalid_byte |= !valid2;
6942 invalid_byte |= !valid3;
6943 invalid_padding |= ct_mask_eq_u8(b0, b'=');
6944 invalid_padding |= ct_mask_eq_u8(b1, b'=');
6945 invalid_padding |= ct_mask_eq_u8(b2, b'=');
6946 invalid_padding |= ct_mask_eq_u8(b3, b'=');
6947
6948 buffer[write] = (v0 << 2) | (v1 >> 4);
6949 buffer[write + 1] = (v1 << 4) | (v2 >> 2);
6950 buffer[write + 2] = (v2 << 6) | v3;
6951 read += 4;
6952 write += 3;
6953 }
6954
6955 match read_tail(buffer, read)? {
6956 [] => {}
6957 [b0, b1] => {
6958 let (v0, valid0) = ct_decode_alphabet_byte::<A>(*b0);
6959 let (v1, valid1) = ct_decode_alphabet_byte::<A>(*b1);
6960 invalid_byte |= !valid0;
6961 invalid_byte |= !valid1;
6962 invalid_padding |= ct_mask_eq_u8(*b0, b'=');
6963 invalid_padding |= ct_mask_eq_u8(*b1, b'=');
6964 invalid_padding |= ct_mask_nonzero_u8(v1 & 0b0000_1111);
6965 buffer[write] = (v0 << 2) | (v1 >> 4);
6966 write += 1;
6967 }
6968 [b0, b1, b2] => {
6969 let (v0, valid0) = ct_decode_alphabet_byte::<A>(*b0);
6970 let (v1, valid1) = ct_decode_alphabet_byte::<A>(*b1);
6971 let (v2, valid2) = ct_decode_alphabet_byte::<A>(*b2);
6972 invalid_byte |= !valid0;
6973 invalid_byte |= !valid1;
6974 invalid_byte |= !valid2;
6975 invalid_padding |= ct_mask_eq_u8(*b0, b'=');
6976 invalid_padding |= ct_mask_eq_u8(*b1, b'=');
6977 invalid_padding |= ct_mask_eq_u8(*b2, b'=');
6978 invalid_padding |= ct_mask_nonzero_u8(v2 & 0b0000_0011);
6979 buffer[write] = (v0 << 2) | (v1 >> 4);
6980 buffer[write + 1] = (v1 << 4) | (v2 >> 2);
6981 write += 2;
6982 }
6983 _ => return Err(DecodeError::InvalidLength),
6984 }
6985
6986 debug_assert_eq!(write, required);
6987 report_ct_error(invalid_byte, invalid_padding)?;
6988 Ok(write)
6989}
6990
6991fn read_tail(input: &[u8], offset: usize) -> Result<&[u8], DecodeError> {
6992 input.get(offset..).ok_or(DecodeError::InvalidLength)
6993}
6994
6995#[inline]
6996fn ct_decode_alphabet_byte<A: Alphabet>(byte: u8) -> (u8, u8) {
6997 let mut decoded = 0u8;
6998 let mut valid = 0u8;
6999 let mut candidate = 0u8;
7000
7001 while candidate < 64 {
7002 let matches = ct_mask_eq_u8(byte, A::ENCODE[candidate as usize]);
7003 decoded |= candidate & matches;
7004 valid |= matches;
7005 candidate += 1;
7006 }
7007
7008 (decoded, valid)
7009}
7010
7011fn ct_padding_len(input: &[u8]) -> usize {
7012 let Some((&last, before_last_prefix)) = input.split_last() else {
7013 return 0;
7014 };
7015 let Some(&before_last) = before_last_prefix.last() else {
7016 return 0;
7017 };
7018 usize::from(ct_mask_eq_u8(last, b'=') & 1) + usize::from(ct_mask_eq_u8(before_last, b'=') & 1)
7019}
7020
7021fn report_ct_error(invalid_byte: u8, invalid_padding: u8) -> Result<(), DecodeError> {
7022 if (invalid_byte | invalid_padding) != 0 {
7023 Err(DecodeError::InvalidInput)
7024 } else {
7025 Ok(())
7026 }
7027}
7028
7029#[cfg(kani)]
7030mod kani_proofs {
7031 use super::{
7032 STANDARD, Standard, checked_encoded_len, ct, decode_byte, decode_chunk,
7033 decode_tail_unpadded, decoded_capacity, validate_tail_unpadded,
7034 };
7035
7036 #[kani::proof]
7037 fn checked_encoded_len_is_bounded_for_small_inputs() {
7038 let len = usize::from(kani::any::<u8>());
7039 let padded = kani::any::<bool>();
7040 let encoded = checked_encoded_len(len, padded).expect("u8 input length cannot overflow");
7041
7042 assert!(encoded >= len);
7043 assert!(encoded <= len / 3 * 4 + 4);
7044 }
7045
7046 #[kani::proof]
7047 fn decoded_capacity_is_bounded_for_small_inputs() {
7048 let len = usize::from(kani::any::<u8>());
7049 let capacity = decoded_capacity(len);
7050
7051 assert!(capacity <= len / 4 * 3 + 2);
7052 }
7053
7054 #[kani::proof]
7055 #[kani::unwind(3)]
7056 fn standard_in_place_decode_returns_prefix_within_buffer() {
7057 let mut buffer = kani::any::<[u8; 8]>();
7058 let result = STANDARD.decode_in_place(&mut buffer);
7059
7060 if let Ok(decoded) = result {
7061 assert!(decoded.len() <= 8);
7062 }
7063 }
7064
7065 #[kani::proof]
7066 #[kani::unwind(3)]
7067 fn standard_decode_slice_returns_written_within_output() {
7068 let input = kani::any::<[u8; 4]>();
7069 let mut output = kani::any::<[u8; 3]>();
7070 let result = STANDARD.decode_slice(&input, &mut output);
7071
7072 if let Ok(written) = result {
7073 assert!(written <= output.len());
7074 }
7075 }
7076
7077 #[kani::proof]
7078 #[kani::unwind(3)]
7079 fn standard_decode_chunk_returns_written_within_output() {
7080 let input = kani::any::<[u8; 4]>();
7081 let mut output = kani::any::<[u8; 3]>();
7082 let result = decode_chunk::<Standard, true>(input, &mut output);
7083
7084 if let Ok(written) = result {
7085 assert!(written <= output.len());
7086 assert!(written <= 3);
7087 }
7088 }
7089
7090 #[kani::proof]
7091 #[kani::unwind(3)]
7092 fn standard_decode_chunk_bit_packing_matches_decoded_values() {
7093 let input = kani::any::<[u8; 4]>();
7094 let mut output = kani::any::<[u8; 3]>();
7095 let result = decode_chunk::<Standard, true>(input, &mut output);
7096
7097 if let Ok(written) = result {
7098 let v0 = decode_byte::<Standard>(input[0], 0).expect("successful chunk has v0");
7099 let v1 = decode_byte::<Standard>(input[1], 1).expect("successful chunk has v1");
7100
7101 assert!(output[0] == ((v0 << 2) | (v1 >> 4)));
7102
7103 if written >= 2 {
7104 let v2 = decode_byte::<Standard>(input[2], 2).expect("successful chunk has v2");
7105 assert!(output[1] == ((v1 << 4) | (v2 >> 2)));
7106 }
7107
7108 if written == 3 {
7109 let v2 = decode_byte::<Standard>(input[2], 2).expect("successful chunk has v2");
7110 let v3 = decode_byte::<Standard>(input[3], 3).expect("successful chunk has v3");
7111 assert!(output[2] == ((v2 << 6) | v3));
7112 }
7113 }
7114 }
7115
7116 #[kani::proof]
7117 #[kani::unwind(3)]
7118 fn standard_validate_tail_unpadded_accepts_or_rejects_without_panic() {
7119 let input = kani::any::<[u8; 3]>();
7120 let len = usize::from(kani::any::<u8>() % 4);
7121 let result = validate_tail_unpadded::<Standard>(&input[..len]);
7122
7123 if result.is_ok() {
7124 assert!(len == 0 || len == 2 || len == 3);
7125 }
7126 }
7127
7128 #[kani::proof]
7129 #[kani::unwind(3)]
7130 fn standard_decode_two_byte_tail_returns_written_within_output() {
7131 let input = kani::any::<[u8; 2]>();
7132 let mut output = kani::any::<[u8; 1]>();
7133 let result = decode_tail_unpadded::<Standard>(&input, &mut output);
7134
7135 if let Ok(written) = result {
7136 assert!(written <= output.len());
7137 assert!(written == 1);
7138 }
7139 }
7140
7141 #[kani::proof]
7142 #[kani::unwind(3)]
7143 fn standard_decode_three_byte_tail_returns_written_within_output() {
7144 let input = kani::any::<[u8; 3]>();
7145 let mut output = kani::any::<[u8; 2]>();
7146 let result = decode_tail_unpadded::<Standard>(&input, &mut output);
7147
7148 if let Ok(written) = result {
7149 assert!(written <= output.len());
7150 assert!(written == 2);
7151 }
7152 }
7153
7154 #[kani::proof]
7155 #[kani::unwind(3)]
7156 fn standard_decode_slice_clear_tail_clears_output_on_error() {
7157 let input = kani::any::<[u8; 4]>();
7158 let mut output = kani::any::<[u8; 3]>();
7159 let result = STANDARD.decode_slice_clear_tail(&input, &mut output);
7160
7161 if result.is_err() {
7162 assert!(output.iter().all(|byte| *byte == 0));
7163 }
7164 }
7165
7166 #[kani::proof]
7167 #[kani::unwind(3)]
7168 fn standard_encode_slice_returns_written_within_output() {
7169 let input = kani::any::<[u8; 3]>();
7170 let mut output = kani::any::<[u8; 4]>();
7171 let result = STANDARD.encode_slice(&input, &mut output);
7172
7173 if let Ok(written) = result {
7174 assert!(written <= output.len());
7175 }
7176 }
7177
7178 #[kani::proof]
7179 #[kani::unwind(4)]
7180 fn standard_encode_in_place_returns_prefix_within_buffer() {
7181 let mut buffer = kani::any::<[u8; 8]>();
7182 let input_len = usize::from(kani::any::<u8>() % 9);
7183 let result = STANDARD.encode_in_place(&mut buffer, input_len);
7184
7185 if let Ok(encoded) = result {
7186 assert!(encoded.len() <= 8);
7187 }
7188 }
7189
7190 #[kani::proof]
7191 #[kani::unwind(3)]
7192 fn standard_clear_tail_decode_clears_buffer_on_error() {
7193 let mut buffer = kani::any::<[u8; 4]>();
7194 let result = STANDARD.decode_in_place_clear_tail(&mut buffer);
7195
7196 if result.is_err() {
7197 assert!(buffer.iter().all(|byte| *byte == 0));
7198 }
7199 }
7200
7201 #[kani::proof]
7202 #[kani::unwind(3)]
7203 fn ct_standard_decode_slice_returns_written_within_output() {
7204 let input = kani::any::<[u8; 4]>();
7205 let mut output = kani::any::<[u8; 3]>();
7206 let result = ct::STANDARD.decode_slice(&input, &mut output);
7207
7208 if let Ok(written) = result {
7209 assert!(written <= output.len());
7210 }
7211 }
7212
7213 #[kani::proof]
7214 #[kani::unwind(3)]
7215 fn ct_standard_decode_slice_clear_tail_clears_output_on_error() {
7216 let input = kani::any::<[u8; 4]>();
7217 let mut output = kani::any::<[u8; 3]>();
7218 let result = ct::STANDARD.decode_slice_clear_tail(&input, &mut output);
7219
7220 if result.is_err() {
7221 assert!(output.iter().all(|byte| *byte == 0));
7222 }
7223 }
7224
7225 #[kani::proof]
7226 #[kani::unwind(3)]
7227 fn ct_standard_decode_in_place_clear_tail_clears_buffer_on_error() {
7228 let mut buffer = kani::any::<[u8; 4]>();
7229 let result = ct::STANDARD.decode_in_place_clear_tail(&mut buffer);
7230
7231 if result.is_err() {
7232 assert!(buffer.iter().all(|byte| *byte == 0));
7233 }
7234 }
7235
7236 #[kani::proof]
7237 #[kani::unwind(3)]
7238 fn ct_standard_validate_matches_decode_for_one_quantum() {
7239 let input = kani::any::<[u8; 4]>();
7240 let mut output = kani::any::<[u8; 3]>();
7241
7242 let validate_ok = ct::STANDARD.validate_result(&input).is_ok();
7243 let decode_ok = ct::STANDARD.decode_slice(&input, &mut output).is_ok();
7244
7245 assert!(validate_ok == decode_ok);
7246 }
7247}
7248
7249#[cfg(test)]
7250mod tests {
7251 use super::*;
7252
7253 fn fill_pattern(output: &mut [u8], seed: usize) {
7254 for (index, byte) in output.iter_mut().enumerate() {
7255 let value = (index * 73 + seed * 19) % 256;
7256 *byte = u8::try_from(value).unwrap();
7257 }
7258 }
7259
7260 fn assert_encode_backend_matches_scalar<A, const PAD: bool>(input: &[u8])
7261 where
7262 A: Alphabet,
7263 {
7264 let engine = Engine::<A, PAD>::new();
7265 let mut dispatched = [0x55; 256];
7266 let mut scalar = [0xaa; 256];
7267
7268 let dispatched_result = engine.encode_slice(input, &mut dispatched);
7269 let scalar_result = backend::scalar_reference_encode_slice::<A, PAD>(input, &mut scalar);
7270
7271 assert_eq!(dispatched_result, scalar_result);
7272 if let Ok(written) = dispatched_result {
7273 assert_eq!(&dispatched[..written], &scalar[..written]);
7274 }
7275
7276 let required = checked_encoded_len(input.len(), PAD).unwrap();
7277 if required > 0 {
7278 let mut dispatched_short = [0x55; 256];
7279 let mut scalar_short = [0xaa; 256];
7280 let available = required - 1;
7281
7282 assert_eq!(
7283 engine.encode_slice(input, &mut dispatched_short[..available]),
7284 backend::scalar_reference_encode_slice::<A, PAD>(
7285 input,
7286 &mut scalar_short[..available],
7287 )
7288 );
7289 }
7290 }
7291
7292 fn assert_decode_backend_matches_scalar<A, const PAD: bool>(input: &[u8])
7293 where
7294 A: Alphabet,
7295 {
7296 let engine = Engine::<A, PAD>::new();
7297 let mut dispatched = [0x55; 128];
7298 let mut scalar = [0xaa; 128];
7299
7300 let dispatched_result = engine.decode_slice(input, &mut dispatched);
7301 let scalar_result = backend::scalar_reference_decode_slice::<A, PAD>(input, &mut scalar);
7302
7303 assert_eq!(dispatched_result, scalar_result);
7304 if let Ok(written) = dispatched_result {
7305 assert_eq!(&dispatched[..written], &scalar[..written]);
7306
7307 if written > 0 {
7308 let mut dispatched_short = [0x55; 128];
7309 let mut scalar_short = [0xaa; 128];
7310 let available = written - 1;
7311
7312 assert_eq!(
7313 engine.decode_slice(input, &mut dispatched_short[..available]),
7314 backend::scalar_reference_decode_slice::<A, PAD>(
7315 input,
7316 &mut scalar_short[..available],
7317 )
7318 );
7319 }
7320 }
7321 }
7322
7323 fn assert_backend_round_trip_matches_scalar<A, const PAD: bool>(input: &[u8])
7324 where
7325 A: Alphabet,
7326 {
7327 assert_encode_backend_matches_scalar::<A, PAD>(input);
7328
7329 let mut encoded = [0; 256];
7330 let encoded_len =
7331 backend::scalar_reference_encode_slice::<A, PAD>(input, &mut encoded).unwrap();
7332 assert_decode_backend_matches_scalar::<A, PAD>(&encoded[..encoded_len]);
7333 }
7334
7335 fn assert_standard_decode_chunk_matches_input(input: &[u8]) {
7336 let mut encoded = [0u8; 4];
7337 let encoded_len = STANDARD.encode_slice(input, &mut encoded).unwrap();
7338 assert_eq!(encoded_len, 4);
7339
7340 let chunk = [encoded[0], encoded[1], encoded[2], encoded[3]];
7341 let mut decoded = [0u8; 3];
7342 let decoded_len = decode_chunk::<Standard, true>(chunk, &mut decoded).unwrap();
7343
7344 assert_eq!(decoded_len, input.len());
7345 assert_eq!(&decoded[..decoded_len], input);
7346 }
7347
7348 #[test]
7349 fn backend_dispatch_matches_scalar_reference_for_canonical_inputs() {
7350 let mut input = [0; 128];
7351
7352 for input_len in 0..=input.len() {
7353 fill_pattern(&mut input[..input_len], input_len);
7354 let input = &input[..input_len];
7355
7356 assert_backend_round_trip_matches_scalar::<Standard, true>(input);
7357 assert_backend_round_trip_matches_scalar::<Standard, false>(input);
7358 assert_backend_round_trip_matches_scalar::<UrlSafe, true>(input);
7359 assert_backend_round_trip_matches_scalar::<UrlSafe, false>(input);
7360 }
7361 }
7362
7363 #[test]
7364 fn backend_dispatch_matches_scalar_reference_for_malformed_inputs() {
7365 for input in [
7366 &b"Z"[..],
7367 b"====",
7368 b"AA=A",
7369 b"Zh==",
7370 b"Zm9=",
7371 b"Zm9v$g==",
7372 b"Zm9vZh==",
7373 ] {
7374 assert_decode_backend_matches_scalar::<Standard, true>(input);
7375 }
7376
7377 for input in [&b"Z"[..], b"AA=A", b"Zh", b"Zm9", b"Zm9vYg$"] {
7378 assert_decode_backend_matches_scalar::<Standard, false>(input);
7379 }
7380
7381 assert_decode_backend_matches_scalar::<UrlSafe, true>(b"AA+A");
7382 assert_decode_backend_matches_scalar::<UrlSafe, false>(b"AA/A");
7383 assert_decode_backend_matches_scalar::<Standard, true>(b"AA-A");
7384 assert_decode_backend_matches_scalar::<Standard, false>(b"AA_A");
7385 }
7386
7387 #[test]
7388 fn decode_chunk_bit_packing_matches_exhaustive_small_inputs() {
7389 for byte in u8::MIN..=u8::MAX {
7390 assert_standard_decode_chunk_matches_input(&[byte]);
7391 }
7392
7393 for first in u8::MIN..=u8::MAX {
7394 for second in u8::MIN..=u8::MAX {
7395 assert_standard_decode_chunk_matches_input(&[first, second]);
7396 }
7397 }
7398 }
7399
7400 #[test]
7401 fn decode_chunk_bit_packing_matches_representative_full_quanta() {
7402 const SAMPLES: [u8; 16] = [
7403 0, 1, 2, 15, 16, 31, 32, 63, 64, 95, 127, 128, 191, 192, 254, 255,
7404 ];
7405
7406 for first in SAMPLES {
7407 for second in SAMPLES {
7408 for third in SAMPLES {
7409 assert_standard_decode_chunk_matches_input(&[first, second, third]);
7410 }
7411 }
7412 }
7413 }
7414
7415 #[cfg(feature = "simd")]
7416 #[test]
7417 fn simd_dispatch_scaffold_keeps_scalar_active() {
7418 assert_eq!(simd::active_backend(), simd::ActiveBackend::Scalar);
7419 let _candidate = simd::detected_candidate();
7420 }
7421
7422 #[test]
7423 fn encodes_standard_vectors() {
7424 let vectors = [
7425 (&b""[..], &b""[..]),
7426 (&b"f"[..], &b"Zg=="[..]),
7427 (&b"fo"[..], &b"Zm8="[..]),
7428 (&b"foo"[..], &b"Zm9v"[..]),
7429 (&b"foob"[..], &b"Zm9vYg=="[..]),
7430 (&b"fooba"[..], &b"Zm9vYmE="[..]),
7431 (&b"foobar"[..], &b"Zm9vYmFy"[..]),
7432 ];
7433 for (input, expected) in vectors {
7434 let mut output = [0u8; 16];
7435 let written = STANDARD.encode_slice(input, &mut output).unwrap();
7436 assert_eq!(&output[..written], expected);
7437 }
7438 }
7439
7440 #[test]
7441 fn decodes_standard_vectors() {
7442 let vectors = [
7443 (&b""[..], &b""[..]),
7444 (&b"Zg=="[..], &b"f"[..]),
7445 (&b"Zm8="[..], &b"fo"[..]),
7446 (&b"Zm9v"[..], &b"foo"[..]),
7447 (&b"Zm9vYg=="[..], &b"foob"[..]),
7448 (&b"Zm9vYmE="[..], &b"fooba"[..]),
7449 (&b"Zm9vYmFy"[..], &b"foobar"[..]),
7450 ];
7451 for (input, expected) in vectors {
7452 let mut output = [0u8; 16];
7453 let written = STANDARD.decode_slice(input, &mut output).unwrap();
7454 assert_eq!(&output[..written], expected);
7455 }
7456 }
7457
7458 #[test]
7459 fn supports_unpadded_url_safe() {
7460 let mut encoded = [0u8; 16];
7461 let written = URL_SAFE_NO_PAD
7462 .encode_slice(b"\xfb\xff", &mut encoded)
7463 .unwrap();
7464 assert_eq!(&encoded[..written], b"-_8");
7465
7466 let mut decoded = [0u8; 2];
7467 let written = URL_SAFE_NO_PAD
7468 .decode_slice(&encoded[..written], &mut decoded)
7469 .unwrap();
7470 assert_eq!(&decoded[..written], b"\xfb\xff");
7471 }
7472
7473 #[test]
7474 fn decodes_in_place() {
7475 let mut buffer = *b"Zm9vYmFy";
7476 let decoded = STANDARD_NO_PAD.decode_in_place(&mut buffer).unwrap();
7477 assert_eq!(decoded, b"foobar");
7478 }
7479
7480 #[test]
7481 fn rejects_non_canonical_padding_bits() {
7482 let mut output = [0u8; 4];
7483 assert_eq!(
7484 STANDARD.decode_slice(b"Zh==", &mut output),
7485 Err(DecodeError::InvalidPadding { index: 1 })
7486 );
7487 assert_eq!(
7488 STANDARD.decode_slice(b"Zm9=", &mut output),
7489 Err(DecodeError::InvalidPadding { index: 2 })
7490 );
7491 }
7492}