hashsigs (Python)
Python package for WOTS+ with optional Rust acceleration from hashsigs-rs.
Installation
pip install hashsigs
For best performance, ensure you have Rust installed (the package will automatically build the Rust extension if available):
# Install Rust toolchain (optional, for better performance)
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
# Then install hashsigs
pip install hashsigs
Quick Usage
import hashsigs
# Create a WOTS+ instance
wots = hashsigs.WOTSPlus()
# Generate a key pair
private_key, public_key = wots.generate_key_pair()
# Sign a message
message = b"Hello, world!"
signature = wots.sign(private_key, message)
# Verify the signature
is_valid = wots.verify(public_key, message, signature)
print(f"Signature valid: {is_valid}") # True
# Check if Rust acceleration is available
try:
import hashsigs._rust
print("Using Rust acceleration")
except ImportError:
print("Using pure Python implementation")
Development Setup
For contributors and advanced users who want to build from source:
# from the repo root
python3 -m venv .hashsigs
source .hashsigs/bin/activate
python -m pip install -U pip pytest pytest-cov
# Ensure Rust toolchain (required to build the optional extension)
# macOS: also ensure Xcode CLT: xcode-select --install
rustup --version || brew install rust
cargo --version
# Install dev deps and try to build rust extension (quote extras in zsh)
pip install -v -e '.[rust,dev]'
# Install keccak provider (required for vectors when falling back to Python)
pip install pycryptodome
# or: pip install pysha3
# Quick check the extension is present (optional)
python -c "import hashsigs._rust as m; print('rust ext ok:', m)"
# Lint + type + tests with coverage; this is the full suite
pytest -q --cov=hashsigs --cov-report=term-missing
If the Rust toolchain is not available, the above will fail on the rust-backed vector tests. See the “Test options” section for alternatives.
Test options
You can choose between three categories:
-
All Tests (vectors + rust-backed + lint + type + coverage) — fails if keccak or rust ext are missing
- pip install -e '.[rust,dev]' && pip install pycryptodome
- pytest -q
-
Basic (pure Python functionality only; requires keccak provider, but no Rust extension)
- pip install -e '.[dev]' pycryptodome
- HASHSIGS_BUILD_RUST=0 pytest -q -m "not requires_rust"
-
Basic (no keccak) — internal consistency tests only using hashlib.sha3_256; no vectors
- pip install -e '.[dev]'
- pytest -q -m "not vectors"
Troubleshooting
-
pysha3 build fails on Python 3.13 (macOS) with missing pystrhex.h
- Symptom: fatal error: 'pystrhex.h' file not found when building _pysha3
- Fix: install pycryptodome instead (preferred). Example: pip install pycryptodome
- Alternative: use Python 3.11/3.12 where pysha3 wheels may exist, or wait for pysha3 to add 3.13 support
-
Rust extension won’t build/import
- Ensure Rust toolchain is installed: curl https://sh.rustup.rs -sSf | sh (or brew install rust)
- On macOS, ensure Xcode Command Line Tools are installed: xcode-select --install
- Clean and rebuild in your venv:
- pip uninstall -y hashsigs; pip install -e .[rust,dev]
- python -c "import hashsigs._rust as m; print('rust ext ok', m)"
- If it still fails, you can run Basic tests while you investigate: HASHSIGS_BUILD_RUST=0 pytest -q -m "not requires_rust"
Usage example
from hashsigs import WOTSPlus
# Prefer the Rust backend if available; falls back to Python keccak provider if not
wots = WOTSPlus.keccak256(prefer_rust=True)
# Derive a keypair from a 32-byte seed
seed = bytes([1]) * 32
pk, sk = wots.generate_key_pair(seed)
# Sign and verify a 32-byte message
msg = bytes([2]) * 32
sig = wots.sign(sk, msg)
assert wots.verify(pk, msg, sig)
print("Signature verifies!")
Quick self-check (from shell)
Run a one-liner to confirm the package imports, the Rust extension is available (optional), and basic operations work:
python - <<'PY'
from hashsigs import WOTSPlus
try:
import hashsigs._rust as _
print('Rust extension: available')
except Exception:
print('Rust extension: not available (falling back to Python)')
wots = WOTSPlus.keccak256(prefer_rust=True)
seed = bytes([1]) * 32
pk, sk = wots.generate_key_pair(seed)
msg = bytes([2]) * 32
sig = wots.sign(sk, msg)
print('verify:', wots.verify(pk, msg, sig))
PY
Rust backend
We now depend on the public crate and repository:
- Crate: hashsigs-rs = "0.0.2"
- Repo: https://github.com/QuipNetwork/hashsigs-rs
The Python bindings (PyO3) will attempt to build against the published crate during installation. If the build fails, the package still installs and falls back to pure Python.
License
AGPL-3.0-or-later; see COPYING
Metadata
Release files for hashsigs 0.0.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Built distributions (wheels)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| hashsigs-0.0.2-py3-none-any.whl | Python 3 | none | any | Details |
| hashsigs-0.0.2-cp311-cp311-win_amd64.whl | CPython 3.11 | CPython 3.11 | Windows x86-64 | Details |
| hashsigs-0.0.2-cp311-cp311-macosx_11_0_universal2.whl | CPython 3.11 | CPython 3.11 | macOS 11.0+ universal2 (ARM64, x86-64) | Details |
Total release size: 451.8 kB
Release files / hashsigs-0.0.2-py3-none-any.whl
| Download URL | hashsigs-0.0.2-py3-none-any.whl |
|---|---|
| Size | 31.9 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a3f3373f79c2d49a7632461609ee9a49b3e3335eff89e99a4e6e53ae2383321d
|
|
BLAKE2b-256 checksum How to use checksums |
a61d20d8d41a5244d80fd30e6b2734a4e2ec5c2bbc66818b03e4b6802a689995
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2025.
Transparency logRelease files / hashsigs-0.0.2-cp311-cp311-win_amd64.whl
| Download URL | hashsigs-0.0.2-cp311-cp311-win_amd64.whl |
|---|---|
| Size | 158.1 kB |
| Tags | CPython 3.11 Windows x86-64 |
|
SHA-256 checksum How to use checksums |
2e6ee3bec429cac8bdbbe03692c71b0dc9a2908caed100ae6eff28395235914c
|
|
BLAKE2b-256 checksum How to use checksums |
9d8ab538954e4b61734f43669ce8beb9b16db1686a78355c3e55a5eee08c8439
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2025.
Transparency logRelease files / hashsigs-0.0.2-cp311-cp311-macosx_11_0_universal2.whl
| Download URL | hashsigs-0.0.2-cp311-cp311-macosx_11_0_universal2.whl |
|---|---|
| Size | 261.8 kB |
| Tags | CPython 3.11 macOS 11.0+ universal2 (ARM64, x86-64) |
|
SHA-256 checksum How to use checksums |
9ec2657feffbfe106e2aca8f819993a0738bd2ff82ca74a58cde50ef40c5e2e9
|
|
BLAKE2b-256 checksum How to use checksums |
e7bc905918e8974573efb49ed0dcc7de9cbfcb228b51dce5657118856a0bc15f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/6.1.0 CPython/3.12.9
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 27, 2025.
Transparency log