@epochcore/qaas-sdk 1.0.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -24
- package/dist/index.d.mts +92 -54
- package/dist/index.d.ts +92 -54
- package/dist/index.js +344 -76
- package/dist/index.mjs +348 -75
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -23,91 +23,232 @@ __export(index_exports, {
|
|
|
23
23
|
ALGORITHMS: () => ALGORITHMS,
|
|
24
24
|
QaaSClient: () => QaaSClient,
|
|
25
25
|
QaaSError: () => QaaSError,
|
|
26
|
-
|
|
26
|
+
QaaSRateLimitError: () => QaaSRateLimitError,
|
|
27
|
+
QaaSValidationError: () => QaaSValidationError,
|
|
28
|
+
SIGNATURE_MAX_AGE_MS: () => SIGNATURE_MAX_AGE_MS
|
|
27
29
|
});
|
|
28
30
|
module.exports = __toCommonJS(index_exports);
|
|
31
|
+
var SDK_VERSION = "1.2.0";
|
|
32
|
+
var SDK_USER_AGENT = `EpochCore-QaaS-SDK/${SDK_VERSION}`;
|
|
33
|
+
var _crypto = typeof globalThis.crypto !== "undefined" ? globalThis.crypto : require("crypto").webcrypto;
|
|
34
|
+
var MIN_TIMEOUT_MS = 5e3;
|
|
35
|
+
var MAX_TIMEOUT_MS = 12e4;
|
|
36
|
+
var DEFAULT_TIMEOUT_MS = 3e4;
|
|
37
|
+
var SIGNATURE_MAX_AGE_MS = 3e5;
|
|
38
|
+
var DEFAULT_RATE_LIMIT = 10;
|
|
39
|
+
var DEFAULT_RATE_BURST = 20;
|
|
40
|
+
var MAX_BODY_SIZE = 1048576;
|
|
41
|
+
var MAX_SHOTS = 1e5;
|
|
42
|
+
var MIN_SHOTS = 1;
|
|
43
|
+
var MAX_ALGORITHM_ID_LENGTH = 64;
|
|
44
|
+
var MAX_RETRY_ATTEMPTS = 3;
|
|
45
|
+
var RETRY_BASE_MS = 500;
|
|
46
|
+
var VALID_BACKENDS = /* @__PURE__ */ new Set([
|
|
47
|
+
"simulator",
|
|
48
|
+
"qiskit_aer",
|
|
49
|
+
"cirq",
|
|
50
|
+
"pennylane",
|
|
51
|
+
"ibm_quantum"
|
|
52
|
+
]);
|
|
53
|
+
var TokenBucket = class {
|
|
54
|
+
constructor(capacity, refillRate) {
|
|
55
|
+
this.capacity = capacity;
|
|
56
|
+
this.refillRate = refillRate;
|
|
57
|
+
this.tokens = capacity;
|
|
58
|
+
this.lastRefill = Date.now();
|
|
59
|
+
}
|
|
60
|
+
tryConsume() {
|
|
61
|
+
this.refill();
|
|
62
|
+
if (this.tokens >= 1) {
|
|
63
|
+
this.tokens -= 1;
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
refill() {
|
|
69
|
+
const now = Date.now();
|
|
70
|
+
const elapsed = (now - this.lastRefill) / 1e3;
|
|
71
|
+
this.tokens = Math.min(this.capacity, this.tokens + elapsed * this.refillRate);
|
|
72
|
+
this.lastRefill = now;
|
|
73
|
+
}
|
|
74
|
+
};
|
|
75
|
+
async function hmacSign(secret, message) {
|
|
76
|
+
const enc = new TextEncoder();
|
|
77
|
+
const key = await _crypto.subtle.importKey(
|
|
78
|
+
"raw",
|
|
79
|
+
enc.encode(secret),
|
|
80
|
+
{ name: "HMAC", hash: "SHA-256" },
|
|
81
|
+
false,
|
|
82
|
+
["sign"]
|
|
83
|
+
);
|
|
84
|
+
const sig = await _crypto.subtle.sign("HMAC", key, enc.encode(message));
|
|
85
|
+
return Array.from(new Uint8Array(sig)).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
86
|
+
}
|
|
87
|
+
function generateNonce() {
|
|
88
|
+
const bytes = new Uint8Array(16);
|
|
89
|
+
_crypto.getRandomValues(bytes);
|
|
90
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
91
|
+
}
|
|
92
|
+
function validateRunRequest(req) {
|
|
93
|
+
if (!req.algorithm_id || typeof req.algorithm_id !== "string") {
|
|
94
|
+
throw new QaaSValidationError("algorithm_id is required and must be a string");
|
|
95
|
+
}
|
|
96
|
+
if (req.algorithm_id.length > MAX_ALGORITHM_ID_LENGTH) {
|
|
97
|
+
throw new QaaSValidationError(`algorithm_id exceeds max length of ${MAX_ALGORITHM_ID_LENGTH}`);
|
|
98
|
+
}
|
|
99
|
+
if (!/^[A-Z0-9_]+$/.test(req.algorithm_id)) {
|
|
100
|
+
throw new QaaSValidationError("algorithm_id must contain only uppercase letters, digits, and underscores");
|
|
101
|
+
}
|
|
102
|
+
if (req.backend !== void 0) {
|
|
103
|
+
if (!VALID_BACKENDS.has(req.backend)) {
|
|
104
|
+
throw new QaaSValidationError(
|
|
105
|
+
`Invalid backend "${req.backend}". Must be one of: ${[...VALID_BACKENDS].join(", ")}`
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
if (req.shots !== void 0) {
|
|
110
|
+
if (typeof req.shots !== "number" || !Number.isInteger(req.shots)) {
|
|
111
|
+
throw new QaaSValidationError("shots must be an integer");
|
|
112
|
+
}
|
|
113
|
+
if (req.shots < MIN_SHOTS || req.shots > MAX_SHOTS) {
|
|
114
|
+
throw new QaaSValidationError(`shots must be between ${MIN_SHOTS} and ${MAX_SHOTS}`);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
if (!req.parameters || typeof req.parameters !== "object" || Array.isArray(req.parameters)) {
|
|
118
|
+
throw new QaaSValidationError("parameters must be a non-null object");
|
|
119
|
+
}
|
|
120
|
+
const serialized = JSON.stringify(req.parameters);
|
|
121
|
+
if (serialized.length > MAX_BODY_SIZE) {
|
|
122
|
+
throw new QaaSValidationError(`parameters exceed max size of ${MAX_BODY_SIZE} bytes`);
|
|
123
|
+
}
|
|
124
|
+
}
|
|
29
125
|
var QaaSClient = class {
|
|
30
126
|
constructor(config = {}) {
|
|
31
|
-
this.baseUrl = config.baseUrl || "https://api.qaas.epochcoreqcs.com";
|
|
127
|
+
this.baseUrl = (config.baseUrl || "https://api.qaas.epochcoreqcs.com").replace(/\/+$/, "");
|
|
32
128
|
this.apiKey = config.apiKey;
|
|
33
|
-
this.
|
|
129
|
+
this.apiSecret = config.apiSecret;
|
|
130
|
+
this.enableSigning = config.enableSigning ?? !!config.apiSecret;
|
|
131
|
+
this.maxRetries = Math.min(Math.max(config.maxRetries ?? MAX_RETRY_ATTEMPTS, 0), 5);
|
|
132
|
+
const raw = config.timeout ?? DEFAULT_TIMEOUT_MS;
|
|
133
|
+
this.timeout = Math.min(Math.max(raw, MIN_TIMEOUT_MS), MAX_TIMEOUT_MS);
|
|
134
|
+
this.rateLimiter = new TokenBucket(
|
|
135
|
+
config.rateBurst ?? DEFAULT_RATE_BURST,
|
|
136
|
+
config.rateLimit ?? DEFAULT_RATE_LIMIT
|
|
137
|
+
);
|
|
34
138
|
}
|
|
35
|
-
async request(path,
|
|
139
|
+
async request(method, path, body) {
|
|
140
|
+
if (!this.rateLimiter.tryConsume()) {
|
|
141
|
+
throw new QaaSRateLimitError("Client-side rate limit exceeded. Wait and retry.");
|
|
142
|
+
}
|
|
143
|
+
if (body && body.length > MAX_BODY_SIZE) {
|
|
144
|
+
throw new QaaSValidationError(`Request body exceeds max size of ${MAX_BODY_SIZE} bytes`);
|
|
145
|
+
}
|
|
146
|
+
const requestId = generateNonce();
|
|
147
|
+
const timestamp = Date.now().toString();
|
|
36
148
|
const headers = {
|
|
37
149
|
"Content-Type": "application/json",
|
|
38
|
-
|
|
150
|
+
"User-Agent": SDK_USER_AGENT,
|
|
151
|
+
"X-Request-Id": requestId,
|
|
152
|
+
"X-Timestamp": timestamp
|
|
39
153
|
};
|
|
40
154
|
if (this.apiKey) {
|
|
41
155
|
headers["X-API-Key"] = this.apiKey;
|
|
42
156
|
}
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
157
|
+
if (this.enableSigning && this.apiSecret) {
|
|
158
|
+
const nonce = generateNonce();
|
|
159
|
+
const sigPayload = [method, path, timestamp, nonce, body || ""].join("\n");
|
|
160
|
+
const signature = await hmacSign(this.apiSecret, sigPayload);
|
|
161
|
+
headers["X-Signature"] = signature;
|
|
162
|
+
headers["X-Nonce"] = nonce;
|
|
163
|
+
}
|
|
164
|
+
let lastError;
|
|
165
|
+
for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
|
|
166
|
+
if (attempt > 0) {
|
|
167
|
+
const delay = RETRY_BASE_MS * Math.pow(2, attempt - 1);
|
|
168
|
+
const jitter = Math.random() * delay * 0.5;
|
|
169
|
+
await new Promise((r) => setTimeout(r, delay + jitter));
|
|
170
|
+
}
|
|
171
|
+
const controller = new AbortController();
|
|
172
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
173
|
+
try {
|
|
174
|
+
const response = await fetch(`${this.baseUrl}${path}`, {
|
|
175
|
+
method,
|
|
176
|
+
headers,
|
|
177
|
+
body: body || void 0,
|
|
178
|
+
signal: controller.signal
|
|
179
|
+
});
|
|
180
|
+
if (response.status === 429 && attempt < this.maxRetries) {
|
|
181
|
+
const retryAfter = response.headers.get("Retry-After");
|
|
182
|
+
if (retryAfter) {
|
|
183
|
+
await new Promise((r) => setTimeout(r, parseInt(retryAfter, 10) * 1e3));
|
|
184
|
+
}
|
|
185
|
+
lastError = new QaaSError("Rate limited by server", 429);
|
|
186
|
+
continue;
|
|
187
|
+
}
|
|
188
|
+
if ([502, 503, 504].includes(response.status) && attempt < this.maxRetries) {
|
|
189
|
+
lastError = new QaaSError(`Server error ${response.status}`, response.status);
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
if (!response.ok) {
|
|
193
|
+
const error = await response.json().catch(() => ({}));
|
|
194
|
+
throw new QaaSError(
|
|
195
|
+
typeof error.error === "string" ? error.error : `Request failed (${response.status})`,
|
|
196
|
+
response.status
|
|
197
|
+
);
|
|
198
|
+
}
|
|
199
|
+
return await response.json();
|
|
200
|
+
} catch (err) {
|
|
201
|
+
if (err instanceof QaaSError) throw err;
|
|
202
|
+
if (err instanceof QaaSValidationError) throw err;
|
|
203
|
+
if (err instanceof DOMException && err.name === "AbortError") {
|
|
204
|
+
lastError = new QaaSError(`Request timed out after ${this.timeout}ms`, 408);
|
|
205
|
+
if (attempt < this.maxRetries) continue;
|
|
206
|
+
throw lastError;
|
|
207
|
+
}
|
|
208
|
+
lastError = new QaaSError(
|
|
209
|
+
err instanceof Error ? err.message : "Network error",
|
|
210
|
+
0
|
|
57
211
|
);
|
|
212
|
+
if (attempt < this.maxRetries) continue;
|
|
213
|
+
} finally {
|
|
214
|
+
clearTimeout(timeoutId);
|
|
58
215
|
}
|
|
59
|
-
return await response.json();
|
|
60
|
-
} finally {
|
|
61
|
-
clearTimeout(timeoutId);
|
|
62
216
|
}
|
|
217
|
+
throw lastError ?? new QaaSError("Request failed after retries", 0);
|
|
63
218
|
}
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
219
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
220
|
+
// API Methods
|
|
221
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
67
222
|
async health() {
|
|
68
|
-
return this.request("/health");
|
|
223
|
+
return this.request("GET", "/health");
|
|
69
224
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Get pricing information for all tiers
|
|
72
|
-
*/
|
|
73
225
|
async getPricing() {
|
|
74
|
-
return this.request("/api/pricing");
|
|
226
|
+
return this.request("GET", "/api/pricing");
|
|
75
227
|
}
|
|
76
|
-
/**
|
|
77
|
-
* Get available algorithms for your tier
|
|
78
|
-
*/
|
|
79
228
|
async getAlgorithms() {
|
|
80
|
-
return this.request("/api/quantum/algorithms");
|
|
229
|
+
return this.request("GET", "/api/quantum/algorithms");
|
|
81
230
|
}
|
|
82
|
-
/**
|
|
83
|
-
* Get algorithms filtered by category
|
|
84
|
-
*/
|
|
85
231
|
async getAlgorithmsByCategory(category) {
|
|
86
232
|
const response = await this.getAlgorithms();
|
|
87
233
|
return response.algorithms.filter((algo) => algo.category === category);
|
|
88
234
|
}
|
|
89
|
-
/**
|
|
90
|
-
* Run a quantum algorithm
|
|
91
|
-
*/
|
|
92
235
|
async runAlgorithm(request) {
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
body: JSON.stringify(request)
|
|
96
|
-
});
|
|
236
|
+
validateRunRequest(request);
|
|
237
|
+
return this.request("POST", "/api/quantum/run", JSON.stringify(request));
|
|
97
238
|
}
|
|
98
|
-
/**
|
|
99
|
-
* Get current usage statistics
|
|
100
|
-
*/
|
|
101
239
|
async getUsage() {
|
|
102
|
-
return this.request("/api/quantum/usage");
|
|
240
|
+
return this.request("GET", "/api/quantum/usage");
|
|
103
241
|
}
|
|
104
|
-
//
|
|
105
|
-
// Convenience methods
|
|
106
|
-
//
|
|
107
|
-
/**
|
|
108
|
-
* Run Markowitz portfolio optimization (QAOA)
|
|
109
|
-
*/
|
|
242
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
243
|
+
// Convenience methods
|
|
244
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
110
245
|
async optimizePortfolio(params) {
|
|
246
|
+
if (!Array.isArray(params.assets) || params.assets.length === 0) {
|
|
247
|
+
throw new QaaSValidationError("assets must be a non-empty array of strings");
|
|
248
|
+
}
|
|
249
|
+
if (params.assets.length !== params.returns.length) {
|
|
250
|
+
throw new QaaSValidationError("assets and returns arrays must have equal length");
|
|
251
|
+
}
|
|
111
252
|
return this.runAlgorithm({
|
|
112
253
|
algorithm_id: "QAOA_PORT_001",
|
|
113
254
|
parameters: {
|
|
@@ -119,24 +260,31 @@ var QaaSClient = class {
|
|
|
119
260
|
backend: params.backend || "simulator"
|
|
120
261
|
});
|
|
121
262
|
}
|
|
122
|
-
/**
|
|
123
|
-
* Run Value at Risk (VaR) estimation
|
|
124
|
-
*/
|
|
125
263
|
async estimateVaR(params) {
|
|
264
|
+
if (typeof params.portfolio_value !== "number" || params.portfolio_value <= 0) {
|
|
265
|
+
throw new QaaSValidationError("portfolio_value must be a positive number");
|
|
266
|
+
}
|
|
267
|
+
if (!Array.isArray(params.returns_history) || params.returns_history.length === 0) {
|
|
268
|
+
throw new QaaSValidationError("returns_history must be a non-empty array");
|
|
269
|
+
}
|
|
270
|
+
const cl = params.confidence_level ?? 0.95;
|
|
271
|
+
if (cl <= 0 || cl >= 1) {
|
|
272
|
+
throw new QaaSValidationError("confidence_level must be between 0 and 1 (exclusive)");
|
|
273
|
+
}
|
|
126
274
|
return this.runAlgorithm({
|
|
127
275
|
algorithm_id: "AE_PROB_004",
|
|
128
276
|
parameters: {
|
|
129
277
|
portfolio_value: params.portfolio_value,
|
|
130
278
|
returns_history: params.returns_history,
|
|
131
|
-
confidence_level:
|
|
279
|
+
confidence_level: cl
|
|
132
280
|
},
|
|
133
281
|
backend: params.backend || "simulator"
|
|
134
282
|
});
|
|
135
283
|
}
|
|
136
|
-
/**
|
|
137
|
-
* Run Grover search for arbitrage opportunities
|
|
138
|
-
*/
|
|
139
284
|
async findArbitrage(params) {
|
|
285
|
+
if (!Array.isArray(params.price_matrix) || params.price_matrix.length === 0) {
|
|
286
|
+
throw new QaaSValidationError("price_matrix must be a non-empty 2D array");
|
|
287
|
+
}
|
|
140
288
|
return this.runAlgorithm({
|
|
141
289
|
algorithm_id: "GROVER_BOOL_003",
|
|
142
290
|
parameters: {
|
|
@@ -146,23 +294,30 @@ var QaaSClient = class {
|
|
|
146
294
|
backend: params.backend || "simulator"
|
|
147
295
|
});
|
|
148
296
|
}
|
|
149
|
-
/**
|
|
150
|
-
* Solve a QUBO problem
|
|
151
|
-
*/
|
|
152
297
|
async solveQUBO(params) {
|
|
298
|
+
if (!Array.isArray(params.Q_matrix) || params.Q_matrix.length === 0) {
|
|
299
|
+
throw new QaaSValidationError("Q_matrix must be a non-empty 2D array");
|
|
300
|
+
}
|
|
301
|
+
const reads = params.num_reads ?? 1e3;
|
|
302
|
+
if (reads < 1 || reads > 1e5) {
|
|
303
|
+
throw new QaaSValidationError("num_reads must be between 1 and 100,000");
|
|
304
|
+
}
|
|
153
305
|
return this.runAlgorithm({
|
|
154
306
|
algorithm_id: "QAOA_QUBO_001",
|
|
155
307
|
parameters: {
|
|
156
308
|
Q: params.Q_matrix,
|
|
157
|
-
num_reads:
|
|
309
|
+
num_reads: reads
|
|
158
310
|
},
|
|
159
311
|
backend: params.backend || "simulator"
|
|
160
312
|
});
|
|
161
313
|
}
|
|
162
|
-
/**
|
|
163
|
-
* Run Monte Carlo amplitude estimation
|
|
164
|
-
*/
|
|
165
314
|
async monteCarloEstimate(params) {
|
|
315
|
+
if (!params.target_function || typeof params.target_function !== "string") {
|
|
316
|
+
throw new QaaSValidationError("target_function is required");
|
|
317
|
+
}
|
|
318
|
+
if (params.target_function.length > 1e4) {
|
|
319
|
+
throw new QaaSValidationError("target_function exceeds max length of 10,000 characters");
|
|
320
|
+
}
|
|
166
321
|
return this.runAlgorithm({
|
|
167
322
|
algorithm_id: "AE_PROB_002",
|
|
168
323
|
parameters: {
|
|
@@ -173,18 +328,132 @@ var QaaSClient = class {
|
|
|
173
328
|
backend: params.backend || "simulator"
|
|
174
329
|
});
|
|
175
330
|
}
|
|
331
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
332
|
+
// Quantum Teleportation (GROT) — via godel-task-router
|
|
333
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
334
|
+
async quantumTeleport(params = {}) {
|
|
335
|
+
return this.request(
|
|
336
|
+
"POST",
|
|
337
|
+
"/v1/quantum/multi-hop/teleport",
|
|
338
|
+
JSON.stringify({
|
|
339
|
+
qubits: params.qubits ?? 8,
|
|
340
|
+
state: params.state ?? "ghz",
|
|
341
|
+
oscillation_cycles: params.oscillation_cycles ?? 3,
|
|
342
|
+
source_backend: params.source_backend,
|
|
343
|
+
destination_backend: params.destination_backend
|
|
344
|
+
})
|
|
345
|
+
);
|
|
346
|
+
}
|
|
347
|
+
async quantumTeleportStatus() {
|
|
348
|
+
return this.request("GET", "/v1/quantum/multi-hop/status");
|
|
349
|
+
}
|
|
350
|
+
async quantumTeleportPlan(params = {}) {
|
|
351
|
+
return this.request(
|
|
352
|
+
"POST",
|
|
353
|
+
"/v1/quantum/multi-hop/plan",
|
|
354
|
+
JSON.stringify({
|
|
355
|
+
qubits: params.qubits ?? 8,
|
|
356
|
+
state: params.state ?? "ghz",
|
|
357
|
+
strategy: params.strategy ?? "combined"
|
|
358
|
+
})
|
|
359
|
+
);
|
|
360
|
+
}
|
|
361
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
362
|
+
// Quantum Random Number Generation (QRNG)
|
|
363
|
+
// ═══════════════════════════════════════════════════════════════════
|
|
364
|
+
/**
|
|
365
|
+
* Generate quantum random bits.
|
|
366
|
+
*
|
|
367
|
+
* @param params.bits - Number of random bits (1–4096, default 256)
|
|
368
|
+
* @param params.format - Output format: 'hex' | 'int' | 'bytes' (default 'hex')
|
|
369
|
+
*/
|
|
370
|
+
async generateQRNG(params = {}) {
|
|
371
|
+
const bits = params.bits ?? 256;
|
|
372
|
+
if (typeof bits !== "number" || !Number.isInteger(bits)) {
|
|
373
|
+
throw new QaaSValidationError("bits must be an integer");
|
|
374
|
+
}
|
|
375
|
+
if (bits < 1 || bits > 4096) {
|
|
376
|
+
throw new QaaSValidationError("bits must be between 1 and 4096");
|
|
377
|
+
}
|
|
378
|
+
const format = params.format ?? "hex";
|
|
379
|
+
if (!["hex", "int", "bytes"].includes(format)) {
|
|
380
|
+
throw new QaaSValidationError("format must be hex, int, or bytes");
|
|
381
|
+
}
|
|
382
|
+
return this.request(
|
|
383
|
+
"POST",
|
|
384
|
+
"/v1/random/generate",
|
|
385
|
+
JSON.stringify({ bits, format })
|
|
386
|
+
);
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* Generate a quantum random number in the range [0, 1).
|
|
390
|
+
* Convenience wrapper over generateQRNG for normalized floats.
|
|
391
|
+
*
|
|
392
|
+
* @param count - How many floats to generate (1–1024, default 1)
|
|
393
|
+
* @returns Array of floats in [0, 1), each derived from 32 quantum bits
|
|
394
|
+
*/
|
|
395
|
+
async generateQuantumFloats(count = 1) {
|
|
396
|
+
if (typeof count !== "number" || !Number.isInteger(count)) {
|
|
397
|
+
throw new QaaSValidationError("count must be an integer");
|
|
398
|
+
}
|
|
399
|
+
if (count < 1 || count > 1024) {
|
|
400
|
+
throw new QaaSValidationError("count must be between 1 and 1024");
|
|
401
|
+
}
|
|
402
|
+
const totalBits = count * 32;
|
|
403
|
+
const response = await this.generateQRNG({ bits: Math.min(totalBits, 4096), format: "bytes" });
|
|
404
|
+
const bytes = response.value;
|
|
405
|
+
const floats = [];
|
|
406
|
+
for (let i = 0; i < count && i * 4 + 3 < bytes.length; i++) {
|
|
407
|
+
const u32 = (bytes[i * 4] << 24 | bytes[i * 4 + 1] << 16 | bytes[i * 4 + 2] << 8 | bytes[i * 4 + 3]) >>> 0;
|
|
408
|
+
floats.push(u32 / 4294967295);
|
|
409
|
+
}
|
|
410
|
+
return floats;
|
|
411
|
+
}
|
|
412
|
+
/**
|
|
413
|
+
* Generate a quantum-random cryptographic key.
|
|
414
|
+
*
|
|
415
|
+
* @param length - Key length in bytes (1–64, default 32)
|
|
416
|
+
*/
|
|
417
|
+
async generateQuantumKey(length = 32) {
|
|
418
|
+
if (typeof length !== "number" || !Number.isInteger(length)) {
|
|
419
|
+
throw new QaaSValidationError("length must be an integer");
|
|
420
|
+
}
|
|
421
|
+
if (length < 1 || length > 64) {
|
|
422
|
+
throw new QaaSValidationError("length must be between 1 and 64");
|
|
423
|
+
}
|
|
424
|
+
return this.request(
|
|
425
|
+
"POST",
|
|
426
|
+
"/v1/random/key",
|
|
427
|
+
JSON.stringify({ length })
|
|
428
|
+
);
|
|
429
|
+
}
|
|
430
|
+
/**
|
|
431
|
+
* Generate a quantum-random UUID v4.
|
|
432
|
+
*/
|
|
433
|
+
async generateQuantumUUID() {
|
|
434
|
+
return this.request("POST", "/v1/random/uuid", "{}");
|
|
435
|
+
}
|
|
176
436
|
};
|
|
177
437
|
var QaaSError = class extends Error {
|
|
178
|
-
constructor(message, statusCode
|
|
438
|
+
constructor(message, statusCode) {
|
|
179
439
|
super(message);
|
|
180
440
|
this.statusCode = statusCode;
|
|
181
|
-
this.response = response;
|
|
182
441
|
this.name = "QaaSError";
|
|
183
442
|
}
|
|
184
443
|
};
|
|
185
|
-
var
|
|
444
|
+
var QaaSValidationError = class extends Error {
|
|
445
|
+
constructor(message) {
|
|
446
|
+
super(message);
|
|
447
|
+
this.name = "QaaSValidationError";
|
|
448
|
+
}
|
|
449
|
+
};
|
|
450
|
+
var QaaSRateLimitError = class extends Error {
|
|
451
|
+
constructor(message) {
|
|
452
|
+
super(message);
|
|
453
|
+
this.name = "QaaSRateLimitError";
|
|
454
|
+
}
|
|
455
|
+
};
|
|
186
456
|
var ALGORITHMS = {
|
|
187
|
-
// Amplitude Estimation
|
|
188
457
|
AMPLITUDE_ESTIMATION: {
|
|
189
458
|
PROB_001: "AE_PROB_001",
|
|
190
459
|
PROB_002: "AE_PROB_002",
|
|
@@ -192,7 +461,6 @@ var ALGORITHMS = {
|
|
|
192
461
|
VAR: "AE_PROB_004",
|
|
193
462
|
CVAR: "AE_PROB_005"
|
|
194
463
|
},
|
|
195
|
-
// Grover Search
|
|
196
464
|
GROVER: {
|
|
197
465
|
BOOLEAN_SAT: "GROVER_BOOL_001",
|
|
198
466
|
PORTFOLIO_CONSTRAINT: "GROVER_BOOL_002",
|
|
@@ -200,7 +468,6 @@ var ALGORITHMS = {
|
|
|
200
468
|
COMPLIANCE: "GROVER_BOOL_004",
|
|
201
469
|
PATTERN: "GROVER_BOOL_005"
|
|
202
470
|
},
|
|
203
|
-
// QAOA Portfolio
|
|
204
471
|
QAOA_PORTFOLIO: {
|
|
205
472
|
MARKOWITZ: "QAOA_PORT_001",
|
|
206
473
|
RISK_PARITY: "QAOA_PORT_002",
|
|
@@ -208,7 +475,6 @@ var ALGORITHMS = {
|
|
|
208
475
|
MIN_VARIANCE: "QAOA_PORT_004",
|
|
209
476
|
BLACK_LITTERMAN: "QAOA_PORT_005"
|
|
210
477
|
},
|
|
211
|
-
// QUBO
|
|
212
478
|
QUBO: {
|
|
213
479
|
GENERAL: "QAOA_QUBO_001",
|
|
214
480
|
MAX_CUT: "QAOA_QUBO_002",
|
|
@@ -222,5 +488,7 @@ var ALGORITHMS = {
|
|
|
222
488
|
ALGORITHMS,
|
|
223
489
|
QaaSClient,
|
|
224
490
|
QaaSError,
|
|
225
|
-
|
|
491
|
+
QaaSRateLimitError,
|
|
492
|
+
QaaSValidationError,
|
|
493
|
+
SIGNATURE_MAX_AGE_MS
|
|
226
494
|
});
|