enigma-memory 0.1.17 → 0.1.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -27
- package/apps/cli/bin/enigma-desktop.mjs +140 -0
- package/apps/cli/bin/enigma-terminal.mjs +78 -0
- package/apps/cli/bin/enigma.mjs +4979 -3263
- package/apps/desktop/electron-main.cjs +217 -0
- package/apps/desktop/package.json +12 -0
- package/apps/desktop/src/app.js +264 -7
- package/apps/desktop/src/index.html +3514 -1373
- package/apps/desktop/src/launch-electron.mjs +51 -0
- package/apps/desktop/src/server.mjs +2914 -0
- package/apps/desktop/src/styles.css +2972 -260
- package/apps/desktop/src/zk-browser-prove.mjs +53 -0
- package/apps/desktop/src/zk-state.mjs +1789 -0
- package/apps/gateway/bin/enigma-gateway.mjs +102 -5
- package/apps/gateway/src/server.mjs +271 -8
- package/apps/ios/EnigmaCore/Package.swift +12 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
- package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
- package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
- package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
- package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
- package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
- package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
- package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
- package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
- package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
- package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
- package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
- package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
- package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
- package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
- package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
- package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
- package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
- package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
- package/apps/native-host/README.md +19 -8
- package/apps/native-host/bin/enigma-native-host.mjs +229 -13
- package/apps/relay/bin/enigma-relay.mjs +103 -5
- package/apps/relay/src/federation-runtime.mjs +618 -0
- package/apps/relay/src/server.mjs +310 -9
- package/apps/verifier/bin/enigma-verify.mjs +327 -11
- package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
- package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
- package/cortex-v3/circuits/build/vk_bytes.json +32 -0
- package/cortex-v3/proving-assets.json +64 -0
- package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
- package/cortex-v3/zk/action-transition-vk.json +119 -0
- package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
- package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
- package/cortex-v3/zk/intent-witness.mjs +365 -0
- package/cortex-v3/zk/intent-witness.test.mjs +485 -0
- package/cortex-v3/zk/proving-assets.mjs +203 -0
- package/cortex-v3/zk/sale-witness.mjs +783 -0
- package/cortex-v3/zk/sale-witness.test.mjs +784 -0
- package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
- package/cortex-v3/zk/settlement-evidence.mjs +722 -0
- package/cortex-v3/zk/setup-intent.mjs +688 -0
- package/cortex-v3/zk/setup-sale.mjs +666 -0
- package/cortex-v3/zk/setup.mjs +594 -0
- package/cortex-v3/zk/witness.mjs +184 -0
- package/cortex-v3/zk/zk-codec.mjs +232 -0
- package/cortex-v3/zk/zk-codec.test.mjs +293 -0
- package/cortex-v3/zk/zk-settle.mjs +370 -0
- package/cortex-v3/zk/zk-tree.mjs +256 -0
- package/cortex-v3/zk/zk-tree.test.mjs +419 -0
- package/deploy/SIMULATION.md +14 -9
- package/deploy/docker-compose.local-production-simulation.yml +54 -12
- package/docs/benchmark-attestation-network.md +487 -487
- package/docs/benchmark-reproducibility.md +289 -289
- package/docs/blockchain-only-mechanisms.md +400 -400
- package/docs/browser-extension-install.md +8 -6
- package/docs/client-connectors.md +16 -12
- package/docs/demo-proof-network.md +275 -275
- package/docs/developer-ecosystem.md +15 -13
- package/docs/developer-proof-quickstart.md +325 -325
- package/docs/enigma-memory-ready-conformance.md +378 -376
- package/docs/install-anywhere.md +64 -30
- package/docs/installers-and-desktop.md +8 -7
- package/docs/memory-benchmarks.md +1 -1
- package/docs/memory-drive-health-model.md +690 -690
- package/docs/novelty-invention-candidates.md +161 -161
- package/docs/proof-network-build-notes.md +240 -240
- package/docs/proof-network-claim-boundaries.md +320 -318
- package/docs/proof-network.md +339 -339
- package/docs/sdk-api.md +324 -324
- package/docs/solana-proof-rail.md +453 -453
- package/examples/01-quickstart-agent/index.mjs +49 -0
- package/examples/01_agent_memory_quickstart.mjs +57 -0
- package/examples/02-multi-agent-swarm/index.mjs +57 -0
- package/examples/02_cross_model_passport.mjs +64 -0
- package/examples/03-langchain-memory/index.mjs +41 -0
- package/examples/03_poseidon_commitment_verification.mjs +71 -0
- package/examples/04-python-trading-agent/trader.py +49 -0
- package/examples/README.md +27 -0
- package/examples/ci/github-actions.yml +7 -2
- package/package.json +410 -278
- package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
- package/packages/connectors/src/index.js +196 -4
- package/packages/connectors/swarm-router.mjs +168 -0
- package/packages/core/src/index.js +249 -2
- package/packages/core/src/version.mjs +7 -0
- package/packages/dev-tools/package.json +19 -0
- package/packages/dev-tools/src/index.js +4 -0
- package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
- package/packages/dev-tools/src/swarm-simulator.js +101 -0
- package/packages/dev-tools/src/vault-inspector.js +114 -0
- package/packages/dev-tools/src/vector-benchmark.js +100 -0
- package/packages/developer-platform/src/access-credentials.js +341 -0
- package/packages/developer-platform/src/http.js +132 -0
- package/packages/developer-platform/src/index.js +4 -0
- package/packages/developer-platform/src/usage-http.js +60 -0
- package/packages/developer-platform/src/usage.js +295 -0
- package/packages/enclave-runtime/attestation.mjs +159 -0
- package/packages/enclave-runtime/index.mjs +47 -0
- package/packages/enclave-runtime/session-manager.mjs +253 -0
- package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
- package/packages/enigma-reflex/package.json +14 -0
- package/packages/enigma-reflex/src/index.js +204 -0
- package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
- package/packages/enigma-reflex/training/requirements.txt +8 -0
- package/packages/enigma-reflex/training/train.py +314 -0
- package/packages/enigma-weave/LICENSE +22 -0
- package/packages/enigma-weave/UPSTREAM.json +21 -0
- package/packages/enigma-weave/package.json +14 -0
- package/packages/enigma-weave/src/index.js +286 -0
- package/packages/hosted-cloud/src/index.js +80 -5
- package/packages/importers/src/index.js +432 -0
- package/packages/inference-runtime/src/browser.js +401 -0
- package/packages/inference-runtime/src/chat.js +265 -0
- package/packages/inference-runtime/src/code.js +407 -0
- package/packages/inference-runtime/src/contracts.js +162 -0
- package/packages/inference-runtime/src/http.js +232 -0
- package/packages/inference-runtime/src/image.js +186 -0
- package/packages/inference-runtime/src/index.js +10 -0
- package/packages/inference-runtime/src/model-router.js +320 -0
- package/packages/inference-runtime/src/platform.js +125 -0
- package/packages/inference-runtime/src/privacy.js +400 -0
- package/packages/inference-runtime/src/video.js +253 -0
- package/packages/mcp-server/README.md +22 -6
- package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
- package/packages/mcp-server/src/index.js +2498 -1185
- package/packages/mcp-server/src/oauth.js +561 -0
- package/packages/mcp-server/src/private-handoff.js +84 -0
- package/packages/mcp-server/src/remote-http.js +273 -0
- package/packages/mcp-server/src/remote-policy.js +72 -0
- package/packages/mcp-server/swarm-bridge.mjs +361 -0
- package/packages/mesh/index.d.ts +283 -0
- package/packages/mesh/package.json +23 -0
- package/packages/mesh/src/crypto.js +189 -0
- package/packages/mesh/src/federation-packets.js +353 -0
- package/packages/mesh/src/gossip.js +311 -0
- package/packages/mesh/src/index.js +6 -0
- package/packages/mesh/src/protocol.js +255 -0
- package/packages/mesh/src/router.js +279 -0
- package/packages/mesh/src/transport.js +306 -0
- package/packages/passport/src/index.js +436 -7
- package/packages/private-economy/src/credits-http.js +100 -0
- package/packages/private-economy/src/credits.js +447 -0
- package/packages/private-economy/src/index.js +5 -0
- package/packages/private-economy/src/payments-http.js +120 -0
- package/packages/private-economy/src/payments.js +509 -0
- package/packages/private-economy/src/x402.js +346 -0
- package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
- package/packages/rag/index.d.ts +182 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
- package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
- package/packages/rag/package.json +27 -0
- package/packages/rag/src/blinded-search.js +109 -0
- package/packages/rag/src/bm25.js +169 -0
- package/packages/rag/src/embeddings.js +459 -0
- package/packages/rag/src/hybrid.js +76 -0
- package/packages/rag/src/index.js +38 -0
- package/packages/rag/src/reranker.js +61 -0
- package/packages/rag/src/research.js +107 -0
- package/packages/rag/src/vector-store.js +430 -0
- package/packages/rag/src/verify-model-artifacts.mjs +4 -0
- package/packages/sdk/index.d.ts +760 -0
- package/packages/sdk/package.json +33 -0
- package/packages/sdk/python/README.md +24 -0
- package/packages/sdk/python/enigma_sdk.py +250 -0
- package/packages/sdk/python/pyproject.toml +34 -0
- package/packages/sdk/python/requirements.txt +1 -0
- package/packages/sdk/python/setup.py +20 -0
- package/packages/sdk/src/federation/capability-grant.js +389 -0
- package/packages/sdk/src/federation/federation-router.js +360 -0
- package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
- package/packages/sdk/src/federation/index.js +3 -0
- package/packages/sdk/src/index.js +1796 -0
- package/packages/sdk/src/intelligence/contradiction.js +337 -0
- package/packages/sdk/src/intelligence/decision-engine.js +155 -0
- package/packages/sdk/src/intelligence/index.js +4 -0
- package/packages/sdk/src/intelligence/ontology.js +122 -0
- package/packages/sdk/src/intelligence/temporal.js +123 -0
- package/packages/sdk/src/market-client.js +142 -0
- package/packages/sdk/src/mesh-client.js +110 -0
- package/packages/sdk/src/middleware/index.js +3 -0
- package/packages/sdk/src/middleware/langchain.js +159 -0
- package/packages/sdk/src/middleware/llamaindex.js +101 -0
- package/packages/sdk/src/middleware/vercel-ai.js +112 -0
- package/packages/sdk/src/rag-client.js +85 -0
- package/packages/sdk/src/swarm-orchestrator.js +260 -0
- package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
- package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
- package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
- package/packages/snapcompact/index.d.ts +284 -0
- package/packages/snapcompact/package.json +25 -0
- package/packages/snapcompact/src/index.js +716 -0
- package/packages/storage/PACKAGE_CONTRACT.md +1 -1
- package/packages/terminal-console/animations.mjs +240 -0
- package/packages/terminal-console/auto-anchor.mjs +220 -0
- package/packages/terminal-console/banner.mjs +91 -0
- package/packages/terminal-console/commands.mjs +459 -0
- package/packages/terminal-console/delegation.mjs +152 -0
- package/packages/terminal-console/index.mjs +5 -0
- package/packages/terminal-console/outbox.mjs +143 -0
- package/packages/terminal-console/phantom-bridge.mjs +637 -0
- package/packages/terminal-console/repl.mjs +136 -0
- package/packages/terminal-console/signer-store.mjs +130 -0
- package/packages/terminal-console/solana-rpc.mjs +214 -0
- package/packages/terminal-console/solana-transport.mjs +189 -0
- package/packages/terminal-tui/dashboard.mjs +214 -0
- package/packages/terminal-tui/index.mjs +28 -0
- package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
- package/packages/terminal-tui/telemetry-hud.mjs +137 -0
- package/packages/vault/index.d.ts +449 -0
- package/packages/vault/package.json +27 -0
- package/packages/vault/src/e2ee.mjs +393 -0
- package/packages/vault/src/enclave.js +481 -0
- package/packages/vault/src/erasure.js +207 -0
- package/packages/vault/src/index.js +1150 -125
- package/packages/vault/src/persistence.js +307 -0
- package/packages/vault/src/poseidon.js +354 -0
- package/packages/vault/src/receipt.js +459 -0
- package/scripts/benchmark-optical-context.mjs +166 -0
- package/scripts/bootstrap-enigma.mjs +502 -0
- package/scripts/build-edge-backend-workers.mjs +20 -5
- package/scripts/build-goal-completion-audit.mjs +72 -25
- package/scripts/build-hosted-api-key-lifecycle.mjs +292 -274
- package/scripts/build-hosted-customer-lifecycle.mjs +493 -476
- package/scripts/build-hosted-probe-worker.mjs +19 -4
- package/scripts/build-installer-assets.mjs +409 -389
- package/scripts/build-operator-evidence-starter.mjs +59 -1
- package/scripts/build-production-backend-env-kit.mjs +2 -0
- package/scripts/build-production-unblocker.mjs +4 -1
- package/scripts/build-proof-network-packet.mjs +213 -213
- package/scripts/check.mjs +25 -4
- package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
- package/scripts/install-enigma-local.mjs +18 -5
- package/scripts/release-audit.mjs +74 -115
- package/scripts/release-provenance.mjs +12 -2
- package/scripts/run-backend-readiness-smoke.mjs +112 -10
- package/scripts/run-standard-memory-benchmarks.mjs +1354 -1352
- package/scripts/scan-secrets.mjs +178 -0
- package/scripts/simulate-production-env.mjs +71 -10
- package/scripts/validate-hosted-backend-live.mjs +112 -1
- package/specs/antibody-pack-v1.schema.json +95 -0
- package/specs/antigen-envelope-v1.schema.json +81 -0
- package/specs/boundary-manifest-v1.schema.json +35 -35
- package/specs/capsule-v1.schema.json +55 -55
- package/specs/claim-boundary-manifest-v1.schema.json +22 -22
- package/specs/claim-ledger-v1.schema.json +291 -0
- package/specs/context-passport-v1.schema.json +59 -0
- package/specs/deletion-tombstone-v1.schema.json +26 -26
- package/specs/evidence-packet-v1.schema.json +177 -0
- package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
- package/specs/immune-scan-report-v1.schema.json +112 -0
- package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
- package/specs/memory-atom-v1.schema.json +59 -0
- package/specs/memory-event-v1.schema.json +42 -42
- package/specs/passport-v1.schema.json +50 -50
- package/specs/proof-of-non-use-v1.schema.json +65 -0
- package/specs/quarantine-record-v1.schema.json +126 -0
- package/specs/receipt-v1.schema.json +61 -61
- package/specs/state-checkpoint-v1.schema.json +37 -37
- package/specs/trust-bundle-v1.schema.json +56 -56
- package/specs/trust-card-v1.schema.json +119 -0
- package/docs/proof-network-launch-plan.md +0 -421
- package/packages/metering/PACKAGE_CONTRACT.md +0 -20
- package/scripts/build-ai-orchestration-plan.mjs +0 -248
|
@@ -0,0 +1,389 @@
|
|
|
1
|
+
// Enigma Blinded Memory Capability Grants.
|
|
2
|
+
// Issues and validates cryptographically signed capability grants for
|
|
3
|
+
// selective, privacy-preserving cross-agent memory federation.
|
|
4
|
+
import crypto from 'node:crypto';
|
|
5
|
+
import { normalizeMemoryType, VALID_MEMORY_TYPES } from '../intelligence/ontology.js';
|
|
6
|
+
|
|
7
|
+
export const BLINDED_GRANT_SCHEMA = 'enigma.blinded_grant.v1';
|
|
8
|
+
export const FEDERATED_QUERY_REQUEST_SCHEMA = 'enigma.federated_query_request.v1';
|
|
9
|
+
|
|
10
|
+
const ED25519_SPKI_PREFIX = Buffer.from('302a300506032b6570032100', 'hex');
|
|
11
|
+
const ED25519_PKCS8_PREFIX = Buffer.from('302e020100300506032b657004220420', 'hex');
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Computes canonical signable string for a capability grant.
|
|
15
|
+
* @param {Object} grant
|
|
16
|
+
* @returns {string}
|
|
17
|
+
*/
|
|
18
|
+
export function getGrantSignablePayload(grant) {
|
|
19
|
+
return JSON.stringify({
|
|
20
|
+
schema: grant.schema || BLINDED_GRANT_SCHEMA,
|
|
21
|
+
version: grant.version || 1,
|
|
22
|
+
grant_id: grant.grant_id,
|
|
23
|
+
granter_agent_id: grant.granter_agent_id,
|
|
24
|
+
granter_pubkey: grant.granter_pubkey,
|
|
25
|
+
grantee_pubkey: grant.grantee_pubkey,
|
|
26
|
+
scope: grant.scope,
|
|
27
|
+
allowed_types: (grant.allowed_types || []).slice().sort(),
|
|
28
|
+
max_access_count: grant.max_access_count,
|
|
29
|
+
valid_until: grant.valid_until,
|
|
30
|
+
issued_at: grant.issued_at,
|
|
31
|
+
metadata: grant.metadata || {},
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Creates and cryptographically signs a BlindedMemoryGrant.
|
|
37
|
+
* @param {Object} params
|
|
38
|
+
* @param {string} params.granterAgentId - Sovereign agent identifier
|
|
39
|
+
* @param {Buffer|string} params.granterSecretKey - 32-byte Ed25519 private key
|
|
40
|
+
* @param {Buffer|string} params.granterPublicKey - 32-byte Ed25519 public key
|
|
41
|
+
* @param {Buffer|string} params.granteePublicKey - 32-byte Ed25519 public key of receiving agent
|
|
42
|
+
* @param {string} [params.scope='enigma.global'] - Scope allowed for extraction
|
|
43
|
+
* @param {string[]} [params.allowedTypes] - Allowed ontology types ('policy', 'preference', etc.)
|
|
44
|
+
* @param {number} [params.maxAccessCount=100] - Usage limit (0 = unlimited)
|
|
45
|
+
* @param {number|string|Date} [params.validUntil] - Expiration timestamp
|
|
46
|
+
* @param {Object} [params.metadata={}]
|
|
47
|
+
* @returns {Object} Signed BlindedMemoryGrant
|
|
48
|
+
*/
|
|
49
|
+
export function createBlindedMemoryGrant(params) {
|
|
50
|
+
if (!params.granterAgentId) throw new Error('granterAgentId is required');
|
|
51
|
+
if (!params.granterSecretKey || !params.granterPublicKey) {
|
|
52
|
+
throw new Error('granterSecretKey and granterPublicKey are required');
|
|
53
|
+
}
|
|
54
|
+
if (!params.granteePublicKey) throw new Error('granteePublicKey is required');
|
|
55
|
+
|
|
56
|
+
const granterPubHex = Buffer.isBuffer(params.granterPublicKey)
|
|
57
|
+
? params.granterPublicKey.toString('hex')
|
|
58
|
+
: String(params.granterPublicKey).toLowerCase();
|
|
59
|
+
const granteePubHex = Buffer.isBuffer(params.granteePublicKey)
|
|
60
|
+
? params.granteePublicKey.toString('hex')
|
|
61
|
+
: String(params.granteePublicKey).toLowerCase();
|
|
62
|
+
if (!/^[0-9a-f]{64}$/.test(granterPubHex)) throw new Error('granterPublicKey must be exactly 32 bytes');
|
|
63
|
+
if (!/^[0-9a-f]{64}$/.test(granteePubHex)) throw new Error('granteePublicKey must be exactly 32 bytes');
|
|
64
|
+
const privBuf = Buffer.isBuffer(params.granterSecretKey)
|
|
65
|
+
? params.granterSecretKey
|
|
66
|
+
: Buffer.from(params.granterSecretKey, 'hex');
|
|
67
|
+
if (privBuf.length !== 32) throw new Error('granterSecretKey must be exactly 32 bytes');
|
|
68
|
+
|
|
69
|
+
const maxAccessCount = params.maxAccessCount === undefined ? 100 : params.maxAccessCount;
|
|
70
|
+
if (!Number.isSafeInteger(maxAccessCount) || maxAccessCount < 0) {
|
|
71
|
+
throw new Error('maxAccessCount must be a finite non-negative safe integer');
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const grantId = `grnt_${Date.now()}_${crypto.randomBytes(4).toString('hex')}`;
|
|
75
|
+
let allowedTypes = [];
|
|
76
|
+
if (params.allowedTypes !== undefined) {
|
|
77
|
+
if (!Array.isArray(params.allowedTypes)) throw new Error('allowedTypes must be an array');
|
|
78
|
+
allowedTypes = params.allowedTypes.map((type) => {
|
|
79
|
+
if (typeof type !== 'string' || !VALID_MEMORY_TYPES.has(type.trim().toLowerCase())) {
|
|
80
|
+
throw new Error(`Unknown allowed memory type: ${type}`);
|
|
81
|
+
}
|
|
82
|
+
return normalizeMemoryType(type);
|
|
83
|
+
});
|
|
84
|
+
if (new Set(allowedTypes).size !== allowedTypes.length) {
|
|
85
|
+
throw new Error('allowedTypes must not contain duplicates');
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
let validUntil;
|
|
90
|
+
try {
|
|
91
|
+
validUntil = params.validUntil === undefined
|
|
92
|
+
? new Date(Date.now() + 86400000 * 30).toISOString()
|
|
93
|
+
: new Date(params.validUntil).toISOString();
|
|
94
|
+
} catch {
|
|
95
|
+
throw new Error('validUntil must be a valid date');
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
const unsignedGrant = {
|
|
99
|
+
schema: BLINDED_GRANT_SCHEMA,
|
|
100
|
+
version: 1,
|
|
101
|
+
grant_id: grantId,
|
|
102
|
+
granter_agent_id: params.granterAgentId,
|
|
103
|
+
granter_pubkey: granterPubHex,
|
|
104
|
+
grantee_pubkey: granteePubHex,
|
|
105
|
+
scope: params.scope || 'enigma.global',
|
|
106
|
+
allowed_types: allowedTypes,
|
|
107
|
+
max_access_count: maxAccessCount,
|
|
108
|
+
valid_until: validUntil,
|
|
109
|
+
issued_at: new Date().toISOString(),
|
|
110
|
+
metadata: params.metadata || {},
|
|
111
|
+
};
|
|
112
|
+
|
|
113
|
+
const signable = getGrantSignablePayload(unsignedGrant);
|
|
114
|
+
const der = Buffer.concat([ED25519_PKCS8_PREFIX, privBuf]);
|
|
115
|
+
const privKeyObj = crypto.createPrivateKey({ key: der, format: 'der', type: 'pkcs8' });
|
|
116
|
+
const signature = crypto.sign(null, Buffer.from(signable, 'utf8'), privKeyObj);
|
|
117
|
+
|
|
118
|
+
return {
|
|
119
|
+
...unsignedGrant,
|
|
120
|
+
signature: signature.toString('hex'),
|
|
121
|
+
};
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Validates a BlindedMemoryGrant offline.
|
|
126
|
+
* @param {Object} grant
|
|
127
|
+
* @param {Object} [options]
|
|
128
|
+
* @param {string} [options.expectedGranteePubkey]
|
|
129
|
+
* @param {number} [options.asOfTime=Date.now()]
|
|
130
|
+
* @returns {{ ok: boolean, valid: boolean, grant_id: string, granter_agent_id: string, signatureValid: boolean, expired: boolean, errors: string[] }}
|
|
131
|
+
*/
|
|
132
|
+
export function verifyBlindedMemoryGrant(grant, options = {}) {
|
|
133
|
+
const errors = [];
|
|
134
|
+
if (!grant || typeof grant !== 'object') {
|
|
135
|
+
return { ok: false, valid: false, grant_id: '', granter_agent_id: '', signatureValid: false, expired: false, errors: ['Invalid grant object'] };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
if (grant.schema !== BLINDED_GRANT_SCHEMA) {
|
|
139
|
+
errors.push(`Unrecognized capability grant schema: ${grant.schema}`);
|
|
140
|
+
}
|
|
141
|
+
if (!grant.grant_id) errors.push('Missing grant_id');
|
|
142
|
+
if (!grant.granter_agent_id) errors.push('Missing granter_agent_id');
|
|
143
|
+
if (!grant.granter_pubkey || !/^[0-9a-fA-F]{64}$/.test(grant.granter_pubkey)) {
|
|
144
|
+
errors.push('Invalid 64-hex granter_pubkey');
|
|
145
|
+
}
|
|
146
|
+
if (!grant.grantee_pubkey || !/^[0-9a-fA-F]{64}$/.test(grant.grantee_pubkey)) {
|
|
147
|
+
errors.push('Invalid 64-hex grantee_pubkey');
|
|
148
|
+
}
|
|
149
|
+
if (!grant.signature || !/^[0-9a-fA-F]{128}$/.test(grant.signature)) {
|
|
150
|
+
errors.push('Invalid 128-hex signature length');
|
|
151
|
+
}
|
|
152
|
+
if (typeof grant.scope !== 'string' || grant.scope.length === 0 || grant.scope.length > 256) {
|
|
153
|
+
errors.push('scope must be a non-empty string of at most 256 characters');
|
|
154
|
+
}
|
|
155
|
+
if (typeof grant.valid_until !== 'string') errors.push('Missing valid_until');
|
|
156
|
+
if (typeof grant.issued_at !== 'string' || !Number.isFinite(new Date(grant.issued_at).getTime())) {
|
|
157
|
+
errors.push('Invalid issued_at timestamp');
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
if (!Number.isSafeInteger(grant.max_access_count) || grant.max_access_count < 0) {
|
|
161
|
+
errors.push('max_access_count must be a finite non-negative safe integer');
|
|
162
|
+
}
|
|
163
|
+
if (!Array.isArray(grant.allowed_types)) {
|
|
164
|
+
errors.push('allowed_types must be an array');
|
|
165
|
+
} else {
|
|
166
|
+
const normalizedTypes = [];
|
|
167
|
+
for (const type of grant.allowed_types) {
|
|
168
|
+
if (typeof type !== 'string' || !VALID_MEMORY_TYPES.has(type.trim().toLowerCase())) {
|
|
169
|
+
errors.push(`Unknown allowed memory type: ${type}`);
|
|
170
|
+
} else {
|
|
171
|
+
normalizedTypes.push(type.trim().toLowerCase());
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
if (new Set(normalizedTypes).size !== normalizedTypes.length) {
|
|
175
|
+
errors.push('allowed_types must not contain duplicates');
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
// Check expected grantee
|
|
180
|
+
if (options.expectedGranteePubkey &&
|
|
181
|
+
grant.grantee_pubkey?.toLowerCase() !== String(options.expectedGranteePubkey).toLowerCase()) {
|
|
182
|
+
errors.push(`grantee_pubkey mismatch: expected ${options.expectedGranteePubkey}, got ${grant.grantee_pubkey}`);
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Check expiration
|
|
186
|
+
let expired = false;
|
|
187
|
+
if (grant.valid_until) {
|
|
188
|
+
const expiresAt = new Date(grant.valid_until).getTime();
|
|
189
|
+
if (!Number.isFinite(expiresAt)) {
|
|
190
|
+
errors.push(`Invalid valid_until timestamp format: ${grant.valid_until}`);
|
|
191
|
+
} else {
|
|
192
|
+
const checkTime = options.asOfTime || Date.now();
|
|
193
|
+
if (checkTime > expiresAt) {
|
|
194
|
+
expired = true;
|
|
195
|
+
errors.push(`Capability grant expired at ${grant.valid_until}`);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Verify Ed25519 signature of granter
|
|
201
|
+
let signatureValid = false;
|
|
202
|
+
try {
|
|
203
|
+
const signable = getGrantSignablePayload(grant);
|
|
204
|
+
const pubBuf = Buffer.from(grant.granter_pubkey, 'hex');
|
|
205
|
+
const der = Buffer.concat([ED25519_SPKI_PREFIX, pubBuf]);
|
|
206
|
+
const pubKeyObj = crypto.createPublicKey({ key: der, format: 'der', type: 'spki' });
|
|
207
|
+
const sigBuf = Buffer.from(grant.signature, 'hex');
|
|
208
|
+
|
|
209
|
+
signatureValid = crypto.verify(null, Buffer.from(signable, 'utf8'), pubKeyObj, sigBuf);
|
|
210
|
+
if (!signatureValid) errors.push('Cryptographic Ed25519 signature verification failed');
|
|
211
|
+
} catch (err) {
|
|
212
|
+
errors.push(`Signature verification exception: ${err.message}`);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
const ok = errors.length === 0 && signatureValid && !expired;
|
|
216
|
+
return {
|
|
217
|
+
ok,
|
|
218
|
+
valid: ok,
|
|
219
|
+
grant_id: grant.grant_id || '',
|
|
220
|
+
granter_agent_id: grant.granter_agent_id || '',
|
|
221
|
+
signatureValid,
|
|
222
|
+
expired,
|
|
223
|
+
errors,
|
|
224
|
+
};
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
/**
|
|
228
|
+
* Canonical payload for a grantee-signed federated query authorization.
|
|
229
|
+
* @param {Object} req
|
|
230
|
+
* @returns {string}
|
|
231
|
+
*/
|
|
232
|
+
export function getFederatedQuerySignablePayload(req) {
|
|
233
|
+
const grantId = req.grant && typeof req.grant === 'object' && req.grant.grant_id
|
|
234
|
+
? req.grant.grant_id
|
|
235
|
+
: req.grant_id;
|
|
236
|
+
return JSON.stringify({
|
|
237
|
+
schema: req.schema || FEDERATED_QUERY_REQUEST_SCHEMA,
|
|
238
|
+
grant_id: grantId,
|
|
239
|
+
query: req.query,
|
|
240
|
+
requester_pubkey: req.requester_pubkey,
|
|
241
|
+
nonce: req.nonce,
|
|
242
|
+
timestamp: req.timestamp,
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Creates and cryptographically signs a proof-of-possession federated query request.
|
|
248
|
+
*/
|
|
249
|
+
export function createFederatedQueryRequest(params) {
|
|
250
|
+
if (!params.grant || !params.grant.grant_id) throw new Error('grant is required');
|
|
251
|
+
if (typeof params.query !== 'string' || params.query.trim().length === 0) {
|
|
252
|
+
throw new Error('query must be a non-empty string');
|
|
253
|
+
}
|
|
254
|
+
if (!params.requesterSecretKey) throw new Error('requesterSecretKey is required');
|
|
255
|
+
|
|
256
|
+
const privBuf = Buffer.isBuffer(params.requesterSecretKey)
|
|
257
|
+
? params.requesterSecretKey
|
|
258
|
+
: Buffer.from(params.requesterSecretKey, 'hex');
|
|
259
|
+
if (privBuf.length !== 32) throw new Error('requesterSecretKey must be exactly 32 bytes');
|
|
260
|
+
|
|
261
|
+
let pubHex;
|
|
262
|
+
if (params.requesterPublicKey) {
|
|
263
|
+
pubHex = Buffer.isBuffer(params.requesterPublicKey)
|
|
264
|
+
? params.requesterPublicKey.toString('hex')
|
|
265
|
+
: String(params.requesterPublicKey).toLowerCase();
|
|
266
|
+
} else {
|
|
267
|
+
const der = Buffer.concat([ED25519_PKCS8_PREFIX, privBuf]);
|
|
268
|
+
const privKeyObj = crypto.createPrivateKey({ key: der, format: 'der', type: 'pkcs8' });
|
|
269
|
+
const pubKeyObj = crypto.createPublicKey(privKeyObj);
|
|
270
|
+
const spkiDer = pubKeyObj.export({ format: 'der', type: 'spki' });
|
|
271
|
+
pubHex = spkiDer.subarray(ED25519_SPKI_PREFIX.length).toString('hex');
|
|
272
|
+
}
|
|
273
|
+
if (!/^[0-9a-f]{64}$/.test(pubHex)) throw new Error('requesterPublicKey must be exactly 32 bytes');
|
|
274
|
+
|
|
275
|
+
const nonce = params.nonce || crypto.randomBytes(16).toString('hex');
|
|
276
|
+
if (!/^[0-9a-f]{32}$/.test(nonce)) {
|
|
277
|
+
throw new Error('nonce must be exactly 16 bytes encoded as lowercase hex');
|
|
278
|
+
}
|
|
279
|
+
const timestamp = params.timestamp || new Date().toISOString();
|
|
280
|
+
if (typeof timestamp !== 'string') throw new Error('timestamp must be a string');
|
|
281
|
+
const unsigned = {
|
|
282
|
+
schema: FEDERATED_QUERY_REQUEST_SCHEMA,
|
|
283
|
+
version: 1,
|
|
284
|
+
grant: params.grant,
|
|
285
|
+
grant_id: params.grant.grant_id,
|
|
286
|
+
query: params.query,
|
|
287
|
+
requester_pubkey: pubHex,
|
|
288
|
+
nonce,
|
|
289
|
+
timestamp,
|
|
290
|
+
};
|
|
291
|
+
|
|
292
|
+
const signable = getFederatedQuerySignablePayload(unsigned);
|
|
293
|
+
const der = Buffer.concat([ED25519_PKCS8_PREFIX, privBuf]);
|
|
294
|
+
const privKeyObj = crypto.createPrivateKey({ key: der, format: 'der', type: 'pkcs8' });
|
|
295
|
+
const signature = crypto.sign(null, Buffer.from(signable, 'utf8'), privKeyObj);
|
|
296
|
+
|
|
297
|
+
return {
|
|
298
|
+
...unsigned,
|
|
299
|
+
signature: signature.toString('hex'),
|
|
300
|
+
};
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
/**
|
|
304
|
+
* Validates a grantee's proof-of-possession federated query request.
|
|
305
|
+
* @param {Object} request
|
|
306
|
+
* @param {Object} [options]
|
|
307
|
+
* @param {number} [options.maxClockSkewMs=300000]
|
|
308
|
+
* @param {number} [options.asOfTime=Date.now()]
|
|
309
|
+
*/
|
|
310
|
+
export function verifyFederatedQueryRequest(request, options = {}) {
|
|
311
|
+
const errors = [];
|
|
312
|
+
if (!request || typeof request !== 'object') {
|
|
313
|
+
return { ok: false, valid: false, signatureValid: false, errors: ['Invalid request object'] };
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
if (request.schema !== FEDERATED_QUERY_REQUEST_SCHEMA || request.version !== 1) {
|
|
317
|
+
errors.push(`Unrecognized federated query request schema or version: ${request.schema}`);
|
|
318
|
+
}
|
|
319
|
+
if (!request.grant || typeof request.grant !== 'object') {
|
|
320
|
+
errors.push('Missing grant in query request');
|
|
321
|
+
}
|
|
322
|
+
if (!request.grant_id) {
|
|
323
|
+
errors.push('Missing grant_id in query request');
|
|
324
|
+
} else if (request.grant?.grant_id && request.grant_id !== request.grant.grant_id) {
|
|
325
|
+
errors.push(`grant_id mismatch: outer grant_id ${request.grant_id} does not match embedded grant ${request.grant.grant_id}`);
|
|
326
|
+
}
|
|
327
|
+
if (typeof request.query !== 'string' || request.query.trim().length === 0) {
|
|
328
|
+
errors.push('Missing query string in request');
|
|
329
|
+
}
|
|
330
|
+
if (!request.requester_pubkey || !/^[0-9a-f]{64}$/.test(request.requester_pubkey)) {
|
|
331
|
+
errors.push('Invalid lowercase 64-hex requester_pubkey');
|
|
332
|
+
}
|
|
333
|
+
if (!request.nonce || !/^[0-9a-f]{32}$/.test(request.nonce)) {
|
|
334
|
+
errors.push('Invalid nonce: expected 32 lowercase hex characters');
|
|
335
|
+
}
|
|
336
|
+
if (!request.signature || !/^[0-9a-fA-F]{128}$/.test(request.signature)) {
|
|
337
|
+
errors.push('Invalid 128-hex signature length');
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (request.grant) {
|
|
341
|
+
const grantVerdict = verifyBlindedMemoryGrant(request.grant, {
|
|
342
|
+
expectedGranteePubkey: request.requester_pubkey,
|
|
343
|
+
asOfTime: options.asOfTime,
|
|
344
|
+
});
|
|
345
|
+
if (!grantVerdict.ok) {
|
|
346
|
+
errors.push(`Grant verification failed: ${grantVerdict.errors.join('; ')}`);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
if (typeof request.timestamp !== 'string') {
|
|
351
|
+
errors.push(request.timestamp === undefined
|
|
352
|
+
? 'Missing timestamp in request'
|
|
353
|
+
: 'Invalid timestamp type: expected string');
|
|
354
|
+
} else {
|
|
355
|
+
const reqDate = new Date(request.timestamp);
|
|
356
|
+
const reqTime = reqDate.getTime();
|
|
357
|
+
if (!Number.isFinite(reqTime) || reqDate.toISOString() !== request.timestamp) {
|
|
358
|
+
errors.push(`Invalid timestamp format in request: ${request.timestamp}`);
|
|
359
|
+
} else {
|
|
360
|
+
const maxSkew = options.maxClockSkewMs === undefined ? 300000 : options.maxClockSkewMs;
|
|
361
|
+
if (!Number.isSafeInteger(maxSkew) || maxSkew < 0) {
|
|
362
|
+
errors.push('maxClockSkewMs must be a finite non-negative safe integer');
|
|
363
|
+
} else {
|
|
364
|
+
const asOfTime = options.asOfTime === undefined ? Date.now() : options.asOfTime;
|
|
365
|
+
if (!Number.isFinite(asOfTime)) {
|
|
366
|
+
errors.push('asOfTime must be a finite timestamp');
|
|
367
|
+
} else if (Math.abs(asOfTime - reqTime) > maxSkew) {
|
|
368
|
+
errors.push(`Query request timestamp expired or out of allowed clock skew: ${request.timestamp}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
let signatureValid = false;
|
|
375
|
+
try {
|
|
376
|
+
const signable = getFederatedQuerySignablePayload(request);
|
|
377
|
+
const pubBuf = Buffer.from(request.requester_pubkey, 'hex');
|
|
378
|
+
const der = Buffer.concat([ED25519_SPKI_PREFIX, pubBuf]);
|
|
379
|
+
const pubKeyObj = crypto.createPublicKey({ key: der, format: 'der', type: 'spki' });
|
|
380
|
+
const sigBuf = Buffer.from(request.signature, 'hex');
|
|
381
|
+
signatureValid = crypto.verify(null, Buffer.from(signable, 'utf8'), pubKeyObj, sigBuf);
|
|
382
|
+
if (!signatureValid) errors.push('Requester proof-of-possession Ed25519 signature failed');
|
|
383
|
+
} catch (err) {
|
|
384
|
+
errors.push(`Requester signature verification exception: ${err.message}`);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
const ok = errors.length === 0 && signatureValid;
|
|
388
|
+
return { ok, valid: ok, signatureValid, errors };
|
|
389
|
+
}
|