Nano64 - 64‑bit Time‑Sortable Identifiers for Rust
Nano64 is a lightweight library for generating time-sortable, globally unique IDs that offer the same practical guarantees as ULID or UUID in half the storage footprint; reducing index and I/O overhead while preserving cryptographic-grade randomness. Includes optional monotonic sequencing and AES-GCM encryption.
Note: This is a Rust port of the original Nano64 TypeScript/JavaScript library by @only-cliches. All credit for the original concept, design, and implementation goes to the original author. This port aims to bring the same powerful, compact ID generation capabilities to the Rust ecosystem. Also, a huge shout out to the Go port!
Features
- Time‑sortable: IDs order by creation time automatically.
- Compact: 8 bytes / 16 hex characters.
- Deterministic format:
[63‥20]=timestamp,[19‥0]=random. - Cross‑database‑safe: Big‑endian bytes preserve order in SQLite, Postgres, MySQL, etc.
- AES-GCM encryption: Optional encryption masks the embedded creation date.
- Unsigned canonical form: Single, portable representation (0..2⁶⁴‑1).
Installation
Usage
Basic ID generation
use *;
Monotonic generation
Ensures strictly increasing values even if created in the same millisecond.
AES‑GCM encryption
IDs can easily be encrypted and decrypted to mask their timestamp value from public view.
Comparison with other identifiers
| Property | Nano64 | ULID | UUIDv4 | Snowflake ID |
|---|---|---|---|---|
| Bits total | 64 | 128 | 128 | 64 |
| Encoded timestamp bits | 44 | 48 | 0 | 41 |
| Random / entropy bits | 20 | 80 | 122 | 22 (per-node sequence) |
| Sortable by time | ✅ Yes (lexicographic & numeric) | ✅ Yes | ❌ No | ✅ Yes |
| Collision risk (1%) | ~145 IDs/ms (~0.04% at 145k/sec) | ~26M/ms | Practically none | None (central sequence) |
| Typical string length | 16 hex chars | 26 Crockford base32 | 36 hex+hyphens | 18–20 decimal digits |
| Encodes creation time | ✅ | ✅ | ❌ | ✅ |
| Can hide timestamp | ✅ via AES-GCM encryption | ⚠️ Not built-in | ✅ (no time field) | ❌ Not by design |
| Database sort order | ✅ Stable with big-endian BLOB | ✅ (lexical) | ❌ Random | ✅ Numeric |
| Cryptographic strength | 20-bit random, optional AES | 80-bit random | 122-bit random | None (deterministic) |
| Dependencies | None (crypto optional) | None | None | Central service or worker ID |
| Target use | Compact, sortable, optionally private IDs | Human-readable sortable IDs | Pure random identifiers | Distributed service IDs |
API Summary
Generation Functions
generate(timestamp: u64, rng: Option<RandomNumberGeneratorImpl>) -> Result<Nano64, Nano64Error>- Creates a new ID with specified timestamp and RNGgenerate_now(rng: Option<RandomNumberGeneratorImpl>) -> Result<Nano64, Nano64Error>- Creates an ID with current timestampgenerate_default() -> Result<Nano64, Nano64Error>- Creates an ID with current timestamp and default RNGgenerate_monotonic(timestamp: u64, rng: Option<RandomNumberGeneratorImpl>) -> Result<Nano64, Nano64Error>- Creates monotonic ID (strictly increasing)generate_monotonic_now(rng: Option<RandomNumberGeneratorImpl>) -> Result<Nano64, Nano64Error>- Creates monotonic ID with current timestampgenerate_monotonic_default() -> Result<Nano64, Nano64Error>- Creates monotonic ID with current timestamp and default RNG
Parsing Functions
from_hex(hex_str: String) -> Result<Nano64, Nano64Error>- Parse from 16-char hex string (with or without dash)from_bytes(bytes: [u8; 8]) -> Nano64- Parse from 8 big-endian bytesfrom_u64(value: u64) -> Nano64- Create from u64 valuenew(value: u64) -> Nano64- Create from u64 value (alias)
ID Methods
to_hex() -> String- Returns 17-char uppercase hex (TIMESTAMP-RANDOM)to_bytes() -> [u8; 8]- Returns 8-byte big-endian encodingto_date() -> SystemTime- Converts embedded timestamp to SystemTimeget_timestamp() -> u64- Extracts embedded millisecond timestampget_random() -> u32- Extracts 20-bit random fieldu64_value() -> u64- Returns raw u64 value
Comparison Functions
nano64::compare(a: &Nano64, b: &Nano64) -> i64- Compare two IDs (-1, 0, 1)<Nano64_Instance>.equals(other &Nano64) -> bool- Check equality
Database Support
In-progress!
Encrypted IDs
- Create factory with 32-byte AES-256 key
encrypted_factory
- Generate and encrypt ID
factory.generate_encrypted
- Encrypt existing ID
factory.encrypt
- Decrypt from hex
factory.from_encrypted_hex
- Decrypt from bytes
factory.from_encrypted_bytes
Design
| Bits | Field | Purpose | Range |
|---|---|---|---|
| 44 | Timestamp (ms) | Chronological order | 1970–2527 |
| 20 | Random | Collision avoidance | 1,048,576 patterns/ms |
Benchmark
Run the collision resistance demonstration:
Benchmark Results:
The collision resistance test performs four comprehensive scenarios:
- Single-threaded high-speed: 5.3M IDs/sec with 0.29% collisions
- Concurrent generation: TBD
- Sustained safe rate: 145k IDs/sec over 10 seconds with <0.05% collisions
- Maximum throughput burst: 3.8M IDs/sec with 0.18% collisions
Tests
Run:
All unit tests cover:
- Hex ↔ bytes conversions
- BigInt encoding
- Timestamp extraction and monotonic logic
- AES‑GCM encryption/decryption integrity
- Overflow edge cases
License
MIT License