enigma-memory 0.1.18 → 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 (276) hide show
  1. package/README.md +76 -24
  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 +1923 -285
  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/docker-compose.local-production-simulation.yml +36 -0
  74. package/docs/browser-extension-install.md +8 -6
  75. package/docs/client-connectors.md +15 -11
  76. package/docs/developer-ecosystem.md +15 -13
  77. package/docs/enigma-memory-ready-conformance.md +11 -9
  78. package/docs/install-anywhere.md +61 -28
  79. package/docs/installers-and-desktop.md +8 -7
  80. package/docs/novelty-invention-candidates.md +161 -161
  81. package/docs/proof-network-claim-boundaries.md +320 -318
  82. package/examples/01-quickstart-agent/index.mjs +49 -0
  83. package/examples/01_agent_memory_quickstart.mjs +57 -0
  84. package/examples/02-multi-agent-swarm/index.mjs +57 -0
  85. package/examples/02_cross_model_passport.mjs +64 -0
  86. package/examples/03-langchain-memory/index.mjs +41 -0
  87. package/examples/03_poseidon_commitment_verification.mjs +71 -0
  88. package/examples/04-python-trading-agent/trader.py +49 -0
  89. package/examples/README.md +27 -0
  90. package/examples/ci/github-actions.yml +7 -2
  91. package/package.json +142 -11
  92. package/packages/adapters/PACKAGE_CONTRACT.md +1 -1
  93. package/packages/connectors/src/index.js +196 -4
  94. package/packages/connectors/swarm-router.mjs +168 -0
  95. package/packages/core/src/index.js +248 -1
  96. package/packages/core/src/version.mjs +7 -0
  97. package/packages/dev-tools/package.json +19 -0
  98. package/packages/dev-tools/src/index.js +4 -0
  99. package/packages/dev-tools/src/memory-benchmark-suite.js +112 -0
  100. package/packages/dev-tools/src/swarm-simulator.js +101 -0
  101. package/packages/dev-tools/src/vault-inspector.js +114 -0
  102. package/packages/dev-tools/src/vector-benchmark.js +100 -0
  103. package/packages/developer-platform/src/access-credentials.js +341 -0
  104. package/packages/developer-platform/src/http.js +132 -0
  105. package/packages/developer-platform/src/index.js +4 -0
  106. package/packages/developer-platform/src/usage-http.js +60 -0
  107. package/packages/developer-platform/src/usage.js +295 -0
  108. package/packages/enclave-runtime/attestation.mjs +159 -0
  109. package/packages/enclave-runtime/index.mjs +47 -0
  110. package/packages/enclave-runtime/session-manager.mjs +253 -0
  111. package/packages/enclave-runtime/zeroization-proof.mjs +227 -0
  112. package/packages/enigma-reflex/package.json +14 -0
  113. package/packages/enigma-reflex/src/index.js +204 -0
  114. package/packages/enigma-reflex/training/generate-dataset.mjs +40 -0
  115. package/packages/enigma-reflex/training/requirements.txt +8 -0
  116. package/packages/enigma-reflex/training/train.py +314 -0
  117. package/packages/enigma-weave/LICENSE +22 -0
  118. package/packages/enigma-weave/UPSTREAM.json +21 -0
  119. package/packages/enigma-weave/package.json +14 -0
  120. package/packages/enigma-weave/src/index.js +286 -0
  121. package/packages/hosted-cloud/src/index.js +80 -5
  122. package/packages/importers/src/index.js +432 -0
  123. package/packages/inference-runtime/src/browser.js +401 -0
  124. package/packages/inference-runtime/src/chat.js +265 -0
  125. package/packages/inference-runtime/src/code.js +407 -0
  126. package/packages/inference-runtime/src/contracts.js +162 -0
  127. package/packages/inference-runtime/src/http.js +232 -0
  128. package/packages/inference-runtime/src/image.js +186 -0
  129. package/packages/inference-runtime/src/index.js +10 -0
  130. package/packages/inference-runtime/src/model-router.js +320 -0
  131. package/packages/inference-runtime/src/platform.js +125 -0
  132. package/packages/inference-runtime/src/privacy.js +400 -0
  133. package/packages/inference-runtime/src/video.js +253 -0
  134. package/packages/mcp-server/README.md +22 -6
  135. package/packages/mcp-server/bin/enigma-mcp.mjs +2 -1
  136. package/packages/mcp-server/src/index.js +1418 -105
  137. package/packages/mcp-server/src/oauth.js +561 -0
  138. package/packages/mcp-server/src/private-handoff.js +84 -0
  139. package/packages/mcp-server/src/remote-http.js +273 -0
  140. package/packages/mcp-server/src/remote-policy.js +72 -0
  141. package/packages/mcp-server/swarm-bridge.mjs +361 -0
  142. package/packages/mesh/index.d.ts +283 -0
  143. package/packages/mesh/package.json +23 -0
  144. package/packages/mesh/src/crypto.js +189 -0
  145. package/packages/mesh/src/federation-packets.js +353 -0
  146. package/packages/mesh/src/gossip.js +311 -0
  147. package/packages/mesh/src/index.js +6 -0
  148. package/packages/mesh/src/protocol.js +255 -0
  149. package/packages/mesh/src/router.js +279 -0
  150. package/packages/mesh/src/transport.js +306 -0
  151. package/packages/passport/src/index.js +426 -1
  152. package/packages/private-economy/src/credits-http.js +100 -0
  153. package/packages/private-economy/src/credits.js +447 -0
  154. package/packages/private-economy/src/index.js +5 -0
  155. package/packages/private-economy/src/payments-http.js +120 -0
  156. package/packages/private-economy/src/payments.js +509 -0
  157. package/packages/private-economy/src/x402.js +346 -0
  158. package/packages/proof-network/PACKAGE_CONTRACT.md +21 -0
  159. package/packages/rag/index.d.ts +182 -0
  160. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/THIRD_PARTY_LICENSES.txt +207 -0
  161. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/config.json +25 -0
  162. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/onnx/model_quantized.onnx +0 -0
  163. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/sha256-manifest.json +28 -0
  164. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer.json +30686 -0
  165. package/packages/rag/models/Xenova/all-MiniLM-L6-v2/tokenizer_config.json +15 -0
  166. package/packages/rag/package.json +27 -0
  167. package/packages/rag/src/blinded-search.js +109 -0
  168. package/packages/rag/src/bm25.js +169 -0
  169. package/packages/rag/src/embeddings.js +459 -0
  170. package/packages/rag/src/hybrid.js +76 -0
  171. package/packages/rag/src/index.js +38 -0
  172. package/packages/rag/src/reranker.js +61 -0
  173. package/packages/rag/src/research.js +107 -0
  174. package/packages/rag/src/vector-store.js +430 -0
  175. package/packages/rag/src/verify-model-artifacts.mjs +4 -0
  176. package/packages/sdk/index.d.ts +760 -0
  177. package/packages/sdk/package.json +33 -0
  178. package/packages/sdk/python/README.md +24 -0
  179. package/packages/sdk/python/enigma_sdk.py +250 -0
  180. package/packages/sdk/python/pyproject.toml +34 -0
  181. package/packages/sdk/python/requirements.txt +1 -0
  182. package/packages/sdk/python/setup.py +20 -0
  183. package/packages/sdk/src/federation/capability-grant.js +389 -0
  184. package/packages/sdk/src/federation/federation-router.js +360 -0
  185. package/packages/sdk/src/federation/ghostmesh-bridge.js +497 -0
  186. package/packages/sdk/src/federation/index.js +3 -0
  187. package/packages/sdk/src/index.js +1796 -0
  188. package/packages/sdk/src/intelligence/contradiction.js +337 -0
  189. package/packages/sdk/src/intelligence/decision-engine.js +155 -0
  190. package/packages/sdk/src/intelligence/index.js +4 -0
  191. package/packages/sdk/src/intelligence/ontology.js +122 -0
  192. package/packages/sdk/src/intelligence/temporal.js +123 -0
  193. package/packages/sdk/src/market-client.js +142 -0
  194. package/packages/sdk/src/mesh-client.js +110 -0
  195. package/packages/sdk/src/middleware/index.js +3 -0
  196. package/packages/sdk/src/middleware/langchain.js +159 -0
  197. package/packages/sdk/src/middleware/llamaindex.js +101 -0
  198. package/packages/sdk/src/middleware/vercel-ai.js +112 -0
  199. package/packages/sdk/src/rag-client.js +85 -0
  200. package/packages/sdk/src/swarm-orchestrator.js +260 -0
  201. package/packages/settlement/PACKAGE_CONTRACT.md +1 -1
  202. package/packages/snapcompact/THIRD_PARTY_LICENSES.txt +40 -0
  203. package/packages/snapcompact/assets/8x13-latin1.bdf +3837 -0
  204. package/packages/snapcompact/index.d.ts +284 -0
  205. package/packages/snapcompact/package.json +25 -0
  206. package/packages/snapcompact/src/index.js +716 -0
  207. package/packages/storage/PACKAGE_CONTRACT.md +1 -1
  208. package/packages/terminal-console/animations.mjs +240 -0
  209. package/packages/terminal-console/auto-anchor.mjs +220 -0
  210. package/packages/terminal-console/banner.mjs +91 -0
  211. package/packages/terminal-console/commands.mjs +459 -0
  212. package/packages/terminal-console/delegation.mjs +152 -0
  213. package/packages/terminal-console/index.mjs +5 -0
  214. package/packages/terminal-console/outbox.mjs +143 -0
  215. package/packages/terminal-console/phantom-bridge.mjs +637 -0
  216. package/packages/terminal-console/repl.mjs +136 -0
  217. package/packages/terminal-console/signer-store.mjs +130 -0
  218. package/packages/terminal-console/solana-rpc.mjs +214 -0
  219. package/packages/terminal-console/solana-transport.mjs +189 -0
  220. package/packages/terminal-tui/dashboard.mjs +214 -0
  221. package/packages/terminal-tui/index.mjs +28 -0
  222. package/packages/terminal-tui/merkle-tree-renderer.mjs +268 -0
  223. package/packages/terminal-tui/telemetry-hud.mjs +137 -0
  224. package/packages/vault/index.d.ts +449 -0
  225. package/packages/vault/package.json +27 -0
  226. package/packages/vault/src/e2ee.mjs +393 -0
  227. package/packages/vault/src/enclave.js +481 -0
  228. package/packages/vault/src/erasure.js +207 -0
  229. package/packages/vault/src/index.js +1018 -155
  230. package/packages/vault/src/persistence.js +307 -0
  231. package/packages/vault/src/poseidon.js +354 -0
  232. package/packages/vault/src/receipt.js +459 -0
  233. package/scripts/benchmark-optical-context.mjs +166 -0
  234. package/scripts/bootstrap-enigma.mjs +502 -0
  235. package/scripts/build-edge-backend-workers.mjs +20 -5
  236. package/scripts/build-goal-completion-audit.mjs +72 -25
  237. package/scripts/build-hosted-api-key-lifecycle.mjs +26 -8
  238. package/scripts/build-hosted-customer-lifecycle.mjs +20 -3
  239. package/scripts/build-hosted-probe-worker.mjs +19 -4
  240. package/scripts/build-installer-assets.mjs +41 -21
  241. package/scripts/build-operator-evidence-starter.mjs +59 -1
  242. package/scripts/build-production-backend-env-kit.mjs +2 -0
  243. package/scripts/build-production-unblocker.mjs +3 -0
  244. package/scripts/check.mjs +17 -3
  245. package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
  246. package/scripts/install-enigma-local.mjs +18 -5
  247. package/scripts/release-audit.mjs +65 -109
  248. package/scripts/release-provenance.mjs +6 -0
  249. package/scripts/run-backend-readiness-smoke.mjs +112 -10
  250. package/scripts/scan-secrets.mjs +1 -0
  251. package/scripts/simulate-production-env.mjs +7 -2
  252. package/scripts/validate-hosted-backend-live.mjs +112 -1
  253. package/specs/antibody-pack-v1.schema.json +95 -0
  254. package/specs/antigen-envelope-v1.schema.json +81 -0
  255. package/specs/boundary-manifest-v1.schema.json +35 -35
  256. package/specs/capsule-v1.schema.json +55 -55
  257. package/specs/claim-boundary-manifest-v1.schema.json +22 -22
  258. package/specs/claim-ledger-v1.schema.json +291 -0
  259. package/specs/context-passport-v1.schema.json +59 -0
  260. package/specs/deletion-tombstone-v1.schema.json +26 -26
  261. package/specs/evidence-packet-v1.schema.json +177 -0
  262. package/specs/hosted-backend-live-evidence-v1.schema.json +72 -3
  263. package/specs/immune-scan-report-v1.schema.json +112 -0
  264. package/specs/lifecycle-receipt-log-v1.schema.json +67 -0
  265. package/specs/memory-atom-v1.schema.json +59 -0
  266. package/specs/memory-event-v1.schema.json +42 -42
  267. package/specs/passport-v1.schema.json +50 -50
  268. package/specs/proof-of-non-use-v1.schema.json +65 -0
  269. package/specs/quarantine-record-v1.schema.json +126 -0
  270. package/specs/receipt-v1.schema.json +61 -61
  271. package/specs/state-checkpoint-v1.schema.json +37 -37
  272. package/specs/trust-bundle-v1.schema.json +56 -56
  273. package/specs/trust-card-v1.schema.json +119 -0
  274. package/docs/proof-network-launch-plan.md +0 -421
  275. package/packages/metering/PACKAGE_CONTRACT.md +0 -20
  276. package/scripts/build-ai-orchestration-plan.mjs +0 -248
@@ -0,0 +1,293 @@
1
+ /**
2
+ * zk-codec.test.mjs — known-answer tests + integration round-trip for the
3
+ * Enigma action-transition snarkjs→raw-BE codec.
4
+ *
5
+ * KAT vectors:
6
+ * - G1 generator (1, 2): externally known BN254 generator.
7
+ * - G2 generator: expected "c1c0" hex is the canonical EIP-196/EIP-197
8
+ * alt_bn128 encoding (im, re) — externally sourced.
9
+ * - Non-trivial G1 pair: expected hex computed independently (Python
10
+ * int.to_bytes(32, 'big')).
11
+ *
12
+ * Run: node --test cortex-v3/zk/zk-codec.test.mjs
13
+ * Integration test waits up to ZK_CODEC_INTEGRATION_WAIT_MS (default 20s) for
14
+ * circuits/build/verification_key.json (produced by zk/setup.mjs), then skips
15
+ * gracefully if absent.
16
+ */
17
+
18
+ import test from "node:test";
19
+ import assert from "node:assert/strict";
20
+ import { existsSync, readFileSync } from "node:fs";
21
+ import path from "node:path";
22
+ import { fileURLToPath } from "node:url";
23
+
24
+ import {
25
+ FR_MODULUS,
26
+ FQ_MODULUS,
27
+ EXPECTED_IC_LENGTH,
28
+ NUM_PUBLIC_INPUTS,
29
+ vkFromSnarkjs,
30
+ proofFromSnarkjs,
31
+ publicInputsFromSnarkjs,
32
+ g1ToBytes,
33
+ g2ToBytes,
34
+ frToBytes32BE,
35
+ } from "./zk-codec.mjs";
36
+
37
+ const HERE = path.dirname(fileURLToPath(import.meta.url));
38
+ const BUILD_DIR = path.resolve(HERE, "..", "circuits", "build");
39
+ const VK_JSON_PATH = path.join(BUILD_DIR, "verification_key.json");
40
+ const VK_BYTES_PATH = path.join(BUILD_DIR, "vk_bytes.json");
41
+
42
+ const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
43
+
44
+ // ---------------------------------------------------------------------------
45
+ // KAT vectors
46
+ // ---------------------------------------------------------------------------
47
+
48
+ // bn254 G1 generator.
49
+ const G1_GEN_DECIMAL = ["1", "2"];
50
+ const G1_GEN_HEX =
51
+ "0000000000000000000000000000000000000000000000000000000000000001" +
52
+ "0000000000000000000000000000000000000000000000000000000000000002";
53
+
54
+ // Non-trivial G1 pair (alpha of a Groth16 vk); expected hex computed
55
+ // independently via Python int.to_bytes(32, "big").
56
+ const G1_ALPHA_DECIMAL = [
57
+ "20491192805390485299153009773594534940189261866228447918068658471970481763042",
58
+ "9383485363053290200918347156157836566562967994039712273449902621266178545958",
59
+ ];
60
+ const G1_ALPHA_HEX =
61
+ "2d4d9aa7e302d9df41749d5507949d05dbea33fbb16c643b22f599a2be6df2e2" +
62
+ "14bedd503c37ceb061d8ec60209fe345ce89830a19230301f076caff004d1926";
63
+
64
+ // bn254 G2 generator in snarkjs JSON limb order [c0, c1] = [re, im].
65
+ const G2_GEN_SNARKJS = [
66
+ [
67
+ "10857046999023057135944570762232829481370756359578518086990519993285655852781",
68
+ "11559732032986387107991004021392285783925812861821192530917403151452391805634",
69
+ ],
70
+ [
71
+ "8495653923123431417604973247489272438418190587263600148770280649306958101930",
72
+ "4082367875863433681332203403145435568316851327593401208105741076214120093531",
73
+ ],
74
+ ["1", "0"],
75
+ ];
76
+ // Canonical EIP-196 alt_bn128 encoding of the G2 generator: (im, re) per coord.
77
+ const G2_GEN_C1C0_HEX =
78
+ "198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2" +
79
+ "1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed" +
80
+ "090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b" +
81
+ "12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa";
82
+ // Raw snarkjs limb order (re, im) per coord — the "c0c1" option.
83
+ const G2_GEN_C0C1_HEX =
84
+ "1800deef121f1e76426a00665e5c4479674322d4f75edadd46debd5cd992f6ed" +
85
+ "198e9393920d483a7260bfb731fb5d25f1aa493335a9e71297e485b7aef312c2" +
86
+ "12c85ea5db8c6deb4aab71808dcb408fe3d1e7690c43d37b4ce6cc0166fa7daa" +
87
+ "090689d0585ff075ec9e99ad690c3395bc4b313370b38ef355acdadcd122975b";
88
+
89
+ // Scalar field modulus r and neighbours.
90
+ const R_DECIMAL = FR_MODULUS.toString(10);
91
+ const R_MINUS_1_HEX =
92
+ "30644e72e131a029b85045b68181585d2833e84879b9709143e1f593f0000000";
93
+
94
+ // ---------------------------------------------------------------------------
95
+ // KAT: G1 decimal pair → exact 64B hex
96
+ // ---------------------------------------------------------------------------
97
+
98
+ test("KAT: G1 generator decimal pair → exact 64B BE hex", () => {
99
+ const out = g1ToBytes(G1_GEN_DECIMAL);
100
+ assert.equal(out.length, 64);
101
+ assert.equal(out.toString("hex"), G1_GEN_HEX);
102
+ });
103
+
104
+ test("KAT: non-trivial G1 decimal pair → exact 64B BE hex", () => {
105
+ const out = g1ToBytes(G1_ALPHA_DECIMAL);
106
+ assert.equal(out.length, 64);
107
+ assert.equal(out.toString("hex"), G1_ALPHA_HEX);
108
+ });
109
+
110
+ // ---------------------------------------------------------------------------
111
+ // KAT: G2 decimal quad → exact 128B hex, both limb orders
112
+ // ---------------------------------------------------------------------------
113
+
114
+ test("KAT: G2 generator → c1c0 (default) matches EIP-196 (im,re) encoding", () => {
115
+ const out = g2ToBytes(G2_GEN_SNARKJS, "c1c0");
116
+ assert.equal(out.length, 128);
117
+ assert.equal(out.toString("hex"), G2_GEN_C1C0_HEX);
118
+ });
119
+
120
+ test("KAT: G2 generator → c0c1 option matches raw snarkjs limb order", () => {
121
+ const out = g2ToBytes(G2_GEN_SNARKJS, "c0c1");
122
+ assert.equal(out.length, 128);
123
+ assert.equal(out.toString("hex"), G2_GEN_C0C1_HEX);
124
+ });
125
+
126
+ test("g2LimbOrder defaults to c1c0 and rejects unknown orders", () => {
127
+ assert.equal(g2ToBytes(G2_GEN_SNARKJS).toString("hex"), G2_GEN_C1C0_HEX);
128
+ assert.throws(() => g2ToBytes(G2_GEN_SNARKJS, "c2c3"), /g2LimbOrder/);
129
+ });
130
+
131
+ // ---------------------------------------------------------------------------
132
+ // KAT: scalar canonicality (< r)
133
+ // ---------------------------------------------------------------------------
134
+
135
+ test("KAT: public input r - 1 → exact 32B BE hex", () => {
136
+ const [out] = publicInputsFromSnarkjs([(FR_MODULUS - 1n).toString(10)]);
137
+ assert.equal(out.length, 32);
138
+ assert.equal(out.toString("hex"), R_MINUS_1_HEX);
139
+ });
140
+
141
+ test("scalar >= r throws (canonicality)", () => {
142
+ assert.throws(() => publicInputsFromSnarkjs([R_DECIMAL]), /canonical/);
143
+ assert.throws(
144
+ () => publicInputsFromSnarkjs([(FR_MODULUS + 1n).toString(10)]),
145
+ /canonical/,
146
+ );
147
+ assert.throws(() => frToBytes32BE(R_DECIMAL), /canonical/);
148
+ });
149
+
150
+ test("public inputs reject non-decimal / negative / negative-zero junk", () => {
151
+ assert.throws(() => publicInputsFromSnarkjs(["0x10"]));
152
+ assert.throws(() => publicInputsFromSnarkjs(["-1"]));
153
+ assert.throws(() => publicInputsFromSnarkjs(["01"])); // non-canonical decimal string
154
+ assert.throws(() => publicInputsFromSnarkjs("not json {"));
155
+ assert.throws(() => publicInputsFromSnarkjs({}));
156
+ });
157
+
158
+ test("G1/G2 coordinates >= q throw (canonicality)", () => {
159
+ assert.throws(() => g1ToBytes([FQ_MODULUS.toString(10), "1"]), /canonical/);
160
+ assert.throws(
161
+ () => g2ToBytes([["1", FQ_MODULUS.toString(10)], ["1", "2"]], "c1c0"),
162
+ /canonical/,
163
+ );
164
+ });
165
+
166
+ // ---------------------------------------------------------------------------
167
+ // KAT: proof passthrough — A is NEVER negated by the codec
168
+ // ---------------------------------------------------------------------------
169
+
170
+ test("proofFromSnarkjs passes A through raw (program negates on-chain)", () => {
171
+ const proofJson = {
172
+ pi_a: [...G1_ALPHA_DECIMAL, "1"],
173
+ pi_b: G2_GEN_SNARKJS,
174
+ pi_c: [...G1_GEN_DECIMAL, "1"],
175
+ };
176
+ const { a, b, c } = proofFromSnarkjs(proofJson);
177
+ assert.equal(a.length, 64);
178
+ assert.equal(b.length, 128);
179
+ assert.equal(c.length, 64);
180
+ assert.equal(a.toString("hex"), G1_ALPHA_HEX, "A must be the raw affine point");
181
+ assert.equal(b.toString("hex"), G2_GEN_C1C0_HEX);
182
+ assert.equal(c.toString("hex"), G1_GEN_HEX);
183
+ const { b: bSwapped } = proofFromSnarkjs(proofJson, { g2LimbOrder: "c0c1" });
184
+ assert.equal(bSwapped.toString("hex"), G2_GEN_C0C1_HEX);
185
+ });
186
+
187
+ // ---------------------------------------------------------------------------
188
+ // KAT: 7-IC vk round-trip shape (v3 contract: ic[0] + 6 public inputs)
189
+ // ---------------------------------------------------------------------------
190
+
191
+ function makeVkJson(icCount) {
192
+ return {
193
+ protocol: "groth16",
194
+ curve: "bn128",
195
+ nPublic: icCount - 1,
196
+ vk_alpha_1: [...G1_ALPHA_DECIMAL, "1"],
197
+ vk_beta_2: G2_GEN_SNARKJS,
198
+ vk_gamma_2: G2_GEN_SNARKJS,
199
+ vk_delta_2: G2_GEN_SNARKJS,
200
+ vk_alphabeta_12: [],
201
+ IC: Array.from({ length: icCount }, (_, i) => [
202
+ String(i + 1),
203
+ String(i + 2),
204
+ "1",
205
+ ]),
206
+ };
207
+ }
208
+
209
+ test("KAT: 7-IC vk round-trip shape (ic[0] + 6 public inputs)", () => {
210
+ assert.equal(NUM_PUBLIC_INPUTS, 6);
211
+ assert.equal(EXPECTED_IC_LENGTH, 7);
212
+ const vk = vkFromSnarkjs(makeVkJson(7));
213
+ assert.equal(vk.alphaG1.length, 64);
214
+ assert.equal(vk.alphaG1.toString("hex"), G1_ALPHA_HEX);
215
+ for (const g2 of [vk.betaG2, vk.gammaG2, vk.deltaG2]) {
216
+ assert.equal(g2.length, 128);
217
+ assert.equal(g2.toString("hex"), G2_GEN_C1C0_HEX);
218
+ }
219
+ assert.equal(vk.ic.length, 7);
220
+ for (const [i, p] of vk.ic.entries()) {
221
+ assert.equal(p.length, 64);
222
+ const expectedX = Buffer.alloc(32);
223
+ expectedX[31] = i + 1;
224
+ const expectedY = Buffer.alloc(32);
225
+ expectedY[31] = i + 2;
226
+ assert.deepEqual(p, Buffer.concat([expectedX, expectedY]));
227
+ }
228
+ // Accepts a JSON string too.
229
+ const fromString = vkFromSnarkjs(JSON.stringify(makeVkJson(7)));
230
+ assert.deepEqual(fromString.ic, vk.ic);
231
+ });
232
+
233
+ test("vkFromSnarkjs rejects IC length != 7 (e.g. old 8-IC epoch circuit)", () => {
234
+ assert.throws(() => vkFromSnarkjs(makeVkJson(8)), /IC length 8 != expected 7/);
235
+ assert.throws(() => vkFromSnarkjs(makeVkJson(6)), /IC length 6 != expected 7/);
236
+ // Explicit override works for foreign circuits.
237
+ const vk8 = vkFromSnarkjs(makeVkJson(8), { expectedIc: 8 });
238
+ assert.equal(vk8.ic.length, 8);
239
+ });
240
+
241
+ test("vkFromSnarkjs rejects malformed vk JSON", () => {
242
+ const bad = makeVkJson(7);
243
+ delete bad.vk_delta_2;
244
+ assert.throws(() => vkFromSnarkjs(bad), /vk_delta_2/);
245
+ assert.throws(() => vkFromSnarkjs("{nope"), /not valid JSON/);
246
+ });
247
+
248
+ // ---------------------------------------------------------------------------
249
+ // Integration: round-trip the real ceremony outputs (setup.mjs product)
250
+ // ---------------------------------------------------------------------------
251
+
252
+ test("integration: circuits/build/verification_key.json → codec → matches vk_bytes.json", async (t) => {
253
+ const waitMs = Number(process.env.ZK_CODEC_INTEGRATION_WAIT_MS ?? 20_000);
254
+ const deadline = Date.now() + waitMs;
255
+ while (!existsSync(VK_JSON_PATH) && Date.now() < deadline) {
256
+ await sleep(1000);
257
+ }
258
+ if (!existsSync(VK_JSON_PATH)) {
259
+ t.skip(
260
+ `verification_key.json not present after ${waitMs}ms — run zk/setup.mjs first ` +
261
+ `(set ZK_CODEC_INTEGRATION_WAIT_MS to wait longer)`,
262
+ );
263
+ return;
264
+ }
265
+
266
+ const vkJson = JSON.parse(readFileSync(VK_JSON_PATH, "utf8"));
267
+ assert.equal(vkJson.nPublic, NUM_PUBLIC_INPUTS, "circuit must have 6 public inputs");
268
+ const vk = vkFromSnarkjs(vkJson); // asserts IC == 7
269
+ assert.equal(vk.ic.length, EXPECTED_IC_LENGTH);
270
+ assert.equal(vk.alphaG1.length, 64);
271
+ for (const g2 of [vk.betaG2, vk.gammaG2, vk.deltaG2]) {
272
+ assert.equal(g2.length, 128);
273
+ }
274
+
275
+ assert.ok(
276
+ existsSync(VK_BYTES_PATH),
277
+ `vk_bytes.json must exist next to verification_key.json (${VK_BYTES_PATH})`,
278
+ );
279
+ const vkBytes = JSON.parse(readFileSync(VK_BYTES_PATH, "utf8"));
280
+ assert.equal(vkBytes.format, "raw-be-hex-v1");
281
+ assert.equal(vkBytes.g2LimbOrder, "c1c0");
282
+ assert.equal(vkBytes.icCount, EXPECTED_IC_LENGTH);
283
+ assert.equal(vkBytes.numPublicInputs, NUM_PUBLIC_INPUTS);
284
+ const strip = (h) => h.replace(/^0x/, "");
285
+ assert.equal(strip(vkBytes.alphaG1), vk.alphaG1.toString("hex"));
286
+ assert.equal(strip(vkBytes.betaG2), vk.betaG2.toString("hex"));
287
+ assert.equal(strip(vkBytes.gammaG2), vk.gammaG2.toString("hex"));
288
+ assert.equal(strip(vkBytes.deltaG2), vk.deltaG2.toString("hex"));
289
+ assert.equal(vkBytes.ic.length, EXPECTED_IC_LENGTH);
290
+ for (const [i, h] of vkBytes.ic.entries()) {
291
+ assert.equal(strip(h), vk.ic[i].toString("hex"), `IC[${i}] mismatch`);
292
+ }
293
+ });
@@ -0,0 +1,370 @@
1
+ // On-chain settlement client for the Enigma shared ZK state layer.
2
+ // Flow: install pinned VK (governance) → initialize shared state (governance) →
3
+ // submit client-generated Groth16 action proofs (permissionless).
4
+ //
5
+ // Sovereignty invariant: only { proof bytes, 6 public inputs } are transmitted.
6
+ // No witness material (ownerKey, rho, payloadCommit, Merkle paths) appears here.
7
+ import { createHash } from 'node:crypto';
8
+ import {
9
+ PublicKey, SystemProgram, Transaction, TransactionInstruction,
10
+ sendAndConfirmTransaction,
11
+ } from '@solana/web3.js';
12
+
13
+ export const PROGRAM_ID = new PublicKey('E18KZR1Jq8fG3FFACpoHsE21ME3t1ftKPEwXL7cFWkoZ');
14
+ export const BPF_UPGRADEABLE_LOADER = new PublicKey('BPFLoaderUpgradeab1e11111111111111111111111');
15
+ export const disc = (name) => createHash('sha256').update(`global:${name}`).digest().subarray(0, 8);
16
+ export const [SHARED_STATE_PDA] = PublicKey.findProgramAddressSync(
17
+ [Buffer.from('shared_state')], PROGRAM_ID);
18
+ export const [PROGRAM_DATA_PDA] = PublicKey.findProgramAddressSync(
19
+ [PROGRAM_ID.toBuffer()], BPF_UPGRADEABLE_LOADER);
20
+
21
+ export function verifyingKeyPda(circuitVersion = 1) {
22
+ const buf = Buffer.alloc(8);
23
+ buf.writeBigUInt64BE(BigInt(circuitVersion));
24
+ return PublicKey.findProgramAddressSync([Buffer.from('verifying_key'), buf], PROGRAM_ID)[0];
25
+ }
26
+
27
+ // --- On-chain VK inspection ----------------------------------------------------
28
+ /**
29
+ * Normalize a VK from any accepted representation (Buffer/Uint8Array or hex
30
+ * string, as produced by resolveVerifyingKey's parsed JSON) into Buffers with
31
+ * EXACT length validation: 64B alpha, 128B beta/gamma/delta, exactly 7×64B IC.
32
+ */
33
+ export function normalizeVkBytes(vk) {
34
+ const toBuf = (v, len, name) => {
35
+ const b = typeof v === 'string' ? Buffer.from(v, 'hex') : Buffer.from(v);
36
+ if (b.length !== len) throw new Error(`VK ${name}: expected ${len} bytes, got ${b.length}`);
37
+ return b;
38
+ };
39
+ if (!vk || typeof vk !== 'object') throw new TypeError('VK must be an object');
40
+ if (!Array.isArray(vk.ic) || vk.ic.length !== 7) {
41
+ throw new Error(`VK ic: expected exactly 7 points, got ${vk.ic?.length}`);
42
+ }
43
+ return {
44
+ alphaG1: toBuf(vk.alphaG1, 64, 'alphaG1'),
45
+ betaG2: toBuf(vk.betaG2, 128, 'betaG2'),
46
+ gammaG2: toBuf(vk.gammaG2, 128, 'gammaG2'),
47
+ deltaG2: toBuf(vk.deltaG2, 128, 'deltaG2'),
48
+ ic: vk.ic.map((p, i) => toBuf(p, 64, `ic[${i}]`)),
49
+ };
50
+ }
51
+
52
+ export function decodeVerifyingKey(d) {
53
+ if (d.length !== 952) throw new Error(`CircuitVerifyingKey: expected 952 bytes, got ${d.length}`);
54
+ const ic = [];
55
+ for (let i = 0; i < 7; i++) ic.push(d.subarray(496 + i * 64, 496 + (i + 1) * 64));
56
+ return {
57
+ authority: d.subarray(8, 40),
58
+ circuitVersion: Number(d.readBigUInt64LE(40)),
59
+ alphaG1: d.subarray(48, 112),
60
+ betaG2: d.subarray(112, 240),
61
+ gammaG2: d.subarray(240, 368),
62
+ deltaG2: d.subarray(368, 496),
63
+ ic,
64
+ };
65
+ }
66
+
67
+ export async function fetchVerifyingKey(connection, circuitVersion = 1) {
68
+ const acct = await connection.getAccountInfo(verifyingKeyPda(circuitVersion));
69
+ if (!acct) return null;
70
+ return decodeVerifyingKey(acct.data);
71
+ }
72
+ // CircuitVerifyingKey layout: 8 disc + 32 authority + 8 circuit_version
73
+ // + 64 alpha_g1 + 128 beta_g2 + 128 gamma_g2 + 128 delta_g2 + 7×64 ic + 8 created_at
74
+
75
+ /**
76
+ * Fail-closed gate: the on-chain VK PDA must EXACTLY equal the manifest-pinned
77
+ * VK before any proof is generated/submitted — proving against a mismatched or
78
+ * absent VK guarantees rejection (or worse, a different ceremony's key).
79
+ * Returns 'match' | 'installed' (when authority installs a missing key).
80
+ * Throws otherwise.
81
+ */
82
+ export async function assertOnChainVerifyingKey(connection, circuitVersion, vkBytes, opts = {}) {
83
+ const onchain = await fetchVerifyingKey(connection, circuitVersion);
84
+ const want = normalizeVkBytes(vkBytes);
85
+ const eq = (a, b) => Buffer.from(a).equals(Buffer.from(b));
86
+ if (!onchain) {
87
+ if (opts.installAuthority) {
88
+ await installVerifyingKey(connection, opts.installAuthority, want, circuitVersion);
89
+ return 'installed';
90
+ }
91
+ throw new Error(
92
+ `no on-chain verifying key for circuit version ${circuitVersion} — install it via governance before proving`,
93
+ );
94
+ }
95
+ const matches = eq(onchain.alphaG1, want.alphaG1) && eq(onchain.betaG2, want.betaG2)
96
+ && eq(onchain.gammaG2, want.gammaG2) && eq(onchain.deltaG2, want.deltaG2)
97
+ && onchain.ic.length === want.ic.length
98
+ && onchain.ic.every((p, i) => eq(p, want.ic[i]));
99
+ if (!matches) {
100
+ throw new Error(
101
+ `on-chain verifying key for circuit version ${circuitVersion} does NOT match the manifest-pinned VK — refusing to prove`,
102
+ );
103
+ }
104
+ return 'match';
105
+ }
106
+
107
+ // --- Governance: install the pinned verifying key -----------------------------
108
+ // vkBytes: { alphaG1, betaG2, gammaG2, deltaG2, ic[7] } as Uint8Array/Buffer
109
+ export async function installVerifyingKey(connection, authority, vkBytes, circuitVersion = 1) {
110
+ // Borsh u64 arg = little-endian (the PDA SEED stays big-endian per program source).
111
+ const versionBuf = Buffer.alloc(8);
112
+ versionBuf.writeBigUInt64LE(BigInt(circuitVersion));
113
+ const icFlat = Buffer.concat(vkBytes.ic.map((p) => Buffer.from(p)));
114
+ const data = Buffer.concat([
115
+ disc('initialize_circuit_verifying_key'),
116
+ versionBuf,
117
+ Buffer.from(vkBytes.alphaG1),
118
+ Buffer.from(vkBytes.betaG2),
119
+ Buffer.from(vkBytes.gammaG2),
120
+ Buffer.from(vkBytes.deltaG2),
121
+ icFlat,
122
+ ]);
123
+ const ix = new TransactionInstruction({
124
+ programId: PROGRAM_ID,
125
+ keys: [
126
+ { pubkey: verifyingKeyPda(circuitVersion), isSigner: false, isWritable: true },
127
+ { pubkey: PROGRAM_ID, isSigner: false, isWritable: false },
128
+ { pubkey: PROGRAM_DATA_PDA, isSigner: false, isWritable: false },
129
+ { pubkey: authority.publicKey, isSigner: true, isWritable: true },
130
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
131
+ ],
132
+ data,
133
+ });
134
+ return sendAndConfirmTransaction(connection, new Transaction().add(ix), [authority]);
135
+ }
136
+
137
+ // --- Governance: initialize the shared state with genesis roots ---------------
138
+ export async function initializeSharedState(connection, authority, genesisNoteRoot, genesisNullRoot) {
139
+ const data = Buffer.concat([
140
+ disc('initialize_shared_state'),
141
+ Buffer.from(genesisNoteRoot),
142
+ Buffer.from(genesisNullRoot),
143
+ ]);
144
+ const ix = new TransactionInstruction({
145
+ programId: PROGRAM_ID,
146
+ keys: [
147
+ { pubkey: SHARED_STATE_PDA, isSigner: false, isWritable: true },
148
+ { pubkey: PROGRAM_ID, isSigner: false, isWritable: false },
149
+ { pubkey: PROGRAM_DATA_PDA, isSigner: false, isWritable: false },
150
+ { pubkey: authority.publicKey, isSigner: true, isWritable: true },
151
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
152
+ ],
153
+ data,
154
+ });
155
+ return sendAndConfirmTransaction(connection, new Transaction().add(ix), [authority]);
156
+ }
157
+
158
+ // --- Permissionless: settle one client-generated action proof ------------------
159
+ // proofBytes: { a: 64B, b: 128B, c: 64B } raw BE (program negates A internally)
160
+ // publicInputs: 6 × 32B BE buffers, canonical < r
161
+ export async function settleAction(connection, payer, proofBytes, publicInputs, circuitVersion = 1) {
162
+ const data = Buffer.concat([
163
+ disc('settle_action'),
164
+ Buffer.from(proofBytes.a),
165
+ Buffer.from(proofBytes.b),
166
+ Buffer.from(proofBytes.c),
167
+ ...publicInputs.map((p) => Buffer.from(p)),
168
+ ]);
169
+ const ix = new TransactionInstruction({
170
+ programId: PROGRAM_ID,
171
+ keys: [
172
+ { pubkey: SHARED_STATE_PDA, isSigner: false, isWritable: true },
173
+ { pubkey: verifyingKeyPda(circuitVersion), isSigner: false, isWritable: false },
174
+ { pubkey: payer.publicKey, isSigner: true, isWritable: true },
175
+ ],
176
+ data,
177
+ });
178
+ return sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer]);
179
+ }
180
+
181
+ export const INTENT_CIRCUIT_VERSION = 2;
182
+ export const SALE_CIRCUIT_VERSION = 3;
183
+
184
+ export function saleReceiptPda(keyCommitBytes, envelopeCommitBytes) {
185
+ const seed = createHash('sha256')
186
+ .update(Buffer.from(keyCommitBytes))
187
+ .update(Buffer.from(envelopeCommitBytes))
188
+ .digest();
189
+ return PublicKey.findProgramAddressSync([Buffer.from('sale_receipt'), seed], PROGRAM_ID)[0];
190
+ }
191
+
192
+ export function saleEscrowPda(buyerPubkey, saleTermsHashBytes) {
193
+ return PublicKey.findProgramAddressSync(
194
+ [Buffer.from('sale_escrow'), buyerPubkey.toBuffer(), Buffer.from(saleTermsHashBytes)], PROGRAM_ID)[0];
195
+ }
196
+
197
+ // --- Sealed Sale (ZKCP): verify encryption-consistent, recipient-bound proof ---
198
+ // publicInputs: 7 × 32B BE [noteRoot, payloadCommitPos, cipherCommit, keyCommit,
199
+ // saleTermsHash, envelopeCommit, payloadLen]. Attestation stores COMMITMENTS
200
+ // ONLY — the envelope (epk/encDek) + CTR nonce are revealed inside claim_sale,
201
+ // atomically with payment (Poseidon5-bound on-chain).
202
+ export async function settleSale(connection, payer, proofBytes, publicInputs) {
203
+ const data = Buffer.concat([
204
+ disc('settle_sale'),
205
+ Buffer.from(proofBytes.a),
206
+ Buffer.from(proofBytes.b),
207
+ Buffer.from(proofBytes.c),
208
+ ...publicInputs.map((p) => Buffer.from(p)),
209
+ ]);
210
+ const ix = new TransactionInstruction({
211
+ programId: PROGRAM_ID,
212
+ keys: [
213
+ { pubkey: SHARED_STATE_PDA, isSigner: false, isWritable: false },
214
+ { pubkey: verifyingKeyPda(SALE_CIRCUIT_VERSION), isSigner: false, isWritable: false },
215
+ { pubkey: saleReceiptPda(publicInputs[3], publicInputs[5]), isSigner: false, isWritable: true },
216
+ { pubkey: payer.publicKey, isSigner: true, isWritable: true },
217
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
218
+ ],
219
+ data,
220
+ });
221
+ return sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer]);
222
+ }
223
+
224
+ export async function createSaleEscrow(connection, buyer, sellerPubkey, saleTermsHashBytes, priceLamports, expirySlot, receiptPubkey) {
225
+ const args = Buffer.alloc(8 + 32 + 8 + 8);
226
+ let o = 0;
227
+ disc('create_sale_escrow').copy(args, 0); o = 8;
228
+ Buffer.from(saleTermsHashBytes).copy(args, o); o += 32;
229
+ args.writeBigUInt64LE(BigInt(priceLamports), o); o += 8;
230
+ args.writeBigUInt64LE(BigInt(expirySlot), o);
231
+ const ix = new TransactionInstruction({
232
+ programId: PROGRAM_ID,
233
+ keys: [
234
+ { pubkey: saleEscrowPda(buyer.publicKey, saleTermsHashBytes), isSigner: false, isWritable: true },
235
+ { pubkey: buyer.publicKey, isSigner: true, isWritable: true },
236
+ { pubkey: sellerPubkey, isSigner: false, isWritable: false },
237
+ { pubkey: receiptPubkey, isSigner: false, isWritable: false },
238
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
239
+ ],
240
+ data: args,
241
+ });
242
+ return sendAndConfirmTransaction(connection, new Transaction().add(ix), [buyer]);
243
+ }
244
+
245
+ export function createClaimSaleInstruction(sellerPubkey, buyerPubkey, saleTermsHashBytes, keyCommitBytes, envelopeCommitBytes, epk, encDek, nonceBytes) {
246
+ const data = Buffer.concat([
247
+ disc('claim_sale'),
248
+ Buffer.from(saleTermsHashBytes),
249
+ Buffer.from(epk),
250
+ Buffer.from(encDek),
251
+ Buffer.from(nonceBytes),
252
+ ]);
253
+ return new TransactionInstruction({
254
+ programId: PROGRAM_ID,
255
+ keys: [
256
+ { pubkey: saleEscrowPda(buyerPubkey, saleTermsHashBytes), isSigner: false, isWritable: true },
257
+ { pubkey: saleReceiptPda(keyCommitBytes, envelopeCommitBytes), isSigner: false, isWritable: true },
258
+ { pubkey: sellerPubkey, isSigner: true, isWritable: true },
259
+ { pubkey: buyerPubkey, isSigner: false, isWritable: true },
260
+ ],
261
+ data,
262
+ });
263
+ }
264
+
265
+ export async function claimSale(connection, seller, buyerPubkey, saleTermsHashBytes, keyCommitBytes, envelopeCommitBytes, epk, encDek, nonceBytes) {
266
+ const ix = createClaimSaleInstruction(seller.publicKey, buyerPubkey, saleTermsHashBytes, keyCommitBytes, envelopeCommitBytes, epk, encDek, nonceBytes);
267
+ return sendAndConfirmTransaction(connection, new Transaction().add(ix), [seller]);
268
+ }
269
+
270
+ // SaleReceipt layout (MUST match the Rust struct field order exactly):
271
+ // 8 disc + 32 sale_terms_hash + 32 key_commit + 32 cipher_commit
272
+ // + 32 envelope_commit + 32 payload_commit_pos + 64 epk + 64 enc_dek
273
+ // + 32 nonce + 8 slot + 8 timestamp = 344 bytes
274
+ export const SALE_RECEIPT_LAYOUT = Object.freeze({
275
+ discriminator: 8,
276
+ saleTermsHash: [8, 40],
277
+ keyCommit: [40, 72],
278
+ cipherCommit: [72, 104],
279
+ envelopeCommit: [104, 136],
280
+ payloadCommitPos: [136, 168],
281
+ epk: [168, 232],
282
+ encDek: [232, 296],
283
+ nonce: [296, 328],
284
+ slot: 328,
285
+ total: 344,
286
+ });
287
+
288
+ export function decodeSaleReceipt(d) {
289
+ const L = SALE_RECEIPT_LAYOUT;
290
+ if (d.length !== L.total) {
291
+ throw new Error(`SaleReceipt decode: expected ${L.total} bytes, got ${d.length}`);
292
+ }
293
+ return {
294
+ saleTermsHash: d.subarray(...L.saleTermsHash),
295
+ keyCommit: d.subarray(...L.keyCommit),
296
+ cipherCommit: d.subarray(...L.cipherCommit),
297
+ envelopeCommit: d.subarray(...L.envelopeCommit),
298
+ payloadCommitPos: d.subarray(...L.payloadCommitPos),
299
+ epk: d.subarray(...L.epk),
300
+ encDek: d.subarray(...L.encDek),
301
+ nonce: d.subarray(...L.nonce),
302
+ slot: Number(d.readBigUInt64LE(L.slot)),
303
+ };
304
+ }
305
+
306
+ export async function fetchSaleReceipt(connection, keyCommitBytes, envelopeCommitBytes) {
307
+ const acct = await connection.getAccountInfo(saleReceiptPda(keyCommitBytes, envelopeCommitBytes));
308
+ if (!acct) return null;
309
+ return decodeSaleReceipt(acct.data);
310
+ }
311
+
312
+ export function createRefundSaleInstruction(buyerPubkey, saleTermsHashBytes) {
313
+ const data = Buffer.concat([disc('refund_sale'), Buffer.from(saleTermsHashBytes)]);
314
+ return new TransactionInstruction({
315
+ programId: PROGRAM_ID,
316
+ keys: [
317
+ { pubkey: saleEscrowPda(buyerPubkey, saleTermsHashBytes), isSigner: false, isWritable: true },
318
+ { pubkey: buyerPubkey, isSigner: true, isWritable: true },
319
+ ],
320
+ data,
321
+ });
322
+ }
323
+
324
+ export async function refundSale(connection, buyer, saleTermsHashBytes) {
325
+ const ix = createRefundSaleInstruction(buyer.publicKey, saleTermsHashBytes);
326
+ return sendAndConfirmTransaction(connection, new Transaction().add(ix), [buyer]);
327
+ }
328
+
329
+ export function intentReceiptPda(nullifierBytes) {
330
+ return PublicKey.findProgramAddressSync(
331
+ [Buffer.from('intent_null'), Buffer.from(nullifierBytes)], PROGRAM_ID)[0];
332
+ }
333
+
334
+ // --- Permissionless: settle a verifiable-agent-intent attestation --------------
335
+ // publicInputs: 4 × 32B BE [noteRoot, actionHash, nullifier, currentSlot]
336
+ export async function settleIntent(connection, payer, proofBytes, publicInputs) {
337
+ const data = Buffer.concat([
338
+ disc('settle_intent'),
339
+ Buffer.from(proofBytes.a),
340
+ Buffer.from(proofBytes.b),
341
+ Buffer.from(proofBytes.c),
342
+ ...publicInputs.map((p) => Buffer.from(p)),
343
+ ]);
344
+ const ix = new TransactionInstruction({
345
+ programId: PROGRAM_ID,
346
+ keys: [
347
+ { pubkey: SHARED_STATE_PDA, isSigner: false, isWritable: false },
348
+ { pubkey: verifyingKeyPda(INTENT_CIRCUIT_VERSION), isSigner: false, isWritable: false },
349
+ { pubkey: intentReceiptPda(publicInputs[2]), isSigner: false, isWritable: true },
350
+ { pubkey: payer.publicKey, isSigner: true, isWritable: true },
351
+ { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
352
+ ],
353
+ data,
354
+ });
355
+ return sendAndConfirmTransaction(connection, new Transaction().add(ix), [payer]);
356
+ }
357
+
358
+ // SharedState layout: 8 disc + 32 authority + 32 note_root + 32 null_root
359
+ // + 8 note_count + 8 null_count + 8 created_at
360
+ export async function fetchSharedState(connection) {
361
+ const acct = await connection.getAccountInfo(SHARED_STATE_PDA);
362
+ if (!acct) return null;
363
+ const d = acct.data;
364
+ return {
365
+ noteRoot: d.subarray(40, 72),
366
+ nullRoot: d.subarray(72, 104),
367
+ noteCount: Number(d.readBigUInt64LE(104)),
368
+ nullCount: Number(d.readBigUInt64LE(112)),
369
+ };
370
+ }