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.
Files changed (290) hide show
  1. package/README.md +85 -27
  2. package/apps/cli/bin/enigma-desktop.mjs +140 -0
  3. package/apps/cli/bin/enigma-terminal.mjs +78 -0
  4. package/apps/cli/bin/enigma.mjs +4979 -3263
  5. package/apps/desktop/electron-main.cjs +217 -0
  6. package/apps/desktop/package.json +12 -0
  7. package/apps/desktop/src/app.js +264 -7
  8. package/apps/desktop/src/index.html +3514 -1373
  9. package/apps/desktop/src/launch-electron.mjs +51 -0
  10. package/apps/desktop/src/server.mjs +2914 -0
  11. package/apps/desktop/src/styles.css +2972 -260
  12. package/apps/desktop/src/zk-browser-prove.mjs +53 -0
  13. package/apps/desktop/src/zk-state.mjs +1789 -0
  14. package/apps/gateway/bin/enigma-gateway.mjs +102 -5
  15. package/apps/gateway/src/server.mjs +271 -8
  16. package/apps/ios/EnigmaCore/Package.swift +12 -0
  17. package/apps/ios/EnigmaCore/Sources/EnigmaCore/EnigmaAPIClient.swift +227 -0
  18. package/apps/ios/EnigmaCore/Sources/EnigmaCore/Models.swift +278 -0
  19. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PKCE.swift +96 -0
  20. package/apps/ios/EnigmaCore/Sources/EnigmaCore/PrivacyMinimizer.swift +187 -0
  21. package/apps/ios/EnigmaCore/Sources/EnigmaCore/ToolModels.swift +129 -0
  22. package/apps/ios/EnigmaCore/Tests/EnigmaCoreTests/EnigmaCoreTests.swift +42 -0
  23. package/apps/ios/EnigmaIOS/Enigma/AppModel.swift +346 -0
  24. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AccentColor.colorset/Contents.json +12 -0
  25. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/Contents.json +11 -0
  26. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/AppIcon.appiconset/EnigmaAppIcon.png +0 -0
  27. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/Contents.json +3 -0
  28. package/apps/ios/EnigmaIOS/Enigma/Assets.xcassets/LaunchBackground.colorset/Contents.json +12 -0
  29. package/apps/ios/EnigmaIOS/Enigma/ChatView.swift +181 -0
  30. package/apps/ios/EnigmaIOS/Enigma/CouncilView.swift +78 -0
  31. package/apps/ios/EnigmaIOS/Enigma/CreateView.swift +152 -0
  32. package/apps/ios/EnigmaIOS/Enigma/EnigmaApp.swift +52 -0
  33. package/apps/ios/EnigmaIOS/Enigma/Info.plist +52 -0
  34. package/apps/ios/EnigmaIOS/Enigma/NaturalLanguagePrivacyTagger.swift +26 -0
  35. package/apps/ios/EnigmaIOS/Enigma/OAuthClient.swift +321 -0
  36. package/apps/ios/EnigmaIOS/Enigma/OnboardingView.swift +105 -0
  37. package/apps/ios/EnigmaIOS/Enigma/PrivateVaultView.swift +275 -0
  38. package/apps/ios/EnigmaIOS/Enigma/SecureStore.swift +76 -0
  39. package/apps/ios/EnigmaIOS/Enigma/SettingsView.swift +60 -0
  40. package/apps/ios/EnigmaIOS/Enigma/Theme.swift +80 -0
  41. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/project.pbxproj +211 -0
  42. package/apps/ios/EnigmaIOS/EnigmaIOS.xcodeproj/xcshareddata/xcschemes/Enigma.xcscheme +23 -0
  43. package/apps/native-host/README.md +19 -8
  44. package/apps/native-host/bin/enigma-native-host.mjs +229 -13
  45. package/apps/relay/bin/enigma-relay.mjs +103 -5
  46. package/apps/relay/src/federation-runtime.mjs +618 -0
  47. package/apps/relay/src/server.mjs +310 -9
  48. package/apps/verifier/bin/enigma-verify.mjs +327 -11
  49. package/cortex-v3/circuits/build/intent_vk_bytes.json +35 -0
  50. package/cortex-v3/circuits/build/sale_vk_bytes.json +35 -0
  51. package/cortex-v3/circuits/build/vk_bytes.json +32 -0
  52. package/cortex-v3/proving-assets.json +64 -0
  53. package/cortex-v3/zk/BUILD-CONTRACT.md +87 -0
  54. package/cortex-v3/zk/action-transition-vk.json +119 -0
  55. package/cortex-v3/zk/alias-adversarial.test.mjs +220 -0
  56. package/cortex-v3/zk/groth16-verify-child.mjs +17 -0
  57. package/cortex-v3/zk/intent-witness.mjs +365 -0
  58. package/cortex-v3/zk/intent-witness.test.mjs +485 -0
  59. package/cortex-v3/zk/proving-assets.mjs +203 -0
  60. package/cortex-v3/zk/sale-witness.mjs +783 -0
  61. package/cortex-v3/zk/sale-witness.test.mjs +784 -0
  62. package/cortex-v3/zk/sealed-sale-release-vk.json +119 -0
  63. package/cortex-v3/zk/settlement-evidence.mjs +722 -0
  64. package/cortex-v3/zk/setup-intent.mjs +688 -0
  65. package/cortex-v3/zk/setup-sale.mjs +666 -0
  66. package/cortex-v3/zk/setup.mjs +594 -0
  67. package/cortex-v3/zk/witness.mjs +184 -0
  68. package/cortex-v3/zk/zk-codec.mjs +232 -0
  69. package/cortex-v3/zk/zk-codec.test.mjs +293 -0
  70. package/cortex-v3/zk/zk-settle.mjs +370 -0
  71. package/cortex-v3/zk/zk-tree.mjs +256 -0
  72. package/cortex-v3/zk/zk-tree.test.mjs +419 -0
  73. package/deploy/SIMULATION.md +14 -9
  74. package/deploy/docker-compose.local-production-simulation.yml +54 -12
  75. package/docs/benchmark-attestation-network.md +487 -487
  76. package/docs/benchmark-reproducibility.md +289 -289
  77. package/docs/blockchain-only-mechanisms.md +400 -400
  78. package/docs/browser-extension-install.md +8 -6
  79. package/docs/client-connectors.md +16 -12
  80. package/docs/demo-proof-network.md +275 -275
  81. package/docs/developer-ecosystem.md +15 -13
  82. package/docs/developer-proof-quickstart.md +325 -325
  83. package/docs/enigma-memory-ready-conformance.md +378 -376
  84. package/docs/install-anywhere.md +64 -30
  85. package/docs/installers-and-desktop.md +8 -7
  86. package/docs/memory-benchmarks.md +1 -1
  87. package/docs/memory-drive-health-model.md +690 -690
  88. package/docs/novelty-invention-candidates.md +161 -161
  89. package/docs/proof-network-build-notes.md +240 -240
  90. package/docs/proof-network-claim-boundaries.md +320 -318
  91. package/docs/proof-network.md +339 -339
  92. package/docs/sdk-api.md +324 -324
  93. package/docs/solana-proof-rail.md +453 -453
  94. package/examples/01-quickstart-agent/index.mjs +49 -0
  95. package/examples/01_agent_memory_quickstart.mjs +57 -0
  96. package/examples/02-multi-agent-swarm/index.mjs +57 -0
  97. package/examples/02_cross_model_passport.mjs +64 -0
  98. package/examples/03-langchain-memory/index.mjs +41 -0
  99. package/examples/03_poseidon_commitment_verification.mjs +71 -0
  100. package/examples/04-python-trading-agent/trader.py +49 -0
  101. package/examples/README.md +27 -0
  102. package/examples/ci/github-actions.yml +7 -2
  103. package/package.json +410 -278
  104. package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
  105. package/packages/connectors/src/index.js +196 -4
  106. package/packages/connectors/swarm-router.mjs +168 -0
  107. package/packages/core/src/index.js +249 -2
  108. package/packages/core/src/version.mjs +7 -0
  109. package/packages/dev-tools/package.json +19 -0
  110. package/packages/dev-tools/src/index.js +4 -0
  111. package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
  112. package/packages/dev-tools/src/swarm-simulator.js +101 -0
  113. package/packages/dev-tools/src/vault-inspector.js +114 -0
  114. package/packages/dev-tools/src/vector-benchmark.js +100 -0
  115. package/packages/developer-platform/src/access-credentials.js +341 -0
  116. package/packages/developer-platform/src/http.js +132 -0
  117. package/packages/developer-platform/src/index.js +4 -0
  118. package/packages/developer-platform/src/usage-http.js +60 -0
  119. package/packages/developer-platform/src/usage.js +295 -0
  120. package/packages/enclave-runtime/attestation.mjs +159 -0
  121. package/packages/enclave-runtime/index.mjs +47 -0
  122. package/packages/enclave-runtime/session-manager.mjs +253 -0
  123. package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
  124. package/packages/enigma-reflex/package.json +14 -0
  125. package/packages/enigma-reflex/src/index.js +204 -0
  126. package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
  127. package/packages/enigma-reflex/training/requirements.txt +8 -0
  128. package/packages/enigma-reflex/training/train.py +314 -0
  129. package/packages/enigma-weave/LICENSE +22 -0
  130. package/packages/enigma-weave/UPSTREAM.json +21 -0
  131. package/packages/enigma-weave/package.json +14 -0
  132. package/packages/enigma-weave/src/index.js +286 -0
  133. package/packages/hosted-cloud/src/index.js +80 -5
  134. package/packages/importers/src/index.js +432 -0
  135. package/packages/inference-runtime/src/browser.js +401 -0
  136. package/packages/inference-runtime/src/chat.js +265 -0
  137. package/packages/inference-runtime/src/code.js +407 -0
  138. package/packages/inference-runtime/src/contracts.js +162 -0
  139. package/packages/inference-runtime/src/http.js +232 -0
  140. package/packages/inference-runtime/src/image.js +186 -0
  141. package/packages/inference-runtime/src/index.js +10 -0
  142. package/packages/inference-runtime/src/model-router.js +320 -0
  143. package/packages/inference-runtime/src/platform.js +125 -0
  144. package/packages/inference-runtime/src/privacy.js +400 -0
  145. package/packages/inference-runtime/src/video.js +253 -0
  146. package/packages/mcp-server/README.md +22 -6
  147. package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
  148. package/packages/mcp-server/src/index.js +2498 -1185
  149. package/packages/mcp-server/src/oauth.js +561 -0
  150. package/packages/mcp-server/src/private-handoff.js +84 -0
  151. package/packages/mcp-server/src/remote-http.js +273 -0
  152. package/packages/mcp-server/src/remote-policy.js +72 -0
  153. package/packages/mcp-server/swarm-bridge.mjs +361 -0
  154. package/packages/mesh/index.d.ts +283 -0
  155. package/packages/mesh/package.json +23 -0
  156. package/packages/mesh/src/crypto.js +189 -0
  157. package/packages/mesh/src/federation-packets.js +353 -0
  158. package/packages/mesh/src/gossip.js +311 -0
  159. package/packages/mesh/src/index.js +6 -0
  160. package/packages/mesh/src/protocol.js +255 -0
  161. package/packages/mesh/src/router.js +279 -0
  162. package/packages/mesh/src/transport.js +306 -0
  163. package/packages/passport/src/index.js +436 -7
  164. package/packages/private-economy/src/credits-http.js +100 -0
  165. package/packages/private-economy/src/credits.js +447 -0
  166. package/packages/private-economy/src/index.js +5 -0
  167. package/packages/private-economy/src/payments-http.js +120 -0
  168. package/packages/private-economy/src/payments.js +509 -0
  169. package/packages/private-economy/src/x402.js +346 -0
  170. package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
  171. package/packages/rag/index.d.ts +182 -0
  172. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
  173. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
  174. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
  175. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
  176. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
  177. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
  178. package/packages/rag/package.json +27 -0
  179. package/packages/rag/src/blinded-search.js +109 -0
  180. package/packages/rag/src/bm25.js +169 -0
  181. package/packages/rag/src/embeddings.js +459 -0
  182. package/packages/rag/src/hybrid.js +76 -0
  183. package/packages/rag/src/index.js +38 -0
  184. package/packages/rag/src/reranker.js +61 -0
  185. package/packages/rag/src/research.js +107 -0
  186. package/packages/rag/src/vector-store.js +430 -0
  187. package/packages/rag/src/verify-model-artifacts.mjs +4 -0
  188. package/packages/sdk/index.d.ts +760 -0
  189. package/packages/sdk/package.json +33 -0
  190. package/packages/sdk/python/README.md +24 -0
  191. package/packages/sdk/python/enigma_sdk.py +250 -0
  192. package/packages/sdk/python/pyproject.toml +34 -0
  193. package/packages/sdk/python/requirements.txt +1 -0
  194. package/packages/sdk/python/setup.py +20 -0
  195. package/packages/sdk/src/federation/capability-grant.js +389 -0
  196. package/packages/sdk/src/federation/federation-router.js +360 -0
  197. package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
  198. package/packages/sdk/src/federation/index.js +3 -0
  199. package/packages/sdk/src/index.js +1796 -0
  200. package/packages/sdk/src/intelligence/contradiction.js +337 -0
  201. package/packages/sdk/src/intelligence/decision-engine.js +155 -0
  202. package/packages/sdk/src/intelligence/index.js +4 -0
  203. package/packages/sdk/src/intelligence/ontology.js +122 -0
  204. package/packages/sdk/src/intelligence/temporal.js +123 -0
  205. package/packages/sdk/src/market-client.js +142 -0
  206. package/packages/sdk/src/mesh-client.js +110 -0
  207. package/packages/sdk/src/middleware/index.js +3 -0
  208. package/packages/sdk/src/middleware/langchain.js +159 -0
  209. package/packages/sdk/src/middleware/llamaindex.js +101 -0
  210. package/packages/sdk/src/middleware/vercel-ai.js +112 -0
  211. package/packages/sdk/src/rag-client.js +85 -0
  212. package/packages/sdk/src/swarm-orchestrator.js +260 -0
  213. package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
  214. package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
  215. package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
  216. package/packages/snapcompact/index.d.ts +284 -0
  217. package/packages/snapcompact/package.json +25 -0
  218. package/packages/snapcompact/src/index.js +716 -0
  219. package/packages/storage/PACKAGE_CONTRACT.md +1 -1
  220. package/packages/terminal-console/animations.mjs +240 -0
  221. package/packages/terminal-console/auto-anchor.mjs +220 -0
  222. package/packages/terminal-console/banner.mjs +91 -0
  223. package/packages/terminal-console/commands.mjs +459 -0
  224. package/packages/terminal-console/delegation.mjs +152 -0
  225. package/packages/terminal-console/index.mjs +5 -0
  226. package/packages/terminal-console/outbox.mjs +143 -0
  227. package/packages/terminal-console/phantom-bridge.mjs +637 -0
  228. package/packages/terminal-console/repl.mjs +136 -0
  229. package/packages/terminal-console/signer-store.mjs +130 -0
  230. package/packages/terminal-console/solana-rpc.mjs +214 -0
  231. package/packages/terminal-console/solana-transport.mjs +189 -0
  232. package/packages/terminal-tui/dashboard.mjs +214 -0
  233. package/packages/terminal-tui/index.mjs +28 -0
  234. package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
  235. package/packages/terminal-tui/telemetry-hud.mjs +137 -0
  236. package/packages/vault/index.d.ts +449 -0
  237. package/packages/vault/package.json +27 -0
  238. package/packages/vault/src/e2ee.mjs +393 -0
  239. package/packages/vault/src/enclave.js +481 -0
  240. package/packages/vault/src/erasure.js +207 -0
  241. package/packages/vault/src/index.js +1150 -125
  242. package/packages/vault/src/persistence.js +307 -0
  243. package/packages/vault/src/poseidon.js +354 -0
  244. package/packages/vault/src/receipt.js +459 -0
  245. package/scripts/benchmark-optical-context.mjs +166 -0
  246. package/scripts/bootstrap-enigma.mjs +502 -0
  247. package/scripts/build-edge-backend-workers.mjs +20 -5
  248. package/scripts/build-goal-completion-audit.mjs +72 -25
  249. package/scripts/build-hosted-api-key-lifecycle.mjs +292 -274
  250. package/scripts/build-hosted-customer-lifecycle.mjs +493 -476
  251. package/scripts/build-hosted-probe-worker.mjs +19 -4
  252. package/scripts/build-installer-assets.mjs +409 -389
  253. package/scripts/build-operator-evidence-starter.mjs +59 -1
  254. package/scripts/build-production-backend-env-kit.mjs +2 -0
  255. package/scripts/build-production-unblocker.mjs +4 -1
  256. package/scripts/build-proof-network-packet.mjs +213 -213
  257. package/scripts/check.mjs +25 -4
  258. package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
  259. package/scripts/install-enigma-local.mjs +18 -5
  260. package/scripts/release-audit.mjs +74 -115
  261. package/scripts/release-provenance.mjs +12 -2
  262. package/scripts/run-backend-readiness-smoke.mjs +112 -10
  263. package/scripts/run-standard-memory-benchmarks.mjs +1354 -1352
  264. package/scripts/scan-secrets.mjs +178 -0
  265. package/scripts/simulate-production-env.mjs +71 -10
  266. package/scripts/validate-hosted-backend-live.mjs +112 -1
  267. package/specs/antibody-pack-v1.schema.json +95 -0
  268. package/specs/antigen-envelope-v1.schema.json +81 -0
  269. package/specs/boundary-manifest-v1.schema.json +35 -35
  270. package/specs/capsule-v1.schema.json +55 -55
  271. package/specs/claim-boundary-manifest-v1.schema.json +22 -22
  272. package/specs/claim-ledger-v1.schema.json +291 -0
  273. package/specs/context-passport-v1.schema.json +59 -0
  274. package/specs/deletion-tombstone-v1.schema.json +26 -26
  275. package/specs/evidence-packet-v1.schema.json +177 -0
  276. package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
  277. package/specs/immune-scan-report-v1.schema.json +112 -0
  278. package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
  279. package/specs/memory-atom-v1.schema.json +59 -0
  280. package/specs/memory-event-v1.schema.json +42 -42
  281. package/specs/passport-v1.schema.json +50 -50
  282. package/specs/proof-of-non-use-v1.schema.json +65 -0
  283. package/specs/quarantine-record-v1.schema.json +126 -0
  284. package/specs/receipt-v1.schema.json +61 -61
  285. package/specs/state-checkpoint-v1.schema.json +37 -37
  286. package/specs/trust-bundle-v1.schema.json +56 -56
  287. package/specs/trust-card-v1.schema.json +119 -0
  288. package/docs/proof-network-launch-plan.md +0 -421
  289. package/packages/metering/PACKAGE_CONTRACT.md +0 -20
  290. package/scripts/build-ai-orchestration-plan.mjs +0 -248
@@ -0,0 +1,311 @@
1
+ // Enigma Encrypted Mesh Protocol ("GhostMesh") — Epidemic Gossip & Node Coordinator.
2
+ // Connects transports, routers, and cryptographic envelopes into an autonomous AI memory mesh node.
3
+ import { EventEmitter } from 'node:events';
4
+ import { PACKET_TYPES, encodePacket, decodePacket, deriveDestination } from './protocol.js';
5
+ import { generateMeshIdentity, sealPayload, unsealPayload, signPacket, verifyPacketSignature } from './crypto.js';
6
+ import { PacketRouter } from './router.js';
7
+ const MAX_DISCOVERED_PEERS = 1_024;
8
+
9
+ export class MeshGossipNode extends EventEmitter {
10
+ /**
11
+ * @param {Object} options
12
+ * @param {Object} [options.identity] - Ed25519 identity keypair
13
+ * @param {string} [options.nodeId] - Node identifier label
14
+ * @param {string} [options.scope='enigma.global']
15
+ * @param {Array<import('./transport.js').AbstractTransport>} [options.transports]
16
+ */
17
+ constructor(options = {}) {
18
+ super();
19
+ this.scope = options.scope || 'enigma.global';
20
+ this.identity = options.identity || generateMeshIdentity(this.scope);
21
+ this.nodeId = options.nodeId || this.identity.destinationHex.slice(0, 12);
22
+ this.router = new PacketRouter({
23
+ nodeIdentity: this.identity,
24
+ nodeId: this.nodeId,
25
+ });
26
+
27
+ this.transports = new Map();
28
+ this.discoveredPeers = new Map();
29
+ if (Array.isArray(options.transports)) {
30
+ for (const t of options.transports) this.addTransport(t);
31
+ }
32
+
33
+ // Bind router events
34
+ this.router.on('delivered', (evt) => this.handleDeliveredPacket(evt));
35
+ this.router.on('routed', (evt) => this.forwardPacket(evt));
36
+ this.router.on('announce', (evt) => this.handleAnnounce(evt));
37
+ }
38
+
39
+ addTransport(transport) {
40
+ if ('identity' in transport && !transport.running) transport.identity = this.identity;
41
+ this.transports.set(transport.id, transport);
42
+ transport.on('packet', async ({ packetBuffer, fromPeerId, transportId }) => {
43
+ const admitted = this.router.registerPeer(fromPeerId, { transportId });
44
+ const result = admitted
45
+ ? await this.router.handleIncomingPacket(packetBuffer, fromPeerId, transportId)
46
+ : { action: 'DROPPED', reason: 'peer_capacity_reached' };
47
+ this.emit('packet:handled', { result, fromPeerId, transportId });
48
+ });
49
+
50
+ transport.on('peer:connect', ({ peerId, publicKey, address }) => {
51
+ const admitted = this.router.registerPeer(peerId, { transportId: transport.id, publicKey, address });
52
+ if (!admitted) return;
53
+ this.emit('peer:connect', { peerId, publicKey, address, transportId: transport.id });
54
+ // Announce immediately to the newly connected peer
55
+ this.announce().catch(() => {});
56
+ });
57
+
58
+ transport.on('peer:disconnect', ({ peerId }) => {
59
+ this.router.unregisterPeer(peerId);
60
+ this.emit('peer:disconnect', { peerId, transportId: transport.id });
61
+ });
62
+ }
63
+
64
+ async start() {
65
+ for (const t of this.transports.values()) {
66
+ if (!t.running) await t.start();
67
+ }
68
+ await this.announce();
69
+ }
70
+
71
+ async stop() {
72
+ for (const t of this.transports.values()) {
73
+ if (t.running) await t.stop();
74
+ }
75
+ }
76
+
77
+ /**
78
+ * Broadcasts a signed Announce beacon to all connected peers across all transports.
79
+ * @param {Object} [metadata] - Optional public node metadata (e.g. supported scopes, note root)
80
+ * @returns {Promise<Buffer>} The signed announce packet buffer
81
+ */
82
+ async announce(metadata = {}) {
83
+ const metaJson = JSON.stringify({
84
+ nodeId: this.nodeId,
85
+ scope: this.scope,
86
+ destinationHex: this.identity.destinationHex,
87
+ encryptionPublicKeyHex: this.identity.encryptionPublicKey ? this.identity.encryptionPublicKey.toString('hex') : null,
88
+ timestamp: Date.now(),
89
+ ...metadata,
90
+ });
91
+
92
+ const unsigned = encodePacket({
93
+ type: PACKET_TYPES.ANNOUNCE,
94
+ destination: this.identity.destination,
95
+ senderPubkey: this.identity.publicKey,
96
+ payload: Buffer.from(metaJson, 'utf8'),
97
+ hopTtl: 5,
98
+ });
99
+
100
+ const signed = signPacket(unsigned, this.identity.secretKey);
101
+ for (const t of this.transports.values()) {
102
+ await t.broadcast(signed);
103
+ }
104
+ return signed;
105
+ }
106
+
107
+ /**
108
+ * Sends an end-to-end encrypted memory capsule to a target destination.
109
+ * @param {Buffer|string} destination - 32-byte destination hash or hex
110
+ * @param {Buffer} recipientEd25519Pub - Recipient's 32-byte Ed25519 public key
111
+ * @param {string|Object} memoryContent - Confidential memory payload
112
+ * @param {Object} [opts]
113
+ * @returns {Promise<{packetId: string, deliveredLocally: boolean, routed: boolean}>}
114
+ */
115
+ async sendEncryptedCapsule(destination, recipientEd25519Pub, memoryContent, opts = {}) {
116
+ const destBuf = Buffer.isBuffer(destination) ? destination : Buffer.from(destination, 'hex');
117
+ const plainJson = typeof memoryContent === 'string' ? memoryContent : JSON.stringify(memoryContent);
118
+
119
+ // 1. Seal payload with ephemeral X25519 ECDH + AES-GCM and bind destination AAD
120
+ const { ciphertext, authTag, ephemeralPubkey } = sealPayload(plainJson, recipientEd25519Pub, {
121
+ ...opts,
122
+ aad: destBuf,
123
+ });
124
+ // 2. Encode packet
125
+ const unsigned = encodePacket({
126
+ type: PACKET_TYPES.MEMORY_CAPSULE,
127
+ destination: destBuf,
128
+ senderPubkey: this.identity.publicKey,
129
+ ephemeralPubkey,
130
+ payload: ciphertext,
131
+ authTag,
132
+ hopTtl: opts.hopTtl || 7,
133
+ });
134
+
135
+ // 3. Sign packet with sender's Ed25519 key
136
+ const signed = signPacket(unsigned, this.identity.secretKey);
137
+
138
+ // 4. Check if destination is self
139
+ if (destBuf.equals(this.identity.destination)) {
140
+ const decrypted = unsealPayload(ciphertext, authTag, ephemeralPubkey, this.identity.encryptionSecretKey, {
141
+ ...opts,
142
+ aad: destBuf,
143
+ });
144
+ this.emit('capsule', {
145
+ plaintext: decrypted.toString('utf8'),
146
+ senderPubkey: this.identity.publicKey,
147
+ destination: destBuf,
148
+ });
149
+ return { packetId: signed.subarray(signed.length - 16).toString('hex'), deliveredLocally: true, routed: false };
150
+ }
151
+
152
+ // 5. Route through best transport
153
+ const route = this.router.getBestRoute(destBuf.toString('hex'));
154
+ if (route) {
155
+ const transport = this.transports.get(route.transportId);
156
+ if (transport) {
157
+ await transport.send(signed, route.peerId);
158
+ return { packetId: signed.subarray(signed.length - 16).toString('hex'), deliveredLocally: false, routed: true };
159
+ }
160
+ }
161
+
162
+ // Fallback: broadcast across all active transports
163
+ let broadcastSent = false;
164
+ for (const t of this.transports.values()) {
165
+ const ok = await t.broadcast(signed);
166
+ if (ok) broadcastSent = true;
167
+ }
168
+
169
+ return { packetId: signed.subarray(signed.length - 16).toString('hex'), deliveredLocally: false, routed: broadcastSent };
170
+ }
171
+ handleAnnounce({ packet, metadata, fromPeerId }) {
172
+ const destinationHex = packet.destinationHex;
173
+ const publicKeyHex = packet.senderPubkey.toString('hex');
174
+ const encryptionPublicKeyHex = metadata.encryptionPublicKeyHex;
175
+ if (!this.discoveredPeers.has(destinationHex) && this.discoveredPeers.size >= MAX_DISCOVERED_PEERS) {
176
+ const oldest = this.discoveredPeers.keys().next().value;
177
+ this.discoveredPeers.delete(oldest);
178
+ }
179
+ this.discoveredPeers.set(destinationHex, {
180
+ destinationHex,
181
+ publicKeyHex,
182
+ encryptionPublicKeyHex,
183
+ agentName: metadata.agentName || metadata.name || `Node ${destinationHex.slice(0, 8)}`,
184
+ nodeId: metadata.nodeId || destinationHex.slice(0, 8),
185
+ scope: metadata.scope,
186
+ lastSeenAt: new Date().toISOString(),
187
+ metadata,
188
+ });
189
+ this.emit('peer:announce', { destinationHex, publicKeyHex, encryptionPublicKeyHex, metadata, fromPeerId });
190
+ }
191
+
192
+ getPeers() {
193
+ return Array.from(this.discoveredPeers.values());
194
+ }
195
+
196
+ /**
197
+ * Gossips a pre-signed Solana ZK proof or transaction to mesh gateway nodes.
198
+ * @param {Object} proofPayload - { signature, publicInputs, proofBytes, txBase64 }
199
+ * @returns {Promise<Buffer>}
200
+ */
201
+ async broadcastZkProof(proofPayload) {
202
+ const payloadJson = JSON.stringify(proofPayload);
203
+ const unsigned = encodePacket({
204
+ type: PACKET_TYPES.ZK_PROOF_GOSSIP,
205
+ destination: Buffer.alloc(32, 0xff), // Broadcast destination
206
+ senderPubkey: this.identity.publicKey,
207
+ payload: Buffer.from(payloadJson, 'utf8'),
208
+ hopTtl: 6,
209
+ });
210
+
211
+ const signed = signPacket(unsigned, this.identity.secretKey);
212
+ for (const t of this.transports.values()) {
213
+ await t.broadcast(signed);
214
+ }
215
+ return signed;
216
+ }
217
+
218
+ /**
219
+ * Gossips a Sealed Sale offer across the mesh for zero-trust buyer discovery.
220
+ * @param {Object} saleListing - Standard Sealed Sale listing JSON
221
+ * @returns {Promise<Buffer>}
222
+ */
223
+ async broadcastSealedSaleOffer(saleListing) {
224
+ const listingJson = JSON.stringify(saleListing);
225
+ const unsigned = encodePacket({
226
+ type: PACKET_TYPES.SEALED_SALE_OFFER,
227
+ destination: Buffer.alloc(32, 0xff),
228
+ senderPubkey: this.identity.publicKey,
229
+ payload: Buffer.from(listingJson, 'utf8'),
230
+ hopTtl: 6,
231
+ });
232
+
233
+ const signed = signPacket(unsigned, this.identity.secretKey);
234
+ for (const t of this.transports.values()) {
235
+ await t.broadcast(signed);
236
+ }
237
+ return signed;
238
+ }
239
+
240
+ handleDeliveredPacket({ packet, fromPeerId }) {
241
+ switch (packet.type) {
242
+ case PACKET_TYPES.MEMORY_CAPSULE: {
243
+ try {
244
+ const decrypted = unsealPayload(
245
+ packet.payload,
246
+ packet.authTag,
247
+ packet.ephemeralPubkey,
248
+ this.identity.encryptionSecretKey,
249
+ { aad: packet.destination }
250
+ );
251
+ this.emit('capsule', {
252
+ plaintext: decrypted.toString('utf8'),
253
+ senderPubkey: packet.senderPubkey,
254
+ senderPubkeyHex: packet.senderPubkeyHex,
255
+ destinationHex: packet.destinationHex,
256
+ fromPeerId,
257
+ });
258
+ } catch (err) {
259
+ this.emit('capsule:error', { error: err.message, fromPeerId });
260
+ }
261
+ break;
262
+ }
263
+ case PACKET_TYPES.ZK_PROOF_GOSSIP: {
264
+ try {
265
+ const data = JSON.parse(packet.payload.toString('utf8'));
266
+ this.emit('zk:proof', { proof: data, senderPubkey: packet.senderPubkeyHex, fromPeerId });
267
+ } catch {}
268
+ break;
269
+ }
270
+ case PACKET_TYPES.SEALED_SALE_OFFER: {
271
+ try {
272
+ const data = JSON.parse(packet.payload.toString('utf8'));
273
+ this.emit('sale:offer', { listing: data, senderPubkey: packet.senderPubkeyHex, fromPeerId });
274
+ } catch {}
275
+ break;
276
+ }
277
+ case PACKET_TYPES.ANNOUNCE: {
278
+ try {
279
+ const data = JSON.parse(packet.payload.toString('utf8'));
280
+ this.emit('announce', { metadata: data, senderPubkey: packet.senderPubkeyHex, fromPeerId });
281
+ } catch {}
282
+ break;
283
+ }
284
+ default:
285
+ this.emit('packet', { packet, fromPeerId });
286
+ }
287
+ }
288
+
289
+ async forwardPacket({ packet, nextHopPeerId, transportId, forwardBuffer }) {
290
+ const transport = this.transports.get(transportId);
291
+ if (transport) {
292
+ await transport.send(forwardBuffer, nextHopPeerId);
293
+ }
294
+ }
295
+
296
+ getStatus() {
297
+ const stats = this.router.getRoutingStats();
298
+ const transportStats = Array.from(this.transports.values()).map((t) => (t.getStats ? t.getStats() : { id: t.id }));
299
+
300
+ return {
301
+ ok: true,
302
+ nodeId: this.nodeId,
303
+ scope: this.scope,
304
+ destinationHex: this.identity.destinationHex,
305
+ publicKeyHex: this.identity.publicKey.toString('hex'),
306
+ encryptionPublicKeyHex: this.identity.encryptionPublicKey ? this.identity.encryptionPublicKey.toString('hex') : null,
307
+ router: stats,
308
+ transports: transportStats,
309
+ };
310
+ }
311
+ }
@@ -529,3 +529,9 @@ export default {
529
529
  verifyFederationGrant,
530
530
  runMeshDemo
531
531
  };
532
+ export * from './protocol.js';
533
+ export * from './crypto.js';
534
+ export * from './router.js';
535
+ export * from './transport.js';
536
+ export * from './gossip.js';
537
+ export * from './federation-packets.js';
@@ -0,0 +1,255 @@
1
+ // Enigma Encrypted Mesh Protocol ("GhostMesh") — Binary Packet Framing & Codec.
2
+ // Implements identity-based destination derivation, binary packet serialization,
3
+ // and zero-copy header parsing for low-bandwidth BLE / LoRa / WebRTC transports.
4
+ import crypto from 'node:crypto';
5
+ export const PROTOCOL_MAGIC = 0x454e; // 'EN'
6
+ export const PROTOCOL_VERSION = 1;
7
+ export const HEADER_SIZE = 112; // Fixed header bytes before variable payload
8
+ export const MAX_PACKET_SIZE = 65535; // 64KB max packet size
9
+ export const DEFAULT_HOP_TTL = 7;
10
+
11
+ export const PACKET_TYPES = Object.freeze({
12
+ ANNOUNCE: 0x01,
13
+ MEMORY_CAPSULE: 0x02,
14
+ ZK_PROOF_GOSSIP: 0x03,
15
+ SEALED_SALE_OFFER: 0x04,
16
+ TREE_SYNC_REQ: 0x05,
17
+ TREE_SYNC_RESP: 0x06,
18
+ STORE_FORWARD_CHUNK: 0x07,
19
+ ACK: 0x08,
20
+ CAPABILITY_GRANT: 0x09,
21
+ FEDERATED_QUERY_REQUEST: 0x0a,
22
+ FEDERATED_QUERY_RESPONSE: 0x0b,
23
+ CAPABILITY_REVOCATION: 0x0c,
24
+ });
25
+
26
+ export const PACKET_TYPE_NAMES = Object.freeze(
27
+ Object.fromEntries(Object.entries(PACKET_TYPES).map(([k, v]) => [v, k]))
28
+ );
29
+
30
+ /**
31
+ * Derives a 32-byte cryptographic destination hash from an agent's signing key, encryption key, and scope.
32
+ * @param {Buffer|Uint8Array|string} ed25519PublicKey - 32-byte Ed25519 public key
33
+ * @param {Buffer|Uint8Array|string|{x: string|bigint, y: string|bigint}|null} [encryptionPublicKey] - 32-byte X25519 public key or BabyJub point
34
+ * @param {string} [scope='enigma.global']
35
+ * @returns {Buffer} 32-byte destination hash
36
+ */
37
+ export function deriveDestination(ed25519PublicKey, encryptionPublicKey = null, scope = 'enigma.global') {
38
+ const h = crypto.createHash('sha256');
39
+ const pubBuf = Buffer.isBuffer(ed25519PublicKey)
40
+ ? ed25519PublicKey
41
+ : typeof ed25519PublicKey === 'string'
42
+ ? Buffer.from(ed25519PublicKey, 'hex')
43
+ : Buffer.from(ed25519PublicKey);
44
+ h.update(pubBuf);
45
+
46
+ if (encryptionPublicKey) {
47
+ if (Buffer.isBuffer(encryptionPublicKey)) {
48
+ h.update(encryptionPublicKey);
49
+ } else if (typeof encryptionPublicKey === 'string') {
50
+ h.update(Buffer.from(encryptionPublicKey, 'hex'));
51
+ } else if (encryptionPublicKey instanceof Uint8Array) {
52
+ h.update(Buffer.from(encryptionPublicKey));
53
+ } else if (encryptionPublicKey.x && encryptionPublicKey.y) {
54
+ const xHex = BigInt(encryptionPublicKey.x).toString(16).padStart(64, '0');
55
+ const yHex = BigInt(encryptionPublicKey.y).toString(16).padStart(64, '0');
56
+ h.update(Buffer.from(xHex, 'hex'));
57
+ h.update(Buffer.from(yHex, 'hex'));
58
+ }
59
+ }
60
+
61
+ h.update(Buffer.from(scope, 'utf8'));
62
+ return h.digest();
63
+ }
64
+
65
+ /**
66
+ * Encodes a structured GhostMesh packet into a raw binary buffer.
67
+ * @param {Object} p
68
+ * @param {number} p.type - Packet type (PACKET_TYPES)
69
+ * @param {Buffer} p.destination - 32-byte destination hash
70
+ * @param {Buffer} p.senderPubkey - 32-byte Ed25519 sender public key
71
+ * @param {Buffer} [p.ephemeralPubkey] - 32-byte X25519 / BabyJub ephemeral key or IV
72
+ * @param {Buffer} p.payload - Raw or encrypted payload buffer
73
+ * @param {Buffer} [p.authTag] - 16-byte Poly1305 / GCM authentication tag
74
+ * @param {Buffer} [p.signature] - 64-byte Ed25519 signature
75
+ * @param {number} [p.hopTtl=DEFAULT_HOP_TTL]
76
+ * @param {number} [p.seqId=0]
77
+ * @param {number} [p.chunkIndex=0]
78
+ * @param {number} [p.chunkTotal=1]
79
+ * @param {number} [p.flags=0]
80
+ * @returns {Buffer}
81
+ */
82
+ export function encodePacket(p) {
83
+ if (!p || typeof p !== 'object') throw new Error('Packet must be an object');
84
+ const payload = Buffer.isBuffer(p.payload) ? p.payload : Buffer.from(p.payload || []);
85
+ if (payload.length > MAX_PACKET_SIZE - HEADER_SIZE - 64 - 16) {
86
+ throw new Error(`Payload size (${payload.length}B) exceeds max packet limit`);
87
+ }
88
+
89
+ const type = p.type === undefined ? PACKET_TYPES.MEMORY_CAPSULE : p.type;
90
+ if (!Number.isInteger(type) || !PACKET_TYPE_NAMES[type]) {
91
+ throw new Error(`Unknown packet type: ${type}`);
92
+ }
93
+
94
+ const byteField = (value, fallback, name) => {
95
+ const normalized = value === undefined ? fallback : value;
96
+ if (!Number.isInteger(normalized) || normalized < 0 || normalized > 0xff) {
97
+ throw new Error(`${name} must be an integer between 0 and 255`);
98
+ }
99
+ return normalized;
100
+ };
101
+ const uint16Field = (value, fallback, name) => {
102
+ const normalized = value === undefined ? fallback : value;
103
+ if (!Number.isInteger(normalized) || normalized < 0 || normalized > 0xffff) {
104
+ throw new Error(`${name} must be an integer between 0 and 65535`);
105
+ }
106
+ return normalized;
107
+ };
108
+
109
+ const flags = byteField(p.flags, 0, 'flags');
110
+ const hopTtl = byteField(p.hopTtl, DEFAULT_HOP_TTL, 'hopTtl');
111
+ const seqId = uint16Field(p.seqId, 0, 'seqId');
112
+ const chunkIndex = uint16Field(p.chunkIndex, 0, 'chunkIndex');
113
+ const chunkTotal = uint16Field(p.chunkTotal, 1, 'chunkTotal');
114
+ if (chunkTotal === 0) throw new Error('chunkTotal must be at least 1');
115
+ if (chunkIndex >= chunkTotal) {
116
+ throw new Error(`chunkIndex ${chunkIndex} must be less than chunkTotal ${chunkTotal}`);
117
+ }
118
+
119
+ const destination = Buffer.from(p.destination || []);
120
+ if (destination.length !== 32) throw new Error('Destination must be a 32-byte buffer');
121
+
122
+ const senderPubkey = Buffer.from(p.senderPubkey || []);
123
+ if (senderPubkey.length !== 32) throw new Error('Sender public key must be a 32-byte buffer');
124
+
125
+ const ephemeralPubkey = p.ephemeralPubkey ? Buffer.from(p.ephemeralPubkey) : Buffer.alloc(32, 0);
126
+ if (ephemeralPubkey.length !== 32) throw new Error('Ephemeral public key must be 32 bytes');
127
+
128
+ const authTag = p.authTag ? Buffer.from(p.authTag) : Buffer.alloc(16, 0);
129
+ if (authTag.length !== 16) throw new Error('Auth tag must be 16 bytes');
130
+
131
+ const signature = p.signature ? Buffer.from(p.signature) : Buffer.alloc(64, 0);
132
+ if (signature.length !== 64) throw new Error('Signature must be 64 bytes');
133
+
134
+ const totalLength = HEADER_SIZE + payload.length + 16 + 64;
135
+ if (totalLength > MAX_PACKET_SIZE) throw new Error(`Packet size (${totalLength}B) exceeds max packet limit`);
136
+ const buf = Buffer.alloc(totalLength);
137
+
138
+ let offset = 0;
139
+ buf.writeUInt16BE(PROTOCOL_MAGIC, offset); offset += 2;
140
+ buf.writeUInt8(PROTOCOL_VERSION, offset); offset += 1;
141
+ buf.writeUInt8(type, offset); offset += 1;
142
+ buf.writeUInt8(flags, offset); offset += 1;
143
+ buf.writeUInt8(hopTtl, offset); offset += 1;
144
+ buf.writeUInt16BE(seqId, offset); offset += 2;
145
+
146
+ destination.copy(buf, offset); offset += 32;
147
+ senderPubkey.copy(buf, offset); offset += 32;
148
+ ephemeralPubkey.copy(buf, offset); offset += 32;
149
+
150
+ buf.writeUInt32BE(payload.length, offset); offset += 4;
151
+ buf.writeUInt16BE(chunkIndex, offset); offset += 2;
152
+ buf.writeUInt16BE(chunkTotal, offset); offset += 2;
153
+
154
+ payload.copy(buf, offset); offset += payload.length;
155
+ authTag.copy(buf, offset); offset += 16;
156
+ signature.copy(buf, offset);
157
+
158
+ return buf;
159
+ }
160
+
161
+ /**
162
+ * Decodes a raw binary buffer into a structured GhostMesh packet object.
163
+ * @param {Buffer|Uint8Array} rawBuffer
164
+ * @returns {Object} Decoded packet structure
165
+ */
166
+ export function decodePacket(rawBuffer) {
167
+ const buf = Buffer.isBuffer(rawBuffer) ? rawBuffer : Buffer.from(rawBuffer);
168
+ if (buf.length < HEADER_SIZE + 16 + 64) {
169
+ throw new Error(`Packet buffer too short (${buf.length} bytes; minimum is ${HEADER_SIZE + 80} bytes)`);
170
+ }
171
+ if (buf.length > MAX_PACKET_SIZE) {
172
+ throw new Error(`Packet buffer too large (${buf.length} bytes; maximum is ${MAX_PACKET_SIZE} bytes)`);
173
+ }
174
+
175
+ let offset = 0;
176
+ const magic = buf.readUInt16BE(offset); offset += 2;
177
+ if (magic !== PROTOCOL_MAGIC) {
178
+ throw new Error(`Invalid protocol magic: 0x${magic.toString(16)} (expected 0x${PROTOCOL_MAGIC.toString(16)})`);
179
+ }
180
+
181
+ const version = buf.readUInt8(offset); offset += 1;
182
+ if (version !== PROTOCOL_VERSION) {
183
+ throw new Error(`Unsupported protocol version: ${version} (expected ${PROTOCOL_VERSION})`);
184
+ }
185
+
186
+ const type = buf.readUInt8(offset); offset += 1;
187
+ if (!PACKET_TYPE_NAMES[type]) throw new Error(`Unknown packet type: ${type}`);
188
+ const flags = buf.readUInt8(offset); offset += 1;
189
+ const hopTtl = buf.readUInt8(offset); offset += 1;
190
+ const seqId = buf.readUInt16BE(offset); offset += 2;
191
+
192
+ const destination = buf.subarray(offset, offset + 32); offset += 32;
193
+ const senderPubkey = buf.subarray(offset, offset + 32); offset += 32;
194
+ const ephemeralPubkey = buf.subarray(offset, offset + 32); offset += 32;
195
+
196
+ const payloadLength = buf.readUInt32BE(offset); offset += 4;
197
+ const chunkIndex = buf.readUInt16BE(offset); offset += 2;
198
+ const chunkTotal = buf.readUInt16BE(offset); offset += 2;
199
+ if (chunkTotal === 0) throw new Error('Invalid packet chunks: chunkTotal must be at least 1');
200
+ if (chunkIndex >= chunkTotal) {
201
+ throw new Error(`Invalid packet chunks: chunkIndex ${chunkIndex} must be less than chunkTotal ${chunkTotal}`);
202
+ }
203
+
204
+ const expectedLength = HEADER_SIZE + payloadLength + 16 + 64;
205
+ if (expectedLength !== buf.length) {
206
+ if (expectedLength > buf.length) {
207
+ throw new Error(`Packet payload truncated (expected exactly ${expectedLength} bytes, got ${buf.length})`);
208
+ }
209
+ throw new Error(`Packet frame has trailing bytes (expected exactly ${expectedLength} bytes, got ${buf.length})`);
210
+ }
211
+
212
+ const payload = buf.subarray(offset, offset + payloadLength); offset += payloadLength;
213
+ const authTag = buf.subarray(offset, offset + 16); offset += 16;
214
+ const signature = buf.subarray(offset, offset + 64);
215
+
216
+ return {
217
+ magic,
218
+ version,
219
+ type,
220
+ typeName: PACKET_TYPE_NAMES[type],
221
+ flags,
222
+ hopTtl,
223
+ seqId,
224
+ destination,
225
+ destinationHex: destination.toString('hex'),
226
+ senderPubkey,
227
+ senderPubkeyHex: senderPubkey.toString('hex'),
228
+ ephemeralPubkey,
229
+ ephemeralPubkeyHex: ephemeralPubkey.toString('hex'),
230
+ payloadLength,
231
+ chunkIndex,
232
+ chunkTotal,
233
+ payload,
234
+ authTag,
235
+ signature,
236
+ rawBytes: buf,
237
+ };
238
+ }
239
+ export function getSignableBytes(packetBuffer) {
240
+ const decoded = decodePacket(packetBuffer);
241
+ const buf = decoded.rawBytes;
242
+ // TTL is the only mutable field. Relays may decrement it without invalidating
243
+ // the end-to-end signature; every other frame byte is immutable.
244
+ const prefix = buf.subarray(0, 5);
245
+ const remainder = buf.subarray(6, buf.length - 64);
246
+ return Buffer.concat([prefix, remainder]);
247
+ }
248
+
249
+ /**
250
+ * Stable replay identity for a packet. It excludes the mutable hop TTL and the
251
+ * signature bytes, so decrementing TTL cannot turn a replay into a new packet.
252
+ */
253
+ export function getPacketReplayIdentity(packetBuffer) {
254
+ return crypto.createHash('sha256').update(getSignableBytes(packetBuffer)).digest('hex');
255
+ }