Skip to main content

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_version that was used during signing

How Verification Works

Signature verification uses the public key corresponding to the key_version to confirm that:

  1. The message has not been modified since it was signed
  2. The signature was produced by the holder of the corresponding private key
  3. The signature is a valid Dilithium3 signature

Verification is a public-key operation — it does not require access to the private key.

Verification with Retired Keys

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

POST/api/v1/signature/verifyVerify a Dilithium3 digital signature
Verify a Signature
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

RequestPOST/api/v1/signature/verify
Content-Type: application/json
x-api-key: qph_your_key_here
{
  "message": "SGVsbG8sIFdvcmxkIQ==",
  "signature": "base64-encoded-signature...",
  "key_version": 1
}
Response200
{
  "data": {
    "valid": true,
    "key_version": 1,
    "algorithm": "Dilithium3"
  },
  "request_id": "880e8400-e29b-41d4-a716-446655440000",
  "timestamp": "2026-02-15T10:33:00Z"
}
FieldDescription
validtrue if the signature is valid, false if verification failed
key_versionThe key version used for verification (matches your request)
algorithmThe signature algorithm used (Dilithium3)
request_idUnique request identifier for tracing and support
Always Check the valid Field

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

ScenarioExplanation
Message modifiedThe message content differs from what was originally signed
Wrong key_versionYou are verifying against a different key than was used to sign
Signature corruptedThe signature bytes were modified, truncated, or incorrectly encoded
Wrong encodingThe 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 StatusError CodeCauseResolution
400ERR_INVALID_001Missing or invalid message, signature, or key_versionEnsure all fields are present and properly base64-encoded
401ERR_AUTH_001Invalid or missing API keyCheck your x-api-key header
404ERR_SIG_003Key version not foundVerify the key_version exists for your tenant
409ERR_SIG_005Key is archived — verification not allowedContact support to restore the key to retired status
429ERR_RATE_001Rate limit exceededReduce request frequency or upgrade your plan