General Principles

The Quantum Origin service is available as a standard RESTful API over TLS.

Regional Availability

The Quantum Origin service is available in a few regions, namely the US and UK. The table below provides information pertaining to the servers that can accept HTTPS server requests.







Authentication Method

Users can be authenticated using 2 available methods, which are listed below:

  1. Using a client certificate and qo-api-key : The thumbprint of the client certificate is checked against onboarded client certificates.

curl -X POST --cert client.crt --key client.cert.prv.key --header "qo-api-key: <customer's own api key>" ...
  1. qo-api-key & client-id : These credentials are checked against onboarded clients.

curl -X POST --header "qo-api-key:<customer's own api key>" --header "uuid: <customer's own client-id>" ...

Request Method

To make keygen and randomness requests, users should use the POST request method. For the usage endpoint, the GET request method should be employed.


Both the keygen and randomness responses are encrypted. The secret used in encryption is the shared_secret, which is provided during onboarding. Hence for decryption, the same shared_secret must be used for AES-256-GCM decryption.

Using the API directly

Users can either access the API directly, through manual web connections (e.g. cURL) or by using Quantinuum-provided software.

A complete example of the cURL request which will return an encrypted payload is shown below.

curl -X POST
    --header "Content-Type: application/json"
    --header "qo-api-key: <customer's qo-api-key>"
    --header "uuid: <customer's client-id>"
    --data-raw "{\"key_type\":\"SPHINCS\", \"key_parameters\":  { \"variant\":\"SPHINCS-HARAKA-128F-ROBUST\" }, \"nonce\":\"abcdabcd\" }"

An equivalent cURL request using client certificate example can be found below.

curl -X POST
    --header "Content-Type: application/json"
    --header "qo-api-key: <customer's qo-api-key>"
    --cert customer_client.crt
    --key customer.client_crt.prv.key
    --data-raw "{\"key_type\":\"RSA\", \"key_parameters\":  { \"size\": 4096 }, \"nonce\":\"abcdabcd\" }"

The qo CLI tool can be used to request keys as follows. Note that decryption is done internally using the shared_secret. When this information is not provided, a nonce is generated internally.

export QO_SECRET=<the shared secret provided during onboarding>
export QO_URL=https://qo-uk.cambridgequantum.com/api/v1
./qo keygen -a HQC -A <qo-api-key> -C <client id> -p "{\"variant\":\"HQC-128\"}" -K hex -O jwk

An alternative approach is presented below.

./qo keygen -a RSA -p "{\"size\":2048}" -A <qo-api-key> -c <cilent cert> -z <client cert key> -n abcdabcd -K hex -O pem

After the completion of this process, the encrypted payload must be decrypted. The last way of requesting keys is accomplished via our libraries. Sample code is provided below.

auto keyGen = std::make_unique<CliKeygen>(params.url, params.certificate, Quantinuum::QuantumOrigin::Common::CertType::PEM, params.privateKeyForCert, params.ApiKey);
// keygen request using client_id + qo-api-key
//auto keyGen = std::make_unique<CliKeygen>(params.url, params.clientId, params.ApiKey);

Quantinuum::QuantumOrigin::Common::KeyRequest keyRequest(params.keyType, params.keyParameters, params.nonce);
auto keyResponse = keyGen->Send(keyRequest);

params.sharedSecret = TransformInputString(params.sharedSecret, params.sharedSecretFormat, "SharedSecret");
params.nonce        = TransformInputString(params.nonce, params.nonceFormat, "Nonce");
auto contentTypeFromResponse = keyResponse.contentType;

CliDecrypt keyDecrypt(params.sharedSecret, params.nonce, keyResponse);
keyDecrypt.runDecrypt(params.useDefaultOutputFormat, params.outputFormat, contentTypeFromResponse, params.outputFilename);

Using the Decryption CLI and Library

Using the decryption command-line interface

Decryption can also performed via the qo-cli tool which has examples on The Command-line Interfaces section. As a quick example, the use of qo-cli is demonstrated below. The Quantum Origin pipes the encrypted material from the key request into the underlying qo CLI tool. For the purposes of this demonstration, the Quantum Origin service exports the shared_secret as an env variable.

-n is used to identify the nonce value given for the request
-K is used to declare the shared secret format
-O is used to declare the output format for the decrypted content

export QO_SECRET=<the shared secret obtained during onboarding>

echo -n '{"content_type":"SPHINCS-HARAKA-128F-ROBUST","counter":0,"encrypted_data":"ZS1MHBFdwmKdjt0KtMRyZiHen+s[...]eCQ9iWVZpGeN5oLn6DA==","seed":"/bLNQdryejWsXDS0dch0caTlCZH9tKab0/wPrIObYbUBXti2"}'
| ./qo keydecrypt -n abcdabcd -K hex -O pem

Using the C Library

The Quantum Origin platform also uses a C library, which is used to decrypt the material in the qo CLI tool. A simple use case is provided below for user convenience purposes.

static int known_answer_test_c_api(void)
    // {"key_type":"AES", "key_parameters":  { "size":256 }, "nonce":"abcdabcd" }
    // {"counter":0,"encrypted_key":"YFXPt6F4kZn8BaLSA6KjlDNYP4wArGk++R94Vi2Vxd+32vH9ODUoqtgO2qBdPzhP","seed":"t79dViOCDEsKG+iCtPM0M9IHFdXtXjaaW4cI+mPieCMkmyum"}

    uint8_t      sharedSecret[32]     = {0x42, 0x2a, 0xbd, 0x08, 0xe8, 0x59, 0xf1, 0xeb, 0x67, 0x2d, 0x89, 0xd2, 0x1d, 0xf3, 0x77, 0x7a,
                                         0x0e, 0xb0, 0xcc, 0xdc, 0x31, 0x6a, 0x59, 0x42, 0x4f, 0x7c, 0x42, 0xc9, 0xad, 0x34, 0x56, 0x20}; // 422ABD08E859F1EB672D89D21DF3777A0EB0CCDC316A59424F7C42C9AD345620  (32 bytes)
    char *       szBase64Nonce        = "abcdabcd";                                                         // 69B71D69B71D  (6 bytes)
    size_t       cbNonce              = 0;
    uint8_t *    pNonce               = base64_decode(szBase64Nonce, strlen(szBase64Nonce), &cbNonce);
    char *       szBase64EncryptedData= "YFXPt6F4kZn8BaLSA6KjlDNYP4wArGk++R94Vi2Vxd+32vH9ODUoqtgO2qBdPzhP"; // 6055CFB7A1789199FC05A2D203A2A39433583F8C00AC693EF91F78562D95C5DFB7DAF1FD383528AAD80EDAA05D3F384F  (48 bytes)
    size_t       cbEncryptedData       = 0;
    uint8_t *    pEncryptedData        = base64_decode(szBase64EncryptedData, strlen(szBase64EncryptedData), &cbEncryptedData);
    const char * szBase64Seed         = "t79dViOCDEsKG+iCtPM0M9IHFdXtXjaaW4cI+mPieCMkmyum";                 // B7BF5D5623820C4B0A1BE882B4F33433D20715D5ED5E369A5B8708FA63E27823249B2BA6  (36 bytes)
    size_t       cbSeed               = 0;
    uint8_t *    pSeed                = base64_decode(szBase64Seed, strlen(szBase64Seed), &cbSeed);
    const char * szBase64ExpectedOutput = "I+bgjK6NgdakodlA0TuDqJxuGzqOu8qgDfChYP/G5BY=";                   // 23E6E08CAE8D81D6A4A1D940D13B83A89C6E1B3A8EBBCAA00DF0A160FFC6E416  (32 bytes)
    size_t       cbExpectedOutput       = 0;
    uint8_t *    pExpectedOutput        = base64_decode(szBase64ExpectedOutput, strlen(szBase64ExpectedOutput), &cbExpectedOutput);
    uint64_t     counterStartValue    = 0;

    uint8_t outputBuffer[48] = {0};
    uint8_t *pOutput = outputBuffer;
    size_t cbOutput = sizeof(outputBuffer);
    size_t plainTextOutSignificantLength = 0;

    tERRORCODE result = qo_decrypt_aes_gcm(sharedSecret,   sizeof(sharedSecret),
                                           pEncryptedData, cbEncryptedData,
                                           pSeed,          cbSeed,
                                           pNonce,         cbNonce,
                                           pOutput,        cbOutput,

    if (result != ERC_OK)
        printf("ERROR: Error returned from qo_decrypt_aes_gcm(): result=%d", result);

    // Clean up

    /// and return.
    return result;