QRCLibGitHub

Both signatures have to pass.

The signature is ML-DSA-65 concatenated with Ed25519. Checking one half and skipping the other is not this construction. Edit the text after signing, or flip a byte, and the check should fail. If the worry is a shortcut in the lattice rather than a quantum computer, use the hash signature.

Try it

  1. 01

    Sign the text.

    The first time also generates the key. The public key is 1,984 bytes: 1,952 of ML-DSA-65, then 32 of Ed25519.

  2. 02

    Change the text and check it.

    The signature is not updated. Check uses the signature you already have against whatever is in the box now.

  3. 03

    Or damage the signature itself.

    The last byte is the Ed25519 half. The first byte is the ML-DSA half. Either change is enough to reject.

Same call in Python
from qrclib.hybrid import generate_sign_keys, sign, verify

keys = generate_sign_keys()
signature = sign(keys.secret_key, message)
assert verify(keys.public_key, message, signature)
assert not verify(keys.public_key, message + b" ", signature)