Base64 encoding and decodings.
For the companion optics and pattern synonyms, see base64-lens.
The following types are supported for both std, padded url-safe, and unpadded url-safe alphabets:
Data.ByteStringData.ByteString.LazyData.ByteString.ShortData.TextData.Text.LazyData.Text.Short
Additionally this library has
- Better performance than
base64-bytestringfor encode and decode. - Optics for handling more complex structures with Base64 representations via the
base64-lenspackage - Parses standard Base64 into a validated
Base64value, and checks Base64url encodings - Rejects non-canonical encodings that do not roundtrip in other base64 libraries like
ZE==.
The library supports GHC 9.6 through 9.14. Its dependencies are base,
bytestring, deepseq, text, and text-short.
Upgrading to 2.0? See the migration guide for the replacement
of isBase64 and isValidBase64, and the release notes for
the optional SIMD implementation.
Use parseBase64 to validate externally supplied standard Base64 and retain the
encoded value in a typed wrapper:
>>> import qualified Data.ByteString.Base64 as B64
>>> :set -XOverloadedStrings
>>> B64.parseBase64 "U3Vu"
Right "U3Vu"
>>> fmap B64.decodeBase64 (B64.parseBase64 "U3Vu")
Right "Sun"
>>> B64.parseBase64 "U3V="
Left "non-canonical encoding detected at offset: 2"Each standard-alphabet module exports parseBase64 :: a -> Either Text (Base64 'StdPadded a), specialized to its string type. Parsing checks the alphabet,
length, padding, and canonical padding bits, then returns the original encoded
input. The Text variants validate Base64 independently of the decoded payload's
UTF-8 validity; use decodeBase64UntypedWith to check that conversion.
parseBase64 replaces isBase64 and isValidBase64. For a Boolean check, use
isRight . parseBase64 from Data.Either. Unlike the old isValidBase64, this
rejects missing padding and non-canonical encodings. The URL-specific validators
isBase64Url and isValidBase64Url retain their existing behavior.
Enable the manual simd Cabal flag to use bundled SIMD kernels for standard
and URL-safe encoding and strict decoding, including the typed decoders:
cabal build -fsimd
cabal test -fsimd --test-show-details=directThe flag is off by default. ARM64 uses NEON; x86-64 selects AVX2 when the CPU and operating system support it, then SSSE3 on older processors. Other targets and short inputs use the existing Haskell loops. No external C library is required. Remainders, padding checks, canonical-encoding checks, and error messages still use the Haskell code. Lenient decoding remains scalar.
Test both configurations and compare optimized benchmark builds separately:
cabal test -f-simd --builddir=dist-scalar --test-show-details=direct
cabal test -fsimd --builddir=dist-simd --test-show-details=direct
cabal bench -f-simd --builddir=dist-scalar -O2 --benchmark-options='--csv scalar.csv'
cabal bench -fsimd --builddir=dist-simd -O2 --benchmark-options='--csv simd.csv'Benchmark names identify the selected flag configuration. The suite covers standard Base64 and padded/unpadded Base64url, encoding and typed/untyped decoding, short and large buffers, and sliced inputs. The test suite exercises block boundaries, scalar tails, slices, invalid input, and wrapper types in both configurations; CI also runs native memory checks on x86-64 and ARM64, explicitly requiring AVX2 on Linux x86-64 and checking the SSSE3 and scalar fallbacks separately.
For native kernel measurements, a standalone benchmark validates every case against scalar output and checks both alphabets. It times pseudorandom, cycling, and repeated inputs at two alignments. It reports the detected backend and writes CSV results:
cc -O2 -std=c99 -Icbits cbits/base64_simd.c benchmarks/simd-native.c -o base64-native-bench
./base64-native-bench --seconds 0.05 --rounds 5 > native.csvAdd --url to time the URL alphabet, or --pattern random to select one
input distribution. On x86-64, compile a second executable with
-DHS_BASE64_SIMD_FORCE_SSSE3 to compare the older backend on the same CPU.
These measurements cover native prefixes only; use the Cabal benchmarks above
to include Haskell allocation and scalar tails.