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
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { randomUUID } from 'node:crypto';
|
|
2
|
-
import { canonicalize, receiptHash, sha256Hex, verifyReceipt } from '../../core/src/index.js';
|
|
2
|
+
import { canonicalize, MerkleSet, receiptHash, sha256Hex, verifyReceipt } from '../../core/src/index.js';
|
|
3
3
|
import {
|
|
4
4
|
createMemoryAccessReceipt,
|
|
5
5
|
createMemoryOptimizationPlan,
|
|
@@ -8,6 +8,50 @@ import {
|
|
|
8
8
|
|
|
9
9
|
const PASSPORT_SCHEMA = 'enigma.passport.v1';
|
|
10
10
|
const CONTEXT_PACK_SCHEMA = 'enigma.context_pack.v1';
|
|
11
|
+
const CONTEXT_PASSPORT_SCHEMA = 'enigma.context_passport.v1';
|
|
12
|
+
const PROOF_OF_NON_USE_SCHEMA = 'enigma.proof_of_non_use.v1';
|
|
13
|
+
const VERIFIED_STATUS = 'verified';
|
|
14
|
+
const FAILED_PROOF_STATUS = 'failed';
|
|
15
|
+
const FAIL_CLOSED_STATUS = 'fail_closed';
|
|
16
|
+
const PROOF_POLICY_DECISIONS = new Set(['allow', 'deny', 'redact', 'quarantine', 'tombstone_only']);
|
|
17
|
+
const PROOF_VERIFIER_STATUSES = new Set([VERIFIED_STATUS, FAILED_PROOF_STATUS, 'inconclusive']);
|
|
18
|
+
const CONTEXT_PASSPORT_FIELDS = Object.freeze([
|
|
19
|
+
'schema',
|
|
20
|
+
'passport_id',
|
|
21
|
+
'issued_at',
|
|
22
|
+
'subject_ref',
|
|
23
|
+
'query_commitment',
|
|
24
|
+
'selected_context_root',
|
|
25
|
+
'omitted_context_root',
|
|
26
|
+
'tombstone_context_root',
|
|
27
|
+
'selected_count',
|
|
28
|
+
'omitted_count',
|
|
29
|
+
'tombstone_count',
|
|
30
|
+
'capability_ids',
|
|
31
|
+
'policy_ids',
|
|
32
|
+
'proof_refs',
|
|
33
|
+
]);
|
|
34
|
+
const PROOF_OF_NON_USE_FIELDS = Object.freeze([
|
|
35
|
+
'schema',
|
|
36
|
+
'proof_id',
|
|
37
|
+
'issued_at',
|
|
38
|
+
'subject_ref',
|
|
39
|
+
'query_commitment',
|
|
40
|
+
'candidate_set_root',
|
|
41
|
+
'selected_set_root',
|
|
42
|
+
'omitted_set_root',
|
|
43
|
+
'tombstone_set_root',
|
|
44
|
+
'candidate_count',
|
|
45
|
+
'selected_count',
|
|
46
|
+
'omitted_count',
|
|
47
|
+
'tombstone_count',
|
|
48
|
+
'policy_id',
|
|
49
|
+
'policy_decision',
|
|
50
|
+
'verifier_status',
|
|
51
|
+
'verifier_ref',
|
|
52
|
+
'receipt_log_root',
|
|
53
|
+
'receipt_refs',
|
|
54
|
+
]);
|
|
11
55
|
const ZERO_ROOT = `sha256:${'0'.repeat(64)}`;
|
|
12
56
|
const ROOT_RE = /^sha256:[a-f0-9]{64}$/;
|
|
13
57
|
const PREVIOUS_RECEIPT_RE = /^(GENESIS|sha256:[a-f0-9]{64})$/;
|
|
@@ -134,12 +178,16 @@ function tokenOverlapScore(queryTokens, memoryTokens) {
|
|
|
134
178
|
}
|
|
135
179
|
|
|
136
180
|
function strictQueryRelevance(args) {
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
181
|
+
if (args.include_unrelated === true || args.includeUnrelated === true) return false;
|
|
182
|
+
if (args.no_strict_relevance === true || args.noStrictRelevance === true) return false;
|
|
183
|
+
if (args.strict_relevance === false || args.strictRelevance === false) return false;
|
|
184
|
+
if (args.require_relevance === false || args.requireRelevance === false) return false;
|
|
185
|
+
if (args.query_relevance === 'fallback' || args.queryRelevance === 'fallback') return false;
|
|
186
|
+
if (args.strict_relevance === true || args.strictRelevance === true) return true;
|
|
187
|
+
if (args.require_relevance === true || args.requireRelevance === true) return true;
|
|
188
|
+
if (args.query_relevance === 'strict' || args.queryRelevance === 'strict') return true;
|
|
189
|
+
const query = typeof args.query === 'string' ? args.query.trim() : String(args.query ?? '').trim();
|
|
190
|
+
return query.length > 0;
|
|
143
191
|
}
|
|
144
192
|
|
|
145
193
|
function relevanceCandidateSet(args, candidates) {
|
|
@@ -578,6 +626,222 @@ function receiptDigest(receipt) {
|
|
|
578
626
|
}
|
|
579
627
|
}
|
|
580
628
|
|
|
629
|
+
function merkleRootFrom(values) {
|
|
630
|
+
return new MerkleSet(sortedRefs(values)).root();
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
function sortedRefs(values) {
|
|
634
|
+
const refs = [];
|
|
635
|
+
for (const value of values ?? []) {
|
|
636
|
+
if (value === undefined || value === null) continue;
|
|
637
|
+
const ref = String(value);
|
|
638
|
+
if (ref.length > 0) refs.push(ref);
|
|
639
|
+
}
|
|
640
|
+
return [...new Set(refs)].sort();
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
function receiptRefsFromReceipts(receipts) {
|
|
644
|
+
const refs = [];
|
|
645
|
+
for (const receipt of receipts ?? []) {
|
|
646
|
+
const digest = typeof receipt === 'string' ? receipt : receiptDigest(publicReceipt(receipt)) ?? receiptDigest(receipt);
|
|
647
|
+
if (typeof digest === 'string' && digest.length > 0) refs.push(digest);
|
|
648
|
+
}
|
|
649
|
+
return sortedRefs(refs);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
function receiptRefsFromContextPack(contextPack) {
|
|
653
|
+
return sortedRefs([
|
|
654
|
+
...(contextPack?.receipt_hashes ?? []),
|
|
655
|
+
...receiptRefsFromReceipts(contextPack?.receipts),
|
|
656
|
+
...receiptRefsFromReceipts(contextPack?.retrieval_receipts),
|
|
657
|
+
...receiptRefsFromReceipts(contextPack?.injection_receipts),
|
|
658
|
+
]);
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
function receiptRefsFromArgs(args, contextPack) {
|
|
662
|
+
return sortedRefs([
|
|
663
|
+
...(args.proof_refs ?? args.proofRefs ?? []),
|
|
664
|
+
...(args.receipt_refs ?? args.receiptRefs ?? []),
|
|
665
|
+
...receiptRefsFromContextPack(contextPack),
|
|
666
|
+
]);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
function hashedRef(prefix, value) {
|
|
670
|
+
return `${prefix}_${sha256Hex(canonical(value)).slice(0, 32)}`;
|
|
671
|
+
}
|
|
672
|
+
|
|
673
|
+
function queryCommitment(args, contextPack) {
|
|
674
|
+
const explicit = args.query_commitment ?? args.queryCommitment;
|
|
675
|
+
if (explicit !== undefined) return String(explicit);
|
|
676
|
+
return `sha256:${sha256Hex(String(args.query ?? contextPack?.query ?? ''))}`;
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
function policyIdsFrom(args, passport, contextPack) {
|
|
680
|
+
const ids = sortedRefs([
|
|
681
|
+
...(args.policy_ids ?? args.policyIds ?? []),
|
|
682
|
+
...(passport?.policies ?? []),
|
|
683
|
+
...((contextPack?.receipts ?? []).map((receipt) => receipt?.policy_id).filter(Boolean)),
|
|
684
|
+
]);
|
|
685
|
+
return ids.length > 0 ? ids : ['local-default'];
|
|
686
|
+
}
|
|
687
|
+
|
|
688
|
+
function capabilityIdsFrom(args) {
|
|
689
|
+
return sortedRefs(args.capability_ids ?? args.capabilityIds ?? ['capability:context-passport']);
|
|
690
|
+
}
|
|
691
|
+
|
|
692
|
+
function explicitRefs(args, snakeKey, camelKey) {
|
|
693
|
+
const refs = args[snakeKey] ?? args[camelKey];
|
|
694
|
+
return refs === undefined ? undefined : sortedRefs(refs);
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function contextPackFromArgs(args) {
|
|
698
|
+
const contextPack = args.contextPack ?? args.context_pack ?? args.pack;
|
|
699
|
+
if (contextPack) return contextPack;
|
|
700
|
+
if (args.vault) return compileContextPack(args);
|
|
701
|
+
return undefined;
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
function contextSelectionSummary(args = {}) {
|
|
705
|
+
const contextPack = args.contextPack ?? args.context_pack ?? args.pack;
|
|
706
|
+
const passport = args.passport;
|
|
707
|
+
const selected = explicitRefs(args, 'selected_context_refs', 'selectedContextRefs')
|
|
708
|
+
?? explicitRefs(args, 'selected_refs', 'selectedRefs')
|
|
709
|
+
?? sortedRefs(memoryAddressesFromPack(contextPack));
|
|
710
|
+
const selectedSet = new Set(selected);
|
|
711
|
+
|
|
712
|
+
const activeRefs = sortedRefs([
|
|
713
|
+
...activeAddressesFrom(args.active_state ?? args.activeState),
|
|
714
|
+
...activeAddressesFrom(args.vault),
|
|
715
|
+
...activeAddressesFrom(passport),
|
|
716
|
+
]);
|
|
717
|
+
const omitted = explicitRefs(args, 'omitted_context_refs', 'omittedContextRefs')
|
|
718
|
+
?? explicitRefs(args, 'omitted_refs', 'omittedRefs')
|
|
719
|
+
?? activeRefs.filter((ref) => !selectedSet.has(ref));
|
|
720
|
+
const tombstone = explicitRefs(args, 'tombstone_context_refs', 'tombstoneContextRefs')
|
|
721
|
+
?? explicitRefs(args, 'tombstone_refs', 'tombstoneRefs')
|
|
722
|
+
?? sortedRefs([
|
|
723
|
+
...tombstoneAddressesFrom(args.tombstones),
|
|
724
|
+
...tombstoneAddressesFrom(args.vault),
|
|
725
|
+
...tombstoneAddressesFrom(passport),
|
|
726
|
+
...(passport?.tombstone_addresses ?? []),
|
|
727
|
+
]);
|
|
728
|
+
|
|
729
|
+
return {
|
|
730
|
+
selected,
|
|
731
|
+
omitted,
|
|
732
|
+
tombstone,
|
|
733
|
+
selected_context_root: merkleRootFrom(selected),
|
|
734
|
+
omitted_context_root: merkleRootFrom(omitted),
|
|
735
|
+
tombstone_context_root: merkleRootFrom(tombstone),
|
|
736
|
+
selected_count: selected.length,
|
|
737
|
+
omitted_count: omitted.length,
|
|
738
|
+
tombstone_count: tombstone.length,
|
|
739
|
+
};
|
|
740
|
+
}
|
|
741
|
+
|
|
742
|
+
function proofSelectionSummary(args = {}) {
|
|
743
|
+
const base = contextSelectionSummary(args);
|
|
744
|
+
const candidate = explicitRefs(args, 'candidate_refs', 'candidateRefs')
|
|
745
|
+
?? sortedRefs([...base.selected, ...base.omitted, ...base.tombstone]);
|
|
746
|
+
return {
|
|
747
|
+
...base,
|
|
748
|
+
candidate,
|
|
749
|
+
candidate_set_root: merkleRootFrom(candidate),
|
|
750
|
+
selected_set_root: merkleRootFrom(base.selected),
|
|
751
|
+
omitted_set_root: merkleRootFrom(base.omitted),
|
|
752
|
+
tombstone_set_root: merkleRootFrom(base.tombstone),
|
|
753
|
+
candidate_count: candidate.length,
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
|
|
757
|
+
function missingBoundaryFields(artifact, requiredFields) {
|
|
758
|
+
const errors = [];
|
|
759
|
+
for (const field of requiredFields) {
|
|
760
|
+
if (artifact?.[field] === undefined || artifact?.[field] === null) errors.push(`missing ${field}`);
|
|
761
|
+
}
|
|
762
|
+
return errors;
|
|
763
|
+
}
|
|
764
|
+
|
|
765
|
+
function validateRootField(artifact, field, errors) {
|
|
766
|
+
if (!ROOT_RE.test(artifact?.[field] ?? '')) errors.push(`invalid ${field}`);
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
function validateCountField(artifact, field, errors) {
|
|
770
|
+
if (!Number.isInteger(artifact?.[field]) || artifact[field] < 0) errors.push(`invalid ${field}`);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
function validateRefArray(artifact, field, errors) {
|
|
774
|
+
const refs = artifact?.[field];
|
|
775
|
+
if (!Array.isArray(refs) || refs.length === 0) {
|
|
776
|
+
errors.push(`missing ${field}`);
|
|
777
|
+
return;
|
|
778
|
+
}
|
|
779
|
+
for (const ref of refs) {
|
|
780
|
+
if (typeof ref !== 'string' || ref.length === 0) errors.push(`invalid ${field}`);
|
|
781
|
+
}
|
|
782
|
+
}
|
|
783
|
+
|
|
784
|
+
function publicBoundaryArtifact(artifact) {
|
|
785
|
+
if (!artifact || typeof artifact !== 'object') return null;
|
|
786
|
+
const fields = artifact.schema === CONTEXT_PASSPORT_SCHEMA
|
|
787
|
+
? CONTEXT_PASSPORT_FIELDS
|
|
788
|
+
: artifact.schema === PROOF_OF_NON_USE_SCHEMA
|
|
789
|
+
? PROOF_OF_NON_USE_FIELDS
|
|
790
|
+
: [];
|
|
791
|
+
if (fields.length === 0) return null;
|
|
792
|
+
const out = {};
|
|
793
|
+
for (const field of fields) {
|
|
794
|
+
if (artifact[field] !== undefined) out[field] = artifact[field];
|
|
795
|
+
}
|
|
796
|
+
return out;
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
|
|
800
|
+
function invalidBoundaryResult(artifact, errors, status = FAIL_CLOSED_STATUS) {
|
|
801
|
+
const publicArtifact = publicBoundaryArtifact(artifact);
|
|
802
|
+
return {
|
|
803
|
+
valid: false,
|
|
804
|
+
verifier_status: status,
|
|
805
|
+
error: errors[0],
|
|
806
|
+
reason: errors[0],
|
|
807
|
+
errors,
|
|
808
|
+
public_artifact: publicArtifact,
|
|
809
|
+
canonical: publicArtifact ? canonical(publicArtifact) : null,
|
|
810
|
+
};
|
|
811
|
+
}
|
|
812
|
+
|
|
813
|
+
function validBoundaryResult(artifact) {
|
|
814
|
+
return {
|
|
815
|
+
valid: true,
|
|
816
|
+
verifier_status: VERIFIED_STATUS,
|
|
817
|
+
public_artifact: artifact,
|
|
818
|
+
canonical: canonical(artifact),
|
|
819
|
+
};
|
|
820
|
+
}
|
|
821
|
+
|
|
822
|
+
function compareRootAndCount(artifact, expected, rootField, countField, expectedRootField, expectedCountField, errors) {
|
|
823
|
+
if (artifact[rootField] !== expected[expectedRootField]) errors.push(`${rootField} mismatch`);
|
|
824
|
+
if (artifact[countField] !== expected[expectedCountField]) errors.push(`${countField} mismatch`);
|
|
825
|
+
}
|
|
826
|
+
|
|
827
|
+
function verifyRequiredReceiptRefs(artifactRefs, expectedRefs, errors, field) {
|
|
828
|
+
if (expectedRefs.length === 0) return;
|
|
829
|
+
const refs = new Set(artifactRefs);
|
|
830
|
+
for (const ref of expectedRefs) {
|
|
831
|
+
if (!refs.has(ref)) errors.push(`missing ${field} receipt ref: ${ref}`);
|
|
832
|
+
}
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
function verifyContextPackWhenTrusted(args, contextPack, errors) {
|
|
836
|
+
if (!contextPack || !trustedKeyOptions(args)) return;
|
|
837
|
+
try {
|
|
838
|
+
const result = verifyContextPack({ ...args, contextPack });
|
|
839
|
+
if (result?.valid !== true) errors.push(`context pack verification failed: ${result?.reason ?? 'invalid'}`);
|
|
840
|
+
} catch (error) {
|
|
841
|
+
errors.push(`context pack verification failed: ${error.message}`);
|
|
842
|
+
}
|
|
843
|
+
}
|
|
844
|
+
|
|
581
845
|
export function createPassport(args = {}) {
|
|
582
846
|
const vault = args.vault;
|
|
583
847
|
const createdAt = nowIso(args.now);
|
|
@@ -775,6 +1039,171 @@ export function verifyContextPack(args = {}) {
|
|
|
775
1039
|
};
|
|
776
1040
|
}
|
|
777
1041
|
|
|
1042
|
+
export function createContextPassport(args = {}) {
|
|
1043
|
+
const contextPack = contextPackFromArgs(args);
|
|
1044
|
+
const passport = args.passport ?? (args.vault ? createPassport({ vault: args.vault, now: args.now }) : undefined);
|
|
1045
|
+
const summary = contextSelectionSummary({ ...args, contextPack, passport });
|
|
1046
|
+
const proofRefs = receiptRefsFromArgs(args, contextPack);
|
|
1047
|
+
if (proofRefs.length === 0) throw new Error('createContextPassport requires proof_refs or context pack receipts');
|
|
1048
|
+
return {
|
|
1049
|
+
schema: CONTEXT_PASSPORT_SCHEMA,
|
|
1050
|
+
passport_id: args.passport_id ?? args.passportId ?? contextPack?.passport_id ?? passport?.passport_id ?? `context_passport_${randomUUID()}`,
|
|
1051
|
+
issued_at: nowIso(args.now),
|
|
1052
|
+
subject_ref: args.subject_ref ?? args.subjectRef ?? hashedRef('subject', passport?.owner?.subject_id ?? args.vault?.subject_id ?? contextPack?.passport_id ?? 'local-subject'),
|
|
1053
|
+
query_commitment: queryCommitment(args, contextPack),
|
|
1054
|
+
selected_context_root: summary.selected_context_root,
|
|
1055
|
+
omitted_context_root: summary.omitted_context_root,
|
|
1056
|
+
tombstone_context_root: summary.tombstone_context_root,
|
|
1057
|
+
selected_count: summary.selected_count,
|
|
1058
|
+
omitted_count: summary.omitted_count,
|
|
1059
|
+
tombstone_count: summary.tombstone_count,
|
|
1060
|
+
capability_ids: capabilityIdsFrom(args),
|
|
1061
|
+
policy_ids: policyIdsFrom(args, passport, contextPack),
|
|
1062
|
+
proof_refs: proofRefs,
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
export function verifyContextPassport(args = {}) {
|
|
1067
|
+
const contextPassport = args.schema === CONTEXT_PASSPORT_SCHEMA ? args : (args.contextPassport ?? args.context_passport ?? args.passportArtifact ?? args.artifact);
|
|
1068
|
+
if (!contextPassport || contextPassport.schema !== CONTEXT_PASSPORT_SCHEMA) {
|
|
1069
|
+
return invalidBoundaryResult(contextPassport, ['verifyContextPassport requires an enigma.context_passport.v1 artifact']);
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
const errors = missingBoundaryFields(contextPassport, [
|
|
1073
|
+
'schema',
|
|
1074
|
+
'passport_id',
|
|
1075
|
+
'issued_at',
|
|
1076
|
+
'subject_ref',
|
|
1077
|
+
'query_commitment',
|
|
1078
|
+
'selected_context_root',
|
|
1079
|
+
'omitted_context_root',
|
|
1080
|
+
'tombstone_context_root',
|
|
1081
|
+
'selected_count',
|
|
1082
|
+
'omitted_count',
|
|
1083
|
+
'tombstone_count',
|
|
1084
|
+
'capability_ids',
|
|
1085
|
+
'policy_ids',
|
|
1086
|
+
'proof_refs',
|
|
1087
|
+
]);
|
|
1088
|
+
validateRootField(contextPassport, 'query_commitment', errors);
|
|
1089
|
+
validateRootField(contextPassport, 'selected_context_root', errors);
|
|
1090
|
+
validateRootField(contextPassport, 'omitted_context_root', errors);
|
|
1091
|
+
validateRootField(contextPassport, 'tombstone_context_root', errors);
|
|
1092
|
+
validateCountField(contextPassport, 'selected_count', errors);
|
|
1093
|
+
validateCountField(contextPassport, 'omitted_count', errors);
|
|
1094
|
+
validateCountField(contextPassport, 'tombstone_count', errors);
|
|
1095
|
+
validateRefArray(contextPassport, 'capability_ids', errors);
|
|
1096
|
+
validateRefArray(contextPassport, 'policy_ids', errors);
|
|
1097
|
+
validateRefArray(contextPassport, 'proof_refs', errors);
|
|
1098
|
+
|
|
1099
|
+
const contextPack = args.contextPack ?? args.context_pack ?? args.pack;
|
|
1100
|
+
if (contextPack || args.vault || args.passport || args.active_state || args.activeState || args.tombstones) {
|
|
1101
|
+
const expected = contextSelectionSummary({ ...args, contextPack });
|
|
1102
|
+
compareRootAndCount(contextPassport, expected, 'selected_context_root', 'selected_count', 'selected_context_root', 'selected_count', errors);
|
|
1103
|
+
compareRootAndCount(contextPassport, expected, 'omitted_context_root', 'omitted_count', 'omitted_context_root', 'omitted_count', errors);
|
|
1104
|
+
compareRootAndCount(contextPassport, expected, 'tombstone_context_root', 'tombstone_count', 'tombstone_context_root', 'tombstone_count', errors);
|
|
1105
|
+
}
|
|
1106
|
+
|
|
1107
|
+
verifyContextPackWhenTrusted(args, contextPack, errors);
|
|
1108
|
+
verifyRequiredReceiptRefs(contextPassport.proof_refs ?? [], receiptRefsFromContextPack(contextPack), errors, 'proof_refs');
|
|
1109
|
+
if (errors.length > 0) return invalidBoundaryResult(contextPassport, errors);
|
|
1110
|
+
return validBoundaryResult(contextPassport);
|
|
1111
|
+
}
|
|
1112
|
+
|
|
1113
|
+
export function createProofOfNonUse(args = {}) {
|
|
1114
|
+
const contextPack = contextPackFromArgs(args);
|
|
1115
|
+
const passport = args.passport ?? (args.vault ? createPassport({ vault: args.vault, now: args.now }) : undefined);
|
|
1116
|
+
const roots = rootsFromVault(args.vault);
|
|
1117
|
+
const receiptLogRoot = args.receipt_log_root ?? args.receiptLogRoot ?? contextPack?.receipt_log_root ?? roots.receipt_log_root;
|
|
1118
|
+
const policyId = args.policy_id ?? args.policyId ?? contextPack?.receipts?.find((receipt) => receipt?.policy_id)?.policy_id ?? passport?.policies?.[0] ?? args.vault?.policy_id ?? 'local-default';
|
|
1119
|
+
const policyDecision = args.policy_decision ?? args.policyDecision ?? 'allow';
|
|
1120
|
+
const verifierRef = args.verifier_ref ?? args.verifierRef ?? hashedRef('verifier', { schema: PROOF_OF_NON_USE_SCHEMA, policy_id: policyId });
|
|
1121
|
+
if (!PROOF_POLICY_DECISIONS.has(policyDecision)) throw new Error('createProofOfNonUse policy_decision must be allow, deny, redact, quarantine, or tombstone_only');
|
|
1122
|
+
const summary = proofSelectionSummary({ ...args, contextPack, passport });
|
|
1123
|
+
const receiptRefs = receiptRefsFromArgs(args, contextPack);
|
|
1124
|
+
if (receiptRefs.length === 0) throw new Error('createProofOfNonUse requires receipt_refs or context pack receipts');
|
|
1125
|
+
return {
|
|
1126
|
+
schema: PROOF_OF_NON_USE_SCHEMA,
|
|
1127
|
+
proof_id: args.proof_id ?? args.proofId ?? `proof_non_use_${randomUUID()}`,
|
|
1128
|
+
issued_at: nowIso(args.now),
|
|
1129
|
+
subject_ref: args.subject_ref ?? args.subjectRef ?? hashedRef('subject', passport?.owner?.subject_id ?? args.vault?.subject_id ?? contextPack?.passport_id ?? 'local-subject'),
|
|
1130
|
+
query_commitment: queryCommitment(args, contextPack),
|
|
1131
|
+
candidate_set_root: summary.candidate_set_root,
|
|
1132
|
+
selected_set_root: summary.selected_set_root,
|
|
1133
|
+
omitted_set_root: summary.omitted_set_root,
|
|
1134
|
+
tombstone_set_root: summary.tombstone_set_root,
|
|
1135
|
+
candidate_count: summary.candidate_count,
|
|
1136
|
+
selected_count: summary.selected_count,
|
|
1137
|
+
omitted_count: summary.omitted_count,
|
|
1138
|
+
tombstone_count: summary.tombstone_count,
|
|
1139
|
+
policy_id: String(policyId),
|
|
1140
|
+
policy_decision: policyDecision,
|
|
1141
|
+
verifier_status: VERIFIED_STATUS,
|
|
1142
|
+
verifier_ref: verifierRef,
|
|
1143
|
+
receipt_log_root: receiptLogRoot,
|
|
1144
|
+
receipt_refs: receiptRefs,
|
|
1145
|
+
};
|
|
1146
|
+
}
|
|
1147
|
+
|
|
1148
|
+
export function verifyProofOfNonUse(args = {}) {
|
|
1149
|
+
const proof = args.schema === PROOF_OF_NON_USE_SCHEMA ? args : (args.proofOfNonUse ?? args.proof_of_non_use ?? args.proof ?? args.artifact);
|
|
1150
|
+
if (!proof || proof.schema !== PROOF_OF_NON_USE_SCHEMA) {
|
|
1151
|
+
return invalidBoundaryResult(proof, ['verifyProofOfNonUse requires an enigma.proof_of_non_use.v1 artifact']);
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
const errors = missingBoundaryFields(proof, [
|
|
1155
|
+
'schema',
|
|
1156
|
+
'proof_id',
|
|
1157
|
+
'issued_at',
|
|
1158
|
+
'subject_ref',
|
|
1159
|
+
'query_commitment',
|
|
1160
|
+
'candidate_set_root',
|
|
1161
|
+
'selected_set_root',
|
|
1162
|
+
'omitted_set_root',
|
|
1163
|
+
'tombstone_set_root',
|
|
1164
|
+
'candidate_count',
|
|
1165
|
+
'selected_count',
|
|
1166
|
+
'omitted_count',
|
|
1167
|
+
'tombstone_count',
|
|
1168
|
+
'policy_id',
|
|
1169
|
+
'policy_decision',
|
|
1170
|
+
'verifier_status',
|
|
1171
|
+
'verifier_ref',
|
|
1172
|
+
'receipt_log_root',
|
|
1173
|
+
'receipt_refs',
|
|
1174
|
+
]);
|
|
1175
|
+
validateRootField(proof, 'query_commitment', errors);
|
|
1176
|
+
validateRootField(proof, 'candidate_set_root', errors);
|
|
1177
|
+
validateRootField(proof, 'selected_set_root', errors);
|
|
1178
|
+
validateRootField(proof, 'omitted_set_root', errors);
|
|
1179
|
+
validateRootField(proof, 'tombstone_set_root', errors);
|
|
1180
|
+
validateCountField(proof, 'candidate_count', errors);
|
|
1181
|
+
validateCountField(proof, 'selected_count', errors);
|
|
1182
|
+
validateCountField(proof, 'omitted_count', errors);
|
|
1183
|
+
validateCountField(proof, 'tombstone_count', errors);
|
|
1184
|
+
if (typeof proof.policy_id !== 'string' || proof.policy_id.length === 0) errors.push('invalid policy_id');
|
|
1185
|
+
if (!PROOF_POLICY_DECISIONS.has(proof.policy_decision)) errors.push('invalid policy_decision');
|
|
1186
|
+
if (!PROOF_VERIFIER_STATUSES.has(proof.verifier_status)) errors.push('invalid verifier_status');
|
|
1187
|
+
if (typeof proof.verifier_ref !== 'string' || proof.verifier_ref.length === 0) errors.push('invalid verifier_ref');
|
|
1188
|
+
validateRootField(proof, 'receipt_log_root', errors);
|
|
1189
|
+
validateRefArray(proof, 'receipt_refs', errors);
|
|
1190
|
+
|
|
1191
|
+
const contextPack = args.contextPack ?? args.context_pack ?? args.pack;
|
|
1192
|
+
if (contextPack || args.vault || args.passport || args.active_state || args.activeState || args.tombstones || args.candidate_refs || args.candidateRefs) {
|
|
1193
|
+
const expected = proofSelectionSummary({ ...args, contextPack });
|
|
1194
|
+
compareRootAndCount(proof, expected, 'candidate_set_root', 'candidate_count', 'candidate_set_root', 'candidate_count', errors);
|
|
1195
|
+
compareRootAndCount(proof, expected, 'selected_set_root', 'selected_count', 'selected_set_root', 'selected_count', errors);
|
|
1196
|
+
compareRootAndCount(proof, expected, 'omitted_set_root', 'omitted_count', 'omitted_set_root', 'omitted_count', errors);
|
|
1197
|
+
compareRootAndCount(proof, expected, 'tombstone_set_root', 'tombstone_count', 'tombstone_set_root', 'tombstone_count', errors);
|
|
1198
|
+
}
|
|
1199
|
+
|
|
1200
|
+
if (contextPack && proof.receipt_log_root !== contextPack.receipt_log_root) errors.push('receipt_log_root mismatch');
|
|
1201
|
+
verifyContextPackWhenTrusted(args, contextPack, errors);
|
|
1202
|
+
verifyRequiredReceiptRefs(proof.receipt_refs ?? [], receiptRefsFromContextPack(contextPack), errors, 'receipt_refs');
|
|
1203
|
+
if (errors.length > 0) return invalidBoundaryResult({ ...proof, verifier_status: FAILED_PROOF_STATUS }, errors);
|
|
1204
|
+
return validBoundaryResult({ ...proof, verifier_status: VERIFIED_STATUS });
|
|
1205
|
+
}
|
|
1206
|
+
|
|
778
1207
|
|
|
779
1208
|
const MEMORY_DRIVE_HEALTH_SCHEMA = 'enigma.memory_drive_health_report.v1';
|
|
780
1209
|
const DEFAULT_HEALTH_NOW = '2026-06-25T00:00:00.000Z';
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
const MAX_BODY_BYTES = 16 * 1024;
|
|
2
|
+
|
|
3
|
+
class CreditsHttpError extends Error {
|
|
4
|
+
constructor(status, code, message) {
|
|
5
|
+
super(message);
|
|
6
|
+
this.name = 'CreditsHttpError';
|
|
7
|
+
this.status = status;
|
|
8
|
+
this.code = code;
|
|
9
|
+
}
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function json(response, status, payload) {
|
|
13
|
+
const body = JSON.stringify(payload);
|
|
14
|
+
response.statusCode = status;
|
|
15
|
+
response.setHeader('Cache-Control', 'no-store');
|
|
16
|
+
response.setHeader('Content-Type', 'application/json; charset=utf-8');
|
|
17
|
+
response.setHeader('Content-Length', Buffer.byteLength(body));
|
|
18
|
+
response.setHeader('Referrer-Policy', 'no-referrer');
|
|
19
|
+
response.setHeader('X-Content-Type-Options', 'nosniff');
|
|
20
|
+
response.end(body);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function body(request) {
|
|
24
|
+
const type = String(request.headers['content-type'] || '').split(';', 1)[0].trim().toLowerCase();
|
|
25
|
+
if (type !== 'application/json') throw new CreditsHttpError(415, 'unsupported_media_type', 'Content-Type must be application/json');
|
|
26
|
+
const chunks = [];
|
|
27
|
+
let size = 0;
|
|
28
|
+
let tooLarge = false;
|
|
29
|
+
for await (const chunk of request) {
|
|
30
|
+
size += chunk.length;
|
|
31
|
+
if (size > MAX_BODY_BYTES) tooLarge = true;
|
|
32
|
+
else chunks.push(chunk);
|
|
33
|
+
}
|
|
34
|
+
if (tooLarge) throw new CreditsHttpError(413, 'payload_too_large', 'request body exceeds 16 KiB');
|
|
35
|
+
try {
|
|
36
|
+
const parsed = JSON.parse(Buffer.concat(chunks, size).toString('utf8') || '{}');
|
|
37
|
+
if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) throw new Error();
|
|
38
|
+
return parsed;
|
|
39
|
+
} catch {
|
|
40
|
+
throw new CreditsHttpError(400, 'invalid_json', 'request body must be a JSON object');
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
function bearer(request) {
|
|
45
|
+
const value = String(request.headers.authorization || '');
|
|
46
|
+
return value.startsWith('Bearer enigma_cv_') ? value.slice(7) : null;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export function createPrivateCreditsHttpHandler(options = {}) {
|
|
50
|
+
const credits = options.credits;
|
|
51
|
+
if (!credits || typeof credits.create !== 'function' || typeof credits.recover !== 'function') throw new TypeError('private credits service is required');
|
|
52
|
+
if (typeof options.authorizeCreation !== 'function') throw new TypeError('authorizeCreation is required to rate-limit anonymous vault creation');
|
|
53
|
+
if (typeof options.admitRecovery !== 'function') throw new TypeError('admitRecovery is required to rate-limit recovery attempts');
|
|
54
|
+
const basePath = String(options.basePath || '/v1/credits').replace(/\/+$/, '');
|
|
55
|
+
|
|
56
|
+
return async function privateCreditsHttpHandler(request, response) {
|
|
57
|
+
const url = new URL(request.url || '/', 'http://localhost');
|
|
58
|
+
if (url.pathname !== basePath && !url.pathname.startsWith(`${basePath}/`)) return false;
|
|
59
|
+
try {
|
|
60
|
+
if (request.method === 'POST' && url.pathname === `${basePath}/vaults`) {
|
|
61
|
+
const admitted = await options.authorizeCreation({ request, headers: request.headers });
|
|
62
|
+
if (!admitted) throw new CreditsHttpError(429, 'creation_not_admitted', 'private credits vault creation is not admitted');
|
|
63
|
+
json(response, 201, await credits.create());
|
|
64
|
+
return true;
|
|
65
|
+
}
|
|
66
|
+
if (request.method === 'POST' && url.pathname === `${basePath}/recover`) {
|
|
67
|
+
const admitted = await options.admitRecovery({ request, headers: request.headers });
|
|
68
|
+
if (!admitted) throw new CreditsHttpError(429, 'recovery_rate_limited', 'private credits recovery is rate limited');
|
|
69
|
+
const input = await body(request);
|
|
70
|
+
if (Object.keys(input).some((key) => key !== 'recoveryCode')) throw new CreditsHttpError(400, 'invalid_request', 'recoveryCode is the only accepted field');
|
|
71
|
+
const recovered = await credits.recover(input.recoveryCode);
|
|
72
|
+
if (!recovered) throw new CreditsHttpError(401, 'invalid_recovery_code', 'recovery code is invalid or has already been rotated');
|
|
73
|
+
json(response, 200, recovered);
|
|
74
|
+
return true;
|
|
75
|
+
}
|
|
76
|
+
if (request.method === 'GET' && url.pathname === basePath) {
|
|
77
|
+
const vault = await credits.status(bearer(request));
|
|
78
|
+
if (!vault) throw new CreditsHttpError(401, 'invalid_credits_session', 'private credits access token is invalid or expired');
|
|
79
|
+
json(response, 200, { vault });
|
|
80
|
+
return true;
|
|
81
|
+
}
|
|
82
|
+
if (request.method === 'DELETE' && url.pathname === `${basePath}/session`) {
|
|
83
|
+
const revoked = await credits.logout(bearer(request));
|
|
84
|
+
if (!revoked) throw new CreditsHttpError(401, 'invalid_credits_session', 'private credits access token is invalid or expired');
|
|
85
|
+
response.statusCode = 204;
|
|
86
|
+
response.setHeader('Cache-Control', 'no-store');
|
|
87
|
+
response.end();
|
|
88
|
+
return true;
|
|
89
|
+
}
|
|
90
|
+
throw new CreditsHttpError(404, 'not_found', 'private credits endpoint not found');
|
|
91
|
+
} catch (error) {
|
|
92
|
+
const normalized = error instanceof CreditsHttpError
|
|
93
|
+
? error
|
|
94
|
+
: new CreditsHttpError(error instanceof TypeError ? 400 : 500, error instanceof TypeError ? 'invalid_request' : 'credits_error', error.message || 'private credits operation failed');
|
|
95
|
+
if (normalized.status === 401) response.setHeader('WWW-Authenticate', 'Bearer');
|
|
96
|
+
json(response, normalized.status, { error: { code: normalized.code, message: normalized.message } });
|
|
97
|
+
return true;
|
|
98
|
+
}
|
|
99
|
+
};
|
|
100
|
+
}
|