QuipNetwork/hashsigs-pyPublic

AI summary: Python implementation of the WOTS+ post-quantum signature scheme with optional Rust acceleration.

Stars
11.2K
+-2 today
Forks
28
Watchers
7
Open issues
0
Open PRs
0
Contributors
~1
Commits
21
Branches
1

PythonAGPL-3.0Created Aug 27, 2025Last push 1y ago+-2 stars this week+-8 this month

Quick answers

What is hashsigs-py?
Python implementation of the WOTS+ post-quantum signature scheme with optional Rust acceleration.
What does hashsigs-py do?
This project provides a Python implementation of the WOTS+ (Winternitz One-Time Signature Plus) post-quantum signature scheme. It serves as a complement to the Quip Network's Rust implementation, offering critical cryptographic primitives for key generation, signing, and signature verification. The system is designed to use pure Python natively, but it includes an optional, high-performance Rust extension backend to significantly boost execution speed. If the compiled Rust binaries cannot be built or are unavailable on the host system, the package gracefully falls back to Python's built-in keccak provider, guaranteeing broad compatibility across diverse deployment environments.
Who is hashsigs-py for?
Cryptographers, security engineers, and backend developers building quantum-resistant systems. It is particularly useful for teams needing to deploy post-quantum cryptography in Python environments with optional high-performance requirements.
How do I get started with hashsigs-py?
pip install hashsigs
How popular is hashsigs-py on GitHub?
QuipNetwork/hashsigs-py has 11,182 stars and 28 forks on GitHub, and gained -2 stars in the last 7 days.
What license does hashsigs-py use?
QuipNetwork/hashsigs-py is released under the AGPL-3.0 license.

Star history

since Jul 28, 2026
05K10KJul 2026Aug 2026Sep 2026Oct 2026
11.2K stars as of Oct 4, 2026. Measured daily since Jul 28, 2026; GitHub no longer exposes earlier star timestamps.

Contribution activity

commits per day, last 52 weeks

Signals and awards

derived from tracked data
  • Widely adopted

    11,182 stars

  • Continuous integration

    Automated checks passing

What hashsigs-py does

This project provides a Python implementation of the WOTS+ (Winternitz One-Time Signature Plus) post-quantum signature scheme. It serves as a complement to the Quip Network's Rust implementation, offering critical cryptographic primitives for key generation, signing, and signature verification. The system is designed to use pure Python natively, but it includes an optional, high-performance Rust extension backend to significantly boost execution speed. If the compiled Rust binaries cannot be built or are unavailable on the host system, the package gracefully falls back to Python's built-in keccak provider, guaranteeing broad compatibility across diverse deployment environments.

Cryptographers, security engineers, and backend developers building quantum-resistant systems. It is particularly useful for teams needing to deploy post-quantum cryptography in Python environments with optional high-performance requirements.

  • WOTS+ Implementation: Provides a complete toolkit for generating post-quantum key pairs, signing messages, and verifying signatures.
  • Optional Rust Acceleration: Automatically attempts to build and utilize a Rust backend during installation to drastically improve cryptographic performance.
  • Pure Python Fallback: Seamlessly defaults to using the pure Python keccak provider via pycryptodome or pysha3 if the Rust toolchain is missing.
  • Comprehensive Test Suite: Includes detailed test vectors, internal consistency checks, and rust-backed testing environments to ensure cryptographic reliability.
  • Flexible Backend Configuration: Allows developers to explicitly prefer the Rust backend or force the pure Python implementation depending on runtime constraints.

Where teams use it

Post-quantum Security Integration

Embed quantum-resistant WOTS+ signatures directly into Python-based backend architectures or secure data pipelines.

Cryptographic Prototyping

Test and analyze hash-based signature algorithms natively within Python Jupyter notebooks or dedicated research scripts.

Cross-platform Verification

Validate signatures on a Python server that were originally generated by Rust or WebAssembly client applications.

Graceful Deployment

Deploy secure cryptography across diverse environments, relying on Rust for speed where available and Python for ultimate portability.

Getting started: pip install hashsigs

README

main branch

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:

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

View on GitHub

Recent activity

commits and pull requests

Code frequency

additions and deletions

Commits per week

last 52 weeks

When work happens

weekday and hour
SunMonTueWedThuFriSat036912151821Sun 0:00 — 0 commitsSun 1:00 — 0 commitsSun 2:00 — 0 commitsSun 3:00 — 0 commitsSun 4:00 — 0 commitsSun 5:00 — 0 commitsSun 6:00 — 0 commitsSun 7:00 — 0 commitsSun 8:00 — 0 commitsSun 9:00 — 0 commitsSun 10:00 — 0 commitsSun 11:00 — 0 commitsSun 12:00 — 0 commitsSun 13:00 — 0 commitsSun 14:00 — 0 commitsSun 15:00 — 0 commitsSun 16:00 — 0 commitsSun 17:00 — 0 commitsSun 18:00 — 0 commitsSun 19:00 — 0 commitsSun 20:00 — 0 commitsSun 21:00 — 0 commitsSun 22:00 — 0 commitsSun 23:00 — 0 commitsMon 0:00 — 0 commitsMon 1:00 — 0 commitsMon 2:00 — 0 commitsMon 3:00 — 0 commitsMon 4:00 — 0 commitsMon 5:00 — 0 commitsMon 6:00 — 0 commitsMon 7:00 — 0 commitsMon 8:00 — 0 commitsMon 9:00 — 0 commitsMon 10:00 — 0 commitsMon 11:00 — 0 commitsMon 12:00 — 0 commitsMon 13:00 — 0 commitsMon 14:00 — 0 commitsMon 15:00 — 0 commitsMon 16:00 — 0 commitsMon 17:00 — 0 commitsMon 18:00 — 0 commitsMon 19:00 — 0 commitsMon 20:00 — 0 commitsMon 21:00 — 0 commitsMon 22:00 — 0 commitsMon 23:00 — 0 commitsTue 0:00 — 0 commitsTue 1:00 — 0 commitsTue 2:00 — 0 commitsTue 3:00 — 0 commitsTue 4:00 — 0 commitsTue 5:00 — 0 commitsTue 6:00 — 0 commitsTue 7:00 — 0 commitsTue 8:00 — 0 commitsTue 9:00 — 0 commitsTue 10:00 — 0 commitsTue 11:00 — 0 commitsTue 12:00 — 0 commitsTue 13:00 — 0 commitsTue 14:00 — 0 commitsTue 15:00 — 0 commitsTue 16:00 — 0 commitsTue 17:00 — 0 commitsTue 18:00 — 0 commitsTue 19:00 — 0 commitsTue 20:00 — 0 commitsTue 21:00 — 0 commitsTue 22:00 — 0 commitsTue 23:00 — 0 commitsWed 0:00 — 0 commitsWed 1:00 — 0 commitsWed 2:00 — 0 commitsWed 3:00 — 0 commitsWed 4:00 — 0 commitsWed 5:00 — 0 commitsWed 6:00 — 0 commitsWed 7:00 — 0 commitsWed 8:00 — 0 commitsWed 9:00 — 0 commitsWed 10:00 — 0 commitsWed 11:00 — 0 commitsWed 12:00 — 2 commitsWed 13:00 — 5 commitsWed 14:00 — 7 commitsWed 15:00 — 7 commitsWed 16:00 — 0 commitsWed 17:00 — 0 commitsWed 18:00 — 0 commitsWed 19:00 — 0 commitsWed 20:00 — 0 commitsWed 21:00 — 0 commitsWed 22:00 — 0 commitsWed 23:00 — 0 commitsThu 0:00 — 0 commitsThu 1:00 — 0 commitsThu 2:00 — 0 commitsThu 3:00 — 0 commitsThu 4:00 — 0 commitsThu 5:00 — 0 commitsThu 6:00 — 0 commitsThu 7:00 — 0 commitsThu 8:00 — 0 commitsThu 9:00 — 0 commitsThu 10:00 — 0 commitsThu 11:00 — 0 commitsThu 12:00 — 0 commitsThu 13:00 — 0 commitsThu 14:00 — 0 commitsThu 15:00 — 0 commitsThu 16:00 — 0 commitsThu 17:00 — 0 commitsThu 18:00 — 0 commitsThu 19:00 — 0 commitsThu 20:00 — 0 commitsThu 21:00 — 0 commitsThu 22:00 — 0 commitsThu 23:00 — 0 commitsFri 0:00 — 0 commitsFri 1:00 — 0 commitsFri 2:00 — 0 commitsFri 3:00 — 0 commitsFri 4:00 — 0 commitsFri 5:00 — 0 commitsFri 6:00 — 0 commitsFri 7:00 — 0 commitsFri 8:00 — 0 commitsFri 9:00 — 0 commitsFri 10:00 — 0 commitsFri 11:00 — 0 commitsFri 12:00 — 0 commitsFri 13:00 — 0 commitsFri 14:00 — 0 commitsFri 15:00 — 0 commitsFri 16:00 — 0 commitsFri 17:00 — 0 commitsFri 18:00 — 0 commitsFri 19:00 — 0 commitsFri 20:00 — 0 commitsFri 21:00 — 0 commitsFri 22:00 — 0 commitsFri 23:00 — 0 commitsSat 0:00 — 0 commitsSat 1:00 — 0 commitsSat 2:00 — 0 commitsSat 3:00 — 0 commitsSat 4:00 — 0 commitsSat 5:00 — 0 commitsSat 6:00 — 0 commitsSat 7:00 — 0 commitsSat 8:00 — 0 commitsSat 9:00 — 0 commitsSat 10:00 — 0 commitsSat 11:00 — 0 commitsSat 12:00 — 0 commitsSat 13:00 — 0 commitsSat 14:00 — 0 commitsSat 15:00 — 0 commitsSat 16:00 — 0 commitsSat 17:00 — 0 commitsSat 18:00 — 0 commitsSat 19:00 — 0 commitsSat 20:00 — 0 commitsSat 21:00 — 0 commitsSat 22:00 — 0 commitsSat 23:00 — 0 commits
Commit volume by weekday and hour (UTC). Larger dots mean more commits.
DateListRankStars gained
Feb 12, 2026daily#24+146
Feb 11, 2026daily#11+267