Skip to content

Where quantum-safe-ts differs from quantum-safe-py ​

The two libraries read and write the same bytes. They are not copies of each other: each follows the conventions of its language and runtime. This page lists every difference that affects what you can do, and the reason for it, so you can pick the right one or use both. The formats that cross are in Interop with quantum-safe-py.

Algorithms and formats ​

quantum-safe-ts 0.2quantum-safe-py 0.4Reason
ML-KEM-512/768/1024, hybrids with X25519 and P-256, X-WingYesYesShared, byte for byte.
ML-DSA-44/65/87, hybrids with Ed25519 and P-256, -v2YesYesShared.
SLH-DSA, all twelve parameter setsYesYesShared; verified in both directions.
HQC-128/192/256, BIKE-L1/3/5NoYes (through liboqs)The TypeScript library implements the standardized algorithms on RustCrypto crates and ships one small WebAssembly module. HQC and BIKE are in liboqs only.
COSE_Sign1, private AKP JWKs, streaming envelopes (format v3)YesYesShared; vectors are checked in both directions.
LMS verificationYes, every runtimeYes ([lms] extra, pyhsslms)Shared.
LMS signingNode.js only; one tree of height 5, 10, 15 or 20; state in a directoryYes ([lms] extra); one tree of height 5 to 25; state in a store you supplySigning is stateful: it needs state that survives a crash. Node.js has a filesystem for it; browsers and Workers do not, so the TypeScript signer refuses to run there.
XMSSNoNoLMS already satisfies CNSA 2.0's "LMS or XMSS".
Hybrid X.509 certificate builderNoYesPython's design is a classical certificate plus a co-signature bundle. Standards-based X.509 for ML-DSA and ML-KEM (IETF LAMPS) is the better target for TypeScript.
TLS SSLContext configurationNoYesPython-specific. Node.js and current browsers negotiate hybrid TLS natively.
Fernet and PyJWT shimsNoYesThey wrap Python libraries; TypeScript has fix hints in the audit tool and the migration guides instead.
Argon2id master-key derivation (deriveMasterKey)YesNoPython has no master-password concept.

Keys ​

quantum-safe-tsquantum-safe-pyReason
Standard ML-DSA secret keyA 32-byte seed (StandardKeyPair)liboqs: 4,032-byte expanded key. With the optional cryptography backend: the 32-byte seedFIPS 204 defines the seed as the key; the RustCrypto implementation works from it. liboqs does not take a seed.
Signing with the other library's keySigns with seed keys; verifies everythingSigns with either; verifies everythingAn expanded key has no recoverable seed. For one key that signs in both, use a seed key (Sign.generateStandardKeyPair() or Python's generate_seed_keypair()).
hedged: false with a -v2 suiteAccepted and ignored, with a QS_HEDGED_IGNORED warning; an error at the next breaking releaseValueErrorThe -v2 formats have no unhedged mode. TypeScript kept its documented 0.1.x behaviour so that nothing breaks in between.
ZeroizationRust zeroize plus explicit free() / using; copies in the JavaScript heap cannot be wipedctypes.memset of secret buffersDifferent memory models.

Runtimes and packaging ​

quantum-safe-tsquantum-safe-py
BackendsOne: Rust compiled to WebAssembly, embedded in the package. A native WebCrypto provider was evaluated and not builtliboqs, RustCrypto, or cryptography, chosen at run time
Where it runsNode.js, Bun, Deno, browsers, Workers, edge runtimesCPython
ErrorsTyped errors with stable code and hintException hierarchy
Warnings (omitted context or AAD)process.emitWarning, type QuantumSafeWarning; warnings.silence()warnings categories ContextOmittedWarning / AadOmittedWarning
Convenience layereasy (strings and bytes in and out)the high-level classes only
Machine-readable docsllms.txt, llms-full.txt, an MCP servern/a
Source scannerquantum-safe-audit scans JavaScript and TypeScriptqs-audit scans Python
NIST ACVP known-answer cases1,317638

Behaviour that is deliberately the same ​

Both libraries fail closed and say little about why: a wrong context, a wrong AAD, a different hedging mode and a modified byte all raise the same verification or decryption error. Both ask for the context and AAD you expect, warn once per call site when you omit them, and treat an omitted expectedContext as "expect empty". Both default new hybrid signatures to Ed25519+ML-DSA-65-v2.

Which should I use? ​

YouUse
Write a browser, edge or Node.js servicequantum-safe-ts
Write a Python service, or need HQC or BIKE, or the hybrid X.509 builderquantum-safe-py
Have both, and exchange keys, ciphertexts or signaturesBoth: the formats above cross unchanged
Sign firmware with LMSNode.js: LmsSigner; Python: the [lms] extra. Verify anywhere

Apache-2.0.