Skip to content

Repository files navigation

base64

A SIMD-accelerated, 100% compatible drop-in replacement for Go's encoding/base64.

import "github.com/xiaost/base64"

s := base64.StdEncoding.EncodeToString(data) // same API as encoding/base64
b, err := base64.URLEncoding.DecodeString(s)

The encoding/base64 API is mirrored for predefined and custom encodings, buffer helpers, string helpers, and streaming encoders/decoders. CorruptInputError is a type alias of encoding/base64.CorruptInputError, so existing error handling keeps working unchanged.

How it works

Bulk data is processed by per-architecture assembly kernels. Everything else — tails, padding, embedded newlines, errors, custom alphabets the kernels can't handle, CPUs without the needed features — is delegated to encoding/base64 itself, so behavior is identical by construction.

arch kernels alphabet support
arm64 NEON (always available) any alphabet
amd64 AVX2, else SSSE3 encode: standard first 62; decode: std/URL
other none stdlib
  • arm64: 48-byte encode blocks via LD3+TBL+ST4 plus a 24-byte tail block; 64-char decode blocks via LD4+TBL/TBX+ST3 plus in-order 16-char tail blocks (custom alphabets decode in 64-char blocks only).
  • amd64: runtime CPUID selects AVX2 or SSSE3; encode blocks are 24 / 12 bytes and decode blocks are 32 / 16 chars, and the AVX2 path hands its 12-byte / 16-char remainder to the SSE kernels.

Inputs below one block (24-byte encode / 16-char decode on arm64, 12 / 16 on amd64) never enter the kernels and mostly measure wrapper and stdlib fallback overhead.

The amd64 kernels implement Wojciech Muła's base64 SIMD algorithms; the arm64 kernels follow the design of aklomp/base64.

Decoding stops the SIMD loop when a 64/32/16-char block contains non-plain alphabet bytes, such as padding, \r, \n, or invalid bytes, and hands the rest to the stdlib. Newline skipping, strict mode, padding checks, and CorruptInputError offsets match the stdlib. One exception keeps line-wrapped base64 (PEM, MIME) fast: when the stop leads to a run of newlines at a 4-char quantum boundary, the decoder scalar-decodes the plain alphabet quanta before the run, skips the newlines and re-enters the kernel. Only whole quanta of plain alphabet chars are ever consumed this way — padding and invalid bytes still go to the stdlib together with everything after them, whose semantics they depend on.

Build with -tags purego to disable all assembly.

Compatibility testing

Verified against encoding/base64 by differential tests and fuzzing, covering predefined and custom/padded/strict encodings, corrupt input, error values, truncations, embedded newlines and streaming APIs. All three kernel sets are exercised in CI-style runs: NEON natively on Apple Silicon, SSSE3 under Rosetta 2, and AVX2 inside a QEMU -cpu max VM. Benchmark output is published by GitHub Actions, so current CI numbers are available at github.com/xiaost/base64/actions.

About

A SIMD-accelerated, 100% compatible drop-in replacement for Go's `encoding/base64`

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages