Obfuskey: Integer Packing and Obfuscation Library
Note: This library is a Rust port of the Obfuskey Python package and is fully cross-language compatible with both the Python and TypeScript/JavaScript implementations. Keys generated in any language can be decoded in any other.
Obfuskey is a Rust library for efficient packing and unpacking of multiple integer values into a single large integer, and for obfuscation/de-obfuscation of these integers into short, human-readable string "keys". It's ideal for scenarios requiring compact data representation (e.g., URL parameters, short identifiers) with optional obfuscation.
The combination of key length and alphabet used will determine the maximum value it can obfuscate: alphabet.len() ^ key_length - 1.
Features
- Bit-packing: Define a schema to pack multiple integer fields into a single integer or byte array.
- Bit-unpacking: Retrieve individual integer fields from a packed integer or byte array.
- Dual-path arithmetic: Optimized
u128fast path for common cases with automaticBigUintfallback for large key spaces. - Native integer API: Ergonomic
u64methods (get_key_u64,get_value_u64) alongsideBigUintmethods for large values. - Customizable alphabets: Define your own character sets for key generation, supporting base conversion up to Base94+.
- O(1) alphabet lookups: Pre-computed lookup table for ASCII alphabets.
- Obfuscation: Scramble integers into short, unique string keys using a configurable prime multiplier.
- Cross-language compatible: Produces identical output to the Python and TypeScript implementations.
- Error handling: Comprehensive error types for clear debugging.
Installation
Add to your Cargo.toml:
[]
= "0.1"
Usage
Obfuskey - Basic Usage
use ;
// Using default multiplier (auto-generated prime)
let mut obfuscator = new.unwrap;
let key = obfuscator.get_key_u64.unwrap;
let value = obfuscator.get_value_u64.unwrap;
assert_eq!;
// Using a specific multiplier (must be odd)
let mut obf = new.unwrap;
let key = obf.get_key_u64.unwrap;
println!;
// Using a custom alphabet
let mut custom = new.unwrap;
let key = custom.get_key_u64.unwrap;
println!;
BigUint API for Large Values
For key spaces that exceed u64 range, use the BigUint API:
use BigUint;
use ;
let mut obf = new.unwrap;
let large_value = from;
let key = obf.get_key_big.unwrap;
let result = obf.get_value_big.unwrap;
assert_eq!;
Obfusbit - Packing Multiple Values
Obfusbit allows you to pack multiple integer values into a single obfuscated key or raw integer.
Basic Packing and Unpacking
use ;
use HashMap;
let schema = vec!;
let mut packer = new.unwrap;
let mut values = new;
values.insert;
values.insert;
values.insert;
// Pack into a u64
let packed = packer.pack_u64.unwrap;
if let Int = packed
// Unpack back
let unpacked = packer.unpack_u64.unwrap;
assert_eq!;
Packing with Obfuscation
use ;
use HashMap;
let schema = vec!;
let obfuskey = new.unwrap;
let mut packer = new.unwrap;
let mut values = new;
values.insert;
values.insert;
values.insert;
// Pack and obfuscate to a string key
let packed = packer.pack_u64.unwrap;
let key = match packed ;
println!; // 3-character string
// Unpack and de-obfuscate
let result = packer.unpack_u64.unwrap;
assert_eq!;
assert_eq!;
assert_eq!;
Byte Serialization
use ;
use HashMap;
let schema = vec!;
let packer = new.unwrap;
let mut values = new;
values.insert;
values.insert;
values.insert;
let bytes = packer.pack_bytes_u64.unwrap;
assert_eq!;
let unpacked = packer.unpack_bytes_u64.unwrap;
assert_eq!;
Determining Key Length for Obfusbit
When using Obfusbit with Obfuskey, the obfuscator must handle the maximum value your schema can produce:
- Total bits = sum of all field bits in the schema
- Max schema value =
2^total_bits - 1 - Max obfuskey value =
alphabet_size^key_length - 1
The obfuskey max must be >= the schema max. To find the minimum key_length:
let total_bits: u32 = 27; // sum of your schema bits
let alphabet_size: f64 = 58.0; // BASE58
let min_key_length = .ceil as u32;
println!; // 5
Large Integer Support
This library uses num-bigint for arbitrary-precision arithmetic. The prime generation function supports integers up to 512 bits. For most practical use cases (key lengths up to ~21 with BASE62), the optimized u128 fast path is used automatically.
API Reference
Structs
Obfuskey
Obfusbit
Pre-defined Alphabets
| Constant | Characters | Base |
|---|---|---|
BASE16 |
0123456789ABCDEF |
16 |
BASE32 |
234567ABCDEFGHIJKLMNOPQRSTUVWXYZ |
32 |
BASE36 |
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ |
36 |
BASE52 |
0-9, consonants upper/lower |
52 |
BASE56 |
2-9, A-Z, a-z (no ambiguous chars) |
56 |
BASE58 |
1-9, A-Z, a-z (Bitcoin-style) |
58 |
BASE62 |
0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz |
62 |
BASE64 |
BASE62 + +/ |
64 |
BASE64_URL_SAFE |
BASE62 + -_ |
64 |
BASE94 |
All printable ASCII (! through ~) |
94 |
CROCKFORD_BASE32 |
0-9, A-Z (no I, L, O, U) |
32 |
ZBASE32 |
ybndrfg8ejkmcpqxot1uwisza345h769 |
32 |
Errors
All errors are variants of ObfuskeyError:
| Variant | Description |
|---|---|
DuplicateError |
Alphabet contains duplicate characters |
MultiplierError |
Multiplier is not an odd integer |
MaximumValueError |
Value exceeds the maximum allowed |
UnknownKeyError |
Key contains characters not in the alphabet |
KeyLengthError |
Key length doesn't match expected length |
SchemaValidationError |
Invalid schema definition |
BitOverflowError |
Field value exceeds allocated bits |
ValueError |
General invalid value |
Cross-Language Compatibility
This crate produces identical output to the Python and TypeScript implementations. For example, with BASE62 alphabet and key_length=6:
| Value | Key |
|---|---|
12345 |
d2Aasl |
0 |
000000 |
A key generated in Python (obfuskey.get_key(12345)) can be decoded in Rust (obf.get_value_u64("d2Aasl")) and vice versa, as long as the same alphabet and key length are used.
Contributing
Contributions are welcome! Please feel free to open issues or submit pull requests.
License
MIT License - see LICENSE for details.