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.
- package/README.md +76 -24
- package/apps/cli/bin/enigma-desktop.mjs +140 -0
- package/apps/cli/bin/enigma-terminal.mjs +78 -0
- package/apps/cli/bin/enigma.mjs +1923 -285
- 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/docker-compose.local-production-simulation.yml +36 -0
- package/docs/browser-extension-install.md +8 -6
- package/docs/client-connectors.md +15 -11
- package/docs/developer-ecosystem.md +15 -13
- package/docs/enigma-memory-ready-conformance.md +11 -9
- package/docs/install-anywhere.md +61 -28
- package/docs/installers-and-desktop.md +8 -7
- package/docs/novelty-invention-candidates.md +161 -161
- package/docs/proof-network-claim-boundaries.md +320 -318
- 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 +142 -11
- 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 +248 -1
- 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 +1418 -105
- 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 +426 -1
- 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 +1018 -155
- 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 +26 -8
- package/scripts/build-hosted-customer-lifecycle.mjs +20 -3
- package/scripts/build-hosted-probe-worker.mjs +19 -4
- package/scripts/build-installer-assets.mjs +41 -21
- 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 +3 -0
- package/scripts/check.mjs +17 -3
- package/scripts/collect-hosted-backend-live-evidence.mjs +49 -12
- package/scripts/install-enigma-local.mjs +18 -5
- package/scripts/release-audit.mjs +65 -109
- package/scripts/release-provenance.mjs +6 -0
- package/scripts/run-backend-readiness-smoke.mjs +112 -10
- package/scripts/scan-secrets.mjs +1 -0
- package/scripts/simulate-production-env.mjs +7 -2
- 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,688 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* setup-intent.mjs — idempotent Groth16 ceremony driver for the Enigma
|
|
3
|
+
* intent-attestation circuit (circuits/intent_attestation.circom,
|
|
4
|
+
* IntentAttestation(NOTE_DEPTH=20, ALLOW_DEPTH=16)).
|
|
5
|
+
*
|
|
6
|
+
* Binding spec (IntentCircuit research): public inputs in exact order
|
|
7
|
+
* [noteRoot, actionHash, nullifier, currentSlot] → IC length 5.
|
|
8
|
+
* The on-chain VK account (verifying_key PDA, circuit_version = 2) holds 7 IC
|
|
9
|
+
* slots, so the exported intent_vk_bytes.json zero-pads ic[5..8] with
|
|
10
|
+
* 64 zero bytes each; the settle_intent handler slices ic[..5].
|
|
11
|
+
*
|
|
12
|
+
* Pipeline:
|
|
13
|
+
* 1. Poll (default up to 30 min) for circuits/build/intent_attestation.r1cs
|
|
14
|
+
* (produced concurrently by IntentCircuitBuild).
|
|
15
|
+
* 2. Read the constraint count from the r1cs binary header (authoritative).
|
|
16
|
+
* 3. REUSE the existing ptau/powersOfTau28_hez_final_18.ptau — NO download.
|
|
17
|
+
* 2^14 would already suffice (~10.7k constraints expected); 2^18 is
|
|
18
|
+
* compatible and r1cs-independent.
|
|
19
|
+
* 4. groth16 setup → zkey contribute ("enigma-intent-dev-1", random entropy)
|
|
20
|
+
* → zkey beacon (random 32B, 10 iterations) → export verificationkey →
|
|
21
|
+
* circuits/build/intent_verification_key.json.
|
|
22
|
+
* 5. vkFromSnarkjs (asserts IC == 5) → zero-pad ic to 7 × 64B →
|
|
23
|
+
* circuits/build/intent_vk_bytes.json (raw-be-hex-v1).
|
|
24
|
+
* 6. Proof-of-life: poll for zk/intent-witness.mjs (IntentWitness runs
|
|
25
|
+
* concurrently), build a self-contained demo witness, groth16 fullProve
|
|
26
|
+
* against the final zkey + compiled wasm, groth16 verify against the
|
|
27
|
+
* exported verification key. Prints timings.
|
|
28
|
+
*
|
|
29
|
+
* intent_verification_key.json + intent_vk_bytes.json are COMMITTABLE;
|
|
30
|
+
* *.zkey, *.r1cs, *.wasm, ptau/ are gitignored.
|
|
31
|
+
*
|
|
32
|
+
* CLAIM BOUNDARY: single-party local setup = development only; production
|
|
33
|
+
* requires a multi-party ceremony.
|
|
34
|
+
*
|
|
35
|
+
* Usage:
|
|
36
|
+
* node zk/setup-intent.mjs [--r1cs <path>] [--build-dir <dir>]
|
|
37
|
+
* [--ptau-dir <dir>] [--poll-minutes <n>] [--witness-poll-minutes <n>]
|
|
38
|
+
* [--witness <path>] [--force] [--skip-proof-of-life]
|
|
39
|
+
*
|
|
40
|
+
* Exit codes: 0 success · 3 blocked (r1cs or witness prerequisite missing) ·
|
|
41
|
+
* 4 ptau missing · 1 other failure.
|
|
42
|
+
*/
|
|
43
|
+
|
|
44
|
+
import { spawnSync } from "node:child_process";
|
|
45
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
46
|
+
import {
|
|
47
|
+
existsSync,
|
|
48
|
+
mkdirSync,
|
|
49
|
+
readFileSync,
|
|
50
|
+
renameSync,
|
|
51
|
+
rmSync,
|
|
52
|
+
statSync,
|
|
53
|
+
writeFileSync,
|
|
54
|
+
} from "node:fs";
|
|
55
|
+
import path from "node:path";
|
|
56
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
57
|
+
|
|
58
|
+
import { vkFromSnarkjs } from "./zk-codec.mjs";
|
|
59
|
+
|
|
60
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
61
|
+
const CORTEX_V3 = path.resolve(HERE, "..");
|
|
62
|
+
|
|
63
|
+
// --- Intent circuit contract (binding spec — do not drift) -------------------
|
|
64
|
+
const CIRCUIT_NAME = "intent_attestation";
|
|
65
|
+
const CIRCUIT_VERSION = 2; // settle_intent VK PDA seed (2u64.to_be_bytes())
|
|
66
|
+
const NUM_PUBLIC_INPUTS = 4; // [noteRoot, actionHash, nullifier, currentSlot]
|
|
67
|
+
const EXPECTED_IC = 1 + NUM_PUBLIC_INPUTS; // 5
|
|
68
|
+
const ONCHAIN_VK_IC_SLOTS = 7; // VK account holds 7 slots; ic[5..7] zero-padded
|
|
69
|
+
const G1_BYTES = 64;
|
|
70
|
+
const POWER = 18; // reuse ptau/powersOfTau28_hez_final_18.ptau (2^18 >> 2^14 need)
|
|
71
|
+
const PTAU_MIN_BYTES = 100 * 1024 * 1024; // size sanity floor (hez_final_18 ≈ 145MB)
|
|
72
|
+
|
|
73
|
+
const DEFAULTS = {
|
|
74
|
+
r1cs: path.join(CORTEX_V3, "circuits", "build", `${CIRCUIT_NAME}.r1cs`),
|
|
75
|
+
buildDir: path.join(CORTEX_V3, "circuits", "build"),
|
|
76
|
+
ptauDir: path.join(CORTEX_V3, "ptau"),
|
|
77
|
+
witness: path.join(HERE, "intent-witness.mjs"),
|
|
78
|
+
pollMinutes: 30,
|
|
79
|
+
witnessPollMinutes: 30,
|
|
80
|
+
force: false,
|
|
81
|
+
skipProofOfLife: false,
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
const log = (msg) =>
|
|
85
|
+
console.log(`[setup-intent ${new Date().toISOString()}] ${msg}`);
|
|
86
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
87
|
+
|
|
88
|
+
class BlockingError extends Error {
|
|
89
|
+
constructor(message, exitCode) {
|
|
90
|
+
super(message);
|
|
91
|
+
this.exitCode = exitCode;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
// CLI
|
|
97
|
+
// ---------------------------------------------------------------------------
|
|
98
|
+
|
|
99
|
+
function parseArgs(argv) {
|
|
100
|
+
const opts = { ...DEFAULTS };
|
|
101
|
+
for (let i = 0; i < argv.length; i++) {
|
|
102
|
+
const a = argv[i];
|
|
103
|
+
const next = () => {
|
|
104
|
+
if (i + 1 >= argv.length) throw new Error(`missing value for ${a}`);
|
|
105
|
+
return argv[++i];
|
|
106
|
+
};
|
|
107
|
+
switch (a) {
|
|
108
|
+
case "--r1cs":
|
|
109
|
+
opts.r1cs = path.resolve(next());
|
|
110
|
+
break;
|
|
111
|
+
case "--build-dir":
|
|
112
|
+
opts.buildDir = path.resolve(next());
|
|
113
|
+
break;
|
|
114
|
+
case "--ptau-dir":
|
|
115
|
+
opts.ptauDir = path.resolve(next());
|
|
116
|
+
break;
|
|
117
|
+
case "--witness":
|
|
118
|
+
opts.witness = path.resolve(next());
|
|
119
|
+
break;
|
|
120
|
+
case "--poll-minutes":
|
|
121
|
+
opts.pollMinutes = Number(next());
|
|
122
|
+
break;
|
|
123
|
+
case "--witness-poll-minutes":
|
|
124
|
+
opts.witnessPollMinutes = Number(next());
|
|
125
|
+
break;
|
|
126
|
+
case "--force":
|
|
127
|
+
opts.force = true;
|
|
128
|
+
break;
|
|
129
|
+
case "--skip-proof-of-life":
|
|
130
|
+
opts.skipProofOfLife = true;
|
|
131
|
+
break;
|
|
132
|
+
default:
|
|
133
|
+
throw new Error(`unknown argument: ${a}`);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
return opts;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// ---------------------------------------------------------------------------
|
|
140
|
+
// snarkjs CLI runner (no npx/.cmd shims — run the CLI entrypoint with node)
|
|
141
|
+
// ---------------------------------------------------------------------------
|
|
142
|
+
|
|
143
|
+
function snarkjsCliPath() {
|
|
144
|
+
const p = path.join(CORTEX_V3, "node_modules", "snarkjs", "build", "cli.cjs");
|
|
145
|
+
if (!existsSync(p)) {
|
|
146
|
+
throw new Error(
|
|
147
|
+
`snarkjs CLI not found at ${p} — run "npm install -D snarkjs" in cortex-v3`,
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
return p;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
function snarkjs(args, { quiet = false } = {}) {
|
|
154
|
+
const fullArgs = [snarkjsCliPath(), ...args];
|
|
155
|
+
log(`$ node ${path.basename(snarkjsCliPath())} ${args.join(" ")}`);
|
|
156
|
+
const res = spawnSync(process.execPath, fullArgs, {
|
|
157
|
+
cwd: CORTEX_V3,
|
|
158
|
+
stdio: quiet ? "pipe" : "inherit",
|
|
159
|
+
encoding: "utf8",
|
|
160
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
161
|
+
});
|
|
162
|
+
if (res.error) throw res.error;
|
|
163
|
+
if (res.status !== 0) {
|
|
164
|
+
throw new Error(
|
|
165
|
+
`snarkjs ${args[0]} exited with code ${res.status}\n${res.stderr ?? ""}`,
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
return (res.stdout ?? "") + (res.stderr ?? "");
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// ---------------------------------------------------------------------------
|
|
172
|
+
// r1cs inspection — parse the binary header directly (authoritative)
|
|
173
|
+
// ---------------------------------------------------------------------------
|
|
174
|
+
|
|
175
|
+
function readR1csHeader(r1csPath) {
|
|
176
|
+
const fd = readFileSync(r1csPath);
|
|
177
|
+
if (fd.length < 12 || fd.toString("ascii", 0, 4) !== "r1cs") {
|
|
178
|
+
throw new Error(`${r1csPath} is not an r1cs file (bad magic)`);
|
|
179
|
+
}
|
|
180
|
+
const nSections = fd.readUInt32LE(8);
|
|
181
|
+
let offset = 12;
|
|
182
|
+
for (let s = 0; s < nSections; s++) {
|
|
183
|
+
const sectionType = fd.readUInt32LE(offset);
|
|
184
|
+
const sectionSize = Number(fd.readBigUInt64LE(offset + 4));
|
|
185
|
+
if (sectionType === 1) {
|
|
186
|
+
const base = offset + 12;
|
|
187
|
+
const fieldSize = fd.readUInt32LE(base);
|
|
188
|
+
let p = base + 4 + fieldSize;
|
|
189
|
+
const nWires = fd.readUInt32LE(p);
|
|
190
|
+
const nPubOut = fd.readUInt32LE(p + 4);
|
|
191
|
+
const nPubIn = fd.readUInt32LE(p + 8);
|
|
192
|
+
const nPrvIn = fd.readUInt32LE(p + 12);
|
|
193
|
+
const nLabels = Number(fd.readBigUInt64LE(p + 16));
|
|
194
|
+
const nConstraints = fd.readUInt32LE(p + 24);
|
|
195
|
+
return { nWires, nPubOut, nPubIn, nPrvIn, nLabels, nConstraints };
|
|
196
|
+
}
|
|
197
|
+
offset += 12 + sectionSize;
|
|
198
|
+
}
|
|
199
|
+
throw new Error(`${r1csPath}: header section (type 1) not found`);
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// ---------------------------------------------------------------------------
|
|
203
|
+
// ptau header — sanity-check that the reused file's power covers the circuit
|
|
204
|
+
// ---------------------------------------------------------------------------
|
|
205
|
+
|
|
206
|
+
function readPtauPower(ptauPath) {
|
|
207
|
+
const fd = readFileSync(ptauPath, { flag: "r" });
|
|
208
|
+
if (fd.length < 12 || fd.toString("ascii", 0, 4) !== "ptau") {
|
|
209
|
+
throw new Error(`${ptauPath} is not a ptau file (bad magic)`);
|
|
210
|
+
}
|
|
211
|
+
const nSections = fd.readUInt32LE(8);
|
|
212
|
+
let offset = 12;
|
|
213
|
+
for (let s = 0; s < nSections; s++) {
|
|
214
|
+
const sectionType = fd.readUInt32LE(offset);
|
|
215
|
+
const sectionSize = Number(fd.readBigUInt64LE(offset + 4));
|
|
216
|
+
if (sectionType === 1) {
|
|
217
|
+
const base = offset + 12;
|
|
218
|
+
const fieldSize = fd.readUInt32LE(base);
|
|
219
|
+
const power = fd.readUInt32LE(base + 4 + fieldSize);
|
|
220
|
+
return power;
|
|
221
|
+
}
|
|
222
|
+
offset += 12 + sectionSize;
|
|
223
|
+
}
|
|
224
|
+
throw new Error(`${ptauPath}: header section (type 1) not found`);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
// Stage 1: wait for the r1cs
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
async function waitForFile(filePath, pollMinutes, what, owner) {
|
|
232
|
+
if (existsSync(filePath)) {
|
|
233
|
+
log(`${what} present: ${filePath}`);
|
|
234
|
+
return;
|
|
235
|
+
}
|
|
236
|
+
log(
|
|
237
|
+
`waiting up to ${pollMinutes} min for ${filePath} (${owner} runs concurrently)...`,
|
|
238
|
+
);
|
|
239
|
+
const deadline = Date.now() + pollMinutes * 60_000;
|
|
240
|
+
while (Date.now() < deadline) {
|
|
241
|
+
if (existsSync(filePath)) {
|
|
242
|
+
// Guard against a partially-written file: size must be stable.
|
|
243
|
+
const s1 = statSync(filePath).size;
|
|
244
|
+
await sleep(2000);
|
|
245
|
+
const s2 = statSync(filePath).size;
|
|
246
|
+
if (s1 === s2 && s2 > 0) {
|
|
247
|
+
log(`${what} appeared (${s2} bytes, stable)`);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
await sleep(15_000);
|
|
252
|
+
}
|
|
253
|
+
throw new BlockingError(
|
|
254
|
+
`BLOCKED: ${filePath} did not appear within ${pollMinutes} minutes.\n` +
|
|
255
|
+
`Prerequisite owner: ${owner}.\n` +
|
|
256
|
+
`Re-run "node zk/setup-intent.mjs" once it exists — all completed stages are reused.`,
|
|
257
|
+
3,
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
// Stage 2: ptau — REUSE the existing 2^18 powers-of-tau (no download)
|
|
263
|
+
// ---------------------------------------------------------------------------
|
|
264
|
+
|
|
265
|
+
function acquirePtau(ptauDir, nConstraints) {
|
|
266
|
+
const dest = path.join(ptauDir, `powersOfTau28_hez_final_${POWER}.ptau`);
|
|
267
|
+
if (!existsSync(dest)) {
|
|
268
|
+
throw new BlockingError(
|
|
269
|
+
`BLOCKED: required powers-of-tau not found at ${dest}.\n` +
|
|
270
|
+
`This ceremony reuses the repo-local ptau (no download). Restore it via\n` +
|
|
271
|
+
`"node zk/setup.mjs" (which acquires the same file) or copy it into ptau/.`,
|
|
272
|
+
4,
|
|
273
|
+
);
|
|
274
|
+
}
|
|
275
|
+
const size = statSync(dest).size;
|
|
276
|
+
if (size < PTAU_MIN_BYTES) {
|
|
277
|
+
throw new BlockingError(
|
|
278
|
+
`BLOCKED: ${dest} fails size sanity (${size} < ${PTAU_MIN_BYTES}) — truncated?`,
|
|
279
|
+
4,
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
const power = readPtauPower(dest);
|
|
283
|
+
if (2 ** power <= nConstraints) {
|
|
284
|
+
throw new Error(
|
|
285
|
+
`constraint count ${nConstraints} does not fit in the 2^${power} powers-of-tau at ${dest}`,
|
|
286
|
+
);
|
|
287
|
+
}
|
|
288
|
+
log(
|
|
289
|
+
`reusing existing ptau: ${dest} (${(size / 1024 / 1024).toFixed(1)}MB, ` +
|
|
290
|
+
`2^${power}; ${nConstraints} constraints fit)`,
|
|
291
|
+
);
|
|
292
|
+
return { path: dest, provenance: "reused repo-local file (no download)", size, power };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// ---------------------------------------------------------------------------
|
|
296
|
+
// Stages 3-5: circuit-specific ceremony
|
|
297
|
+
// ---------------------------------------------------------------------------
|
|
298
|
+
|
|
299
|
+
function stagePaths(buildDir, r1csPath) {
|
|
300
|
+
const stem = path.basename(r1csPath).replace(/\.r1cs$/, "");
|
|
301
|
+
return {
|
|
302
|
+
zkey0: path.join(buildDir, `${stem}_0000.zkey`),
|
|
303
|
+
zkey1: path.join(buildDir, `${stem}_0001.zkey`),
|
|
304
|
+
// Final proving key name is CONTRACT: proof-of-life + Main's e2e load <stem>.zkey.
|
|
305
|
+
zkeyFinal: path.join(buildDir, `${stem}.zkey`),
|
|
306
|
+
vkJson: path.join(buildDir, "intent_verification_key.json"),
|
|
307
|
+
vkBytes: path.join(buildDir, "intent_vk_bytes.json"),
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
function runCeremony(r1csPath, ptauPath, paths, force) {
|
|
312
|
+
mkdirSync(path.dirname(paths.zkey0), { recursive: true });
|
|
313
|
+
if (force) {
|
|
314
|
+
for (const f of Object.values(paths)) rmSync(f, { force: true });
|
|
315
|
+
}
|
|
316
|
+
if (!existsSync(paths.zkey0)) {
|
|
317
|
+
snarkjs(["groth16", "setup", r1csPath, ptauPath, paths.zkey0]);
|
|
318
|
+
} else {
|
|
319
|
+
log(`reusing ${paths.zkey0}`);
|
|
320
|
+
}
|
|
321
|
+
if (!existsSync(paths.zkey1)) {
|
|
322
|
+
snarkjs([
|
|
323
|
+
"zkey", "contribute", paths.zkey0, paths.zkey1,
|
|
324
|
+
"--name=enigma-intent-dev-1",
|
|
325
|
+
`-e=${randomBytes(32).toString("hex")}`,
|
|
326
|
+
]);
|
|
327
|
+
} else {
|
|
328
|
+
log(`reusing ${paths.zkey1}`);
|
|
329
|
+
}
|
|
330
|
+
if (!existsSync(paths.zkeyFinal)) {
|
|
331
|
+
const beacon = randomBytes(32).toString("hex");
|
|
332
|
+
snarkjs(["zkey", "beacon", paths.zkey1, paths.zkeyFinal, beacon, "10"]);
|
|
333
|
+
log(`zkey beacon applied (dev beacon ${beacon})`);
|
|
334
|
+
} else {
|
|
335
|
+
log(`reusing ${paths.zkeyFinal}`);
|
|
336
|
+
}
|
|
337
|
+
if (!existsSync(paths.vkJson)) {
|
|
338
|
+
snarkjs(["zkey", "export", "verificationkey", paths.zkeyFinal, paths.vkJson]);
|
|
339
|
+
} else {
|
|
340
|
+
log(`reusing ${paths.vkJson}`);
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
function exportVkBytes(paths, meta) {
|
|
345
|
+
const vkJson = JSON.parse(readFileSync(paths.vkJson, "utf8"));
|
|
346
|
+
// Throws unless IC == 5 (ic[0] + 4 public inputs).
|
|
347
|
+
const vk = vkFromSnarkjs(vkJson, { expectedIc: EXPECTED_IC, g2LimbOrder: "c1c0" });
|
|
348
|
+
const hex = (b) => b.toString("hex"); // plain hex strings (zk-codec convention)
|
|
349
|
+
// The on-chain VK account (circuit_version = 2) holds 7 IC slots; the intent
|
|
350
|
+
// circuit only has 5. Zero-pad ic[5] and ic[6] with 64 zero bytes each.
|
|
351
|
+
const icPadded = vk.ic.map(hex);
|
|
352
|
+
while (icPadded.length < ONCHAIN_VK_IC_SLOTS) {
|
|
353
|
+
icPadded.push(Buffer.alloc(G1_BYTES).toString("hex"));
|
|
354
|
+
}
|
|
355
|
+
if (icPadded.length !== ONCHAIN_VK_IC_SLOTS) {
|
|
356
|
+
throw new Error(`internal: ic padding overflow (${icPadded.length})`);
|
|
357
|
+
}
|
|
358
|
+
const out = {
|
|
359
|
+
format: "raw-be-hex-v1",
|
|
360
|
+
curve: "bn128",
|
|
361
|
+
g2LimbOrder: "c1c0", // alt_bn128 / EIP-196 (im,re)
|
|
362
|
+
proofNote: "pi_a is raw — the on-chain program negates A",
|
|
363
|
+
circuit: CIRCUIT_NAME,
|
|
364
|
+
circuitVersion: CIRCUIT_VERSION,
|
|
365
|
+
numPublicInputs: NUM_PUBLIC_INPUTS,
|
|
366
|
+
icCount: vk.ic.length, // 5 real IC points from the ceremony
|
|
367
|
+
icPaddedTo: ONCHAIN_VK_IC_SLOTS, // ic[5], ic[6] = 64 zero bytes each
|
|
368
|
+
alphaG1: hex(vk.alphaG1),
|
|
369
|
+
betaG2: hex(vk.betaG2),
|
|
370
|
+
gammaG2: hex(vk.gammaG2),
|
|
371
|
+
deltaG2: hex(vk.deltaG2),
|
|
372
|
+
ic: icPadded,
|
|
373
|
+
ceremony: "development single-party",
|
|
374
|
+
ceremonyDetail: meta,
|
|
375
|
+
source: path.basename(paths.vkJson),
|
|
376
|
+
createdAt: new Date().toISOString(),
|
|
377
|
+
};
|
|
378
|
+
const tmp = `${paths.vkBytes}.tmp`;
|
|
379
|
+
writeFileSync(tmp, JSON.stringify(out, null, 2) + "\n");
|
|
380
|
+
renameSync(tmp, paths.vkBytes);
|
|
381
|
+
return out;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// ---------------------------------------------------------------------------
|
|
385
|
+
// r1cs fingerprint — ceremony artifacts are only valid for the exact r1cs
|
|
386
|
+
// they were derived from. If the r1cs changes (circuit recompile), every
|
|
387
|
+
// circuit-specific stage MUST be redone; the ptau is r1cs-independent.
|
|
388
|
+
// ---------------------------------------------------------------------------
|
|
389
|
+
|
|
390
|
+
function sha256File(p) {
|
|
391
|
+
return createHash("sha256").update(readFileSync(p)).digest("hex");
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
function statePath(buildDir) {
|
|
395
|
+
// Distinct from setup.mjs's zk-setup-state.json (action-transition ceremony).
|
|
396
|
+
return path.join(buildDir, "zk-setup-intent-state.json");
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
function readState(buildDir) {
|
|
400
|
+
const p = statePath(buildDir);
|
|
401
|
+
if (!existsSync(p)) return null;
|
|
402
|
+
try {
|
|
403
|
+
return JSON.parse(readFileSync(p, "utf8"));
|
|
404
|
+
} catch {
|
|
405
|
+
return null;
|
|
406
|
+
}
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function writeState(buildDir, state) {
|
|
410
|
+
const tmp = `${statePath(buildDir)}.tmp`;
|
|
411
|
+
writeFileSync(tmp, JSON.stringify(state, null, 2) + "\n");
|
|
412
|
+
renameSync(tmp, statePath(buildDir));
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
/** Delete circuit-specific artifacts; returns list of removed paths. */
|
|
416
|
+
function purgeStageArtifacts(paths) {
|
|
417
|
+
const removed = [];
|
|
418
|
+
for (const key of ["zkey0", "zkey1", "zkeyFinal", "vkJson", "vkBytes"]) {
|
|
419
|
+
if (existsSync(paths[key])) {
|
|
420
|
+
rmSync(paths[key], { force: true });
|
|
421
|
+
removed.push(paths[key]);
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
return removed;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// ---------------------------------------------------------------------------
|
|
428
|
+
// Stage 6: proof-of-life — fullProve + verify with IntentWitness's builder
|
|
429
|
+
// ---------------------------------------------------------------------------
|
|
430
|
+
|
|
431
|
+
// Demo fixture derives the note leaf via IntentWitness's own helpers
|
|
432
|
+
// (computePayloadCommit / computeIntentNote / AllowlistTree), exactly the way
|
|
433
|
+
// the circuit computes it — fullProve/verify below is self-checking.
|
|
434
|
+
|
|
435
|
+
async function proofOfLife(opts, paths) {
|
|
436
|
+
await waitForFile(
|
|
437
|
+
opts.witness,
|
|
438
|
+
opts.witnessPollMinutes,
|
|
439
|
+
"intent witness module",
|
|
440
|
+
"IntentWitness (zk/intent-witness.mjs)",
|
|
441
|
+
);
|
|
442
|
+
const wasmPath = path.join(
|
|
443
|
+
opts.buildDir,
|
|
444
|
+
`${CIRCUIT_NAME}_js`,
|
|
445
|
+
`${CIRCUIT_NAME}.wasm`,
|
|
446
|
+
);
|
|
447
|
+
if (!existsSync(wasmPath)) {
|
|
448
|
+
throw new BlockingError(
|
|
449
|
+
`BLOCKED: ${wasmPath} missing (IntentCircuitBuild compile output).`,
|
|
450
|
+
3,
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
// snarkjs ESM entry has named exports only (no default).
|
|
455
|
+
const { groth16 } = await import("snarkjs");
|
|
456
|
+
const { NoteTree } = await import("./zk-tree.mjs");
|
|
457
|
+
const witnessMod = await import(pathToFileURL(opts.witness).href);
|
|
458
|
+
const {
|
|
459
|
+
buildIntentWitness,
|
|
460
|
+
AllowlistTree,
|
|
461
|
+
INTENT_PUBLIC_SIGNALS,
|
|
462
|
+
computePayloadCommit,
|
|
463
|
+
computeIntentNote,
|
|
464
|
+
} = witnessMod;
|
|
465
|
+
if (typeof buildIntentWitness !== "function") {
|
|
466
|
+
throw new Error(`${opts.witness} does not export buildIntentWitness`);
|
|
467
|
+
}
|
|
468
|
+
if (typeof AllowlistTree !== "function") {
|
|
469
|
+
throw new Error(`${opts.witness} does not export AllowlistTree`);
|
|
470
|
+
}
|
|
471
|
+
if (
|
|
472
|
+
typeof computePayloadCommit !== "function" ||
|
|
473
|
+
typeof computeIntentNote !== "function"
|
|
474
|
+
) {
|
|
475
|
+
throw new Error(
|
|
476
|
+
`${opts.witness} does not export computePayloadCommit/computeIntentNote`,
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
const publicSignalNames = INTENT_PUBLIC_SIGNALS ?? [
|
|
480
|
+
"noteRoot",
|
|
481
|
+
"actionHash",
|
|
482
|
+
"nullifier",
|
|
483
|
+
"currentSlot",
|
|
484
|
+
];
|
|
485
|
+
|
|
486
|
+
// Self-contained demo fixture: one policy note + one-recipient allowlist.
|
|
487
|
+
const ownerKey = BigInt("0x" + randomBytes(31).toString("hex"));
|
|
488
|
+
const rho = BigInt("0x" + randomBytes(31).toString("hex"));
|
|
489
|
+
const maxAmount = 1_000_000n; // lamports
|
|
490
|
+
const amountLamports = 500_000n;
|
|
491
|
+
const validAfterSlot = 0n;
|
|
492
|
+
const currentSlot = 100n;
|
|
493
|
+
const recipient = "11111111111111111111111111111111"; // 32 zero bytes
|
|
494
|
+
const mint = "So11111111111111111111111111111111111111112"; // wSOL mint
|
|
495
|
+
const nonceBytes = randomBytes(16);
|
|
496
|
+
|
|
497
|
+
const allowlist = new AllowlistTree();
|
|
498
|
+
allowlist.insert(recipient);
|
|
499
|
+
const allowlistRoot = allowlist.root();
|
|
500
|
+
|
|
501
|
+
const payloadCommit = computePayloadCommit({
|
|
502
|
+
maxAmount,
|
|
503
|
+
allowlistRoot,
|
|
504
|
+
validAfterSlot,
|
|
505
|
+
});
|
|
506
|
+
const note = computeIntentNote(ownerKey, rho, payloadCommit);
|
|
507
|
+
const noteTree = new NoteTree();
|
|
508
|
+
const { index: noteIndex } = noteTree.insert(note);
|
|
509
|
+
|
|
510
|
+
const input = await buildIntentWitness({
|
|
511
|
+
noteTree,
|
|
512
|
+
noteIndex,
|
|
513
|
+
ownerKey,
|
|
514
|
+
rho,
|
|
515
|
+
maxAmount,
|
|
516
|
+
allowlist,
|
|
517
|
+
validAfterSlot,
|
|
518
|
+
recipient,
|
|
519
|
+
mint,
|
|
520
|
+
amountLamports,
|
|
521
|
+
nonceBytes,
|
|
522
|
+
currentSlot,
|
|
523
|
+
});
|
|
524
|
+
|
|
525
|
+
const t0 = Date.now();
|
|
526
|
+
const { proof, publicSignals } = await groth16.fullProve(
|
|
527
|
+
input,
|
|
528
|
+
wasmPath,
|
|
529
|
+
paths.zkeyFinal,
|
|
530
|
+
);
|
|
531
|
+
const proveMs = Date.now() - t0;
|
|
532
|
+
|
|
533
|
+
// The builder's declared public signals MUST match what the prover emits,
|
|
534
|
+
// in the binding order [noteRoot, actionHash, nullifier, currentSlot].
|
|
535
|
+
if (publicSignals.length !== NUM_PUBLIC_INPUTS) {
|
|
536
|
+
throw new Error(
|
|
537
|
+
`fullProve emitted ${publicSignals.length} public signals, expected ${NUM_PUBLIC_INPUTS}`,
|
|
538
|
+
);
|
|
539
|
+
}
|
|
540
|
+
for (let i = 0; i < NUM_PUBLIC_INPUTS; i++) {
|
|
541
|
+
const declared = String(input[publicSignalNames[i]]);
|
|
542
|
+
if (declared !== String(publicSignals[i])) {
|
|
543
|
+
throw new Error(
|
|
544
|
+
`public signal ${publicSignalNames[i]} mismatch: witness ${declared} != prover ${publicSignals[i]}`,
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
const t1 = Date.now();
|
|
550
|
+
const vkJsonObj = JSON.parse(readFileSync(paths.vkJson, "utf8"));
|
|
551
|
+
const ok = await groth16.verify(vkJsonObj, publicSignals, proof);
|
|
552
|
+
const verifyMs = Date.now() - t1;
|
|
553
|
+
if (!ok) {
|
|
554
|
+
throw new Error("PROOF-OF-LIFE FAILED: groth16.verify returned false");
|
|
555
|
+
}
|
|
556
|
+
log(
|
|
557
|
+
`proof-of-life OK — fullProve ${proveMs}ms, verify ${verifyMs}ms ` +
|
|
558
|
+
`(public signals [${publicSignalNames.join(", ")}] match witness)`,
|
|
559
|
+
);
|
|
560
|
+
return { proveMs, verifyMs, publicSignals };
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
// ---------------------------------------------------------------------------
|
|
564
|
+
// main
|
|
565
|
+
// ---------------------------------------------------------------------------
|
|
566
|
+
|
|
567
|
+
async function main() {
|
|
568
|
+
const opts = parseArgs(process.argv.slice(2));
|
|
569
|
+
const paths = stagePaths(opts.buildDir, opts.r1cs);
|
|
570
|
+
|
|
571
|
+
await waitForFile(
|
|
572
|
+
opts.r1cs,
|
|
573
|
+
opts.pollMinutes,
|
|
574
|
+
"r1cs",
|
|
575
|
+
"IntentCircuitBuild (circuits/intent_attestation.circom → circom compile)",
|
|
576
|
+
);
|
|
577
|
+
|
|
578
|
+
const r1csSha256 = sha256File(opts.r1cs);
|
|
579
|
+
log(`r1cs sha256: ${r1csSha256}`);
|
|
580
|
+
const priorState = readState(opts.buildDir);
|
|
581
|
+
const artifactsComplete =
|
|
582
|
+
existsSync(paths.vkJson) &&
|
|
583
|
+
existsSync(paths.vkBytes) &&
|
|
584
|
+
existsSync(paths.zkeyFinal);
|
|
585
|
+
|
|
586
|
+
if (opts.force || priorState?.r1csSha256 !== r1csSha256) {
|
|
587
|
+
const reason = opts.force
|
|
588
|
+
? "--force"
|
|
589
|
+
: priorState
|
|
590
|
+
? `r1cs changed (${priorState.r1csSha256} → ${r1csSha256})`
|
|
591
|
+
: "no prior setup state";
|
|
592
|
+
const removed = purgeStageArtifacts(paths);
|
|
593
|
+
if (removed.length > 0) {
|
|
594
|
+
log(
|
|
595
|
+
`${reason}: purged ${removed.length} stale circuit-specific artifact(s); ` +
|
|
596
|
+
`ptau reused (r1cs-independent)`,
|
|
597
|
+
);
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
|
|
601
|
+
const header = readR1csHeader(opts.r1cs);
|
|
602
|
+
log(
|
|
603
|
+
`r1cs: ${header.nConstraints} constraints, ${header.nWires} wires, ` +
|
|
604
|
+
`${header.nPubIn} pub-in, ${header.nPubOut} pub-out`,
|
|
605
|
+
);
|
|
606
|
+
const impliedIc = 1 + header.nPubIn + header.nPubOut;
|
|
607
|
+
if (impliedIc !== EXPECTED_IC) {
|
|
608
|
+
log(
|
|
609
|
+
`WARNING: r1cs implies IC length ${impliedIc} (1 + ${header.nPubIn} + ${header.nPubOut}) ` +
|
|
610
|
+
`but the intent contract expects ${EXPECTED_IC}; vk export will fail if the vk disagrees`,
|
|
611
|
+
);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
const ptau = acquirePtau(opts.ptauDir, header.nConstraints);
|
|
615
|
+
log(`ptau provenance: ${ptau.provenance} (${(ptau.size / 1024 / 1024).toFixed(1)}MB)`);
|
|
616
|
+
|
|
617
|
+
const freshArtifacts =
|
|
618
|
+
existsSync(paths.vkJson) &&
|
|
619
|
+
existsSync(paths.vkBytes) &&
|
|
620
|
+
existsSync(paths.zkeyFinal);
|
|
621
|
+
if (!freshArtifacts) {
|
|
622
|
+
runCeremony(opts.r1cs, ptau.path, paths, opts.force);
|
|
623
|
+
exportVkBytes(paths, {
|
|
624
|
+
ptau: ptau.provenance,
|
|
625
|
+
ptauBytes: ptau.size,
|
|
626
|
+
ptauPower: ptau.power,
|
|
627
|
+
r1csSha256,
|
|
628
|
+
constraintCount: header.nConstraints,
|
|
629
|
+
contribution:
|
|
630
|
+
"enigma-intent-dev-1 (random entropy) + random beacon (10 iterations)",
|
|
631
|
+
});
|
|
632
|
+
log(
|
|
633
|
+
`ceremony artifacts already complete for r1cs ${r1csSha256} — reusing ` +
|
|
634
|
+
`(zkey + intent_verification_key.json + intent_vk_bytes.json)`,
|
|
635
|
+
);
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// Persist the ceremony fingerprint NOW, so a proof-of-life failure does not
|
|
639
|
+
// force a ceremony redo on the next run (artifacts are already r1cs-bound).
|
|
640
|
+
writeState(opts.buildDir, {
|
|
641
|
+
r1csSha256,
|
|
642
|
+
constraintCount: header.nConstraints,
|
|
643
|
+
powerOfTau: ptau.power,
|
|
644
|
+
ptau: ptau.provenance,
|
|
645
|
+
zkeyFinal: path.basename(paths.zkeyFinal),
|
|
646
|
+
icCount: EXPECTED_IC,
|
|
647
|
+
icPaddedTo: ONCHAIN_VK_IC_SLOTS,
|
|
648
|
+
completedAt: new Date().toISOString(),
|
|
649
|
+
});
|
|
650
|
+
|
|
651
|
+
if (opts.skipProofOfLife) {
|
|
652
|
+
log("--skip-proof-of-life: ceremony complete, skipping fullProve/verify.");
|
|
653
|
+
} else {
|
|
654
|
+
const pol = await proofOfLife(opts, paths);
|
|
655
|
+
writeState(opts.buildDir, {
|
|
656
|
+
r1csSha256,
|
|
657
|
+
constraintCount: header.nConstraints,
|
|
658
|
+
powerOfTau: ptau.power,
|
|
659
|
+
ptau: ptau.provenance,
|
|
660
|
+
zkeyFinal: path.basename(paths.zkeyFinal),
|
|
661
|
+
icCount: EXPECTED_IC,
|
|
662
|
+
icPaddedTo: ONCHAIN_VK_IC_SLOTS,
|
|
663
|
+
proofOfLife: {
|
|
664
|
+
ok: true,
|
|
665
|
+
proveMs: pol.proveMs,
|
|
666
|
+
verifyMs: pol.verifyMs,
|
|
667
|
+
at: new Date().toISOString(),
|
|
668
|
+
},
|
|
669
|
+
completedAt: new Date().toISOString(),
|
|
670
|
+
});
|
|
671
|
+
}
|
|
672
|
+
log("setup-intent complete.");
|
|
673
|
+
}
|
|
674
|
+
|
|
675
|
+
// snarkjs's in-process JS API (proof-of-life) keeps worker threads alive;
|
|
676
|
+
// exit explicitly once the driver has finished.
|
|
677
|
+
main()
|
|
678
|
+
.then(() => process.exit(0))
|
|
679
|
+
.catch((err) => {
|
|
680
|
+
if (err instanceof BlockingError) {
|
|
681
|
+
console.error(`\n${err.message}`);
|
|
682
|
+
process.exit(err.exitCode);
|
|
683
|
+
}
|
|
684
|
+
console.error(
|
|
685
|
+
`\nsetup-intent.mjs FAILED: ${err.stack ?? err.message ?? err}`,
|
|
686
|
+
);
|
|
687
|
+
process.exit(1);
|
|
688
|
+
});
|