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
|
@@ -16,6 +16,37 @@ const ED25519 = 'Ed25519';
|
|
|
16
16
|
const GENESIS = 'GENESIS';
|
|
17
17
|
const ROOT_RE = /^sha256:[a-f0-9]{64}$/;
|
|
18
18
|
const HASH_RE = /^[a-f0-9]{64}$/;
|
|
19
|
+
const NULLIFIER_RE = /^nullifier:hmac-sha256:[a-f0-9]{64}$/;
|
|
20
|
+
const SECRET_VALUE_RE = /(?:-----BEGIN [A-Z ]*PRIVATE KEY-----|(?:sk|pk|rk)_(?:live|test|proj)_[A-Za-z0-9_-]{12,}|gh[pousr]_[A-Za-z0-9_]{20,}|xox[baprs]-[A-Za-z0-9-]{20,}|bearer\s+[A-Za-z0-9._~+/=-]{20,})/i;
|
|
21
|
+
const LOCAL_PATH_RE = /^(?:[A-Za-z]:[\\/]|\\\\|\/(?:Users|home|tmp|var|etc|private|Volumes)\/)/;
|
|
22
|
+
const FORBIDDEN_PUBLIC_CLAIM_RE = /\b(?:provider(?:-native)?\s+(?:deletion|memory\s+control)|model\s+forgetting|compliance\s+certification|certif(?:y|ies|ied)\s+compliance|benchmark\s+superiority|hosted\s+(?:saas|cloud)\s+ready|byoc\s+ready|patent(?:ability|able)|legal\s+conclusion|raw\s+embeddings?\s+(?:are\s+)?safe|hardware\s+tamper[-\s]?proof|tamper[-\s]?proof\s+hardware)\b/i;
|
|
23
|
+
const PUBLIC_FORBIDDEN_KEYS = new Set([
|
|
24
|
+
'api_key',
|
|
25
|
+
'authorization',
|
|
26
|
+
'body',
|
|
27
|
+
'content',
|
|
28
|
+
'cookie',
|
|
29
|
+
'credential',
|
|
30
|
+
'credentials',
|
|
31
|
+
'embedding',
|
|
32
|
+
'embeddings',
|
|
33
|
+
'file_path',
|
|
34
|
+
'local_path',
|
|
35
|
+
'password',
|
|
36
|
+
'plaintext',
|
|
37
|
+
'private_key',
|
|
38
|
+
'prompt',
|
|
39
|
+
'provider_response',
|
|
40
|
+
'raw',
|
|
41
|
+
'raw_memory',
|
|
42
|
+
'response',
|
|
43
|
+
'secret',
|
|
44
|
+
'text',
|
|
45
|
+
'token',
|
|
46
|
+
'transcript',
|
|
47
|
+
'vector',
|
|
48
|
+
'vectors'
|
|
49
|
+
]);
|
|
19
50
|
const RECEIPT_TOP_LEVEL_FIELDS = new Set([
|
|
20
51
|
'schema',
|
|
21
52
|
'receipt_id',
|
|
@@ -80,7 +111,7 @@ function canonicalizeValue(value, seen) {
|
|
|
80
111
|
}
|
|
81
112
|
|
|
82
113
|
const prototype = Object.getPrototypeOf(value);
|
|
83
|
-
if (prototype !== Object.prototype && prototype !== null) {
|
|
114
|
+
if (prototype !== Object.prototype && prototype !== null && prototype.constructor?.name !== 'Object') {
|
|
84
115
|
throw new TypeError('canonical JSON only accepts plain objects, arrays, and primitives');
|
|
85
116
|
}
|
|
86
117
|
|
|
@@ -155,12 +186,12 @@ export function createReceipt(receiptOrArgs, maybeOptions = {}) {
|
|
|
155
186
|
const previous_receipt_hash = normalizePreviousHash(
|
|
156
187
|
options.previous_receipt_hash ?? options.previousReceiptHash ?? (sequence === 0 ? GENESIS : undefined)
|
|
157
188
|
);
|
|
158
|
-
const signer = normalizeSigner(options.signer, options.key_id ?? options.keyId, options.privateKey);
|
|
159
189
|
const event_hash = normalizeSha256Root(options.event_hash ?? options.eventHash ?? source.event_hash ?? eventHash(source), 'event_hash');
|
|
160
190
|
const active_set_root = normalizeSha256Root(options.active_set_root ?? options.activeSetRoot ?? EMPTY_MERKLE_ROOT, 'active_set_root');
|
|
161
191
|
const receipt_log_root = normalizeSha256Root(options.receipt_log_root ?? options.receiptLogRoot ?? EMPTY_MERKLE_ROOT, 'receipt_log_root');
|
|
162
192
|
const operation = requiredString(options.operation ?? source.operation, 'operation');
|
|
163
193
|
const timestamp = requiredString(options.timestamp ?? source.timestamp ?? new Date().toISOString(), 'timestamp');
|
|
194
|
+
const signer = normalizeSigner(options.signer, options.key_id ?? options.keyId, options.privateKey);
|
|
164
195
|
|
|
165
196
|
const body = {
|
|
166
197
|
schema: RECEIPT_SCHEMA,
|
|
@@ -503,6 +534,132 @@ export function createMemoryAddress(args = {}, maybeValue, maybeOptions = {}) {
|
|
|
503
534
|
return `${prefix}:hmac-sha256:${digest}`;
|
|
504
535
|
}
|
|
505
536
|
|
|
537
|
+
export function sha256Root(value) {
|
|
538
|
+
return prefixedSha256(value);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
export function publicSafeHash(value, options = {}) {
|
|
542
|
+
assertPublicSafeFields(value, options);
|
|
543
|
+
return prefixedSha256(canonicalize(value));
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
export function merkleSetRoot(values = []) {
|
|
547
|
+
if (!Array.isArray(values)) throw new TypeError('merkleSetRoot requires an array');
|
|
548
|
+
return new MerkleSet(values).root();
|
|
549
|
+
}
|
|
550
|
+
|
|
551
|
+
export function createMerkleRoot(values = []) {
|
|
552
|
+
return merkleSetRoot(values);
|
|
553
|
+
}
|
|
554
|
+
|
|
555
|
+
export function createMerkleMembershipProof(valuesOrArgs, maybeValue) {
|
|
556
|
+
const args = Array.isArray(valuesOrArgs) ? { values: valuesOrArgs, value: maybeValue } : valuesOrArgs ?? {};
|
|
557
|
+
if (!Array.isArray(args.values)) throw new TypeError('createMerkleMembershipProof requires values');
|
|
558
|
+
return new MerkleSet(args.values).proveMembership(args.value);
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
export function verifyMerkleMembershipProof(proofOrArgs, maybeExpectedRoot) {
|
|
562
|
+
const args = isPlainRecord(proofOrArgs) && Object.prototype.hasOwnProperty.call(proofOrArgs, 'proof')
|
|
563
|
+
? proofOrArgs
|
|
564
|
+
: { proof: proofOrArgs, expectedRoot: maybeExpectedRoot };
|
|
565
|
+
return MerkleSet.verifyMembership(args.proof, args.expectedRoot ?? args.expected_root ?? args.proof?.root);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
export function createMerkleProof(valuesOrArgs, maybeValue) {
|
|
569
|
+
return createMerkleMembershipProof(valuesOrArgs, maybeValue);
|
|
570
|
+
}
|
|
571
|
+
|
|
572
|
+
export function verifyMerkleProof(proofOrArgs, maybeExpectedRoot) {
|
|
573
|
+
return verifyMerkleMembershipProof(proofOrArgs, maybeExpectedRoot);
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
export function createMerkleNonMembershipProof(valuesOrArgs, maybeValue) {
|
|
577
|
+
const args = Array.isArray(valuesOrArgs) ? { values: valuesOrArgs, value: maybeValue } : valuesOrArgs ?? {};
|
|
578
|
+
if (!Array.isArray(args.values)) throw new TypeError('createMerkleNonMembershipProof requires values');
|
|
579
|
+
return new MerkleSet(args.values).proveNonMembership(args.value);
|
|
580
|
+
}
|
|
581
|
+
|
|
582
|
+
export function verifyMerkleNonMembershipProof(proofOrArgs, maybeExpectedRoot) {
|
|
583
|
+
const args = isPlainRecord(proofOrArgs) && Object.prototype.hasOwnProperty.call(proofOrArgs, 'proof')
|
|
584
|
+
? proofOrArgs
|
|
585
|
+
: { proof: proofOrArgs, expectedRoot: maybeExpectedRoot };
|
|
586
|
+
return MerkleSet.verifyNonMembership(args.proof, args.expectedRoot ?? args.expected_root ?? args.proof?.root);
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
export function deriveNullifier(args = {}, maybeValue, maybeOptions = {}) {
|
|
590
|
+
const options = isPlainRecord(args) && (Object.prototype.hasOwnProperty.call(args, 'secret') || Object.prototype.hasOwnProperty.call(args, 'key'))
|
|
591
|
+
? args
|
|
592
|
+
: { secret: args, value: maybeValue, ...maybeOptions };
|
|
593
|
+
const secret = options.secret ?? options.key;
|
|
594
|
+
if (secret === undefined) throw new TypeError('deriveNullifier requires a secret key');
|
|
595
|
+
const payload = {
|
|
596
|
+
domain: 'enigma.nullifier.v1',
|
|
597
|
+
scope: options.scope ?? options.namespace ?? 'memory-boundary',
|
|
598
|
+
subject_ref: options.subject_ref ?? options.subjectRef ?? null,
|
|
599
|
+
capability_id: options.capability_id ?? options.capabilityId ?? null,
|
|
600
|
+
policy_id: options.policy_id ?? options.policyId ?? null,
|
|
601
|
+
value: options.value ?? options.claim ?? options.ref ?? options.components ?? null
|
|
602
|
+
};
|
|
603
|
+
return `nullifier:hmac-sha256:${hmacSha256Hex({ key: secret, value: payload })}`;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
export function isSha256Root(value) {
|
|
607
|
+
return ROOT_RE.test(value ?? '');
|
|
608
|
+
}
|
|
609
|
+
|
|
610
|
+
export function isNullifier(value) {
|
|
611
|
+
return NULLIFIER_RE.test(value ?? '');
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
export function verifySha256Root(value, field = 'root') {
|
|
615
|
+
const ok = isSha256Root(value);
|
|
616
|
+
return verificationResult(ok, ok ? [] : [`${field} must be a sha256 root`]);
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
export function verifyNullifier(value, field = 'nullifier') {
|
|
620
|
+
const ok = isNullifier(value);
|
|
621
|
+
return verificationResult(ok, ok ? [] : [`${field} must be a nullifier`]);
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
export function scanPublicSafeFields(value, options = {}) {
|
|
625
|
+
const errors = [];
|
|
626
|
+
const forbidden_paths = [];
|
|
627
|
+
scanPublicSafeValue(value, '$', errors, forbidden_paths, new WeakSet(), options);
|
|
628
|
+
return verificationResult(errors.length === 0, errors, { forbidden_paths });
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
export function assertPublicSafeFields(value, options = {}) {
|
|
632
|
+
const result = scanPublicSafeFields(value, options);
|
|
633
|
+
if (!result.ok) throw new TypeError(`public-safe scan failed: ${result.errors.join('; ')}`);
|
|
634
|
+
return value;
|
|
635
|
+
}
|
|
636
|
+
|
|
637
|
+
export function verifyPublicSafeArtifact(value, options = {}) {
|
|
638
|
+
const result = scanPublicSafeFields(value, options);
|
|
639
|
+
return verificationResult(result.ok, result.errors, {
|
|
640
|
+
forbidden_paths: result.forbidden_paths,
|
|
641
|
+
public_hash: result.ok ? prefixedSha256(canonicalize(value)) : null
|
|
642
|
+
});
|
|
643
|
+
}
|
|
644
|
+
|
|
645
|
+
export function verifyPublicSafeHash(value, maybeExpectedHash, options = {}) {
|
|
646
|
+
const expected = options.expected_hash ?? options.expectedHash ?? options.hash ?? options.public_hash ?? options.publicHash ?? maybeExpectedHash;
|
|
647
|
+
const scan = scanPublicSafeFields(value, options);
|
|
648
|
+
if (!scan.ok) {
|
|
649
|
+
return verificationResult(false, scan.errors, { forbidden_paths: scan.forbidden_paths, public_hash: null });
|
|
650
|
+
}
|
|
651
|
+
const publicHash = prefixedSha256(canonicalize(value));
|
|
652
|
+
const errors = [];
|
|
653
|
+
if (expected !== undefined) {
|
|
654
|
+
try {
|
|
655
|
+
if (normalizeSha256Root(expected, 'expectedHash') !== publicHash) errors.push('public hash mismatch');
|
|
656
|
+
} catch {
|
|
657
|
+
errors.push('expectedHash must be a sha256 root');
|
|
658
|
+
}
|
|
659
|
+
}
|
|
660
|
+
return verificationResult(errors.length === 0, errors, { forbidden_paths: [], public_hash: publicHash });
|
|
661
|
+
}
|
|
662
|
+
|
|
506
663
|
function bytesForHash(value) {
|
|
507
664
|
if (typeof value === 'string') return value;
|
|
508
665
|
if (Buffer.isBuffer(value) || ArrayBuffer.isView(value) || value instanceof ArrayBuffer) return value;
|
|
@@ -761,6 +918,96 @@ function withoutUndefinedFields(record) {
|
|
|
761
918
|
return cleaned;
|
|
762
919
|
}
|
|
763
920
|
|
|
921
|
+
function scanPublicSafeValue(value, path, errors, forbiddenPaths, seen, options) {
|
|
922
|
+
if (value === null) return;
|
|
923
|
+
if (value === undefined) {
|
|
924
|
+
addPublicSafeError(errors, forbiddenPaths, path, 'undefined is not public-safe JSON');
|
|
925
|
+
return;
|
|
926
|
+
}
|
|
927
|
+
const type = typeof value;
|
|
928
|
+
if (type === 'string') {
|
|
929
|
+
scanPublicSafeString(value, path, errors, forbiddenPaths, options);
|
|
930
|
+
return;
|
|
931
|
+
}
|
|
932
|
+
if (type === 'number') {
|
|
933
|
+
if (!Number.isFinite(value)) addPublicSafeError(errors, forbiddenPaths, path, 'number must be finite');
|
|
934
|
+
return;
|
|
935
|
+
}
|
|
936
|
+
if (type === 'boolean') return;
|
|
937
|
+
if (type !== 'object') {
|
|
938
|
+
addPublicSafeError(errors, forbiddenPaths, path, `${type} is not public-safe JSON`);
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
if (seen.has(value)) {
|
|
942
|
+
addPublicSafeError(errors, forbiddenPaths, path, 'value must not be circular');
|
|
943
|
+
return;
|
|
944
|
+
}
|
|
945
|
+
seen.add(value);
|
|
946
|
+
try {
|
|
947
|
+
if (Array.isArray(value)) {
|
|
948
|
+
if (looksLikeEmbeddingVector(value)) addPublicSafeError(errors, forbiddenPaths, path, 'numeric vector-like arrays are not public-safe');
|
|
949
|
+
for (let index = 0; index < value.length; index += 1) {
|
|
950
|
+
if (!Object.prototype.hasOwnProperty.call(value, index)) {
|
|
951
|
+
addPublicSafeError(errors, forbiddenPaths, `${path}[${index}]`, 'sparse arrays are not public-safe');
|
|
952
|
+
continue;
|
|
953
|
+
}
|
|
954
|
+
scanPublicSafeValue(value[index], `${path}[${index}]`, errors, forbiddenPaths, seen, options);
|
|
955
|
+
}
|
|
956
|
+
return;
|
|
957
|
+
}
|
|
958
|
+
if (!isPlainRecord(value)) {
|
|
959
|
+
addPublicSafeError(errors, forbiddenPaths, path, 'unsupported object is not public-safe JSON');
|
|
960
|
+
return;
|
|
961
|
+
}
|
|
962
|
+
for (const key of Object.keys(value)) {
|
|
963
|
+
const childPath = `${path}.${key}`;
|
|
964
|
+
if (isForbiddenPublicKey(key)) addPublicSafeError(errors, forbiddenPaths, childPath, 'field name is not public-safe');
|
|
965
|
+
scanPublicSafeValue(value[key], childPath, errors, forbiddenPaths, seen, options);
|
|
966
|
+
}
|
|
967
|
+
} finally {
|
|
968
|
+
seen.delete(value);
|
|
969
|
+
}
|
|
970
|
+
}
|
|
971
|
+
|
|
972
|
+
function scanPublicSafeString(value, path, errors, forbiddenPaths, options) {
|
|
973
|
+
if (SECRET_VALUE_RE.test(value)) addPublicSafeError(errors, forbiddenPaths, path, 'secret-shaped string is not public-safe');
|
|
974
|
+
if (LOCAL_PATH_RE.test(value)) addPublicSafeError(errors, forbiddenPaths, path, 'local absolute path is not public-safe');
|
|
975
|
+
if (FORBIDDEN_PUBLIC_CLAIM_RE.test(value)) addPublicSafeError(errors, forbiddenPaths, path, 'forbidden public claim is not allowed');
|
|
976
|
+
if (options.strictStrings === true && !isPublicSafeString(value)) {
|
|
977
|
+
addPublicSafeError(errors, forbiddenPaths, path, 'string is outside public artifact grammar');
|
|
978
|
+
}
|
|
979
|
+
}
|
|
980
|
+
|
|
981
|
+
function isForbiddenPublicKey(key) {
|
|
982
|
+
const normalized = key.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase();
|
|
983
|
+
if (PUBLIC_FORBIDDEN_KEYS.has(normalized)) return true;
|
|
984
|
+
return /(?:^|_)(?:plaintext|prompt|response|transcript|embedding|embeddings|vector|vectors|private_key|token|secret|password|api_key|credential|credentials|cookie|authorization)$/.test(normalized);
|
|
985
|
+
}
|
|
986
|
+
|
|
987
|
+
function looksLikeEmbeddingVector(value) {
|
|
988
|
+
if (value.length < 32) return false;
|
|
989
|
+
let numeric = 0;
|
|
990
|
+
for (const item of value) {
|
|
991
|
+
if (typeof item === 'number' && Number.isFinite(item)) numeric += 1;
|
|
992
|
+
else return false;
|
|
993
|
+
}
|
|
994
|
+
return numeric === value.length;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
function isPublicSafeString(value) {
|
|
998
|
+
if (value.length === 0) return true;
|
|
999
|
+
if (ROOT_RE.test(value) || HASH_RE.test(value) || NULLIFIER_RE.test(value)) return true;
|
|
1000
|
+
if (/^[a-z][a-z0-9_]*(?:\.[a-z0-9_]+)*\.v\d+$/u.test(value)) return true;
|
|
1001
|
+
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{3})?Z$/u.test(value)) return true;
|
|
1002
|
+
if (/^(?:ok|valid|invalid|active|quarantine|quarantined|tombstone|tombstoned|revoked|granted|omitted|selected|provided|missing|blocked|pass|fail|unknown)$/u.test(value)) return true;
|
|
1003
|
+
return /^[a-z][a-z0-9+.-]*:[A-Za-z0-9._~:@/+?#[\]!$&'()*%,;=-]{1,256}$/u.test(value);
|
|
1004
|
+
}
|
|
1005
|
+
|
|
1006
|
+
function addPublicSafeError(errors, forbiddenPaths, path, message) {
|
|
1007
|
+
errors.push(`${path}: ${message}`);
|
|
1008
|
+
forbiddenPaths.push(path);
|
|
1009
|
+
}
|
|
1010
|
+
|
|
764
1011
|
function isPlainRecord(value) {
|
|
765
1012
|
return value !== null && typeof value === 'object' && !Array.isArray(value);
|
|
766
1013
|
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// Single source of truth for the package version at runtime.
|
|
2
|
+
// Derived from the repository root package.json — never hard-code versions elsewhere.
|
|
3
|
+
import { readFileSync } from 'node:fs';
|
|
4
|
+
|
|
5
|
+
const PACKAGE_JSON_URL = new URL('../../../package.json', import.meta.url);
|
|
6
|
+
|
|
7
|
+
export const ENIGMA_VERSION = JSON.parse(readFileSync(PACKAGE_JSON_URL, 'utf8')).version;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@enigma/dev-tools",
|
|
3
|
+
"version": "0.1.22",
|
|
4
|
+
"description": "Enigma Developer Tooling: Vector Benchmarks, Vault Inspectors, and Swarm Simulators",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "src/index.js",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": "./src/index.js",
|
|
9
|
+
"./benchmark": "./src/vector-benchmark.js",
|
|
10
|
+
"./inspector": "./src/vault-inspector.js",
|
|
11
|
+
"./simulator": "./src/swarm-simulator.js"
|
|
12
|
+
},
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@enigma/core": "workspace:*",
|
|
15
|
+
"@enigma/rag": "workspace:*",
|
|
16
|
+
"@enigma/mesh": "workspace:*",
|
|
17
|
+
"@enigma/vault": "workspace:*"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// Enigma Developer Tooling: Comprehensive Quantitative Memory Benchmark Suite.
|
|
2
|
+
// Evaluates Recall@10, Temporal Accuracy, Contradiction Resolution,
|
|
3
|
+
// Search Latency Percentiles (P50/P95/P99), and RAM Efficiency.
|
|
4
|
+
import { Enigma } from '../../sdk/src/index.js';
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @param {Object} [options]
|
|
8
|
+
* @param {number} [options.corpusSize]
|
|
9
|
+
* @param {(options: Object) => Promise<Enigma>} [options.enigmaFactory]
|
|
10
|
+
*/
|
|
11
|
+
export async function runMemoryBenchmarkSuite(options = {}) {
|
|
12
|
+
const corpusSize = Math.max(10, Math.min(options.corpusSize || 50, 1000));
|
|
13
|
+
const enigmaFactory = options.enigmaFactory || ((connectOptions) => Enigma.connect(connectOptions));
|
|
14
|
+
const enigma = await enigmaFactory({ scope: 'benchmark.eval.suite' });
|
|
15
|
+
|
|
16
|
+
// 1. Ingest Synthetic Ground Truth Benchmark Dataset
|
|
17
|
+
const startIngest = Date.now();
|
|
18
|
+
const testFacts = [
|
|
19
|
+
// Standard semantic facts
|
|
20
|
+
{ text: 'Solana block production slot duration is targeted at 400 milliseconds.', query: 'What is the slot time on Solana?', expect: true },
|
|
21
|
+
{ text: 'Enigma vaults utilize AES-256-GCM authenticated encryption at rest.', query: 'How does Enigma encrypt vault data?', expect: true },
|
|
22
|
+
{ text: 'GhostMesh implements ephemeral X25519 ECDH session key agreement.', query: 'What key exchange does GhostMesh use?', expect: true },
|
|
23
|
+
{ text: 'The Sealed Sale marketplace compiles an 87,422-constraint Groth16 circuit.', query: 'How many constraints are in the Sealed Sale circuit?', expect: true },
|
|
24
|
+
{ text: 'Aztec-style Indexed Merkle Trees prevent double-spend of revoked nullifiers.', query: 'How does Enigma handle nullifier revocations?', expect: true },
|
|
25
|
+
];
|
|
26
|
+
|
|
27
|
+
for (let i = 0; i < corpusSize; i++) {
|
|
28
|
+
const fact = testFacts[i % testFacts.length];
|
|
29
|
+
await enigma.remember(`${fact.text} [Fact #${i + 1}]`, {
|
|
30
|
+
type: i % 3 === 0 ? 'policy' : (i % 2 === 0 ? 'preference' : 'semantic'),
|
|
31
|
+
importance: 1.0 + (i % 5) * 0.2,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
const ingestDurationMs = Date.now() - startIngest;
|
|
35
|
+
const ingestThroughput = Math.round((corpusSize / (ingestDurationMs / 1000 || 0.001)) * 10) / 10;
|
|
36
|
+
|
|
37
|
+
// 2. Measure Recall@10 & Latency Percentiles
|
|
38
|
+
const queryLatencies = [];
|
|
39
|
+
let recallHits = 0;
|
|
40
|
+
|
|
41
|
+
for (const item of testFacts) {
|
|
42
|
+
const qStart = performance.now();
|
|
43
|
+
const results = await enigma.recall(item.query, { topK: 10 });
|
|
44
|
+
const qDuration = performance.now() - qStart;
|
|
45
|
+
queryLatencies.push(qDuration);
|
|
46
|
+
|
|
47
|
+
const hit = results.some(r => r.text.toLowerCase().includes(item.text.slice(0, 20).toLowerCase()));
|
|
48
|
+
if (hit) recallHits++;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
queryLatencies.sort((a, b) => a - b);
|
|
52
|
+
const p50 = Math.round(queryLatencies[Math.floor(queryLatencies.length * 0.5)] * 100) / 100;
|
|
53
|
+
const p95 = Math.round(queryLatencies[Math.floor(queryLatencies.length * 0.95)] * 100) / 100;
|
|
54
|
+
const p99 = Math.round(queryLatencies[queryLatencies.length - 1] * 100) / 100;
|
|
55
|
+
const recallAt10Percent = Math.round((recallHits / testFacts.length) * 100);
|
|
56
|
+
|
|
57
|
+
// 3. Measure Temporal Accuracy
|
|
58
|
+
// Add historical memory vs current memory
|
|
59
|
+
const t1 = Date.parse('2026-01-01T00:00:00Z');
|
|
60
|
+
const t2 = Date.parse('2026-08-01T00:00:00Z');
|
|
61
|
+
|
|
62
|
+
const oldLoc = await enigma.remember('User primary residence is Austin, Texas.', {
|
|
63
|
+
validFrom: t1,
|
|
64
|
+
validUntil: t2,
|
|
65
|
+
observedAt: t1,
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
const newLoc = await enigma.remember('User moved and current primary residence is Dallas, Texas.', {
|
|
69
|
+
validFrom: t2,
|
|
70
|
+
validUntil: null,
|
|
71
|
+
observedAt: t2,
|
|
72
|
+
supersedes: [oldLoc.id],
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Query as of Jan 2026 (historical) vs August 2026 (current)
|
|
76
|
+
const currentRecall = await enigma.recall('primary residence', { asOfTime: Date.parse('2026-08-15T00:00:00Z') });
|
|
77
|
+
const temporalAccuracy = currentRecall.length > 0 && currentRecall[0].text.includes('Dallas') ? 100 : 0;
|
|
78
|
+
|
|
79
|
+
// 4. Measure Contradiction Resolution Rate
|
|
80
|
+
const activeRecall = await enigma.recall('primary residence', { filterSuperseded: true });
|
|
81
|
+
const contradictionResolved = activeRecall.every(r => !r.text.includes('Austin')) ? 100 : 0;
|
|
82
|
+
|
|
83
|
+
// 5. Memory Footprint Calculation
|
|
84
|
+
const uncompressedBytes = corpusSize * 384 * 4; // Float32
|
|
85
|
+
const quantizedBytes = corpusSize * 384 * 1; // Int8
|
|
86
|
+
const memoryReductionPercent = Math.round(((uncompressedBytes - quantizedBytes) / uncompressedBytes) * 100);
|
|
87
|
+
|
|
88
|
+
return {
|
|
89
|
+
ok: true,
|
|
90
|
+
benchmark: 'enigma_memory_intelligence_v1',
|
|
91
|
+
corpusSize,
|
|
92
|
+
ingest: {
|
|
93
|
+
totalDurationMs: ingestDurationMs,
|
|
94
|
+
throughputPerSecond: ingestThroughput,
|
|
95
|
+
},
|
|
96
|
+
retrieval: {
|
|
97
|
+
queriesEvaluated: testFacts.length,
|
|
98
|
+
recallAt10Percent,
|
|
99
|
+
latencyMs: {
|
|
100
|
+
p50,
|
|
101
|
+
p95,
|
|
102
|
+
p99,
|
|
103
|
+
},
|
|
104
|
+
},
|
|
105
|
+
intelligence: {
|
|
106
|
+
temporalAccuracyPercent: temporalAccuracy,
|
|
107
|
+
contradictionResolutionRatePercent: contradictionResolved,
|
|
108
|
+
memoryReductionPercent,
|
|
109
|
+
},
|
|
110
|
+
timestamp: Date.now(),
|
|
111
|
+
};
|
|
112
|
+
}
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
// Enigma GhostMesh Multi-Node Swarm Simulator.
|
|
2
|
+
// Simulates P2P routing convergence, multi-hop packet dispatching,
|
|
3
|
+
// and delivery success metrics across N autonomous agent nodes.
|
|
4
|
+
import {
|
|
5
|
+
MeshGossipNode,
|
|
6
|
+
InMemoryBus,
|
|
7
|
+
InMemoryTransport,
|
|
8
|
+
generateMeshIdentity,
|
|
9
|
+
} from '../../mesh/src/index.js';
|
|
10
|
+
|
|
11
|
+
export async function simulateSwarmNetwork(options = {}) {
|
|
12
|
+
const nodeCount = Math.max(2, Math.min(options.nodeCount || 5, 20));
|
|
13
|
+
const messageCount = Math.max(1, options.messageCount || 10);
|
|
14
|
+
const bus = new InMemoryBus();
|
|
15
|
+
|
|
16
|
+
const nodes = [];
|
|
17
|
+
const identities = [];
|
|
18
|
+
const receivedMessages = new Map(); // targetDestinationHex -> Array<plaintext>
|
|
19
|
+
|
|
20
|
+
// 1. Initialize nodes
|
|
21
|
+
for (let i = 0; i < nodeCount; i++) {
|
|
22
|
+
const identity = generateMeshIdentity();
|
|
23
|
+
const nodeId = `sim_node_${i + 1}`;
|
|
24
|
+
const transport = new InMemoryTransport(nodeId, bus);
|
|
25
|
+
const node = new MeshGossipNode({
|
|
26
|
+
nodeId,
|
|
27
|
+
identity,
|
|
28
|
+
transports: [transport],
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const destHex = identity.destinationHex;
|
|
32
|
+
receivedMessages.set(destHex, []);
|
|
33
|
+
node.on('capsule', ({ plaintext }) => {
|
|
34
|
+
const list = receivedMessages.get(destHex);
|
|
35
|
+
if (list) list.push(plaintext);
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
await node.start();
|
|
39
|
+
nodes.push(node);
|
|
40
|
+
identities.push(identity);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 2. Announce routes sequentially to establish topology
|
|
44
|
+
for (let i = 0; i < nodeCount; i++) {
|
|
45
|
+
await nodes[i].announce({ name: `Agent-${i + 1}`, index: i });
|
|
46
|
+
}
|
|
47
|
+
await new Promise(r => setTimeout(r, 60));
|
|
48
|
+
|
|
49
|
+
// 3. Dispatch simulated messages across random pairs
|
|
50
|
+
let deliveredCount = 0;
|
|
51
|
+
const deliveryLatenciesMs = [];
|
|
52
|
+
|
|
53
|
+
for (let m = 0; m < messageCount; m++) {
|
|
54
|
+
const senderIdx = m % nodeCount;
|
|
55
|
+
let targetIdx = (m + 1) % nodeCount;
|
|
56
|
+
if (senderIdx === targetIdx) targetIdx = (targetIdx + 1) % nodeCount;
|
|
57
|
+
|
|
58
|
+
const sender = nodes[senderIdx];
|
|
59
|
+
const target = identities[targetIdx];
|
|
60
|
+
const payload = `Swarm message #${m + 1} from Node ${senderIdx + 1} to Node ${targetIdx + 1}`;
|
|
61
|
+
|
|
62
|
+
const start = Date.now();
|
|
63
|
+
const res = await sender.sendEncryptedCapsule(
|
|
64
|
+
target.destinationHex,
|
|
65
|
+
target.encryptionPublicKey,
|
|
66
|
+
payload
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// Wait briefly for in-memory delivery to process
|
|
70
|
+
await new Promise(r => setTimeout(r, 10));
|
|
71
|
+
|
|
72
|
+
const targetInbox = receivedMessages.get(target.destinationHex) || [];
|
|
73
|
+
const received = targetInbox.includes(payload);
|
|
74
|
+
|
|
75
|
+
if (res.routed && received) {
|
|
76
|
+
deliveredCount++;
|
|
77
|
+
deliveryLatenciesMs.push(Date.now() - start);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// 4. Teardown
|
|
82
|
+
for (const n of nodes) {
|
|
83
|
+
await n.stop();
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const successRate = Math.round((deliveredCount / messageCount) * 100);
|
|
87
|
+
const meanLatency = deliveryLatenciesMs.length > 0
|
|
88
|
+
? Math.round((deliveryLatenciesMs.reduce((a, b) => a + b, 0) / deliveryLatenciesMs.length) * 10) / 10
|
|
89
|
+
: 0;
|
|
90
|
+
|
|
91
|
+
return {
|
|
92
|
+
ok: true,
|
|
93
|
+
simulation: 'ghostmesh_swarm_simulation_v1',
|
|
94
|
+
nodeCount,
|
|
95
|
+
messageCount,
|
|
96
|
+
deliveredCount,
|
|
97
|
+
deliverySuccessRatePercent: successRate,
|
|
98
|
+
meanLatencyMs: meanLatency,
|
|
99
|
+
timestamp: Date.now(),
|
|
100
|
+
};
|
|
101
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
// Enigma Vault Bundle Inspector.
|
|
2
|
+
// Analyzes encrypted vault headers, KDF metadata, scope distribution,
|
|
3
|
+
// and Merkle tree roots with strict zero-leakage boundaries.
|
|
4
|
+
import fs from 'node:fs';
|
|
5
|
+
import path from 'node:path';
|
|
6
|
+
import crypto from 'node:crypto';
|
|
7
|
+
import { deriveKeysFromPassphrase, PBKDF2_KDF_SPEC } from '../../vault/src/index.js';
|
|
8
|
+
|
|
9
|
+
export async function inspectVaultBundle(bundlePath, options = {}) {
|
|
10
|
+
const resolved = path.resolve(bundlePath);
|
|
11
|
+
if (!fs.existsSync(resolved)) {
|
|
12
|
+
throw new Error(`Vault file not found at path: ${resolved}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const fileStats = fs.statSync(resolved);
|
|
16
|
+
const rawText = fs.readFileSync(resolved, 'utf8');
|
|
17
|
+
|
|
18
|
+
let bundle;
|
|
19
|
+
try {
|
|
20
|
+
bundle = JSON.parse(rawText);
|
|
21
|
+
} catch (err) {
|
|
22
|
+
throw new Error(`Corrupt JSON in vault file: ${err.message}`);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const format = bundle.format || 'unknown';
|
|
26
|
+
const version = bundle.version || 1;
|
|
27
|
+
const isEncrypted = typeof bundle.ciphertext === 'string' && typeof bundle.authTag === 'string';
|
|
28
|
+
const kdf = bundle.kdf || null;
|
|
29
|
+
|
|
30
|
+
const inspectionReport = {
|
|
31
|
+
ok: true,
|
|
32
|
+
file: {
|
|
33
|
+
path: resolved,
|
|
34
|
+
sizeBytes: fileStats.size,
|
|
35
|
+
updatedAt: fileStats.mtime.toISOString(),
|
|
36
|
+
},
|
|
37
|
+
envelope: {
|
|
38
|
+
format,
|
|
39
|
+
version,
|
|
40
|
+
isEncrypted,
|
|
41
|
+
count: bundle.count || 0,
|
|
42
|
+
kdf: kdf ? {
|
|
43
|
+
algorithm: kdf.algorithm,
|
|
44
|
+
iterations: kdf.iterations,
|
|
45
|
+
hash: kdf.hash,
|
|
46
|
+
saltPresent: Boolean(kdf.salt),
|
|
47
|
+
} : null,
|
|
48
|
+
ivLengthBytes: bundle.iv ? Buffer.from(bundle.iv, 'hex').length : 0,
|
|
49
|
+
authTagLengthBytes: bundle.authTag ? Buffer.from(bundle.authTag, 'hex').length : 0,
|
|
50
|
+
},
|
|
51
|
+
contents: null,
|
|
52
|
+
};
|
|
53
|
+
|
|
54
|
+
// If passphrase is provided, perform deep inspection
|
|
55
|
+
if (options.passphrase && isEncrypted) {
|
|
56
|
+
try {
|
|
57
|
+
if (!kdf || !kdf.salt) throw new Error('Missing KDF salt in bundle');
|
|
58
|
+
const saltBuf = /^[0-9a-fA-F]+$/.test(kdf.salt)
|
|
59
|
+
? Buffer.from(kdf.salt, 'hex')
|
|
60
|
+
: Buffer.from(kdf.salt, 'base64');
|
|
61
|
+
const kdfSpec = {
|
|
62
|
+
algorithm: kdf.algorithm || 'scrypt',
|
|
63
|
+
n: kdf.n || 16384,
|
|
64
|
+
r: kdf.r || 8,
|
|
65
|
+
p: kdf.p || 1,
|
|
66
|
+
iterations: kdf.iterations || 600000,
|
|
67
|
+
hash: kdf.hash || 'sha256',
|
|
68
|
+
};
|
|
69
|
+
const vaultKey = deriveKeysFromPassphrase(options.passphrase, saltBuf, kdfSpec).vaultKey;
|
|
70
|
+
|
|
71
|
+
const iv = Buffer.from(bundle.iv, 'hex');
|
|
72
|
+
const authTag = Buffer.from(bundle.authTag, 'hex');
|
|
73
|
+
const ciphertext = Buffer.from(bundle.ciphertext, 'base64');
|
|
74
|
+
|
|
75
|
+
const decipher = crypto.createDecipheriv('aes-256-gcm', vaultKey, iv);
|
|
76
|
+
if (bundle.aad) {
|
|
77
|
+
decipher.setAAD(Buffer.isBuffer(bundle.aad) ? bundle.aad : Buffer.from(bundle.aad));
|
|
78
|
+
}
|
|
79
|
+
decipher.setAuthTag(authTag);
|
|
80
|
+
const decrypted = Buffer.concat([decipher.update(ciphertext), decipher.final()]);
|
|
81
|
+
const data = JSON.parse(decrypted.toString('utf8'));
|
|
82
|
+
|
|
83
|
+
const scopes = {};
|
|
84
|
+
const memories = data.memories || [];
|
|
85
|
+
let oldest = Infinity;
|
|
86
|
+
let newest = 0;
|
|
87
|
+
|
|
88
|
+
for (const m of memories) {
|
|
89
|
+
const sc = m.scope || 'default';
|
|
90
|
+
scopes[sc] = (scopes[sc] || 0) + 1;
|
|
91
|
+
if (m.createdAt && m.createdAt < oldest) oldest = m.createdAt;
|
|
92
|
+
if (m.createdAt && m.createdAt > newest) newest = m.createdAt;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
inspectionReport.contents = {
|
|
96
|
+
unlocked: true,
|
|
97
|
+
memoryCount: memories.length,
|
|
98
|
+
scopeDistribution: scopes,
|
|
99
|
+
timeline: {
|
|
100
|
+
oldestMemory: oldest !== Infinity ? new Date(oldest).toISOString() : null,
|
|
101
|
+
newestMemory: newest !== 0 ? new Date(newest).toISOString() : null,
|
|
102
|
+
},
|
|
103
|
+
hasVectorBundle: Boolean(data.vectorBundle),
|
|
104
|
+
};
|
|
105
|
+
} catch (err) {
|
|
106
|
+
inspectionReport.contents = {
|
|
107
|
+
unlocked: false,
|
|
108
|
+
error: `Decryption failed: ${err.message}`,
|
|
109
|
+
};
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
return inspectionReport;
|
|
114
|
+
}
|