Fast, functional IP / CIDR toolkit backed by a native Zig core
Project description
zcidr
Parse millions of IP addresses per second and match them against huge CIDR rule sets — from Python.
zcidr is a fast, functional IP / CIDR toolkit backed by a native
Zig core. On an ordinary laptop it parses 44M IPv4
addresses/s (~43× the stdlib) and answers "is this IP in any of these 2,000
networks?" at 19M queries/s — about 2,900× a stdlib scan and 170×
netaddr (benchmarks).
If you filter request logs against blocklists, geo-map flows, enrich telemetry with network tags, or score millions of addresses against threat feeds, the address handling itself stops being your bottleneck.
Why it's fast
Pure-Python IP libraries pay twice: interpreted parsing, and one boxed address
object per element. zcidr removes both costs:
- A native core. Parsing, formatting, and longest-prefix-match run in optimized Zig behind a narrow C ABI.
- Batch by design. The
*_lines/*_manyfunctions cross the Python↔native boundary once per workload, not once per address — buffers in, arrays out, no per-element objects. Errors don't interrupt a batch either: results carry a 1/0 validity mask instead of raising halfway. - Functional API. Simple values in, simple values out — ints,
bytes,array— which is exactly what you can hand to NumPy, pandas, or a file without conversion. - True parallelism. Every native call releases the GIL, so batch calls scale across threads.
Install
pip install zcidr
Wheels bundle the prebuilt native library (loaded with cffi in ABI mode); no
compiler is needed at install time. One wheel per platform serves every
supported Python version (3.10+).
Sixty seconds of zcidr
import zcidr
# --- one-offs -------------------------------------------------------------
zcidr.parse_ipv4("192.168.0.1") # -> 3232235521
zcidr.format_ipv4(3232235521) # -> "192.168.0.1"
zcidr.parse_ipv6("::1") # -> b'\x00...\x01' (16 bytes)
zcidr.normalize("2001:0db8:0000::1") # -> "2001:db8::1"
zcidr.is_valid("::gg") # -> False
# --- the batch path (where the speed lives) --------------------------------
# One native call for a whole file: values + validity mask, no objects.
data = open("ips.txt", "rb").read()
values, valid = zcidr.parse_ipv4_lines(data) # array('I'), bytes of 1/0
# The same function takes str blobs, open files, generators, lists:
values, valid = zcidr.parse_ipv4_lines(["1.2.3.4", "8.8.8.8"])
zcidr.format_ipv4_lines(values) # -> b"1.2.3.4\n8.8.8.8"
# --- CIDR matching ----------------------------------------------------------
# Build a longest-prefix matcher from any mix of IPv4/IPv6 networks.
m = zcidr.build(["10.0.0.0/8", "10.1.2.0/24", "2001:db8::/32"])
zcidr.match(m, "10.1.2.9") # -> 1 (index of the longest match)
zcidr.match(m, "8.8.8.8") # -> None
zcidr.contains(m, "2001:db8::5") # -> True
# The fused fast path: parse + match a whole workload in ONE native pass.
verdicts, found = zcidr.match_lines(m, data) # array('Q'), bytes of 1/0
Values, not just membership
Each network can carry a uint64 payload — a rule ID, an ASN, a country
code — returned on match. By default it's the network's index.
m = zcidr.build(["10.0.0.0/8", "172.16.0.0/12"], values=[3356, 64512])
zcidr.match(m, "172.20.1.1") # -> 64512
build() takes rule sets the same way the parsers take addresses: a list, a
generator, an open file, or a newline-delimited blob — inserted with one
native batch call into an arena-allocated trie (~7M rules/s). Matchers free
their native memory on garbage collection, eagerly via zcidr.free(m), or
scoped:
with zcidr.build(open("blocklist.txt")) as m:
_, found = zcidr.match_lines(m, open("access.log.ips"))
Big files, zero copies
Anything with the buffer protocol is read in place — bytes, bytearray,
memoryview, NumPy arrays, mmap. A multi-gigabyte address file never gets
copied into Python:
import mmap, zcidr
with open("addresses.txt", "rb") as f:
with mmap.mmap(f.fileno(), 0, access=mmap.ACCESS_READ) as mm:
values, valid = zcidr.parse_ipv4_lines(mm) # native reads the mmap directly
Iterables of strings are consumed in bounded chunks, so streaming an unbounded generator works too — but when your data can be bytes, feed bytes: skipping per-line Python strings is itself a ~2× win.
Input conventions at a glance
| Suffix | Direction | Input |
|---|---|---|
*_lines |
text side | newline-delimited str / bytes-like buffer, or any iterable of strings |
*_many |
binary side | fixed-width record buffer (uint32 for IPv4, 16-byte packed for IPv6) |
Batch parses return (values, valid_mask); batch matches return
(values, found_mask). Masks are bytes of 1/0 per record — invalid records
never shift positions, and a string containing a stray newline raises instead
of silently desyncing.
Performance
See benchmarks/ for the harness and full tables.
Representative (Apple Silicon, ReleaseFast):
| Workload | zcidr | vs stdlib ipaddress |
|---|---|---|
| IPv4 parse (batch) | 44 M ops/s | ~43× |
| IPv6 parse (batch) | 7.2 M ops/s | ~15× |
| Membership, 2k rules (fused) | 19 M queries/s | ~2,900× (170× netaddr) |
| Matcher build, 200k rules | 3.7–7 M rules/s | 7.5×¹ |
¹ vs merely parsing the rules with ip_network() — which builds no index.
Building from source
Requires Zig 0.16 (or pip install ziglang).
zig build -Doptimize=ReleaseFast # native library -> zig-out/lib/
zig build test # Zig unit tests
pip install -e . && pytest # Python wrapper + test suite
Architecture
- Core (
src/): Zig, exposed over a C ABI (include/zcidr.h). Bytes / ints / bools across the FFI line; an arena-backed longest-prefix-match trie for CIDR containment; batch parse/format/insert/match primitives that loop natively — including a fused parse+match kernel (zcidr_trie_match_lines). - Wrapper (
zcidr/): purely functionalcffiABI/dlopen binding — no build step at install, one wheel per platform for all Python versions. - Packaging:
cibuildwheel(manylinux / macOS / Windows) with the native toolchain supplied by theziglangwheel.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zcidr-0.0.2.tar.gz.
File metadata
- Download URL: zcidr-0.0.2.tar.gz
- Upload date:
- Size: 38.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6f6d1f547188f072183c325300439761cc246d00f4a3b44e4f7ed32c89cbeb59
|
|
| MD5 |
a724d6db23f19db63b720eeecf5b8035
|
|
| BLAKE2b-256 |
4898973b1bc3ad8ad29f7a5f36219a8fce5fbb36bd9c59fd69d1ca21d7e93741
|
Provenance
The following attestation bundles were made for zcidr-0.0.2.tar.gz:
Publisher:
wheels.yml on gustavoschmidt/zcidr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zcidr-0.0.2.tar.gz -
Subject digest:
6f6d1f547188f072183c325300439761cc246d00f4a3b44e4f7ed32c89cbeb59 - Sigstore transparency entry: 2082110208
- Sigstore integration time:
-
Permalink:
gustavoschmidt/zcidr@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/gustavoschmidt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file zcidr-0.0.2-py3-none-win_amd64.whl.
File metadata
- Download URL: zcidr-0.0.2-py3-none-win_amd64.whl
- Upload date:
- Size: 118.1 kB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
693dffb000b2426434ce0365dfdbd94df556d1c44308d15b4ff1b3906f9c9d7d
|
|
| MD5 |
079dbf43fd9e57c97a0f3e15c9521ce6
|
|
| BLAKE2b-256 |
a9426a6fb3807d9096e411d937498a503053be97a450aa129ee01e3890fbff60
|
Provenance
The following attestation bundles were made for zcidr-0.0.2-py3-none-win_amd64.whl:
Publisher:
wheels.yml on gustavoschmidt/zcidr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zcidr-0.0.2-py3-none-win_amd64.whl -
Subject digest:
693dffb000b2426434ce0365dfdbd94df556d1c44308d15b4ff1b3906f9c9d7d - Sigstore transparency entry: 2082110244
- Sigstore integration time:
-
Permalink:
gustavoschmidt/zcidr@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/gustavoschmidt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file zcidr-0.0.2-py3-none-musllinux_1_2_x86_64.whl.
File metadata
- Download URL: zcidr-0.0.2-py3-none-musllinux_1_2_x86_64.whl
- Upload date:
- Size: 52.0 kB
- Tags: Python 3, musllinux: musl 1.2+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
41e62ece392b27f885e9b1f428450d6b5751aa1c0f23875bde8af93d657ffd2c
|
|
| MD5 |
7c21e95d5231277cd799b4226e74c753
|
|
| BLAKE2b-256 |
3308cfcbc78c96a19db74599eb08694dc456254eafbb1077972009feff63d230
|
Provenance
The following attestation bundles were made for zcidr-0.0.2-py3-none-musllinux_1_2_x86_64.whl:
Publisher:
wheels.yml on gustavoschmidt/zcidr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zcidr-0.0.2-py3-none-musllinux_1_2_x86_64.whl -
Subject digest:
41e62ece392b27f885e9b1f428450d6b5751aa1c0f23875bde8af93d657ffd2c - Sigstore transparency entry: 2082110230
- Sigstore integration time:
-
Permalink:
gustavoschmidt/zcidr@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/gustavoschmidt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file zcidr-0.0.2-py3-none-musllinux_1_2_aarch64.whl.
File metadata
- Download URL: zcidr-0.0.2-py3-none-musllinux_1_2_aarch64.whl
- Upload date:
- Size: 48.7 kB
- Tags: Python 3, musllinux: musl 1.2+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
453dd57077c3e3d5ccd8dafc70d43e2f5fd34cca1dc08749b30d384fbee38c64
|
|
| MD5 |
1d9db67486bc14cca350fb3ed551173d
|
|
| BLAKE2b-256 |
684b890a9c9c8f0cb1edb85adf1c6258cbc36210e5de39d8c7177ace5f69182e
|
Provenance
The following attestation bundles were made for zcidr-0.0.2-py3-none-musllinux_1_2_aarch64.whl:
Publisher:
wheels.yml on gustavoschmidt/zcidr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zcidr-0.0.2-py3-none-musllinux_1_2_aarch64.whl -
Subject digest:
453dd57077c3e3d5ccd8dafc70d43e2f5fd34cca1dc08749b30d384fbee38c64 - Sigstore transparency entry: 2082110222
- Sigstore integration time:
-
Permalink:
gustavoschmidt/zcidr@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/gustavoschmidt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file zcidr-0.0.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl.
File metadata
- Download URL: zcidr-0.0.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl
- Upload date:
- Size: 51.4 kB
- Tags: Python 3, manylinux: glibc 2.17+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
46931f0af61344626a24a097fe15488e2e6a8cf397524b1f7144de8a864d0d39
|
|
| MD5 |
4c09cd270f846b6a1c393cb7378e75b6
|
|
| BLAKE2b-256 |
6028b2642cd2382f5f22e53cc5d61c47c2a582b3fa7b48f3155cc813f1e3d4ab
|
Provenance
The following attestation bundles were made for zcidr-0.0.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl:
Publisher:
wheels.yml on gustavoschmidt/zcidr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zcidr-0.0.2-py3-none-manylinux_2_17_x86_64.manylinux2014_x86_64.whl -
Subject digest:
46931f0af61344626a24a097fe15488e2e6a8cf397524b1f7144de8a864d0d39 - Sigstore transparency entry: 2082110236
- Sigstore integration time:
-
Permalink:
gustavoschmidt/zcidr@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/gustavoschmidt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file zcidr-0.0.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl.
File metadata
- Download URL: zcidr-0.0.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl
- Upload date:
- Size: 48.6 kB
- Tags: Python 3, manylinux: glibc 2.17+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b69e236822498ed2d3c9916e2804e498c599b49a664145fae24093ef6c892ab0
|
|
| MD5 |
26fba7fb7b6c1afd262be62e5243ba28
|
|
| BLAKE2b-256 |
4c3e2a6b55a02a4c3e2177300b4db6d6e703e431e7fc76c011c266c272915115
|
Provenance
The following attestation bundles were made for zcidr-0.0.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl:
Publisher:
wheels.yml on gustavoschmidt/zcidr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zcidr-0.0.2-py3-none-manylinux_2_17_aarch64.manylinux2014_aarch64.whl -
Subject digest:
b69e236822498ed2d3c9916e2804e498c599b49a664145fae24093ef6c892ab0 - Sigstore transparency entry: 2082110213
- Sigstore integration time:
-
Permalink:
gustavoschmidt/zcidr@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/gustavoschmidt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file zcidr-0.0.2-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: zcidr-0.0.2-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 23.7 kB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
3d4676cb10c0925c889d136bbda249897bfce5e0df5d52e5e3ae8dcf3a755435
|
|
| MD5 |
6b45b468e655d02b350d0043337d04fb
|
|
| BLAKE2b-256 |
3b1bcf7c891e0464ed0fe14f8beabca3fa2f7d6dabda6733a5ef0ebb8eb5161b
|
Provenance
The following attestation bundles were made for zcidr-0.0.2-py3-none-macosx_11_0_arm64.whl:
Publisher:
wheels.yml on gustavoschmidt/zcidr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zcidr-0.0.2-py3-none-macosx_11_0_arm64.whl -
Subject digest:
3d4676cb10c0925c889d136bbda249897bfce5e0df5d52e5e3ae8dcf3a755435 - Sigstore transparency entry: 2082110259
- Sigstore integration time:
-
Permalink:
gustavoschmidt/zcidr@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/gustavoschmidt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Trigger Event:
push
-
Statement type:
File details
Details for the file zcidr-0.0.2-py3-none-macosx_10_13_x86_64.whl.
File metadata
- Download URL: zcidr-0.0.2-py3-none-macosx_10_13_x86_64.whl
- Upload date:
- Size: 23.6 kB
- Tags: Python 3, macOS 10.13+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5a431a03438c4207c151ac08c9cb7c33ffaf1fe8bae1de4388f8a11a0c89e9c6
|
|
| MD5 |
570a89b3911bcfa14ce7a39b94b31b13
|
|
| BLAKE2b-256 |
b42baab74fe076570399c334d77f30042e6b0a41f94b6ebec5dbe7372408fa95
|
Provenance
The following attestation bundles were made for zcidr-0.0.2-py3-none-macosx_10_13_x86_64.whl:
Publisher:
wheels.yml on gustavoschmidt/zcidr
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
zcidr-0.0.2-py3-none-macosx_10_13_x86_64.whl -
Subject digest:
5a431a03438c4207c151ac08c9cb7c33ffaf1fe8bae1de4388f8a11a0c89e9c6 - Sigstore transparency entry: 2082110255
- Sigstore integration time:
-
Permalink:
gustavoschmidt/zcidr@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Branch / Tag:
refs/tags/v0.0.2 - Owner: https://github.com/gustavoschmidt
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
wheels.yml@ffd1b38b290d637f5ceef3f6ac3087917c9bf3b4 -
Trigger Event:
push
-
Statement type: