Verify Signatures with Dilithium3
This guide shows you how to verify Dilithium3 (ML-DSA-65) post-quantum digital signatures using Qpher, including verification with retired key versions.
Prerequisites
- A Qpher account with an active API key
- The original message (base64-encoded) that was signed
- The signature produced by the Sign Documents endpoint
- The
key_versionthat was used during signing
How Verification Works
Signature verification uses the public key corresponding to the key_version to confirm that:
- The message has not been modified since it was signed
- The signature was produced by the holder of the corresponding private key
- The signature is a valid Dilithium3 signature
Verification is a public-key operation — it does not require access to the private key.
Unlike signing (which requires an active key), verification works with both active and retired keys. This ensures you can always verify previously signed documents, even after key rotation.
Step 1: Gather the Required Inputs
You need three pieces of data from the original signing operation:
- message: The exact base64-encoded message that was signed
- signature: The base64-encoded signature returned by the sign endpoint
- key_version: The key version used during signing
Step 2: Send the Verify Request
curl -X POST https://api.qpher.ai/api/v1/signature/verify \
-H "Content-Type: application/json" \
-H "x-api-key: qph_your_key_here" \
-d '{
"message": "SGVsbG8sIFdvcmxkIQ==",
"signature": "base64-encoded-signature...",
"key_version": 1
}'Step 3: Understand the Response
/api/v1/signature/verifyContent-Type: application/json
x-api-key: qph_your_key_here{
"message": "SGVsbG8sIFdvcmxkIQ==",
"signature": "base64-encoded-signature...",
"key_version": 1
}{
"data": {
"valid": true,
"key_version": 1,
"algorithm": "Dilithium3"
},
"request_id": "880e8400-e29b-41d4-a716-446655440000",
"timestamp": "2026-02-15T10:33:00Z"
}| Field | Description |
|---|---|
valid | true if the signature is valid, false if verification failed |
key_version | The key version used for verification (matches your request) |
algorithm | The signature algorithm used (Dilithium3) |
request_id | Unique request identifier for tracing and support |
A 200 OK response does not mean the signature is valid. You must check the valid field in the response body. A response with "valid": false means the signature does not match — the message may have been tampered with or the wrong key was used.
Verification Scenarios
Valid Signature
The valid field is true. The message is authentic and has not been modified.
Invalid Signature — Possible Causes
| Scenario | Explanation |
|---|---|
| Message modified | The message content differs from what was originally signed |
| Wrong key_version | You are verifying against a different key than was used to sign |
| Signature corrupted | The signature bytes were modified, truncated, or incorrectly encoded |
| Wrong encoding | The message was not base64-encoded the same way during sign and verify |
Verifying with Retired Keys
After key rotation, old signatures remain valid and can be verified with retired keys:
Key Status | Sign | Verify
------------- | ---- | ------
active | Yes | Yes
retired | No | Yes
archived | No | No
Error Handling
| HTTP Status | Error Code | Cause | Resolution |
|---|---|---|---|
| 400 | ERR_INVALID_001 | Missing or invalid message, signature, or key_version | Ensure all fields are present and properly base64-encoded |
| 401 | ERR_AUTH_001 | Invalid or missing API key | Check your x-api-key header |
| 404 | ERR_SIG_003 | Key version not found | Verify the key_version exists for your tenant |
| 409 | ERR_SIG_005 | Key is archived — verification not allowed | Contact support to restore the key to retired status |
| 429 | ERR_RATE_001 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
Related Guides
- Sign Documents — Create Dilithium3 digital signatures
- Key Management — Generate and manage your signing keys
- Key Versioning — Understand how key rotation affects verification
- Migration Guide — Migrate from RSA/ECDSA to Dilithium3