A low-level TLS 1.3 client toolkit for Python, built on Facebook's Fizz
Project description
fizzpy
A small TLS 1.3 HTTP client for Python, built on Facebook's Fizz (C++) via pybind11.
By default it offers a post-quantum key exchange — the standardized hybrid
X25519MLKEM768 group (codepoint 4588). An ordinary GET negotiates a hybrid
ML-KEM handshake against servers that support it (Cloudflare, Google) and falls
back to classical X25519 against those that don't.
TLS 1.3 only, HTTP/1.1 only. This is a focused toolkit / learning project, not a drop-in
requestsreplacement. See Status.
A fizzpy request captured in Wireshark: the TLS 1.3 ClientHello offers the
post-quantum X25519MLKEM768 group (0x11ec), and a custom marker extension
(0xFE5A, see below) makes it unmistakably
ours — generated by examples/pq_marker.py.
Install
pip install fizzpy
The Linux wheels are self-contained: folly, Fizz, and liboqs are statically
linked into the extension, so a fresh pip install has working post-quantum
TLS with no system packages to add. certifi (pulled in automatically) supplies
the default trust store.
Wheels are produced by CI (manylinux_2_28, x86_64, CPython 3.10–3.14); if one
isn't available for your platform yet, build from source — see
BUILDING.md.
Usage
Synchronous:
import fizzpy
r = fizzpy.get("https://www.cloudflare.com")
print(r.status_code) # 200
print(r.headers["content-type"]) # text/html; charset=UTF-8
print(r.text[:64])
# The negotiated TLS 1.3 parameters are attached to every response:
print(r.tls)
# {'version': 'TLSv1.3', 'cipher': 'TLS_AES_128_GCM_SHA256',
# 'group': 'X25519MLKEM768', 'group_code': 4588,
# 'alpn': 'http/1.1', 'sni': 'www.cloudflare.com', 'peer_cert': '...'}
Asynchronous (the same C++ core, resolved on the running event loop):
import asyncio
from fizzpy.aio import AsyncClient
async def main():
async with AsyncClient() as client:
r = await client.get("https://www.google.com")
print(r.status_code, r.tls["group"], r.tls["group_code"])
asyncio.run(main())
Choosing the key exchange
The default offers [x25519_mlkem768, x25519], mirroring how Chrome and Firefox
send both key shares. Override it per client:
import fizzpy
from fizzpy import NamedGroup
# Force post-quantum only (handshake fails if the server lacks ML-KEM):
pq = fizzpy.Client(groups=[NamedGroup.x25519_mlkem768])
# Classical only:
classical = fizzpy.Client(groups=[NamedGroup.x25519])
Custom ClientHello extensions
fizzpy surfaces Fizz's low-level extension hook, so you can append arbitrary
extensions to the TLS 1.3 ClientHello. Each is an opaque (type, data) pair;
fizzpy rejects types it manages itself (key_share, supported_versions, …) and
out-of-range or duplicate types.
import fizzpy
client = fizzpy.Client(
extensions=[fizzpy.Extension(0xFE5A, b"hello from fizzpy")],
)
r = client.get("https://blog.cloudflare.com")
print(r.tls["group"]) # still negotiates X25519MLKEM768
The extension is sent verbatim in the ClientHello — see it on the wire with
examples/pq_marker.py and the screenshot above.
Certificate verification
Certificate chains are verified against the certifi CA bundle and the hostname is checked against the certificate's SAN by default. Point at a custom CA, or disable verification entirely:
fizzpy.Client(cafile="/path/to/ca.pem") # trust a specific CA
fizzpy.Client(verify=False) # accept any certificate (insecure)
Status
What works today:
- TLS 1.3 handshake with classical or post-quantum (ML-KEM) key exchange
GET/POST/HEAD/PUT/DELETE, sync and async- HTTP/1.1 response framing (content-length, chunked, gzip/deflate)
- Connection keep-alive with a per-host pool; automatic redirect following
- Chain + hostname certificate verification, certifi default + custom CA trust
Current limitations:
- TLS 1.3 only (a Fizz constraint) — it cannot talk to TLS 1.2-only servers
- HTTP/1.1 only (no HTTP/2)
Building
The post-quantum handshake requires a Fizz built against
liboqs. The CI wheels build the
whole folly + Fizz + liboqs tree from source inside manylinux_2_28; see
BUILDING.md for that recipe and for local development builds.
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 fizzpy-0.3.0.tar.gz.
File metadata
- Download URL: fizzpy-0.3.0.tar.gz
- Upload date:
- Size: 431.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
92073ed3af79bac3a220f5c70c7bac7168e45b339de09df297cd4d0d030fef04
|
|
| MD5 |
ff039e9e332c08a881bbe114338c1280
|
|
| BLAKE2b-256 |
d94f1378168b55dcf961c5a4df51e3ddbc397bd22a61a5d3ceb3af61cda2ea36
|
Provenance
The following attestation bundles were made for fizzpy-0.3.0.tar.gz:
Publisher:
publish.yml on Xevion/fizz-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fizzpy-0.3.0.tar.gz -
Subject digest:
92073ed3af79bac3a220f5c70c7bac7168e45b339de09df297cd4d0d030fef04 - Sigstore transparency entry: 1809914171
- Sigstore integration time:
-
Permalink:
Xevion/fizz-py@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Xevion
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fizzpy-0.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: fizzpy-0.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 5.5 MB
- Tags: CPython 3.14, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
29ee199f0cb7314e82b01b73f502b686b12f0ce4367789c8db9a96ab5e47b878
|
|
| MD5 |
ea6afaa69b8a9b6ca8b59339022573b6
|
|
| BLAKE2b-256 |
46abc498315c4bdb3d2357bc809714bbd2fd90f7a2431b1306d831d6f2852b12
|
Provenance
The following attestation bundles were made for fizzpy-0.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:
Publisher:
publish.yml on Xevion/fizz-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fizzpy-0.3.0-cp314-cp314-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl -
Subject digest:
29ee199f0cb7314e82b01b73f502b686b12f0ce4367789c8db9a96ab5e47b878 - Sigstore transparency entry: 1809914208
- Sigstore integration time:
-
Permalink:
Xevion/fizz-py@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Xevion
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fizzpy-0.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: fizzpy-0.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 5.5 MB
- Tags: CPython 3.13, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
842b7e1c39c6b27957ee658c7767d0c99e503497d2e52769be18c44d6d6ff022
|
|
| MD5 |
b529e282cf80faff9446d58abd45a15f
|
|
| BLAKE2b-256 |
472dd9aac3a55e48264425cda6dd1088a3dc1c853d363f6a1a51e38831d13be0
|
Provenance
The following attestation bundles were made for fizzpy-0.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:
Publisher:
publish.yml on Xevion/fizz-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fizzpy-0.3.0-cp313-cp313-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl -
Subject digest:
842b7e1c39c6b27957ee658c7767d0c99e503497d2e52769be18c44d6d6ff022 - Sigstore transparency entry: 1809914214
- Sigstore integration time:
-
Permalink:
Xevion/fizz-py@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Xevion
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fizzpy-0.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: fizzpy-0.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 5.5 MB
- Tags: CPython 3.12, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
42b0ae9f9701c9d349e4f2d87a1a63efad6ff5040ef4bbda6c969a22f18e88f9
|
|
| MD5 |
3e8c6acbf399730439e7507af1833544
|
|
| BLAKE2b-256 |
99b2fda8ab877ae52987d7ef6c5700df7749c6f9b28923a47249406ce7c68116
|
Provenance
The following attestation bundles were made for fizzpy-0.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:
Publisher:
publish.yml on Xevion/fizz-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fizzpy-0.3.0-cp312-cp312-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl -
Subject digest:
42b0ae9f9701c9d349e4f2d87a1a63efad6ff5040ef4bbda6c969a22f18e88f9 - Sigstore transparency entry: 1809914188
- Sigstore integration time:
-
Permalink:
Xevion/fizz-py@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Xevion
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fizzpy-0.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: fizzpy-0.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 5.5 MB
- Tags: CPython 3.11, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
140608577df4b6b7de680597e8711e95cac3c5b3ac4cb5cad29974226e7e6741
|
|
| MD5 |
047cb09b270652c46a3462e7db5e31e1
|
|
| BLAKE2b-256 |
c1bb39068e97b8db459a4fdd9c5b4bfd25155f66e2c4970c7a8fbd4201053651
|
Provenance
The following attestation bundles were made for fizzpy-0.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:
Publisher:
publish.yml on Xevion/fizz-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fizzpy-0.3.0-cp311-cp311-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl -
Subject digest:
140608577df4b6b7de680597e8711e95cac3c5b3ac4cb5cad29974226e7e6741 - Sigstore transparency entry: 1809914198
- Sigstore integration time:
-
Permalink:
Xevion/fizz-py@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Xevion
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Trigger Event:
push
-
Statement type:
File details
Details for the file fizzpy-0.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl.
File metadata
- Download URL: fizzpy-0.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl
- Upload date:
- Size: 5.5 MB
- Tags: CPython 3.10, manylinux: glibc 2.27+ x86-64, manylinux: glibc 2.28+ x86-64
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d98dd8a33a4e10bc62ad2495a90030dfdbe7c3b9c3317630309362a79cc81b85
|
|
| MD5 |
f08a12624aa73815772c37821f31b311
|
|
| BLAKE2b-256 |
dec492b85a263c251373a1d566e8622d39b9f76252a43283ffed4bde6ae4293a
|
Provenance
The following attestation bundles were made for fizzpy-0.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl:
Publisher:
publish.yml on Xevion/fizz-py
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
fizzpy-0.3.0-cp310-cp310-manylinux_2_27_x86_64.manylinux_2_28_x86_64.whl -
Subject digest:
d98dd8a33a4e10bc62ad2495a90030dfdbe7c3b9c3317630309362a79cc81b85 - Sigstore transparency entry: 1809914179
- Sigstore integration time:
-
Permalink:
Xevion/fizz-py@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Branch / Tag:
refs/tags/v0.3.0 - Owner: https://github.com/Xevion
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@02e93d3d9525e516ce3fa0a66f355eda829e7159 -
Trigger Event:
push
-
Statement type: