Skip to main content

Signature API

The Signature API provides post-quantum digital signatures using the Dilithium3 algorithm (NIST ML-DSA-65, FIPS 204). Use it to sign messages and verify signatures with quantum-resistant security.

Private keys never leave Qpher

Signing operations happen inside the Qpher secure enclave. Your private signing keys are never exposed or exported.

Composite ML-DSA hybrid signatures (Starter+)

Pass "algorithm": "Composite-ML-DSA" in sign/verify requests to use hybrid signatures (ECDSA P-256 + ML-DSA-65). If omitted, the default is "Dilithium3" (PQC-only, backward-compatible).

Both ECDSA and ML-DSA components must verify for the signature to be valid, ensuring security if either algorithm is compromised.

Important: Composite ML-DSA signatures use Qpher's internal wire format and must be verified using this API. They are not interoperable with external Composite ML-DSA implementations.

See Security Architecture for details.


Sign​

POST/api/v1/signature/signSign a message using Dilithium3 post-quantum digital signatures.

Signs the provided message with the specified key version. The key must be in active status.

Request body​

FieldTypeRequiredDescription
messagestring (base64)YesBase64-encoded message to sign.
key_versionintegerYesThe version of the Dilithium3 key to use. Must reference an active key.
algorithmstringNo"Dilithium3" (default) or "Composite-ML-DSA" (hybrid, Starter+). If omitted, defaults to Dilithium3.

Response (200 OK)​

FieldTypeDescription
data.signaturestring (base64)The signature, base64-encoded.
data.key_versionintegerThe key version used for signing.
data.algorithmstring"Dilithium3" or "Composite-ML-DSA", matching the algorithm used for the operation.

Example​

RequestPOST/api/v1/signature/sign
X-API-Key: qph_your_key_here
Content-Type: application/json
{
  "message": "SW52b2ljZSAjMTIzNCAtIFRvdGFsOiAkOTkuMDA=",
  "key_version": 1
}
Response200
{
  "data": {
    "signature": "c2lnbmF0dXJlX2J5dGVzX2hlcmUuLi4=",
    "key_version": 1,
    "algorithm": "Dilithium3"
  },
  "request_id": "c3d4e5f6-a7b8-9012-cdef-123456789012",
  "timestamp": "2026-01-15T10:30:02.000Z"
}
Sign example
curl -X POST https://api.qpher.ai/api/v1/signature/sign \
  -H "X-API-Key: qph_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "SW52b2ljZSAjMTIzNCAtIFRvdGFsOiAkOTkuMDA=",
    "key_version": 1
  }'

Errors​

HTTP StatusError CodeDescription
400ERR_SIG_001Invalid sign request — missing message, bad base64 encoding, or invalid key_version.
400ERR_SIG_002Message exceeds maximum allowed size.
401ERR_AUTH_001Missing or invalid API key.
404ERR_NOT_FOUND_001Key version not found or key is not in active status.
429ERR_RATE_LIMIT_001Rate limit exceeded — reduce request frequency or upgrade your plan.

Verify​

POST/api/v1/signature/verifyVerify a Dilithium3 signature against a message.

Verifies that a signature is valid for the given message and key version. Verification can use keys in active or retired status.

Request body​

FieldTypeRequiredDescription
messagestring (base64)YesBase64-encoded original message that was signed.
signaturestring (base64)YesBase64-encoded signature to verify.
key_versionintegerYesThe key version that was used to create the signature.
algorithmstringNo"Dilithium3" (default) or "Composite-ML-DSA" (hybrid, Starter+). If omitted, defaults to Dilithium3.

Response (200 OK)​

FieldTypeDescription
data.validbooleantrue if the signature is valid for the given message and key, false otherwise.
data.key_versionintegerThe key version used for verification.
data.algorithmstring"Dilithium3" or "Composite-ML-DSA", matching the algorithm used for the operation.

Example​

RequestPOST/api/v1/signature/verify
X-API-Key: qph_your_key_here
Content-Type: application/json
{
  "message": "SW52b2ljZSAjMTIzNCAtIFRvdGFsOiAkOTkuMDA=",
  "signature": "c2lnbmF0dXJlX2J5dGVzX2hlcmUuLi4=",
  "key_version": 1
}
Response200
{
  "data": {
    "valid": true,
    "key_version": 1,
    "algorithm": "Dilithium3"
  },
  "request_id": "d4e5f6a7-b8c9-0123-4567-890abcdef012",
  "timestamp": "2026-01-15T10:30:03.000Z"
}
Verify example
curl -X POST https://api.qpher.ai/api/v1/signature/verify \
  -H "X-API-Key: qph_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "message": "SW52b2ljZSAjMTIzNCAtIFRvdGFsOiAkOTkuMDA=",
    "signature": "c2lnbmF0dXJlX2J5dGVzX2hlcmUuLi4=",
    "key_version": 1
  }'

Errors​

HTTP StatusError CodeDescription
400ERR_SIG_001Invalid verify request — bad base64 encoding for message or signature.
400ERR_SIG_002Message or signature exceeds maximum allowed size.
401ERR_AUTH_001Missing or invalid API key.
404ERR_NOT_FOUND_001Key version not found or key is in archived status.
429ERR_RATE_LIMIT_001Rate limit exceeded — reduce request frequency or upgrade your plan.
Verification does not throw on invalid signatures

A signature that does not match returns {"valid": false} with HTTP 200 — not an error. Errors (4xx/5xx) indicate malformed requests or missing resources, not invalid signatures.


Sign Hash​

POST/api/v1/signature/sign-hashSign a pre-computed hash using Dilithium3 post-quantum digital signatures.

Signs a pre-computed hash digest instead of the raw message. This is ideal for large files or artifacts where you compute the hash client-side and send only the digest. The key must be in active status.

Request body​

FieldTypeRequiredDescription
hashstring (base64)YesBase64-encoded hash digest to sign.
hash_algorithmstringYesHash algorithm used to compute the digest: "SHA-256", "SHA-384", or "SHA-512".
key_versionintegerYesThe version of the Dilithium3 key to use. Must reference an active key.
algorithmstringNo"Dilithium3" (default) or "Composite-ML-DSA" (hybrid, Starter+). If omitted, defaults to Dilithium3.

Response (200 OK)​

FieldTypeDescription
data.signaturestring (base64)The signature, base64-encoded.
data.key_versionintegerThe key version used for signing.
data.algorithmstring"Dilithium3" or "Composite-ML-DSA", matching the algorithm used for the operation.
data.hash_algorithmstringThe hash algorithm that was specified in the request.
data.signature_typestringAlways "detached" — indicates the signature covers a hash, not the raw message.

Example​

Sign Hash example
curl -X POST https://api.qpher.ai/api/v1/signature/sign-hash \
  -H "X-API-Key: qph_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "hash": "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=",
    "hash_algorithm": "SHA-256",
    "key_version": 1
  }'

Errors​

HTTP StatusError CodeDescription
400ERR_SIG_010Unsupported hash algorithm — use SHA-256, SHA-384, or SHA-512.
400ERR_SIG_011Hash length does not match declared hash_algorithm (SHA-256=32, SHA-384=48, SHA-512=64 bytes).
401ERR_AUTH_001Missing or invalid API key.
404ERR_NOT_FOUND_001Key version not found or key is not in active status.
429ERR_RATE_LIMIT_001Rate limit exceeded — reduce request frequency or upgrade your plan.

Verify Hash​

POST/api/v1/signature/verify-hashVerify a Dilithium3 signature against a pre-computed hash.

Verifies that a signature is valid for the given hash digest and key version. Verification can use keys in active or retired status.

Request body​

FieldTypeRequiredDescription
hashstring (base64)YesBase64-encoded hash digest that was signed.
hash_algorithmstringYesHash algorithm used to compute the digest: "SHA-256", "SHA-384", or "SHA-512".
signaturestring (base64)YesBase64-encoded signature to verify.
key_versionintegerYesThe key version that was used to create the signature.
algorithmstringNo"Dilithium3" (default) or "Composite-ML-DSA" (hybrid, Starter+). If omitted, defaults to Dilithium3.

Response (200 OK)​

FieldTypeDescription
data.validbooleantrue if the signature is valid for the given hash and key, false otherwise.
data.key_versionintegerThe key version used for verification.
data.algorithmstring"Dilithium3" or "Composite-ML-DSA", matching the algorithm used for the operation.
data.hash_algorithmstringThe hash algorithm that was specified in the request.

Example​

Verify Hash example
curl -X POST https://api.qpher.ai/api/v1/signature/verify-hash \
  -H "X-API-Key: qph_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
    "hash": "n4bQgYhMfWWaL+qgxVrQFaO/TxsrC4Is0V1sFbDwCgg=",
    "hash_algorithm": "SHA-256",
    "signature": "c2lnbmF0dXJlX2J5dGVzX2hlcmUuLi4=",
    "key_version": 1
  }'

Errors​

HTTP StatusError CodeDescription
400ERR_SIG_010Unsupported hash algorithm — use SHA-256, SHA-384, or SHA-512.
400ERR_SIG_011Hash length does not match declared hash_algorithm (SHA-256=32, SHA-384=48, SHA-512=64 bytes).
401ERR_AUTH_001Missing or invalid API key.
404ERR_NOT_FOUND_001Key version not found or key is in archived status.
429ERR_RATE_LIMIT_001Rate limit exceeded — reduce request frequency or upgrade your plan.
Verification does not throw on invalid signatures

A signature that does not match returns {"valid": false} with HTTP 200 — not an error. Errors (4xx/5xx) indicate malformed requests or missing resources, not invalid signatures.


Key Version Requirements​

The key_version field is mandatory on all signature operations. There is no implicit "use latest key" behavior.

OperationAllowed Key Statuses
Signactive only
Verifyactive or retired
Sign Hashactive only
Verify Hashactive or retired

Use the Key Management API to list your keys and find the current active version.