Documentation
¶
Overview ¶
Package base32 provides Crockford Base32 encoding and CRC-10 checksums for human-readable, error-correcting identifiers.
The Base32 implementation uses Crockford's alphabet (excludes I, L, O, U) and provides case-insensitive decoding with automatic error correction.
The CRC-10 checksum provides 99.9%+ error detection for single character errors, transpositions, and double errors.
Example:
// Encode a value
id, err := base32.EncodeBase32(12345, 8) // "00000C1S", nil
// Add checksum
idWithChecksum, err := base32.AppendChecksum(id)
// Validate
if base32.ValidateChecksum(idWithChecksum) {
// Valid ID
}
Index ¶
- Variables
- func AppendChecksum(data string) (string, error)
- func CalculateChecksum(data string) (string, error)
- func DecodeBase32(encoded string) (uint64, error)
- func EncodeBase32(value uint64, length int) (string, error)
- func EncodeBase32Compact(value uint64) string
- func ExtractChecksum(input string) string
- func IsValidBase32Char(c rune) bool
- func NormalizeBase32(input string) string
- func StripChecksum(input string) string
- func ValidateChecksum(input string) bool
Examples ¶
Constants ¶
This section is empty.
Variables ¶
var ( // ErrEmptyInput is returned when an operation requires Base32 content but // the input is empty, or empty after normalization (separator-only input // such as "---"). ErrEmptyInput = errors.New("empty Base32 input") // ErrInvalidCharacter is returned when the input contains a character that // is not part of the Crockford Base32 alphabet after normalization. ErrInvalidCharacter = errors.New("invalid Base32 character") // ErrOverflow is returned when a Base32 string decodes to a value that does // not fit in a uint64. ErrOverflow = errors.New("Base32 value overflows uint64") // ErrValueTooLarge is returned when a value cannot be encoded within the // requested fixed length. ErrValueTooLarge = errors.New("value too large for requested Base32 length") )
Sentinel errors returned (wrapped) by this package. Match them with errors.Is rather than string-comparing messages; the wrapped errors carry human-readable detail (offending character, position, original input).
Functions ¶
func AppendChecksum ¶
AppendChecksum adds a 2-character checksum to the end of the data.
This is the recommended way to create checksummed strings.
The input is normalized via NormalizeBase32 before the checksum is computed, so lowercase, dashed, or spaced input (e.g. "0000-c1p9") works; the returned string is always the normalized data plus its checksum. Clean input is unaffected by normalization.
Returns ErrEmptyInput if the input is empty after normalization (e.g. "---", which normalizes to "") and ErrInvalidCharacter if it contains characters outside the Crockford alphabet. Match with errors.Is.
Example:
id, _ := base32.EncodeBase32(12345, 6) // "000C1S"
idWithChecksum, _ := base32.AppendChecksum(id) // "000C1S69"
withDashes, _ := base32.AppendChecksum("0000-c1p9") // "0000C1P9Q0" (normalized)
Parameters:
- data: The Base32 string to checksum (normalized before checksumming)
Returns:
- The normalized input string with a 2-character checksum appended
- An error if the normalized input is empty or contains invalid characters
Example ¶
package main
import (
"fmt"
"github.com/jasoet/pkg/v3/base32"
)
func main() {
withChecksum, _ := base32.AppendChecksum("ABC123")
fmt.Println(withChecksum)
}
Output: ABC123TF
Example (Normalized) ¶
AppendChecksum normalizes its input, so dashed/lowercase identifiers work.
package main
import (
"fmt"
"github.com/jasoet/pkg/v3/base32"
)
func main() {
withChecksum, _ := base32.AppendChecksum("0000-c1p9")
fmt.Println(withChecksum)
}
Output: 0000C1P9Q0
func CalculateChecksum ¶
CalculateChecksum computes a 2-character Base32 checksum using CRC-10/ATM.
The checksum provides strong error detection for:
- Single character errors
- Character transpositions
- Double errors
- Most insertion/deletion errors
The CRC-10 algorithm processes each Base32 character (5 bits) and produces a 10-bit checksum, which is then encoded as 2 Base32 characters.
Leading-zero blind spot: because the CRC register is initialized to zero, inserting or deleting leading '0' characters does not change the checksum (e.g. CalculateChecksum("C1S") == CalculateChecksum("000C1S")), and any all-zero string checksums to "00" and validates. Do not rely on the checksum to catch loss or addition of leading zeros; encode identifiers at a fixed length (see EncodeBase32) when that matters. This is a compatibility contract pinned by the golden vectors and will not change within v3.
Returns ErrEmptyInput for empty input and ErrInvalidCharacter for characters outside the Crockford alphabet. Match with errors.Is.
Example:
checksum, err := base32.CalculateChecksum("ABC123") // "TF", nil
Parameters:
- data: The Base32 string to checksum (must contain only valid Base32 characters)
Returns:
- A 2-character Base32 checksum
- An error if the input is empty or contains invalid characters
Example ¶
package main
import (
"fmt"
"github.com/jasoet/pkg/v3/base32"
)
func main() {
checksum, _ := base32.CalculateChecksum("ABC123")
fmt.Println(checksum)
}
Output: TF
func DecodeBase32 ¶
DecodeBase32 decodes a Base32 string to an unsigned integer.
The input is normalized via NormalizeBase32 first: it is uppercased, separators (dashes, spaces, tabs, newlines) are removed per the Crockford spec, and common lookalikes are corrected (I→1, L→1, O→0). This keeps DecodeBase32 consistent with the checksum entry points, so the Validate → Strip → Decode pipeline works on dashed/lowercase input.
Returns ErrEmptyInput when the input is empty (or empty after normalization), ErrInvalidCharacter for characters outside the alphabet, and ErrOverflow when the value does not fit in a uint64. Match with errors.Is.
Example:
val, err := base32.DecodeBase32("C1S") // 12345, nil
val, err := base32.DecodeBase32("c1s") // 12345, nil (case-insensitive)
val, err := base32.DecodeBase32("I0") // 32, nil (I→1 correction)
val, err := base32.DecodeBase32("00 0C1S") // 12345, nil (separators ignored)
Parameters:
- encoded: The Base32-encoded string to decode
Returns:
- The decoded unsigned integer value
- An error if the input is empty or contains invalid characters
Example ¶
package main
import (
"fmt"
"github.com/jasoet/pkg/v3/base32"
)
func main() {
value, _ := base32.DecodeBase32("C1S")
fmt.Println(value)
}
Output: 12345
func EncodeBase32 ¶
EncodeBase32 encodes an unsigned integer to a Base32 string of specified length.
The encoded value is left-padded with '0's to reach the specified length. Uses Crockford's Base32 alphabet (0-9, A-Z excluding I, L, O, U).
Returns an error if the value is too large to fit in the specified length.
Example:
base32.EncodeBase32(42, 4) // "001A", nil base32.EncodeBase32(999, 3) // "0Z7", nil base32.EncodeBase32(32, 2) // "10", nil base32.EncodeBase32(1024, 2) // "", error (overflow)
Parameters:
- value: The unsigned integer to encode
- length: The desired length of the output string
Returns:
- A Base32-encoded string of exactly 'length' characters, or "" on error
- An error if length <= 0 or the value overflows the specified length
Example ¶
package main
import (
"fmt"
"github.com/jasoet/pkg/v3/base32"
)
func main() {
id, _ := base32.EncodeBase32(12345, 8)
fmt.Println(id)
}
Output: 00000C1S
func EncodeBase32Compact ¶
EncodeBase32Compact encodes a value to the minimum number of Base32 characters needed.
Unlike EncodeBase32, this function does not pad the output to a fixed length.
Example:
base32.EncodeBase32Compact(0) // "0" base32.EncodeBase32Compact(31) // "Z" base32.EncodeBase32Compact(32) // "10" base32.EncodeBase32Compact(12345) // "C1S"
Example ¶
package main
import (
"fmt"
"github.com/jasoet/pkg/v3/base32"
)
func main() {
fmt.Println(base32.EncodeBase32Compact(12345))
fmt.Println(base32.EncodeBase32Compact(123456789))
}
Output: C1S 3NQK8N
func ExtractChecksum ¶
ExtractChecksum extracts the last 2 characters (checksum) from a string.
The input is normalized via NormalizeBase32 first, mirroring AppendChecksum/ValidateChecksum, so the checksum of a validated dashed/lowercase string (e.g. "0000-c1p9-q0" → "Q0") is returned rather than a byte-sliced fragment of the raw input. Normalizing also avoids splitting a multibyte rune when slicing.
Returns an empty string if the normalized input has fewer than 2 characters.
Example:
checksum := base32.ExtractChecksum("ABC123TF") // "TF"
checksum := base32.ExtractChecksum("0000-c1p9-q0") // "Q0" (normalized first)
checksum := base32.ExtractChecksum("A") // ""
Parameters:
- input: The string with checksum appended (normalized before extracting)
Returns:
- The last 2 characters of the normalized input
func IsValidBase32Char ¶
IsValidBase32Char returns true if the character is valid in Base32 encoding.
Valid characters include: 0-9, A-Z (excluding I, L, O, U), and their lowercase equivalents. Also accepts I, L, O as they are auto-corrected to 1, 1, 0.
Example:
base32.IsValidBase32Char('A') // true
base32.IsValidBase32Char('a') // true
base32.IsValidBase32Char('O') // true (auto-corrected to 0)
base32.IsValidBase32Char('U') // false
func NormalizeBase32 ¶
NormalizeBase32 normalizes a Base32 string by:
- Converting to uppercase
- Removing dashes, spaces, tabs, and newlines
- Correcting common mistakes (I→1, L→1, O→0)
This function is useful for processing user input to ensure consistency.
Example:
base32.NormalizeBase32("abc-def") // "ABCDEF"
base32.NormalizeBase32("1O 2I") // "1021"
base32.NormalizeBase32("hell0") // "HE110" (L→1 correction)
Example ¶
package main
import (
"fmt"
"github.com/jasoet/pkg/v3/base32"
)
func main() {
fmt.Println(base32.NormalizeBase32("abc-def"))
fmt.Println(base32.NormalizeBase32("1O 2I"))
}
Output: ABCDEF 1021
func StripChecksum ¶
StripChecksum removes the last 2 characters (checksum) from a string.
The input is normalized via NormalizeBase32 first, mirroring AppendChecksum/ValidateChecksum. This is required for correctness: a checksummed string that validated in dashed/lowercase form (e.g. "0000-c1p9-q0") strips to the normalized payload ("0000C1P9") rather than a byte-sliced fragment of the raw input. Normalizing also avoids splitting a multibyte rune when slicing.
Returns an empty string if the normalized input has 2 or fewer characters.
Example:
data := base32.StripChecksum("ABC123TF") // "ABC123"
data := base32.StripChecksum("0000-c1p9-q0") // "0000C1P9" (normalized first)
data := base32.StripChecksum("AB") // ""
Parameters:
- input: The string with checksum appended (normalized before stripping)
Returns:
- The normalized input string without the last 2 characters
func ValidateChecksum ¶
ValidateChecksum verifies that the checksum in a string is correct.
Expected format: [data][2 chars checksum]
The input is normalized via NormalizeBase32 before validation, so lowercase, dashed, or spaced input (e.g. "0000-c1p9-q0") validates against its normalized form. Clean input is unaffected by normalization.
This function is useful for validating user input or detecting data corruption. Returns false if the input is too short or contains invalid Base32 characters.
Example:
valid := base32.ValidateChecksum("ABC123TF") // true (TF is the checksum of "ABC123")
valid := base32.ValidateChecksum("abc-123-tf") // true (normalized before validation)
valid := base32.ValidateChecksum("ABC123ZZ") // false (ZZ is the wrong checksum)
Parameters:
- input: The string with checksum appended (minimum 3 characters after normalization)
Returns:
- true if the checksum is valid, false otherwise
Example ¶
package main
import (
"fmt"
"github.com/jasoet/pkg/v3/base32"
)
func main() {
fmt.Println(base32.ValidateChecksum("ABC123TF"))
fmt.Println(base32.ValidateChecksum("0000-c1p9-q0")) // normalized before validation
fmt.Println(base32.ValidateChecksum("ABC123ZZ"))
}
Output: true true false
Types ¶
This section is empty.