QuickStart
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.
Region
Server
UK
qo-uk.cambridgequantum.com/api/v1
US
qo-us.cambridgequantum.com/api/v1
Authentication Method
Users can be authenticated using 2 available methods, which are listed below:
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>" ...
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.
Encryption/Decryption
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\" }"
'https://qo-uk.cambridgequantum.com/api/v1/keygen'
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\" }"
'https://qo-uk.cambridgequantum.com/api/v1/keygen'
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,
counterStartValue,
pNonce, cbNonce,
pOutput, cbOutput,
&plainTextOutSignificantLength);
if (result != ERC_OK)
{
printf("ERROR: Error returned from qo_decrypt_aes_gcm(): result=%d", result);
}
// Clean up
free(pNonce);
free(pEncryptedData);
free(pSeed);
free(pExpectedOutput);
/// and return.
return result;
}