HypΓ v4 is a hybrid post-quantum signature scheme. Every signature requires independent verification from two cryptographically unrelated primitives. Breaking the scheme requires breaking both simultaneously.
Layer 1 — SL(3,p) Schnorr-Γ: Scalar Schnorr protocol over the special linear group of 3×3 matrices with determinant 1 over GF(p), where p = 2255−31. Classical security ~189 bits via the 379-bit probable-prime factor Q₃₇₉ in p²+p+1. Shor-vulnerable in its cyclic subgroup — covered by Layer 2.
Layer 2 — Falcon-512: NIST FIPS 206 standard. 128-bit post-quantum security from NTRU lattice hardness. Hash-then-sign over the same message hash, with the SL(3,p) commitment R bound into the Falcon message to prevent signature stripping attacks.
v3 used 2×2 matrices in SL(2,p) with ~70-bit classical security (139-bit largest prime factor in p+1). v4 upgrades to 3×3 matrices in SL(3,p) with ~189-bit classical security (379-bit Q₃₇₉ in p²+p+1) — a 2.7× improvement in security bits using the same prime. Walk format changed from GF1: (2-bit packed, 4 generators) to GF3: (nibble-packed, 6 generators). Public keys grew from 256 hex (128B) to 576 hex (288B). Both formats remain verifiable via hybrid_verify_any().
Scalar Schnorr protocol over SL(3, GF(p)) with prime p = 2^255 − 31. Three base generators + three inverses (6 total) derived deterministically from SHAKE-256. Walk length 768 steps (v3 was 512). Matrix exponentiation g^x via binary exponentiation modulo p — exact, O(log x) cost. Full 256-bit Fiat-Shamir challenge with pk-binding. Exponent blinding against timing/DPA. Constant-time challenge comparison via hmac.compare_digest.
Falcon-512 from the pqcrypto library (no mock, no fallback — ImportError at load time if missing). Provides 128-bit post-quantum security against Shor's algorithm and lattice sieving. Falcon signs message_hash ‖ R.serialize() where R is the SL(3,p) commitment, cross-binding the two layers. Signature ~655 bytes, public key ~897 bytes, secret key ~1281 bytes.
| Adversary | Layer 1: SL(3,p) | Layer 2: Falcon-512 | Hybrid |
|---|---|---|---|
| Classical | ~189 bits (Pollard rho on Q₃₇₉) | ~256 bits (NTRU lattice) | min(189, 256) = 189 bits |
| Quantum (Shor) | Vulnerable (cyclic subgroup) | 128 bits (lattice sieving bound) | 128 bits (Falcon covers PQ) |
| Quantum (Grover) | ~95 bits (√189) | ~128 bits | 128 bits |
A quantum adversary must solve the NTRU lattice (Falcon) AND the SL(3,p) DLP. A classical adversary must break DLP-189 AND NTRU-256. Neither alone suffices.
| Component | Size |
|---|---|
| Public key y (3×3) | 288 bytes (9 × 32B big-endian ints → 576 hex) |
| Commitment R (3×3) | 288 bytes (576 hex) |
| Response Z (3×3) | 288 bytes (576 hex) |
| Challenge c | 32 bytes (64 hex, 256 bits) |
| Scalar s | 256 bytes (512 hex — large due to |G| ≈ 2^2040) |
| SL(3,p) Signature total | ~900 bytes (JSON wire) |
| Falcon-512 Signature | ~655 bytes (base64 in wire) |
| Hybrid Signature total | ~1.5 KB (JSON wire) |
| Wire version (v4) | hybrid_sl3p_falcon_v2 |
| Wire version (v3 legacy) | hybrid_sl2p_falcon_v1 |
| SL(3,p) only version | schnorr_gamma_gf_v4 |
Sign: ~3ms · Verify: ~4ms · 100% round-trip reliability
Three generators g₁, g₂, g₃ ∈ SL(3,p) are derived from SHAKE-256: SHAKE-256("HYPGAMMA_GF_SL3_GENERATORS_V4" ‖ p_bytes). Each generator is a random 3×3 matrix with det ≡ 1 (mod p), guaranteed non-abelian (g₁g₂ ≠ g₂g₁). The walk alphabet has 6 elements: {g₁, g₁⁻¹, g₂, g₂⁻¹, g₃, g₃⁻¹}. Random walks use reduced form (no self-cancellation: step i+1 ≠ inverse of step i). The 768-step walk over 6 generators produces ~768·log₂(5) ≈ 1783 bits of effective entropy (reduced walk removes ~1 choice per step).
The scalar Schnorr protocol works in the cyclic subgroup generated by a single element g ∈ SL(3,p). The order of g divides |SL(3,p)| = p³(p²−1)(p³−1). The DLP security depends on the largest prime factor of the group order. For SL(3,p) with p = 2^255−31, the factor p²+p+1 contains a 379-bit probable-prime Q₃₇₉. Pollard rho on Q₃₇₉ requires ~√Q₃₇₉ ≈ 2^189 operations. Compare v3's SL(2,p) where the largest prime in p+1 was only 139 bits (DLP ~70 bits). The jump to 3×3 matrices exposes the richer factorization structure of p²+p+1.
Falcon-512 is one of three signature algorithms standardized by NIST in the post-quantum cryptography project (FIPS 206). It provides 128-bit security against quantum computers via the hardness of the NTRU lattice problem. QTCL uses Falcon-512 from the pqcrypto Python library — no mock implementations, no fallbacks. If pqcrypto is not installed, the entire cryptographic module refuses to load.
| Parameter | Value |
|---|---|
| Standard | NIST FIPS 206 (finalized 2024) |
| Security Level | 128-bit post-quantum |
| Hardness | Short integer solution (SIS) over NTRU lattice |
| Public Key | ~897 bytes |
| Secret Key | ~1281 bytes |
| Signature | ~655 bytes (variable) |
| Library | pqcrypto.sign.falcon_512 |
Falcon does not simply sign the message hash independently. To prevent signature stripping attacks (swapping the Falcon component from a different message), the Falcon message is:
falcon_message = message_hash ‖ R.serialize() # Where R is the SL(3,p) commitment matrix. # An attacker cannot re-use a Falcon signature # from msg_A on msg_B because R differs. # Both layers are cryptographically bound.
Verification reconstructs the same binding: falcon_verify(msg_hash ‖ R.serialize(), sig, pk)
GeodesicLWE is an encryption scheme operating over the {8,3} hyperbolic tessellation in the Poincaré disk. Hardness rests on the Hyperbolic Closest Vector Problem (HCVP) — recovering a secret point from noisy geodesic distance samples. The exponential volume growth of hyperbolic space (vol ∝ e^2r vs r^n in flat space) makes enumeration attacks exponentially harder than Euclidean CVP. BKZ reduction is inapplicable because the parallelogram law fails in H².
This layer is optional — it requires hyp_group.py (mpmath), hyp_tessellation.py (Supabase/Neon DB), and is separate from the signature subsystem. QTCL uses it for quantum-bound encryption via IBM QLDPC hardware (ibm_marrakesh/ibm_kingston).
Wallet private keys at rest are protected by a password-based encryption layer that does not require the tessellation database. Implemented in hyp_lwe.py using pure Python stdlib:
_fullWalletPurge() / _vaultSecurityPurge() triggered on visibility/tab events — RAM-only key state# Finite-field group p = 2^255 − 31 # 255-bit prime, ≡ 1 mod 24 G = SL(3,p) # 3×3 matrices, det ≡ 1 |G| = p³(p²−1)(p³−1) # ≈ 2^2040 # DLP security Q₃₇₉ # 379-bit prob-prime factor in p²+p+1 DLP = ~189 bits # Pollard rho on Q₃₇₉ # Generators (deterministic) g1,g2,g3 = SHAKE-256("HYPGAMMA_GF_SL3_GENERATORS_V4") alphabet = [g1, g1⁻¹, g2, g2⁻¹, g3, g3⁻¹] # 6 gens # Key generation WALK_LENGTH = 768 # v4 (v3 was 512) N_GENERATORS = 6 # v4 (v3 was 4) WALK_PREFIX = "GF3:" # v4 (v3 was "GF1:") PUB_HEX_LEN = 576 # v4 (v3 was 256) # Schnorr-Γ CHALLENGE_BITS = 256 # full Fiat-Shamir DOMAIN_TAG_VER = 4 # embedded in tag # Falcon-512 FALCON_STD = "NIST FIPS 206" FALCON_PQ_BITS = 128 # post-quantum FALCON_PK_SIZE = 897 # bytes FALCON_SK_SIZE = 1281 # bytes FALCON_SIG_SIZE = ~655 # bytes (variable)
# Geometry TESSELLATION = "{8,3}" TILING_DEPTH = 8 # production depth DISK_MODEL = "Poincaré" # GeodesicLWE BASIS_DIM = 8 # basis vectors SECRET_DIM = 1024 # secret vector bits SIGMA = 2.5 # noise scale factor # Wallet encryption (hyp_lwe.py) PBKDF2_ROUNDS = 600000 # HMAC-SHA256 CIPHER = "SHAKE-256-CTR" MAC = "SHA3-256 EtM" SHAMIR_FIELD = "GF(2^256)" # Security estimates # Classical SL(3,p): ~189 bits # Quantum (Falcon): 128 bits # Hybrid minimum: 128 bits PQ
Signing pipeline — hyp_finite_field is pure stdlib; hyp_pqc adds pqcrypto (Falcon-512)
Stubs — backward compat only. All code lives in hyp_finite_field.py + hyp_pqc.py
from hyp_pqc import HypGammaEngine # or backward compat: from hyp_engine import HypGammaEngine engine = HypGammaEngine() # singleton, thread-safe # ── Hybrid Keypair Generation ────────────────────────────────── kp_dict = engine.generate_hybrid_keypair() # → { # "version": "hybrid_sl3p_falcon_v2", # "sl3p": { # "private_walk_hex": "GF3:...", # 768-step nibble-packed walk # "public_hex": "...", # 576-hex (288 bytes, 3×3 matrix) # "address": "..." # 64-hex SHA3-256² # }, # "falcon": { # "public_key": "...", # base64, ~897 bytes # "secret_key": "..." # base64, ~1281 bytes # } # } # ── Hybrid Sign ──────────────────────────────────────────────── sig_dict = engine.hybrid_sign(message_hash, kp_dict) # message_hash: 32 bytes (SHA3-256 digest) # → { "version": "hybrid_sl3p_falcon_v2", # "sl3p_R_hex", "sl3p_Z_hex", "sl3p_c_hex", # "sl3p_s_scalar_hex", "sl3p_R_canonical", # "falcon_signature": "" } # ── Hybrid Verify ────────────────────────────────────────────── valid, reason = engine.hybrid_verify(message_hash, sig_dict, pub_dict) # Returns (True, "ok") or (False, "sl3p_signature_invalid") etc. # BOTH layers must pass. Handles v1 (SL(2,p)) and v2 (SL(3,p)) wire formats. # ── Block Operations ────────────────────────────────────────── sig = engine.sign_block_hybrid(block_dict, kp_dict) ok, msg = engine.verify_block_hybrid(block_dict, sig_dict, pub_dict) # ── SL(3,p)-only (non-hybrid) ───────────────────────────────── gf_kp = engine.generate_keypair() # GFKeyPair sig = engine.sign_hash(msg_hash, kp) # dict ok = engine.verify_signature(msg_hash, sig, pk) # ── PQC Status ───────────────────────────────────────────────── status = engine.pqc_status() # → { "falcon_real": True, "sl3p_classical_bits": 189, # "wire_version": "hybrid_sl3p_falcon_v2", ... }
from hyp_engine import HypGammaEngine still works via the stub. The HypGammaEngine API is identical. Wire format keys changed from sl2p_* to sl3p_*. hybrid_verify_any() auto-detects and routes both. hybrid_keypair_from_dict() accepts both sl3p and sl2p blocks. Existing chain history is fully verifiable.
| Attack | Target | Classical | Quantum | Status |
|---|---|---|---|---|
| Pollard rho on Q₃₇₉ | SL(3,p) DLP | ~2^189 (√Q₃₇₉) | Shor polynomial — Falcon covers PQ | ✓ Falcon-512 layered |
| Lattice sieving (BKZ) | Falcon-512 | ~2^256 (NTRU) | ~2^128 (quantum sieving) | ✓ Blocked |
| Signature stripping | Hybrid binding | falcon_msg = hash ‖ R.ser — layers cross-bound | Same | ✓ Blocked |
| Timing / DPA | SL(3,p) signing | 64-bit exponent blinding, hmac.compare_digest | N/A | ✓ Mitigated |
| HCVP (encryption) | GeodesicLWE | Exponential in hyperbolic radius | No speedup known | ✓ Blocked |
| Brute-force walk | Private key | 6^768 ≈ 2^1986 search space | ~2^993 (Grover) | ✓ Acceptable |
| Meet-in-the-middle | Walk preimage | ~2^993 (birthday on walks) | ~2^496 (Grover) | ✓ Acceptable |
| Property | v3 — SL(2,p) | v4 — SL(3,p) |
|---|---|---|
| Matrix dimension | 2×2 | 3×3 |
| Group order | |SL(2,p)| ≈ 2^765 | |SL(3,p)| ≈ 2^2040 |
| Classical DLP | ~70 bits (139-bit prime in p+1) | ~189 bits (Q₃₇₉ in p²+p+1) |
| Walk length | 512 steps | 768 steps |
| Generators | 4 (2 base + 2 inv) | 6 (3 base + 3 inv) |
| Walk entropy | ~810 bits | ~1783 bits |
| Public key size | 256 hex (128B) | 576 hex (288B) |
| Walk prefix | GF1: | GF3: |
| Wire version | hybrid_sl2p_falcon_v1 | hybrid_sl3p_falcon_v2 |
| Backward compat | — | hybrid_verify_any routes both |
{
"version": "hybrid_sl3p_falcon_v2",
"sl3p": {
"private_walk_hex": "GF3:...",
"public_hex": "<576 hex>",
"address": "<64 hex>"
},
"falcon": {
"public_key": "<base64>",
"secret_key": "<base64>"
}
}
{
"version": "hybrid_sl3p_falcon_v2",
"sl3p_R_hex": "<576 hex>",
"sl3p_Z_hex": "<576 hex>",
"sl3p_c_hex": "<64 hex>",
"sl3p_s_scalar_hex": "<512 hex>",
"sl3p_R_canonical": "<576 hex>",
"falcon_signature": "<base64>"
}
addr = SHA3-256(SHA3-256("QTCL_ADDR_SL3P_V4\x00" ‖ bytes.fromhex(public_hex))).hex() # v4 domain tag prevents cross-version address collision # 64-char hex output — standard QTCL address format
Python integers are variable-time in CPython (PyLong uses variable-width limbs; mul/mod timing leaks Hamming weight). Mitigation: hmac.compare_digest for all equality checks, Montgomery ladder for scalar exponentiation, exponent blinding (x + r·|G| for random r). These defend against remote-timing and network-timing attacks but NOT hardware power analysis (Termux/Android is not an HSM).
The LDPC error sampler in hyp_ldpc.py could not produce low-weight codewords as claimed. The constraint was never enforced in the encryption path. Resolution: hyp_ldpc.py removed entirely. File now raises ImportError with explanation. Attack surface reduced.
Exponentiation without blinding leaks scalar bits via DPA/timing. Mitigation: _blinded_pow(base, x, order) replaces x with x_blind = x + r·order where r is 64-bit random. Since base^order = I, base^(x+r·order) = base^x. The loop sees x_blind ≠ x, defeating single-trace DPA. 2^64 possible blinded exponents prevents statistical recovery.
Previous iterations allowed mock Falcon implementations for development. v4 enforces real pqcrypto at import time. If pqcrypto.sign.falcon_512 is not available, hyp_pqc.py raises ImportError with a clear error box explaining installation requirements. This ensures no deployment ever runs with degraded PQ security.
| Tool | Category | Description |
|---|---|---|
qtcl_create_wallet | wallet | SL(3,p) Schnorr-Γ keypair (non-hybrid) |
qtcl_create_hybrid_wallet | wallet | Hybrid SL(3,p) + Falcon-512 keypair (v4) |
qtcl_sign_message | signing | Sign with SL(3,p) Schnorr-Γ only |
qtcl_sign_message_hybrid | signing | Sign with both SL(3,p) + Falcon-512 |
qtcl_get_pqc_status | pqc | Module status, security parameters, wire versions |
qtcl_quantum_encrypt | encryption | Quantum-bound encryption via IBM QLDPC |
qtcl_quantum_decrypt | encryption | Decrypt quantum-bound ciphertext |
qtcl_quantum_pipeline | encryption | Full QLDPC pipeline on IBM quantum hardware |
Transport: Streamable HTTP at /mcp · Protocol: 2025-06-18 · Auth: none (open public endpoint; send_transaction requires on-chain hybrid signatures)