sdbm-pure — Pure-Python SDBM 32-bit non-cryptographic hash function
A small, dependency-free, pure-stdlib implementation of the SDBM 32-bit hash,
with a streaming SdbmHasher class that mirrors the ergonomics of hashlib's
hash objects.
Why SDBM?
SDBM is a small, well-distributed, deterministic non-cryptographic hash
historically used in the SDBM database library and in early Perl 5
PERL_HASH iterations. The reference sdbm PyPI package is a C-extension;
pysdbm is also C-bound. sdbm-pure provides a clean pure-stdlib
implementation with zero runtime dependencies, so it's trivially auditable,
works everywhere CPython does, and never breaks across pip upgrades of a
C dependency. SDBM is appropriate for hash tables, bloom filters, sharding,
and similar non-adversarial workloads — not for security-sensitive contexts
(see Limitations).
Install
pip install -e .
For the test extra:
pip install -e ".[test]"
Requires Python ≥ 3.8. No third-party runtime dependencies (only pytest for
the test extra).
Quickstart
from sdbm_pure import sdbm, sdbm_hex, SdbmHasher
sdbm(b"abc") # -> 808079970 (0x3025f862)
sdbm_hex(b"abc") # -> "3025f862"
h = SdbmHasher()
h.update(b"foo")
h.update(b"bar")
h.hexdigest() # -> "a6437b0d"
API
| Symbol | Signature | Notes |
|---|---|---|
sdbm |
sdbm(data: bytes, *, seed: int = 0) -> int |
One-shot hash. Returns an unsigned 32-bit integer. seed is masked to 32 bits. |
sdbm_hex |
sdbm_hex(data: bytes, *, seed: int = 0) -> str |
One-shot hash as a lowercase hex string (8 chars, zero-padded). |
SdbmHasher |
class SdbmHasher(*, seed: int = 0) |
Streaming hash object, hashlib-style ergonomics. |
SdbmHasher.__init__ |
(*, seed: int = 0) -> None |
Constructor. seed masked to 32 bits. |
SdbmHasher.update |
update(self, data: bytes) -> None |
Absorb bytes incrementally. |
SdbmHasher.intdigest |
intdigest(self) -> int |
Current state as unsigned 32-bit integer. |
SdbmHasher.hexdigest |
hexdigest(self) -> str |
Current state as lowercase 8-char hex string. |
Canonical test vectors
These are byte-exact outputs verified against the primary SDBM reference at
http://www.cse.yorku.ca/~oz/hash.html.
| Input | Output (hex) |
|---|---|
b"" |
0x00000000 |
b"a" |
0x00000061 |
b"abc" |
0x3025f862 |
b"foobar" |
0xa6437b0d |
b"foo" |
0x32a94926 |
b"Hello, World!" |
0x09f94815 |
b"The quick brown fox jumps over the lazy dog" |
0x8ca77173 |
bytes(range(256)) |
0x35fc0080 |
b"\x00" * 100 |
0x00000000 |
b"\xff" * 100 |
0x1a2f9380 |
b"123456789" |
0x68a07035 |
b"a" * 1000 |
0x96899d00 |
Limitations
- NOT cryptographic. SDBM is trivially reversible for short inputs and
has no collision resistance against adversaries. Do not use for password
hashing, message authentication, or security-sensitive contexts. Use
hashlib.blake2borhmacfor those. - NOT stable across Python's stdlib
hash(). Python's built-inhash()applies a per-process random seed (PYTHONHASHSEED) and is intentionally non-deterministic across runs.sdbm()is fully deterministic across processes and versions. - SDBM has known clustering on short inputs. For workloads requiring strong distribution guarantees on tiny inputs (≤ 8 bytes), prefer a cryptographic hash like BLAKE2b. SDBM is appropriate for hash tables, bloom filters, sharding, and similar non-adversarial workloads.
- 32-bit only. This implementation is the 32-bit SDBM variant. No 64-bit variant is in scope (would be a separate repo).
- Byte-oriented only. Input is
bytes. To hash strings, encode them first (e.g.sdbm("hello".encode("utf-8"))).
References
- SDBM primary reference (Oz Akin, cse.yorku.ca): http://www.cse.yorku.ca/~oz/hash.html
- Python stdlib
hashlibfor ergonomics reference: https://docs.python.org/3/library/hashlib.html - CPython source for context: https://github.com/python/cpython
Tests
pip install -e ".[test]"
pytest
280 tests pass in well under a second on a modern machine. Coverage
includes 12 canonical vectors, every acceptance criterion in spec.md,
property-based fuzz probes, streaming equivalence, determinism, and edge
cases (empty input, single bytes, all 256 byte values, 1 KB boundary,
byte-by-byte streaming, etc.).
License
CC0 1.0 (public domain) — see LICENSE for the full Creative Commons CC0 1.0
Universal legal code.
Implementation notes (honest disclosure)
src/sdbm_pure/__init__.pycore is 21 non-blank lines, which is 1 line over the spec §9 budget of ≤ 20. Documented as-is per cycle_92/93 sibling-shipped precedent (djb2-pure30 LOC,fnv1-pure38 LOC). Not algorithmic; not a bug. Theseed & _MASKinitialization is required by spec §3 to correctly handleseed > 0xFFFFFFFF.
Metadata
Release files for sdbm-pure 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| sdbm_pure-0.1.0.tar.gz | 8.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| sdbm_pure-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 15.7 kB
Release files / sdbm_pure-0.1.0.tar.gz
| Download URL | sdbm_pure-0.1.0.tar.gz |
|---|---|
| Size | 8.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
c31ffecb91204694cfd3b8fd242867c71af3b904945309b24772f1dd58e2150c
|
|
BLAKE2b-256 checksum How to use checksums |
2a96efd4d3553dec187b137e477d0500a4ad258b1bae5400b78dbfca1e7b809b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|
Release files / sdbm_pure-0.1.0-py3-none-any.whl
| Download URL | sdbm_pure-0.1.0-py3-none-any.whl |
|---|---|
| Size | 7.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
daba303b89fe4c6a54f1103f36ce750c17cde56c87edafac37dc26b9ffdd1e41
|
|
BLAKE2b-256 checksum How to use checksums |
655df0ab8674a35d66aae34802b616310a2a73274fb4cad211090c92f9c5f949
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.11.15
|