Skip to main content

WOTS+ hash-based signatures in Python with optional Rust acceleration

Project description

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

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distributions

If you're not sure about the file name format, learn more about wheel file names.

hashsigs-0.0.2-py3-none-any.whl (31.9 kB view details)

Uploaded Python 3

hashsigs-0.0.2-cp311-cp311-win_amd64.whl (158.1 kB view details)

Uploaded CPython 3.11Windows x86-64

hashsigs-0.0.2-cp311-cp311-macosx_11_0_universal2.whl (261.8 kB view details)

Uploaded CPython 3.11macOS 11.0+ universal2 (ARM64, x86-64)

File details

Details for the file hashsigs-0.0.2-py3-none-any.whl.

File metadata

  • Download URL: hashsigs-0.0.2-py3-none-any.whl
  • Upload date:
  • Size: 31.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for hashsigs-0.0.2-py3-none-any.whl
Algorithm Hash digest
SHA256 a3f3373f79c2d49a7632461609ee9a49b3e3335eff89e99a4e6e53ae2383321d
MD5 ce4093ed13dce829ca70c462f93061e9
BLAKE2b-256 a61d20d8d41a5244d80fd30e6b2734a4e2ec5c2bbc66818b03e4b6802a689995

See more details on using hashes here.

Provenance

The following attestation bundles were made for hashsigs-0.0.2-py3-none-any.whl:

Publisher: publish.yml on QuipNetwork/hashsigs-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hashsigs-0.0.2-cp311-cp311-win_amd64.whl.

File metadata

  • Download URL: hashsigs-0.0.2-cp311-cp311-win_amd64.whl
  • Upload date:
  • Size: 158.1 kB
  • Tags: CPython 3.11, Windows x86-64
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.12.9

File hashes

Hashes for hashsigs-0.0.2-cp311-cp311-win_amd64.whl
Algorithm Hash digest
SHA256 2e6ee3bec429cac8bdbbe03692c71b0dc9a2908caed100ae6eff28395235914c
MD5 b19af35faa3cfa6a9b1f57da36fa2ed6
BLAKE2b-256 9d8ab538954e4b61734f43669ce8beb9b16db1686a78355c3e55a5eee08c8439

See more details on using hashes here.

Provenance

The following attestation bundles were made for hashsigs-0.0.2-cp311-cp311-win_amd64.whl:

Publisher: publish.yml on QuipNetwork/hashsigs-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file hashsigs-0.0.2-cp311-cp311-macosx_11_0_universal2.whl.

File metadata

File hashes

Hashes for hashsigs-0.0.2-cp311-cp311-macosx_11_0_universal2.whl
Algorithm Hash digest
SHA256 9ec2657feffbfe106e2aca8f819993a0738bd2ff82ca74a58cde50ef40c5e2e9
MD5 ee6cbe417b0c2b03b278a398e1c7d035
BLAKE2b-256 e7bc905918e8974573efb49ed0dcc7de9cbfcb228b51dce5657118856a0bc15f

See more details on using hashes here.

Provenance

The following attestation bundles were made for hashsigs-0.0.2-cp311-cp311-macosx_11_0_universal2.whl:

Publisher: publish.yml on QuipNetwork/hashsigs-py

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page