enigma-memory 0.1.17 → 0.1.22
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 +85 -27
- package/apps/cli/bin/enigma-desktop.mjs +140 -0
- package/apps/cli/bin/enigma-terminal.mjs +78 -0
- package/apps/cli/bin/enigma.mjs +4979 -3263
- package/apps/desktop/electron-main.cjs +217 -0
- package/apps/desktop/package.json +12 -0
- package/apps/desktop/src/app.js +264 -7
- package/apps/desktop/src/index.html +3514 -1373
- package/apps/desktop/src/launch-electron.mjs +51 -0
- package/apps/desktop/src/server.mjs +2914 -0
- package/apps/desktop/src/styles.css +2972 -260
- package/apps/desktop/src/zk-browser-prove.mjs +53 -0
- package/apps/desktop/src/zk-state.mjs +1789 -0
- package/apps/gateway/bin/enigma-gateway.mjs +102 -5
- package/apps/gateway/src/server.mjs +271 -8
- package/apps/ios/EnigmaCore/Package.swift +12 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
- package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
- package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
- package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
- package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
- package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
- package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
- package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
- package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
- package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
- package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
- package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
- package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
- package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
- package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
- package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
- package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
- package/apps/native-host/README.md +19 -8
- package/apps/native-host/bin/enigma-native-host.mjs +229 -13
- package/apps/relay/bin/enigma-relay.mjs +103 -5
- package/apps/relay/src/federation-runtime.mjs +618 -0
- package/apps/relay/src/server.mjs +310 -9
- package/apps/verifier/bin/enigma-verify.mjs +327 -11
- package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
- package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
- package/cortex-v3/circuits/build/vk_bytes.json +32 -0
- package/cortex-v3/proving-assets.json +64 -0
- package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
- package/cortex-v3/zk/action-transition-vk.json +119 -0
- package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
- package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
- package/cortex-v3/zk/intent-witness.mjs +365 -0
- package/cortex-v3/zk/intent-witness.test.mjs +485 -0
- package/cortex-v3/zk/proving-assets.mjs +203 -0
- package/cortex-v3/zk/sale-witness.mjs +783 -0
- package/cortex-v3/zk/sale-witness.test.mjs +784 -0
- package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
- package/cortex-v3/zk/settlement-evidence.mjs +722 -0
- package/cortex-v3/zk/setup-intent.mjs +688 -0
- package/cortex-v3/zk/setup-sale.mjs +666 -0
- package/cortex-v3/zk/setup.mjs +594 -0
- package/cortex-v3/zk/witness.mjs +184 -0
- package/cortex-v3/zk/zk-codec.mjs +232 -0
- package/cortex-v3/zk/zk-codec.test.mjs +293 -0
- package/cortex-v3/zk/zk-settle.mjs +370 -0
- package/cortex-v3/zk/zk-tree.mjs +256 -0
- package/cortex-v3/zk/zk-tree.test.mjs +419 -0
- package/deploy/SIMULATION.md +14 -9
- package/deploy/docker-compose.local-production-simulation.yml +54 -12
- package/docs/benchmark-attestation-network.md +487 -487
- package/docs/benchmark-reproducibility.md +289 -289
- package/docs/blockchain-only-mechanisms.md +400 -400
- package/docs/browser-extension-install.md +8 -6
- package/docs/client-connectors.md +16 -12
- package/docs/demo-proof-network.md +275 -275
- package/docs/developer-ecosystem.md +15 -13
- package/docs/developer-proof-quickstart.md +325 -325
- package/docs/enigma-memory-ready-conformance.md +378 -376
- package/docs/install-anywhere.md +64 -30
- package/docs/installers-and-desktop.md +8 -7
- package/docs/memory-benchmarks.md +1 -1
- package/docs/memory-drive-health-model.md +690 -690
- package/docs/novelty-invention-candidates.md +161 -161
- package/docs/proof-network-build-notes.md +240 -240
- package/docs/proof-network-claim-boundaries.md +320 -318
- package/docs/proof-network.md +339 -339
- package/docs/sdk-api.md +324 -324
- package/docs/solana-proof-rail.md +453 -453
- package/examples/01-quickstart-agent/index.mjs +49 -0
- package/examples/01_agent_memory_quickstart.mjs +57 -0
- package/examples/02-multi-agent-swarm/index.mjs +57 -0
- package/examples/02_cross_model_passport.mjs +64 -0
- package/examples/03-langchain-memory/index.mjs +41 -0
- package/examples/03_poseidon_commitment_verification.mjs +71 -0
- package/examples/04-python-trading-agent/trader.py +49 -0
- package/examples/README.md +27 -0
- package/examples/ci/github-actions.yml +7 -2
- package/package.json +410 -278
- package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
- package/packages/connectors/src/index.js +196 -4
- package/packages/connectors/swarm-router.mjs +168 -0
- package/packages/core/src/index.js +249 -2
- package/packages/core/src/version.mjs +7 -0
- package/packages/dev-tools/package.json +19 -0
- package/packages/dev-tools/src/index.js +4 -0
- package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
- package/packages/dev-tools/src/swarm-simulator.js +101 -0
- package/packages/dev-tools/src/vault-inspector.js +114 -0
- package/packages/dev-tools/src/vector-benchmark.js +100 -0
- package/packages/developer-platform/src/access-credentials.js +341 -0
- package/packages/developer-platform/src/http.js +132 -0
- package/packages/developer-platform/src/index.js +4 -0
- package/packages/developer-platform/src/usage-http.js +60 -0
- package/packages/developer-platform/src/usage.js +295 -0
- package/packages/enclave-runtime/attestation.mjs +159 -0
- package/packages/enclave-runtime/index.mjs +47 -0
- package/packages/enclave-runtime/session-manager.mjs +253 -0
- package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
- package/packages/enigma-reflex/package.json +14 -0
- package/packages/enigma-reflex/src/index.js +204 -0
- package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
- package/packages/enigma-reflex/training/requirements.txt +8 -0
- package/packages/enigma-reflex/training/train.py +314 -0
- package/packages/enigma-weave/LICENSE +22 -0
- package/packages/enigma-weave/UPSTREAM.json +21 -0
- package/packages/enigma-weave/package.json +14 -0
- package/packages/enigma-weave/src/index.js +286 -0
- package/packages/hosted-cloud/src/index.js +80 -5
- package/packages/importers/src/index.js +432 -0
- package/packages/inference-runtime/src/browser.js +401 -0
- package/packages/inference-runtime/src/chat.js +265 -0
- package/packages/inference-runtime/src/code.js +407 -0
- package/packages/inference-runtime/src/contracts.js +162 -0
- package/packages/inference-runtime/src/http.js +232 -0
- package/packages/inference-runtime/src/image.js +186 -0
- package/packages/inference-runtime/src/index.js +10 -0
- package/packages/inference-runtime/src/model-router.js +320 -0
- package/packages/inference-runtime/src/platform.js +125 -0
- package/packages/inference-runtime/src/privacy.js +400 -0
- package/packages/inference-runtime/src/video.js +253 -0
- package/packages/mcp-server/README.md +22 -6
- package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
- package/packages/mcp-server/src/index.js +2498 -1185
- package/packages/mcp-server/src/oauth.js +561 -0
- package/packages/mcp-server/src/private-handoff.js +84 -0
- package/packages/mcp-server/src/remote-http.js +273 -0
- package/packages/mcp-server/src/remote-policy.js +72 -0
- package/packages/mcp-server/swarm-bridge.mjs +361 -0
- package/packages/mesh/index.d.ts +283 -0
- package/packages/mesh/package.json +23 -0
- package/packages/mesh/src/crypto.js +189 -0
- package/packages/mesh/src/federation-packets.js +353 -0
- package/packages/mesh/src/gossip.js +311 -0
- package/packages/mesh/src/index.js +6 -0
- package/packages/mesh/src/protocol.js +255 -0
- package/packages/mesh/src/router.js +279 -0
- package/packages/mesh/src/transport.js +306 -0
- package/packages/passport/src/index.js +436 -7
- package/packages/private-economy/src/credits-http.js +100 -0
- package/packages/private-economy/src/credits.js +447 -0
- package/packages/private-economy/src/index.js +5 -0
- package/packages/private-economy/src/payments-http.js +120 -0
- package/packages/private-economy/src/payments.js +509 -0
- package/packages/private-economy/src/x402.js +346 -0
- package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
- package/packages/rag/index.d.ts +182 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
- package/packages/rag/package.json +27 -0
- package/packages/rag/src/blinded-search.js +109 -0
- package/packages/rag/src/bm25.js +169 -0
- package/packages/rag/src/embeddings.js +459 -0
- package/packages/rag/src/hybrid.js +76 -0
- package/packages/rag/src/index.js +38 -0
- package/packages/rag/src/reranker.js +61 -0
- package/packages/rag/src/research.js +107 -0
- package/packages/rag/src/vector-store.js +430 -0
- package/packages/rag/src/verify-model-artifacts.mjs +4 -0
- package/packages/sdk/index.d.ts +760 -0
- package/packages/sdk/package.json +33 -0
- package/packages/sdk/python/README.md +24 -0
- package/packages/sdk/python/enigma_sdk.py +250 -0
- package/packages/sdk/python/pyproject.toml +34 -0
- package/packages/sdk/python/requirements.txt +1 -0
- package/packages/sdk/python/setup.py +20 -0
- package/packages/sdk/src/federation/capability-grant.js +389 -0
- package/packages/sdk/src/federation/federation-router.js +360 -0
- package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
- package/packages/sdk/src/federation/index.js +3 -0
- package/packages/sdk/src/index.js +1796 -0
- package/packages/sdk/src/intelligence/contradiction.js +337 -0
- package/packages/sdk/src/intelligence/decision-engine.js +155 -0
- package/packages/sdk/src/intelligence/index.js +4 -0
- package/packages/sdk/src/intelligence/ontology.js +122 -0
- package/packages/sdk/src/intelligence/temporal.js +123 -0
- package/packages/sdk/src/market-client.js +142 -0
- package/packages/sdk/src/mesh-client.js +110 -0
- package/packages/sdk/src/middleware/index.js +3 -0
- package/packages/sdk/src/middleware/langchain.js +159 -0
- package/packages/sdk/src/middleware/llamaindex.js +101 -0
- package/packages/sdk/src/middleware/vercel-ai.js +112 -0
- package/packages/sdk/src/rag-client.js +85 -0
- package/packages/sdk/src/swarm-orchestrator.js +260 -0
- package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
- package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
- package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
- package/packages/snapcompact/index.d.ts +284 -0
- package/packages/snapcompact/package.json +25 -0
- package/packages/snapcompact/src/index.js +716 -0
- package/packages/storage/PACKAGE_CONTRACT.md +1 -1
- package/packages/terminal-console/animations.mjs +240 -0
- package/packages/terminal-console/auto-anchor.mjs +220 -0
- package/packages/terminal-console/banner.mjs +91 -0
- package/packages/terminal-console/commands.mjs +459 -0
- package/packages/terminal-console/delegation.mjs +152 -0
- package/packages/terminal-console/index.mjs +5 -0
- package/packages/terminal-console/outbox.mjs +143 -0
- package/packages/terminal-console/phantom-bridge.mjs +637 -0
- package/packages/terminal-console/repl.mjs +136 -0
- package/packages/terminal-console/signer-store.mjs +130 -0
- package/packages/terminal-console/solana-rpc.mjs +214 -0
- package/packages/terminal-console/solana-transport.mjs +189 -0
- package/packages/terminal-tui/dashboard.mjs +214 -0
- package/packages/terminal-tui/index.mjs +28 -0
- package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
- package/packages/terminal-tui/telemetry-hud.mjs +137 -0
- package/packages/vault/index.d.ts +449 -0
- package/packages/vault/package.json +27 -0
- package/packages/vault/src/e2ee.mjs +393 -0
- package/packages/vault/src/enclave.js +481 -0
- package/packages/vault/src/erasure.js +207 -0
- package/packages/vault/src/index.js +1150 -125
- package/packages/vault/src/persistence.js +307 -0
- package/packages/vault/src/poseidon.js +354 -0
- package/packages/vault/src/receipt.js +459 -0
- package/scripts/benchmark-optical-context.mjs +166 -0
- package/scripts/bootstrap-enigma.mjs +502 -0
- package/scripts/build-edge-backend-workers.mjs +20 -5
- package/scripts/build-goal-completion-audit.mjs +72 -25
- package/scripts/build-hosted-api-key-lifecycle.mjs +292 -274
- package/scripts/build-hosted-customer-lifecycle.mjs +493 -476
- package/scripts/build-hosted-probe-worker.mjs +19 -4
- package/scripts/build-installer-assets.mjs +409 -389
- package/scripts/build-operator-evidence-starter.mjs +59 -1
- package/scripts/build-production-backend-env-kit.mjs +2 -0
- package/scripts/build-production-unblocker.mjs +4 -1
- package/scripts/build-proof-network-packet.mjs +213 -213
- package/scripts/check.mjs +25 -4
- package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
- package/scripts/install-enigma-local.mjs +18 -5
- package/scripts/release-audit.mjs +74 -115
- package/scripts/release-provenance.mjs +12 -2
- package/scripts/run-backend-readiness-smoke.mjs +112 -10
- package/scripts/run-standard-memory-benchmarks.mjs +1354 -1352
- package/scripts/scan-secrets.mjs +178 -0
- package/scripts/simulate-production-env.mjs +71 -10
- package/scripts/validate-hosted-backend-live.mjs +112 -1
- package/specs/antibody-pack-v1.schema.json +95 -0
- package/specs/antigen-envelope-v1.schema.json +81 -0
- package/specs/boundary-manifest-v1.schema.json +35 -35
- package/specs/capsule-v1.schema.json +55 -55
- package/specs/claim-boundary-manifest-v1.schema.json +22 -22
- package/specs/claim-ledger-v1.schema.json +291 -0
- package/specs/context-passport-v1.schema.json +59 -0
- package/specs/deletion-tombstone-v1.schema.json +26 -26
- package/specs/evidence-packet-v1.schema.json +177 -0
- package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
- package/specs/immune-scan-report-v1.schema.json +112 -0
- package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
- package/specs/memory-atom-v1.schema.json +59 -0
- package/specs/memory-event-v1.schema.json +42 -42
- package/specs/passport-v1.schema.json +50 -50
- package/specs/proof-of-non-use-v1.schema.json +65 -0
- package/specs/quarantine-record-v1.schema.json +126 -0
- package/specs/receipt-v1.schema.json +61 -61
- package/specs/state-checkpoint-v1.schema.json +37 -37
- package/specs/trust-bundle-v1.schema.json +56 -56
- package/specs/trust-card-v1.schema.json +119 -0
- package/docs/proof-network-launch-plan.md +0 -421
- package/packages/metering/PACKAGE_CONTRACT.md +0 -20
- package/scripts/build-ai-orchestration-plan.mjs +0 -248
|
@@ -0,0 +1,295 @@
|
|
|
1
|
+
import { AsyncLocalStorage } from 'node:async_hooks';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { mkdir, open, readFile, rename } from 'node:fs/promises';
|
|
4
|
+
import { dirname, resolve } from 'node:path';
|
|
5
|
+
|
|
6
|
+
export const ENIGMA_USAGE_STORE_SCHEMA = 'enigma.platform_usage_store.v1';
|
|
7
|
+
export const ENIGMA_USAGE_EVENT_SCHEMA = 'enigma.platform_usage_event.v1';
|
|
8
|
+
export const ENIGMA_USAGE_AGGREGATE_SCHEMA = 'enigma.platform_usage_aggregate.v1';
|
|
9
|
+
const MODALITY_UNITS = Object.freeze({ text: 'tokens', image: 'images', video: 'videos', code: 'executions', browser: 'sessions' });
|
|
10
|
+
const USAGE_INPUT_FIELDS = new Set([
|
|
11
|
+
'modality', 'operation', 'provider', 'model', 'inputTokens', 'inputUnits', 'outputTokens', 'outputUnits',
|
|
12
|
+
'totalTokens', 'units', 'durationMs', 'promptRef', 'routeReceiptId', 'occurredAt',
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
function requiredString(value, name, maximum = 512) {
|
|
16
|
+
if (typeof value !== 'string' || !value.trim()) throw new TypeError(`${name} is required`);
|
|
17
|
+
const normalized = value.trim();
|
|
18
|
+
if (normalized.length > maximum) throw new TypeError(`${name} exceeds ${maximum} characters`);
|
|
19
|
+
return normalized;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
function nonNegativeInteger(value, name, fallback = 0) {
|
|
23
|
+
const resolved = value === undefined ? fallback : value;
|
|
24
|
+
if (!Number.isSafeInteger(resolved) || resolved < 0) throw new TypeError(`${name} must be a non-negative integer`);
|
|
25
|
+
return resolved;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function boundedInteger(value, name, minimum, maximum, fallback) {
|
|
29
|
+
const resolved = value === undefined ? fallback : value;
|
|
30
|
+
if (!Number.isInteger(resolved) || resolved < minimum || resolved > maximum) throw new TypeError(`${name} must be from ${minimum} through ${maximum}`);
|
|
31
|
+
return resolved;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
function timestamp(value, name) {
|
|
35
|
+
const milliseconds = value === undefined ? Date.now() : typeof value === 'number' ? value : Date.parse(value);
|
|
36
|
+
if (!Number.isFinite(milliseconds)) throw new TypeError(`${name} must be an ISO timestamp or epoch milliseconds`);
|
|
37
|
+
return milliseconds;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
function emptyState() {
|
|
41
|
+
return { schema: ENIGMA_USAGE_STORE_SCHEMA, revision: 0, events: {} };
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function normalizePrincipal(value = {}) {
|
|
45
|
+
return {
|
|
46
|
+
ownerId: requiredString(value.ownerId || value.subject, 'usage ownerId'),
|
|
47
|
+
tenantId: requiredString(value.tenantId || value.tenant_id || 'default', 'usage tenantId'),
|
|
48
|
+
keyId: value.keyId ? requiredString(value.keyId, 'usage keyId') : null,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
function eventPublicView(event) {
|
|
53
|
+
return {
|
|
54
|
+
schema: event.schema,
|
|
55
|
+
id: event.id,
|
|
56
|
+
tenantId: event.tenantId,
|
|
57
|
+
ownerId: event.ownerId,
|
|
58
|
+
keyId: event.keyId,
|
|
59
|
+
modality: event.modality,
|
|
60
|
+
operation: event.operation,
|
|
61
|
+
provider: event.provider,
|
|
62
|
+
model: event.model,
|
|
63
|
+
unit: event.unit,
|
|
64
|
+
inputUnits: event.inputUnits,
|
|
65
|
+
outputUnits: event.outputUnits,
|
|
66
|
+
units: event.units,
|
|
67
|
+
estimatedCostMicrousd: event.estimatedCostMicrousd,
|
|
68
|
+
priced: event.estimatedCostMicrousd !== null,
|
|
69
|
+
occurredAt: event.occurredAt,
|
|
70
|
+
receiptRef: event.receiptRef,
|
|
71
|
+
};
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
function createStoreAdapter(load, save, { clock, retentionMs, maxEvents }) {
|
|
75
|
+
let queue = Promise.resolve();
|
|
76
|
+
const transaction = (operation) => {
|
|
77
|
+
const run = queue.then(async () => {
|
|
78
|
+
const state = await load();
|
|
79
|
+
const cutoff = clock() - retentionMs;
|
|
80
|
+
for (const [id, event] of Object.entries(state.events)) {
|
|
81
|
+
if (Date.parse(event.occurredAt) < cutoff) delete state.events[id];
|
|
82
|
+
}
|
|
83
|
+
const result = await operation(state);
|
|
84
|
+
const ordered = Object.values(state.events).sort((a, b) => a.occurredAt.localeCompare(b.occurredAt));
|
|
85
|
+
for (let index = 0; index < ordered.length - maxEvents; index += 1) delete state.events[ordered[index].id];
|
|
86
|
+
state.revision += 1;
|
|
87
|
+
await save(state);
|
|
88
|
+
return result;
|
|
89
|
+
});
|
|
90
|
+
queue = run.catch(() => undefined);
|
|
91
|
+
return run;
|
|
92
|
+
};
|
|
93
|
+
const view = async (operation) => {
|
|
94
|
+
await queue;
|
|
95
|
+
return operation(await load());
|
|
96
|
+
};
|
|
97
|
+
return Object.freeze({
|
|
98
|
+
async append(event) {
|
|
99
|
+
return transaction((state) => {
|
|
100
|
+
if (state.events[event.id]) return { inserted: false, event: structuredClone(state.events[event.id]) };
|
|
101
|
+
state.events[event.id] = structuredClone(event);
|
|
102
|
+
return { inserted: true, event: structuredClone(event) };
|
|
103
|
+
});
|
|
104
|
+
},
|
|
105
|
+
async query({ ownerId, tenantId, from, to, limit }) {
|
|
106
|
+
return transaction((state) => Object.values(state.events)
|
|
107
|
+
.filter((event) => event.ownerId === ownerId && event.tenantId === tenantId)
|
|
108
|
+
.filter((event) => {
|
|
109
|
+
const at = Date.parse(event.occurredAt);
|
|
110
|
+
return at >= from && at < to;
|
|
111
|
+
})
|
|
112
|
+
.sort((a, b) => b.occurredAt.localeCompare(a.occurredAt))
|
|
113
|
+
.slice(0, limit)
|
|
114
|
+
.map((event) => structuredClone(event)));
|
|
115
|
+
},
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export function createEphemeralUsageStore(options = {}) {
|
|
120
|
+
const clock = options.clock || Date.now;
|
|
121
|
+
const retentionMs = boundedInteger(options.retentionDays, 'retentionDays', 1, 3660, 400) * 24 * 60 * 60_000;
|
|
122
|
+
const maxEvents = boundedInteger(options.maxEvents, 'maxEvents', 100, 10_000_000, 100_000);
|
|
123
|
+
let state = emptyState();
|
|
124
|
+
return createStoreAdapter(async () => structuredClone(state), async (next) => { state = structuredClone(next); }, { clock, retentionMs, maxEvents });
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
export function createFileUsageStore(options = {}) {
|
|
128
|
+
const path = resolve(String(options.path || '.enigma/usage.json'));
|
|
129
|
+
const clock = options.clock || Date.now;
|
|
130
|
+
const retentionMs = boundedInteger(options.retentionDays, 'retentionDays', 1, 3660, 400) * 24 * 60 * 60_000;
|
|
131
|
+
const maxEvents = boundedInteger(options.maxEvents, 'maxEvents', 100, 10_000_000, 100_000);
|
|
132
|
+
async function load() {
|
|
133
|
+
try {
|
|
134
|
+
const state = JSON.parse(await readFile(path, 'utf8'));
|
|
135
|
+
if (state?.schema !== ENIGMA_USAGE_STORE_SCHEMA) throw new Error('unsupported usage store schema');
|
|
136
|
+
return state;
|
|
137
|
+
} catch (error) {
|
|
138
|
+
if (error.code === 'ENOENT') return emptyState();
|
|
139
|
+
throw error;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
async function save(state) {
|
|
143
|
+
await mkdir(dirname(path), { recursive: true, mode: 0o700 });
|
|
144
|
+
const temporary = `${path}.${process.pid}.${randomUUID()}.tmp`;
|
|
145
|
+
const handle = await open(temporary, 'wx', 0o600);
|
|
146
|
+
try {
|
|
147
|
+
await handle.writeFile(JSON.stringify(state));
|
|
148
|
+
await handle.sync();
|
|
149
|
+
} finally {
|
|
150
|
+
await handle.close();
|
|
151
|
+
}
|
|
152
|
+
await rename(temporary, path);
|
|
153
|
+
}
|
|
154
|
+
return createStoreAdapter(load, save, { clock, retentionMs, maxEvents });
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
function pricingCostMicrousd(input, pricing) {
|
|
158
|
+
if (!pricing) return null;
|
|
159
|
+
if (input.modality === 'text') {
|
|
160
|
+
if (!Number.isFinite(pricing.inputPerMillionMicrousd) || !Number.isFinite(pricing.outputPerMillionMicrousd)) return null;
|
|
161
|
+
return Math.round((input.inputUnits / 1_000_000) * pricing.inputPerMillionMicrousd
|
|
162
|
+
+ (input.outputUnits / 1_000_000) * pricing.outputPerMillionMicrousd);
|
|
163
|
+
}
|
|
164
|
+
if (!Number.isFinite(pricing.perUnitMicrousd)) return null;
|
|
165
|
+
return Math.round(input.units * pricing.perUnitMicrousd);
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function aggregateBucket(target, event) {
|
|
169
|
+
target.eventCount += 1;
|
|
170
|
+
target.inputUnits += event.inputUnits;
|
|
171
|
+
target.outputUnits += event.outputUnits;
|
|
172
|
+
target.units += event.units;
|
|
173
|
+
if (event.estimatedCostMicrousd === null) target.unpricedEvents += 1;
|
|
174
|
+
else target.knownCostMicrousd += event.estimatedCostMicrousd;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
function emptyAggregateBucket(fields = {}) {
|
|
178
|
+
return { ...fields, eventCount: 0, inputUnits: 0, outputUnits: 0, units: 0, knownCostMicrousd: 0, unpricedEvents: 0 };
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export function aggregatePlatformUsage(events, identity, { from, to } = {}) {
|
|
182
|
+
const totals = emptyAggregateBucket({ currency: 'USD' });
|
|
183
|
+
const byDay = new Map();
|
|
184
|
+
const byModel = new Map();
|
|
185
|
+
const byModality = new Map();
|
|
186
|
+
for (const event of events) {
|
|
187
|
+
aggregateBucket(totals, event);
|
|
188
|
+
const day = event.occurredAt.slice(0, 10);
|
|
189
|
+
if (!byDay.has(day)) byDay.set(day, emptyAggregateBucket({ day }));
|
|
190
|
+
aggregateBucket(byDay.get(day), event);
|
|
191
|
+
const modelKey = `${event.provider}\0${event.model}`;
|
|
192
|
+
if (!byModel.has(modelKey)) byModel.set(modelKey, emptyAggregateBucket({ provider: event.provider, model: event.model }));
|
|
193
|
+
aggregateBucket(byModel.get(modelKey), event);
|
|
194
|
+
if (!byModality.has(event.modality)) byModality.set(event.modality, emptyAggregateBucket({ modality: event.modality, unit: event.unit }));
|
|
195
|
+
aggregateBucket(byModality.get(event.modality), event);
|
|
196
|
+
}
|
|
197
|
+
return {
|
|
198
|
+
schema: ENIGMA_USAGE_AGGREGATE_SCHEMA,
|
|
199
|
+
generatedAt: new Date().toISOString(),
|
|
200
|
+
tenantId: identity.tenantId,
|
|
201
|
+
ownerId: identity.ownerId,
|
|
202
|
+
period: { from: new Date(from).toISOString(), to: new Date(to).toISOString() },
|
|
203
|
+
totals,
|
|
204
|
+
byDay: [...byDay.values()].sort((a, b) => a.day.localeCompare(b.day)),
|
|
205
|
+
byModel: [...byModel.values()].sort((a, b) => (a.provider + a.model).localeCompare(b.provider + b.model)),
|
|
206
|
+
byModality: [...byModality.values()].sort((a, b) => a.modality.localeCompare(b.modality)),
|
|
207
|
+
costBoundary: totals.unpricedEvents
|
|
208
|
+
? 'knownCostMicrousd excludes unpriced events and is not a complete invoice total'
|
|
209
|
+
: 'knownCostMicrousd is an estimate from configured operator pricing, not a provider invoice',
|
|
210
|
+
contentStored: false,
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export function createUsageService(options = {}) {
|
|
215
|
+
const store = options.store;
|
|
216
|
+
if (!store || typeof store.append !== 'function' || typeof store.query !== 'function') throw new TypeError('usage store is required');
|
|
217
|
+
const clock = options.clock || Date.now;
|
|
218
|
+
const context = new AsyncLocalStorage();
|
|
219
|
+
const defaultPrincipal = options.defaultPrincipal ? normalizePrincipal(options.defaultPrincipal) : null;
|
|
220
|
+
const pricing = options.pricing || {};
|
|
221
|
+
const maxQueryEvents = boundedInteger(options.maxQueryEvents, 'maxQueryEvents', 100, 1_000_000, 100_000);
|
|
222
|
+
|
|
223
|
+
function currentPrincipal(explicit) {
|
|
224
|
+
if (explicit) return normalizePrincipal(explicit);
|
|
225
|
+
const active = context.getStore()?.principal;
|
|
226
|
+
return active ? normalizePrincipal(active) : defaultPrincipal;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return Object.freeze({
|
|
230
|
+
run(requestContext, operation) {
|
|
231
|
+
if (typeof operation !== 'function') throw new TypeError('usage.run requires an operation');
|
|
232
|
+
return context.run({ principal: requestContext?.principal || null }, operation);
|
|
233
|
+
},
|
|
234
|
+
setPrincipal(principal) {
|
|
235
|
+
const active = context.getStore();
|
|
236
|
+
if (!active) return false;
|
|
237
|
+
active.principal = principal;
|
|
238
|
+
return true;
|
|
239
|
+
},
|
|
240
|
+
async record(input = {}, explicitPrincipal = null) {
|
|
241
|
+
const principal = currentPrincipal(explicitPrincipal);
|
|
242
|
+
if (!principal) throw new Error('usage event has no authenticated principal');
|
|
243
|
+
const modality = requiredString(input.modality, 'usage modality', 32);
|
|
244
|
+
if (!Object.hasOwn(MODALITY_UNITS, modality)) throw new TypeError('unsupported usage modality');
|
|
245
|
+
const inputUnits = nonNegativeInteger(input.inputTokens ?? input.inputUnits, 'input units');
|
|
246
|
+
const outputUnits = nonNegativeInteger(input.outputTokens ?? input.outputUnits, 'output units');
|
|
247
|
+
const units = nonNegativeInteger(input.units, 'units', modality === 'text' ? inputUnits + outputUnits : 1);
|
|
248
|
+
const provider = requiredString(input.provider || 'unknown', 'usage provider', 160);
|
|
249
|
+
const model = requiredString(input.model || 'unknown', 'usage model', 160);
|
|
250
|
+
const occurredAt = new Date(input.occurredAt ? timestamp(input.occurredAt, 'occurredAt') : clock()).toISOString();
|
|
251
|
+
const pricingRule = pricing[`${provider}/${model}`] || pricing[model] || pricing[modality] || null;
|
|
252
|
+
const normalized = { modality, inputUnits, outputUnits, units };
|
|
253
|
+
const forbiddenField = Object.keys(input).find((key) => !USAGE_INPUT_FIELDS.has(key));
|
|
254
|
+
if (forbiddenField) throw new TypeError(`usage input field ${forbiddenField} is not allowed`);
|
|
255
|
+
const event = {
|
|
256
|
+
schema: ENIGMA_USAGE_EVENT_SCHEMA,
|
|
257
|
+
id: randomUUID(),
|
|
258
|
+
tenantId: principal.tenantId,
|
|
259
|
+
ownerId: principal.ownerId,
|
|
260
|
+
keyId: principal.keyId,
|
|
261
|
+
modality,
|
|
262
|
+
operation: requiredString(input.operation || `${modality}.generate`, 'usage operation', 160),
|
|
263
|
+
provider,
|
|
264
|
+
model,
|
|
265
|
+
unit: MODALITY_UNITS[modality],
|
|
266
|
+
inputUnits,
|
|
267
|
+
outputUnits,
|
|
268
|
+
units,
|
|
269
|
+
estimatedCostMicrousd: pricingCostMicrousd(normalized, pricingRule),
|
|
270
|
+
occurredAt,
|
|
271
|
+
receiptRef: input.routeReceiptId ? requiredString(input.routeReceiptId, 'receiptRef', 512) : null,
|
|
272
|
+
};
|
|
273
|
+
const stored = await store.append(event);
|
|
274
|
+
return eventPublicView(stored.event);
|
|
275
|
+
},
|
|
276
|
+
async events(input = {}) {
|
|
277
|
+
const identity = currentPrincipal(input.principal || input);
|
|
278
|
+
if (!identity) throw new Error('usage query has no authenticated principal');
|
|
279
|
+
const to = input.to === undefined ? clock() + 1 : timestamp(input.to, 'to');
|
|
280
|
+
const from = input.from === undefined ? to - 30 * 24 * 60 * 60_000 : timestamp(input.from, 'from');
|
|
281
|
+
if (from >= to) throw new TypeError('usage from must be before to');
|
|
282
|
+
const limit = boundedInteger(input.limit, 'limit', 1, maxQueryEvents, Math.min(1000, maxQueryEvents));
|
|
283
|
+
return (await store.query({ ...identity, from, to, limit })).map(eventPublicView);
|
|
284
|
+
},
|
|
285
|
+
async aggregate(input = {}) {
|
|
286
|
+
const identity = currentPrincipal(input.principal || input);
|
|
287
|
+
if (!identity) throw new Error('usage aggregate has no authenticated principal');
|
|
288
|
+
const to = input.to === undefined ? clock() + 1 : timestamp(input.to, 'to');
|
|
289
|
+
const from = input.from === undefined ? to - 30 * 24 * 60 * 60_000 : timestamp(input.from, 'from');
|
|
290
|
+
if (from >= to) throw new TypeError('usage from must be before to');
|
|
291
|
+
const events = await store.query({ ...identity, from, to, limit: maxQueryEvents });
|
|
292
|
+
return aggregatePlatformUsage(events, identity, { from, to });
|
|
293
|
+
},
|
|
294
|
+
});
|
|
295
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { createHash, timingSafeEqual } from 'node:crypto';
|
|
2
|
+
|
|
3
|
+
const PCR_ZERO = Buffer.alloc(32);
|
|
4
|
+
const HEX_256 = /^[a-f0-9]{64}$/;
|
|
5
|
+
|
|
6
|
+
export const ENCLAVE_RUNTIME_MEASUREMENT = 'enigma-memory:enclave-runtime:v1';
|
|
7
|
+
export const ZEROIZATION_POLICY_MEASUREMENT = 'best-effort-volatile-buffer:random-ff-zero:three-pass:v1';
|
|
8
|
+
|
|
9
|
+
export function canonicalJson(value) {
|
|
10
|
+
if (value === null || typeof value !== 'object') return JSON.stringify(value);
|
|
11
|
+
if (Array.isArray(value)) return `[${value.map((item) => canonicalJson(item)).join(',')}]`;
|
|
12
|
+
return `{${Object.keys(value).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(value[key])}`).join(',')}}`;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function sha256Hex(value) {
|
|
16
|
+
const input = Buffer.isBuffer(value) || value instanceof Uint8Array
|
|
17
|
+
? value
|
|
18
|
+
: Buffer.from(typeof value === 'string' ? value : canonicalJson(value));
|
|
19
|
+
return createHash('sha256').update(input).digest('hex');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export function extendPcr(currentDigest, measurement) {
|
|
23
|
+
const current = currentDigest == null
|
|
24
|
+
? PCR_ZERO
|
|
25
|
+
: Buffer.from(String(currentDigest).replace(/^sha256:/, ''), 'hex');
|
|
26
|
+
if (current.length !== 32) throw new TypeError('PCR digest must be a 32-byte SHA-256 value.');
|
|
27
|
+
const measured = Buffer.from(String(measurement).replace(/^sha256:/, ''), 'hex');
|
|
28
|
+
if (measured.length !== 32) throw new TypeError('Measurement must be a 32-byte SHA-256 value.');
|
|
29
|
+
return sha256Hex(Buffer.concat([current, measured]));
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
function measurePcr(input) {
|
|
33
|
+
return extendPcr(null, sha256Hex(input));
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export function createAttestation({
|
|
37
|
+
bundle,
|
|
38
|
+
bundleHash,
|
|
39
|
+
nonce,
|
|
40
|
+
now = new Date().toISOString(),
|
|
41
|
+
runtimeMeasurement = ENCLAVE_RUNTIME_MEASUREMENT,
|
|
42
|
+
policyMeasurement = ZEROIZATION_POLICY_MEASUREMENT,
|
|
43
|
+
platform = `${process.platform}:${process.arch}:node-${process.versions.node.split('.')[0]}`,
|
|
44
|
+
} = {}) {
|
|
45
|
+
const resolvedBundleHash = bundleHash
|
|
46
|
+
? String(bundleHash).replace(/^sha256:/, '').toLowerCase()
|
|
47
|
+
: bundle === undefined
|
|
48
|
+
? sha256Hex('no-bundle')
|
|
49
|
+
: sha256Hex(bundle);
|
|
50
|
+
if (!HEX_256.test(resolvedBundleHash)) throw new TypeError('bundleHash must be a SHA-256 digest.');
|
|
51
|
+
|
|
52
|
+
const pcrs = {
|
|
53
|
+
'0': measurePcr(runtimeMeasurement),
|
|
54
|
+
'1': measurePcr(policyMeasurement),
|
|
55
|
+
'2': measurePcr(platform),
|
|
56
|
+
'3': extendPcr(null, resolvedBundleHash),
|
|
57
|
+
};
|
|
58
|
+
const measurementHash = sha256Hex({ pcrs, runtimeMeasurement, policyMeasurement });
|
|
59
|
+
|
|
60
|
+
return {
|
|
61
|
+
schema: 'enigma.enclave.attestation.v1',
|
|
62
|
+
mode: 'simulated',
|
|
63
|
+
provider: 'enigma-local-pcr-simulator',
|
|
64
|
+
measured_at: now,
|
|
65
|
+
nonce: nonce ?? null,
|
|
66
|
+
runtime_measurement: runtimeMeasurement,
|
|
67
|
+
zeroization_policy_measurement: policyMeasurement,
|
|
68
|
+
platform_measurement: platform,
|
|
69
|
+
bundle_commitment: `sha256:${resolvedBundleHash}`,
|
|
70
|
+
pcr_bank: 'sha256',
|
|
71
|
+
pcrs,
|
|
72
|
+
measurement_hash: `sha256:${measurementHash}`,
|
|
73
|
+
claim_boundary: {
|
|
74
|
+
hardware_backed: false,
|
|
75
|
+
pcr_registers_simulated: true,
|
|
76
|
+
buffer_overwrite_best_effort: true,
|
|
77
|
+
hardware_ram_zeroization_proved: false,
|
|
78
|
+
runtime_copies_gc_caches_in_scope: false,
|
|
79
|
+
physical_media_sanitization_claimed: false,
|
|
80
|
+
},
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function verifyAttestation(attestation, { expectedBundleHash, expectedMeasurementHash } = {}) {
|
|
85
|
+
const errors = [];
|
|
86
|
+
if (!attestation || typeof attestation !== 'object') {
|
|
87
|
+
return { valid: false, errors: ['ATTESTATION_REQUIRED'] };
|
|
88
|
+
}
|
|
89
|
+
if (attestation.schema !== 'enigma.enclave.attestation.v1') errors.push('INVALID_SCHEMA');
|
|
90
|
+
if (attestation.mode !== 'simulated') errors.push('UNSUPPORTED_ATTESTATION_MODE');
|
|
91
|
+
if (attestation.pcr_bank !== 'sha256') errors.push('UNSUPPORTED_PCR_BANK');
|
|
92
|
+
|
|
93
|
+
const runtimeMeasurement = attestation.runtime_measurement;
|
|
94
|
+
const policyMeasurement = attestation.zeroization_policy_measurement;
|
|
95
|
+
const platformMeasurement = attestation.platform_measurement;
|
|
96
|
+
const bundleDigest = String(attestation.bundle_commitment ?? '').replace(/^sha256:/, '');
|
|
97
|
+
const declarationsValid = typeof runtimeMeasurement === 'string' && runtimeMeasurement.length > 0
|
|
98
|
+
&& typeof policyMeasurement === 'string' && policyMeasurement.length > 0
|
|
99
|
+
&& typeof platformMeasurement === 'string' && platformMeasurement.length > 0
|
|
100
|
+
&& HEX_256.test(bundleDigest);
|
|
101
|
+
if (!declarationsValid) errors.push('INVALID_MEASUREMENT_DECLARATION');
|
|
102
|
+
|
|
103
|
+
const suppliedPcrs = attestation.pcrs;
|
|
104
|
+
const suppliedBankValid = suppliedPcrs
|
|
105
|
+
&& ['0', '1', '2', '3'].every((index) => HEX_256.test(String(suppliedPcrs[index] ?? '')));
|
|
106
|
+
if (!suppliedBankValid) errors.push('INVALID_PCR_BANK');
|
|
107
|
+
|
|
108
|
+
let computedMeasurementHash;
|
|
109
|
+
if (declarationsValid) {
|
|
110
|
+
const expectedPcrs = {
|
|
111
|
+
'0': measurePcr(runtimeMeasurement),
|
|
112
|
+
'1': measurePcr(policyMeasurement),
|
|
113
|
+
'2': measurePcr(platformMeasurement),
|
|
114
|
+
'3': extendPcr(null, bundleDigest),
|
|
115
|
+
};
|
|
116
|
+
if (suppliedBankValid) {
|
|
117
|
+
for (const index of ['0', '1', '2', '3']) {
|
|
118
|
+
if (!safeStringEqual(expectedPcrs[index], suppliedPcrs[index])) errors.push(`PCR_${index}_MISMATCH`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
computedMeasurementHash = `sha256:${sha256Hex({
|
|
122
|
+
pcrs: expectedPcrs,
|
|
123
|
+
runtimeMeasurement,
|
|
124
|
+
policyMeasurement,
|
|
125
|
+
})}`;
|
|
126
|
+
if (!safeStringEqual(computedMeasurementHash, attestation.measurement_hash)) errors.push('MEASUREMENT_HASH_MISMATCH');
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
if (expectedBundleHash) {
|
|
130
|
+
const normalizedExpected = String(expectedBundleHash).replace(/^sha256:/, '').toLowerCase();
|
|
131
|
+
if (!HEX_256.test(normalizedExpected)
|
|
132
|
+
|| !safeStringEqual(`sha256:${normalizedExpected}`, attestation.bundle_commitment)) {
|
|
133
|
+
errors.push('BUNDLE_COMMITMENT_MISMATCH');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
if (expectedMeasurementHash
|
|
137
|
+
&& !safeStringEqual(expectedMeasurementHash, computedMeasurementHash ?? attestation.measurement_hash)) {
|
|
138
|
+
errors.push('UNEXPECTED_MEASUREMENT');
|
|
139
|
+
}
|
|
140
|
+
const boundary = attestation.claim_boundary;
|
|
141
|
+
if (boundary?.hardware_backed !== false
|
|
142
|
+
|| boundary?.pcr_registers_simulated !== true
|
|
143
|
+
|| boundary?.hardware_ram_zeroization_proved !== false
|
|
144
|
+
|| boundary?.runtime_copies_gc_caches_in_scope !== false) {
|
|
145
|
+
errors.push('INVALID_CLAIM_BOUNDARY');
|
|
146
|
+
}
|
|
147
|
+
return {
|
|
148
|
+
valid: errors.length === 0,
|
|
149
|
+
errors,
|
|
150
|
+
measurement_hash: computedMeasurementHash ?? attestation.measurement_hash,
|
|
151
|
+
bundle_commitment: attestation.bundle_commitment,
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function safeStringEqual(left, right) {
|
|
156
|
+
const a = Buffer.from(String(left ?? ''));
|
|
157
|
+
const b = Buffer.from(String(right ?? ''));
|
|
158
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
159
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export {
|
|
2
|
+
ENCLAVE_RUNTIME_MEASUREMENT,
|
|
3
|
+
ZEROIZATION_POLICY_MEASUREMENT,
|
|
4
|
+
canonicalJson,
|
|
5
|
+
createAttestation,
|
|
6
|
+
extendPcr,
|
|
7
|
+
sha256Hex,
|
|
8
|
+
verifyAttestation,
|
|
9
|
+
} from './attestation.mjs';
|
|
10
|
+
|
|
11
|
+
export {
|
|
12
|
+
merkleRoot,
|
|
13
|
+
createZeroizationReceipt,
|
|
14
|
+
verifyZeroizationReceipt,
|
|
15
|
+
verifyStateNullification,
|
|
16
|
+
} from './zeroization-proof.mjs';
|
|
17
|
+
|
|
18
|
+
export {
|
|
19
|
+
VOLATILE_OVERWRITE_PROFILE,
|
|
20
|
+
EnclaveSessionManager,
|
|
21
|
+
SessionManager,
|
|
22
|
+
defaultSessionManager,
|
|
23
|
+
buffersEqual,
|
|
24
|
+
generateEphemeralSessionKey,
|
|
25
|
+
isZeroFilled,
|
|
26
|
+
overwriteVolatileBuffer,
|
|
27
|
+
zeroizeBuffer,
|
|
28
|
+
} from './session-manager.mjs';
|
|
29
|
+
|
|
30
|
+
import { createAttestation } from './attestation.mjs';
|
|
31
|
+
import { defaultSessionManager } from './session-manager.mjs';
|
|
32
|
+
|
|
33
|
+
export function initializeEnclaveSession(options) {
|
|
34
|
+
return defaultSessionManager.initializeSession(options);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function deriveEnclaveSessionKey(sessionId, purpose, options) {
|
|
38
|
+
return defaultSessionManager.deriveSessionKey(sessionId, purpose, options);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export function zeroizeEnclaveSession(sessionId, options) {
|
|
42
|
+
return defaultSessionManager.zeroizeSession(sessionId, options);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function attestEnclave(options) {
|
|
46
|
+
return createAttestation(options);
|
|
47
|
+
}
|