PQ signature verification — integration guide

Confium supports composite signatures for post-quantum (PQ) migration. A composite signature combines a classical algorithm (Ed25519, ECDSA-P256) with a PQ algorithm (ML-DSA-65, SLH-DSA) so that breaking either alone doesn’t break the composite.

Built-in verifiers

Confium ships built-in verifiers for:

  • Ed25519 (Ed25519)
  • ECDSA-P256 (ECDSA-P256)

Caller-supplied verifiers (PQ algorithms)

For PQ algorithms that don’t yet have a pure-Rust verifier crate in the Confium workspace, use the caller-supplied verifier callback:

sig = Confium::Composite::Signature.new(components)
result = sig.verify(message, {
  "ML-DSA-65" => ->(pk_bytes, msg_bytes, sig_bytes) {
    # Call your ML-DSA verifier here (e.g. via FFI to a C library,
    # or a WebAssembly module, or a remote verification service).
    my_ml_dsa_verifier.verify(pk_bytes, msg_bytes, sig_bytes)
  },
})
puts result.all_verified?

Native ML-DSA support

Native ML-DSA-65 verification routes through a pure-Rust verifier crate when one is bundled into the deployment’s plugin set. Candidates:

  • ml-dsa (RustCrypto) — RustCrypto’s pure-Rust implementation.
  • pqcrypto — wraps the NIST reference C implementation.

Absent a bundled verifier, the callback surface is the supported path.

WASM equivalent

The @confium/confium-wasm package supports the same callback pattern:

import init, { CompositeSignature } from "@confium/confium-wasm";
await init();
const sig = CompositeSignature.from_json(jsonString);
const result = sig.verify(messageBytes, {
  "ML-DSA-65": (pk, msg, sig) => myVerifier(pk, msg, sig),
});