paragonie/ext-pqcrypto

PHP extension for post-quantum cryptography (ML-KEM, X-Wing, ML-DSA, SLH-DSA)

Maintainers

Package info

github.com/paragonie/ext-pqcrypto

Language:Rust

Type:php-ext

Ext name:ext-pqcrypto

pkg:composer/paragonie/ext-pqcrypto

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 7

Open Issues: 0

v0.2.2 2026-04-14 16:55 UTC

This package is auto-updated.

Last update: 2026-04-14 16:56:32 UTC


README

CI Latest Stable Version License Downloads crates.io

A PHP extension (written in Rust) that exposes post-quantum cryptography algorithms from the RustCrypto project.

Implements FIPS 203 (ML-KEM), FIPS 204 (ML-DSA), FIPS 205 (SLH-DSA), and X-Wing (hybrid X25519 + ML-KEM-768).

Requirements

  • PHP >= 8.1
  • Rust toolchain (rustc >= 1.85, nightly)
  • php-config in PATH (for ext-php-rs build)

Building

make build   # cargo build --release
make test    # run PHP test suite
make install # copy to PHP extension dir

After installing, add extension=pqcrypto to your php.ini, then run:

var_dump(extension_loaded('pqcrypto')); // bool(true)

Usage

X-Wing (Hybrid KEM: X25519 + ML-KEM-768)

Tip

X-Wing is the recommend hybrid post-quantum KEM.

[$sk, $pk] = PQCrypto\XWing::generateKeypair();

[$sharedSecret, $ciphertext] = $pk->encapsulate();
$recipientSecret = $sk->decapsulate($ciphertext);

assert(hash_equals($recipientSecret, $sharedSecret));

ML-KEM (Key Encapsulation)

Tip

We do not recommend ML-KEM-512, but include it for completeness. ML-KEM-768 or ML-KEM-1024 should be used if X-Wing is not acceptable.

// ML-KEM-768 (also: MLKem512, MLKem1024)
[$sk, $pk] = PQCrypto\MLKem768::generateKeypair();

[$sharedSecret, $ciphertext] = $pk->encapsulate();
$recipientSecret = $sk->decapsulate($ciphertext);

assert(hash_equals($recipientSecret, $sharedSecret));

// Serialize / restore
$skBytes = $sk->bytes();  // 64-byte seed
$sk2 = PQCrypto\MLKem768\DecapsulationKey::fromBytes($skBytes);

ML-DSA (Digital Signatures)

Tip

ML-DSA-44 is fine. The larger parameter sets should only be used if you specifically need them for compliance reasons (i.e., CNSA 2.0).

// ML-DSA-44 (also: MLDSA65, MLDSA87)
[$signingKey, $verifyingKey] = PQCrypto\MLDSA44::generateKeypair();

$signature = $signingKey->sign('message');
$valid = $verifyingKey->verify($signature, 'message'); // true
$invalid = $verifyingKey->verify($signature, 'wrong');  // false

// Serialize / restore
$seed = $signingKey->bytes(); // 32-byte seed
$sk2 = PQCrypto\MLDSA44\SigningKey::fromBytes($seed);

SLH-DSA (Stateless Hash-Based Signatures)

// Parameters: hash function + speed
// Hash: 'shake128', 'shake192', 'shake256',
//       'sha2-128', 'sha2-192', 'sha2-256'
// Speed: 'fast' (larger sigs) or 'small' (smaller sigs)
$slh = new PQCrypto\SLHDSA('shake256', 'fast');

[$signingKey, $verifyingKey] = $slh->generateKeypair();

$signature = $signingKey->sign('message');
$valid = $verifyingKey->verify($signature, 'message');

// Import keys
$sk2 = $slh->importSigningKey($signingKey->bytes());
$vk2 = $slh->importVerifyingKey($verifyingKey->bytes());

Key Sizes

KEM

Algorithm Seed Public Key Ciphertext Shared Secret
ML-KEM-512 64 800 768 32
ML-KEM-768 64 1184 1088 32
ML-KEM-1024 64 1568 1568 32
X-Wing 32 1216 1120 32

Signatures

Algorithm Seed Public Key Signature
ML-DSA-44 32 1312 2420
ML-DSA-65 32 1952 3309
ML-DSA-87 32 2592 4627
SLH-DSA-*-128s 64 32 7856
SLH-DSA-*-128f 64 32 17088
SLH-DSA-*-192s 96 48 16224
SLH-DSA-*-192f 96 48 35664
SLH-DSA-*-256s 128 64 29792
SLH-DSA-*-256f 128 64 49856

All sizes above are measured in bytes.

Secret keys are stored as seeds, never semi-expanded secrets. This is a deliberate design choice.