Plugin Signing

How Spirefy signs and verifies plugins with ML-DSA-65, the post-quantum signature standard.

Browse documentation

Marketplace plugins are signed so the app can prove a package has not been tampered with before it runs. Spirefy uses ML-DSA-65, the post-quantum signature scheme standardized by NIST as FIPS 204, rather than Ed25519, because plugin signatures need a multi-year shelf life.

Generate a key

spirefy key-gen --label my-key

Keys live in your local keystore (~/.config/zora/keys). A key’s fingerprint is the SHA-256 of its public key, written as 64 hex characters, and that fingerprint is how the marketplace and your local store identify it. Add --register to publish the public key once you have a marketplace account.

Sign while packing

Signing happens as part of packaging:

spirefy pack --sign --key my-key

The signature covers the manifest, the WebAssembly, and the WIT, hashed together with length prefixes so the boundaries between them cannot be confused. It is stored inside the .zp package.

Verify

spirefy verify my-plugin-1.0.0.zp --strict --key my-key

spirefy verify checks a package locally. Without --strict, an unsigned plugin warns but passes, while an invalid signature always fails. With --strict, the package must carry a valid ML-DSA-65 signature from a key you trust. Verification happens before the WebAssembly is decompressed, so a tampered package never runs, and the command exits non-zero on failure so it fits in CI.

At load time

When the app loads a plugin it logs the file’s SHA-256 hash, and on POSIX it refuses to load a world-writable plugin file. A marketplace plugin’s signature is checked before it runs.