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,594 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* setup.mjs — idempotent Groth16 ceremony driver for the Enigma
|
|
3
|
+
* action-transition circuit (BUILD-CONTRACT.md v3).
|
|
4
|
+
*
|
|
5
|
+
* Pipeline:
|
|
6
|
+
* 1. Poll (default up to 40 min) for circuits/build/action_transition.r1cs
|
|
7
|
+
* (produced concurrently by CircuitBuild).
|
|
8
|
+
* 2. Read the constraint count from the r1cs binary header (authoritative);
|
|
9
|
+
* log CircuitBuild's metadata file if one exists.
|
|
10
|
+
* 3. Acquire powersOfTau28_hez_final_<power>.ptau into ptau/:
|
|
11
|
+
* power 18 if constraints < 260_000 (expected, ~60-100k), else 19.
|
|
12
|
+
* Mirrors: storage.googleapis.com/zkevm/ptau/ then
|
|
13
|
+
* hermez.s3-eu-west-1.amazonaws.com. Sanity-checked size.
|
|
14
|
+
* Fallback: local `snarkjs powersoftau new/contribute/beacon/
|
|
15
|
+
* prepare phase2` ceremony.
|
|
16
|
+
* 4. groth16 setup → zkey contribute (name "enigma-dev-1", random entropy)
|
|
17
|
+
* → zkey beacon (random 32B, 10 iterations) → export verificationkey →
|
|
18
|
+
* circuits/build/verification_key.json.
|
|
19
|
+
* 5. vkFromSnarkjs (asserts IC == 7) → circuits/build/vk_bytes.json
|
|
20
|
+
* (raw-be-hex-v1).
|
|
21
|
+
*
|
|
22
|
+
* verification_key.json + vk_bytes.json are COMMITTABLE; ptau/, *.zkey,
|
|
23
|
+
* *.wasm, *.r1cs are gitignored.
|
|
24
|
+
*
|
|
25
|
+
* CLAIM BOUNDARY: single-party local setup = development only; production
|
|
26
|
+
* requires a multi-party ceremony.
|
|
27
|
+
*
|
|
28
|
+
* Usage:
|
|
29
|
+
* node zk/setup.mjs [--r1cs <path>] [--build-dir <dir>] [--ptau-dir <dir>]
|
|
30
|
+
* [--power <18|19|...>] [--poll-minutes <n>]
|
|
31
|
+
* [--expected-ic <n>] [--force]
|
|
32
|
+
* [--local-ptau] (skip mirrors; run the local powersoftau
|
|
33
|
+
* fallback ceremony — offline/dev escape hatch)
|
|
34
|
+
*
|
|
35
|
+
* Exit codes: 0 success · 3 blocked (r1cs prerequisite missing) ·
|
|
36
|
+
* 4 ptau acquisition failed · 1 other failure.
|
|
37
|
+
*/
|
|
38
|
+
|
|
39
|
+
import { spawnSync } from "node:child_process";
|
|
40
|
+
import { createHash, randomBytes } from "node:crypto";
|
|
41
|
+
import {
|
|
42
|
+
createWriteStream,
|
|
43
|
+
existsSync,
|
|
44
|
+
mkdirSync,
|
|
45
|
+
readFileSync,
|
|
46
|
+
renameSync,
|
|
47
|
+
rmSync,
|
|
48
|
+
statSync,
|
|
49
|
+
writeFileSync,
|
|
50
|
+
} from "node:fs";
|
|
51
|
+
import path from "node:path";
|
|
52
|
+
import { Readable, Transform } from "node:stream";
|
|
53
|
+
import { pipeline } from "node:stream/promises";
|
|
54
|
+
import { fileURLToPath } from "node:url";
|
|
55
|
+
|
|
56
|
+
import {
|
|
57
|
+
vkFromSnarkjs,
|
|
58
|
+
EXPECTED_IC_LENGTH,
|
|
59
|
+
NUM_PUBLIC_INPUTS,
|
|
60
|
+
} from "./zk-codec.mjs";
|
|
61
|
+
|
|
62
|
+
const HERE = path.dirname(fileURLToPath(import.meta.url));
|
|
63
|
+
const CORTEX_V3 = path.resolve(HERE, "..");
|
|
64
|
+
|
|
65
|
+
const DEFAULTS = {
|
|
66
|
+
r1cs: path.join(CORTEX_V3, "circuits", "build", "action_transition.r1cs"),
|
|
67
|
+
buildDir: path.join(CORTEX_V3, "circuits", "build"),
|
|
68
|
+
ptauDir: path.join(CORTEX_V3, "ptau"),
|
|
69
|
+
pollMinutes: 40,
|
|
70
|
+
expectedIc: EXPECTED_IC_LENGTH,
|
|
71
|
+
power: null, // auto from constraint count
|
|
72
|
+
force: false,
|
|
73
|
+
localPtau: false,
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// ~260k constraints is the 2^18 ceiling per the build contract.
|
|
77
|
+
const PTAU_18_MAX_CONSTRAINTS = 260_000;
|
|
78
|
+
const PTAU_MIRRORS = (power) => [
|
|
79
|
+
`https://storage.googleapis.com/zkevm/ptau/powersOfTau28_hez_final_${power}.ptau`,
|
|
80
|
+
`https://hermez.s3-eu-west-1.amazonaws.com/powersOfTau28_hez_final_${power}.ptau`,
|
|
81
|
+
];
|
|
82
|
+
const MIN_PTAU_BYTES = (power) => {
|
|
83
|
+
if (power === 19) return 150 * 1024 * 1024; // >150MB mandated for 2^19
|
|
84
|
+
if (power === 18) return 100 * 1024 * 1024; // hez_final_18 ≈ 145MB
|
|
85
|
+
return 2 ** power * 400; // scaled sanity for test powers
|
|
86
|
+
};
|
|
87
|
+
|
|
88
|
+
const log = (msg) => console.log(`[setup ${new Date().toISOString()}] ${msg}`);
|
|
89
|
+
const sleep = (ms) => new Promise((r) => setTimeout(r, ms));
|
|
90
|
+
|
|
91
|
+
class BlockingError extends Error {
|
|
92
|
+
constructor(message, exitCode) {
|
|
93
|
+
super(message);
|
|
94
|
+
this.exitCode = exitCode;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// ---------------------------------------------------------------------------
|
|
99
|
+
// CLI
|
|
100
|
+
// ---------------------------------------------------------------------------
|
|
101
|
+
|
|
102
|
+
function parseArgs(argv) {
|
|
103
|
+
const opts = { ...DEFAULTS };
|
|
104
|
+
for (let i = 0; i < argv.length; i++) {
|
|
105
|
+
const a = argv[i];
|
|
106
|
+
const next = () => {
|
|
107
|
+
if (i + 1 >= argv.length) throw new Error(`missing value for ${a}`);
|
|
108
|
+
return argv[++i];
|
|
109
|
+
};
|
|
110
|
+
switch (a) {
|
|
111
|
+
case "--r1cs":
|
|
112
|
+
opts.r1cs = path.resolve(next());
|
|
113
|
+
break;
|
|
114
|
+
case "--build-dir":
|
|
115
|
+
opts.buildDir = path.resolve(next());
|
|
116
|
+
break;
|
|
117
|
+
case "--ptau-dir":
|
|
118
|
+
opts.ptauDir = path.resolve(next());
|
|
119
|
+
break;
|
|
120
|
+
case "--power":
|
|
121
|
+
opts.power = Number(next());
|
|
122
|
+
break;
|
|
123
|
+
case "--poll-minutes":
|
|
124
|
+
opts.pollMinutes = Number(next());
|
|
125
|
+
break;
|
|
126
|
+
case "--expected-ic":
|
|
127
|
+
opts.expectedIc = Number(next());
|
|
128
|
+
break;
|
|
129
|
+
case "--force":
|
|
130
|
+
opts.force = true;
|
|
131
|
+
break;
|
|
132
|
+
case "--local-ptau":
|
|
133
|
+
opts.localPtau = true;
|
|
134
|
+
break;
|
|
135
|
+
default:
|
|
136
|
+
throw new Error(`unknown argument: ${a}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
if (opts.power !== null && (!Number.isInteger(opts.power) || opts.power < 4 || opts.power > 20)) {
|
|
140
|
+
throw new Error(`--power must be an integer in [4, 20], got ${opts.power}`);
|
|
141
|
+
}
|
|
142
|
+
return opts;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// ---------------------------------------------------------------------------
|
|
146
|
+
// snarkjs CLI runner (no npx/.cmd shims — run the CLI entrypoint with node)
|
|
147
|
+
// ---------------------------------------------------------------------------
|
|
148
|
+
|
|
149
|
+
function snarkjsCliPath() {
|
|
150
|
+
const p = path.join(CORTEX_V3, "node_modules", "snarkjs", "build", "cli.cjs");
|
|
151
|
+
if (!existsSync(p)) {
|
|
152
|
+
throw new Error(
|
|
153
|
+
`snarkjs CLI not found at ${p} — run "npm install -D snarkjs" in cortex-v3`,
|
|
154
|
+
);
|
|
155
|
+
}
|
|
156
|
+
return p;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function snarkjs(args, { quiet = false } = {}) {
|
|
160
|
+
const fullArgs = [snarkjsCliPath(), ...args];
|
|
161
|
+
log(`$ node ${path.basename(snarkjsCliPath())} ${args.join(" ")}`);
|
|
162
|
+
const res = spawnSync(process.execPath, fullArgs, {
|
|
163
|
+
cwd: CORTEX_V3,
|
|
164
|
+
stdio: quiet ? "pipe" : "inherit",
|
|
165
|
+
encoding: "utf8",
|
|
166
|
+
maxBuffer: 64 * 1024 * 1024,
|
|
167
|
+
});
|
|
168
|
+
if (res.error) throw res.error;
|
|
169
|
+
if (res.status !== 0) {
|
|
170
|
+
throw new Error(
|
|
171
|
+
`snarkjs ${args[0]} exited with code ${res.status}\n${res.stderr ?? ""}`,
|
|
172
|
+
);
|
|
173
|
+
}
|
|
174
|
+
return (res.stdout ?? "") + (res.stderr ?? "");
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// ---------------------------------------------------------------------------
|
|
178
|
+
// r1cs inspection — parse the binary header directly (authoritative)
|
|
179
|
+
// ---------------------------------------------------------------------------
|
|
180
|
+
|
|
181
|
+
function readR1csHeader(r1csPath) {
|
|
182
|
+
const fd = readFileSync(r1csPath); // r1cs for ~100-400k constraints is tens of MB; fine
|
|
183
|
+
if (fd.length < 12 || fd.toString("ascii", 0, 4) !== "r1cs") {
|
|
184
|
+
throw new Error(`${r1csPath} is not an r1cs file (bad magic)`);
|
|
185
|
+
}
|
|
186
|
+
const nSections = fd.readUInt32LE(8);
|
|
187
|
+
let offset = 12;
|
|
188
|
+
for (let s = 0; s < nSections; s++) {
|
|
189
|
+
const sectionType = fd.readUInt32LE(offset);
|
|
190
|
+
const sectionSize = Number(fd.readBigUInt64LE(offset + 4));
|
|
191
|
+
if (sectionType === 1) {
|
|
192
|
+
const base = offset + 12;
|
|
193
|
+
const fieldSize = fd.readUInt32LE(base);
|
|
194
|
+
let p = base + 4 + fieldSize;
|
|
195
|
+
const nWires = fd.readUInt32LE(p);
|
|
196
|
+
const nPubOut = fd.readUInt32LE(p + 4);
|
|
197
|
+
const nPubIn = fd.readUInt32LE(p + 8);
|
|
198
|
+
const nPrvIn = fd.readUInt32LE(p + 12);
|
|
199
|
+
const nLabels = Number(fd.readBigUInt64LE(p + 16));
|
|
200
|
+
const nConstraints = fd.readUInt32LE(p + 24);
|
|
201
|
+
return { nWires, nPubOut, nPubIn, nPrvIn, nLabels, nConstraints };
|
|
202
|
+
}
|
|
203
|
+
offset += 12 + sectionSize;
|
|
204
|
+
}
|
|
205
|
+
throw new Error(`${r1csPath}: header section (type 1) not found`);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
function readConstraintMetadata(buildDir, r1csPath) {
|
|
209
|
+
const stem = path.basename(r1csPath).replace(/\.r1cs$/, "");
|
|
210
|
+
for (const name of [
|
|
211
|
+
`${stem}.meta.json`,
|
|
212
|
+
`${stem}.constraints.json`,
|
|
213
|
+
"build-metadata.json",
|
|
214
|
+
]) {
|
|
215
|
+
const p = path.join(buildDir, name);
|
|
216
|
+
if (existsSync(p)) {
|
|
217
|
+
try {
|
|
218
|
+
const meta = JSON.parse(readFileSync(p, "utf8"));
|
|
219
|
+
log(`metadata file ${name}: ${JSON.stringify(meta)}`);
|
|
220
|
+
return meta;
|
|
221
|
+
} catch {
|
|
222
|
+
log(`metadata file ${name} is not valid JSON — ignoring`);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
return null;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
// Stage 1: wait for the r1cs
|
|
231
|
+
// ---------------------------------------------------------------------------
|
|
232
|
+
|
|
233
|
+
async function waitForR1cs(r1csPath, pollMinutes) {
|
|
234
|
+
if (existsSync(r1csPath)) {
|
|
235
|
+
log(`r1cs present: ${r1csPath}`);
|
|
236
|
+
return;
|
|
237
|
+
}
|
|
238
|
+
log(`waiting up to ${pollMinutes} min for ${r1csPath} (CircuitBuild runs concurrently)...`);
|
|
239
|
+
const deadline = Date.now() + pollMinutes * 60_000;
|
|
240
|
+
while (Date.now() < deadline) {
|
|
241
|
+
if (existsSync(r1csPath)) {
|
|
242
|
+
// Guard against a partially-written file: size must be stable.
|
|
243
|
+
const s1 = statSync(r1csPath).size;
|
|
244
|
+
await sleep(2000);
|
|
245
|
+
const s2 = statSync(r1csPath).size;
|
|
246
|
+
if (s1 === s2 && s2 > 0) {
|
|
247
|
+
log(`r1cs appeared (${s2} bytes, stable)`);
|
|
248
|
+
return;
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
await sleep(15_000);
|
|
252
|
+
}
|
|
253
|
+
throw new BlockingError(
|
|
254
|
+
`BLOCKED: ${r1csPath} did not appear within ${pollMinutes} minutes.\n` +
|
|
255
|
+
`Prerequisite owner: CircuitBuild (circuits/action_transition.circom → circom compile).\n` +
|
|
256
|
+
`Re-run "node zk/setup.mjs" once the r1cs exists — all completed stages are reused.`,
|
|
257
|
+
3,
|
|
258
|
+
);
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
// ---------------------------------------------------------------------------
|
|
262
|
+
// Stage 2: ptau acquisition
|
|
263
|
+
// ---------------------------------------------------------------------------
|
|
264
|
+
|
|
265
|
+
async function downloadPtau(url, dest, minBytes) {
|
|
266
|
+
const tmp = `${dest}.download`;
|
|
267
|
+
rmSync(tmp, { force: true });
|
|
268
|
+
log(`downloading ${url}`);
|
|
269
|
+
const controller = new AbortController();
|
|
270
|
+
const timeout = setTimeout(() => controller.abort(), 45 * 60_000);
|
|
271
|
+
try {
|
|
272
|
+
const res = await fetch(url, { signal: controller.signal });
|
|
273
|
+
if (!res.ok || !res.body) {
|
|
274
|
+
throw new Error(`HTTP ${res.status} ${res.statusText}`);
|
|
275
|
+
}
|
|
276
|
+
const total = Number(res.headers.get("content-length") ?? 0);
|
|
277
|
+
let received = 0;
|
|
278
|
+
let lastLog = 0;
|
|
279
|
+
// Stream to disk with progress logging via a meter transform.
|
|
280
|
+
const meter = new Transform({
|
|
281
|
+
transform(chunk, _enc, cb) {
|
|
282
|
+
received += chunk.length;
|
|
283
|
+
if (received - lastLog >= 32 * 1024 * 1024) {
|
|
284
|
+
lastLog = received;
|
|
285
|
+
log(
|
|
286
|
+
` … ${(received / 1024 / 1024).toFixed(0)}MB` +
|
|
287
|
+
(total ? ` / ${(total / 1024 / 1024).toFixed(0)}MB` : ""),
|
|
288
|
+
);
|
|
289
|
+
}
|
|
290
|
+
cb(null, chunk);
|
|
291
|
+
},
|
|
292
|
+
});
|
|
293
|
+
await pipeline(Readable.fromWeb(res.body), meter, createWriteStream(tmp));
|
|
294
|
+
const size = statSync(tmp).size;
|
|
295
|
+
if (size < minBytes) {
|
|
296
|
+
throw new Error(
|
|
297
|
+
`sanity check failed: downloaded ${size} bytes < required minimum ${minBytes} ` +
|
|
298
|
+
`(truncated or wrong file)`,
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
renameSync(tmp, dest);
|
|
302
|
+
log(`ptau saved: ${dest} (${(size / 1024 / 1024).toFixed(1)}MB) from ${url}`);
|
|
303
|
+
return { provenance: url, size };
|
|
304
|
+
} finally {
|
|
305
|
+
clearTimeout(timeout);
|
|
306
|
+
rmSync(tmp, { force: true });
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
function localPowersOfTau(power, finalPath) {
|
|
311
|
+
// Fallback ceremony when every mirror is unreachable. Development only.
|
|
312
|
+
const dir = path.dirname(finalPath);
|
|
313
|
+
const pot0 = path.join(dir, `pot${power}_0.ptau`);
|
|
314
|
+
const pot1 = path.join(dir, `pot${power}_1.ptau`);
|
|
315
|
+
const potBeacon = path.join(dir, `pot${power}_beacon.ptau`);
|
|
316
|
+
const beacon = randomBytes(32).toString("hex");
|
|
317
|
+
snarkjs(["powersoftau", "new", "bn128", String(power), pot0, "-v"]);
|
|
318
|
+
snarkjs([
|
|
319
|
+
"powersoftau", "contribute", pot0, pot1,
|
|
320
|
+
"--name=enigma-dev-pot-1",
|
|
321
|
+
`-e=${randomBytes(32).toString("hex")}`,
|
|
322
|
+
]);
|
|
323
|
+
snarkjs(["powersoftau", "beacon", pot1, potBeacon, beacon, "10"]);
|
|
324
|
+
snarkjs(["powersoftau", "prepare", "phase2", potBeacon, finalPath, "-v"]);
|
|
325
|
+
for (const f of [pot0, pot1, potBeacon]) rmSync(f, { force: true });
|
|
326
|
+
return { provenance: `local single-party powersoftau ceremony (beacon ${beacon})`, size: statSync(finalPath).size };
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
async function acquirePtau(power, ptauDir, { localOnly = false } = {}) {
|
|
330
|
+
mkdirSync(ptauDir, { recursive: true });
|
|
331
|
+
const dest = path.join(ptauDir, `powersOfTau28_hez_final_${power}.ptau`);
|
|
332
|
+
const minBytes = MIN_PTAU_BYTES(power);
|
|
333
|
+
if (existsSync(dest)) {
|
|
334
|
+
const size = statSync(dest).size;
|
|
335
|
+
if (size >= minBytes) {
|
|
336
|
+
log(`reusing existing ptau: ${dest} (${(size / 1024 / 1024).toFixed(1)}MB)`);
|
|
337
|
+
return { path: dest, provenance: "reused existing file", size };
|
|
338
|
+
}
|
|
339
|
+
log(`existing ptau fails size sanity (${size} < ${minBytes}) — re-acquiring`);
|
|
340
|
+
rmSync(dest, { force: true });
|
|
341
|
+
}
|
|
342
|
+
const errors = [];
|
|
343
|
+
if (localOnly) {
|
|
344
|
+
log("--local-ptau: skipping mirrors, running LOCAL powersoftau ceremony (dev only)");
|
|
345
|
+
const { provenance, size } = localPowersOfTau(power, dest);
|
|
346
|
+
return { path: dest, provenance, size };
|
|
347
|
+
}
|
|
348
|
+
for (const url of PTAU_MIRRORS(power)) {
|
|
349
|
+
try {
|
|
350
|
+
const { provenance, size } = await downloadPtau(url, dest, minBytes);
|
|
351
|
+
return { path: dest, provenance, size };
|
|
352
|
+
} catch (err) {
|
|
353
|
+
errors.push(`${url}: ${err.message}`);
|
|
354
|
+
log(`mirror failed — ${url}: ${err.message}`);
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
log("all ptau mirrors failed; falling back to LOCAL powersoftau ceremony (dev only)");
|
|
358
|
+
try {
|
|
359
|
+
const { provenance, size } = localPowersOfTau(power, dest);
|
|
360
|
+
return { path: dest, provenance, size };
|
|
361
|
+
} catch (err) {
|
|
362
|
+
throw new BlockingError(
|
|
363
|
+
`BLOCKED: could not acquire a powers-of-tau for 2^${power}.\n` +
|
|
364
|
+
`Mirror failures:\n - ${errors.join("\n - ")}\n` +
|
|
365
|
+
`Local ceremony failure: ${err.message}`,
|
|
366
|
+
4,
|
|
367
|
+
);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
// ---------------------------------------------------------------------------
|
|
372
|
+
// Stages 3-5: circuit-specific ceremony
|
|
373
|
+
// ---------------------------------------------------------------------------
|
|
374
|
+
|
|
375
|
+
function stagePaths(buildDir, r1csPath) {
|
|
376
|
+
const stem = path.basename(r1csPath).replace(/\.r1cs$/, "");
|
|
377
|
+
return {
|
|
378
|
+
zkey0: path.join(buildDir, `${stem}_0000.zkey`),
|
|
379
|
+
zkey1: path.join(buildDir, `${stem}_0001.zkey`),
|
|
380
|
+
// Final proving key name is CONTRACT: Main's e2e loads <stem>.zkey.
|
|
381
|
+
zkeyFinal: path.join(buildDir, `${stem}.zkey`),
|
|
382
|
+
vkJson: path.join(buildDir, "verification_key.json"),
|
|
383
|
+
vkBytes: path.join(buildDir, "vk_bytes.json"),
|
|
384
|
+
};
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
function runCeremony(r1csPath, ptauPath, paths, force) {
|
|
388
|
+
mkdirSync(path.dirname(paths.zkey0), { recursive: true });
|
|
389
|
+
if (force) {
|
|
390
|
+
for (const f of Object.values(paths)) rmSync(f, { force: true });
|
|
391
|
+
}
|
|
392
|
+
if (!existsSync(paths.zkey0)) {
|
|
393
|
+
snarkjs(["groth16", "setup", r1csPath, ptauPath, paths.zkey0]);
|
|
394
|
+
} else {
|
|
395
|
+
log(`reusing ${paths.zkey0}`);
|
|
396
|
+
}
|
|
397
|
+
if (!existsSync(paths.zkey1)) {
|
|
398
|
+
snarkjs([
|
|
399
|
+
"zkey", "contribute", paths.zkey0, paths.zkey1,
|
|
400
|
+
"--name=enigma-dev-1",
|
|
401
|
+
`-e=${randomBytes(32).toString("hex")}`,
|
|
402
|
+
]);
|
|
403
|
+
} else {
|
|
404
|
+
log(`reusing ${paths.zkey1}`);
|
|
405
|
+
}
|
|
406
|
+
if (!existsSync(paths.zkeyFinal)) {
|
|
407
|
+
const beacon = randomBytes(32).toString("hex");
|
|
408
|
+
snarkjs(["zkey", "beacon", paths.zkey1, paths.zkeyFinal, beacon, "10"]);
|
|
409
|
+
log(`zkey beacon applied (dev beacon ${beacon})`);
|
|
410
|
+
} else {
|
|
411
|
+
log(`reusing ${paths.zkeyFinal}`);
|
|
412
|
+
}
|
|
413
|
+
if (!existsSync(paths.vkJson)) {
|
|
414
|
+
snarkjs(["zkey", "export", "verificationkey", paths.zkeyFinal, paths.vkJson]);
|
|
415
|
+
} else {
|
|
416
|
+
log(`reusing ${paths.vkJson}`);
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function exportVkBytes(paths, expectedIc, meta) {
|
|
421
|
+
const vkJson = JSON.parse(readFileSync(paths.vkJson, "utf8"));
|
|
422
|
+
const vk = vkFromSnarkjs(vkJson, { expectedIc }); // throws unless IC == expectedIc
|
|
423
|
+
const hex = (b) => b.toString("hex"); // plain hex strings (Main's e2e contract)
|
|
424
|
+
const out = {
|
|
425
|
+
format: "raw-be-hex-v1",
|
|
426
|
+
curve: "bn128",
|
|
427
|
+
g2LimbOrder: "c1c0", // alt_bn128 / EIP-196 (im,re); flip only via empirical on-chain resolution
|
|
428
|
+
proofNote: "pi_a is raw — the on-chain program negates A",
|
|
429
|
+
numPublicInputs: expectedIc - 1,
|
|
430
|
+
icCount: vk.ic.length,
|
|
431
|
+
alphaG1: hex(vk.alphaG1),
|
|
432
|
+
betaG2: hex(vk.betaG2),
|
|
433
|
+
gammaG2: hex(vk.gammaG2),
|
|
434
|
+
deltaG2: hex(vk.deltaG2),
|
|
435
|
+
ic: vk.ic.map(hex),
|
|
436
|
+
ceremony: meta,
|
|
437
|
+
source: path.basename(paths.vkJson),
|
|
438
|
+
createdAt: new Date().toISOString(),
|
|
439
|
+
};
|
|
440
|
+
const tmp = `${paths.vkBytes}.tmp`;
|
|
441
|
+
writeFileSync(tmp, JSON.stringify(out, null, 2) + "\n");
|
|
442
|
+
renameSync(tmp, paths.vkBytes);
|
|
443
|
+
return out;
|
|
444
|
+
}
|
|
445
|
+
|
|
446
|
+
// ---------------------------------------------------------------------------
|
|
447
|
+
// r1cs fingerprint — ceremony artifacts are only valid for the exact r1cs
|
|
448
|
+
// they were derived from. If the r1cs changes (circuit recompile), every
|
|
449
|
+
// circuit-specific stage MUST be redone; the ptau is r1cs-independent.
|
|
450
|
+
// ---------------------------------------------------------------------------
|
|
451
|
+
|
|
452
|
+
function sha256File(p) {
|
|
453
|
+
return createHash("sha256").update(readFileSync(p)).digest("hex");
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
function statePath(buildDir) {
|
|
457
|
+
return path.join(buildDir, "zk-setup-state.json");
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function readState(buildDir) {
|
|
461
|
+
const p = statePath(buildDir);
|
|
462
|
+
if (!existsSync(p)) return null;
|
|
463
|
+
try {
|
|
464
|
+
return JSON.parse(readFileSync(p, "utf8"));
|
|
465
|
+
} catch {
|
|
466
|
+
return null;
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
function writeState(buildDir, state) {
|
|
471
|
+
const tmp = `${statePath(buildDir)}.tmp`;
|
|
472
|
+
writeFileSync(tmp, JSON.stringify(state, null, 2) + "\n");
|
|
473
|
+
renameSync(tmp, statePath(buildDir));
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/** Delete circuit-specific artifacts; returns list of removed paths. */
|
|
477
|
+
function purgeStageArtifacts(paths) {
|
|
478
|
+
const removed = [];
|
|
479
|
+
for (const key of ["zkey0", "zkey1", "zkeyFinal", "vkJson", "vkBytes"]) {
|
|
480
|
+
if (existsSync(paths[key])) {
|
|
481
|
+
rmSync(paths[key], { force: true });
|
|
482
|
+
removed.push(paths[key]);
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
return removed;
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
// ---------------------------------------------------------------------------
|
|
489
|
+
// main
|
|
490
|
+
// ---------------------------------------------------------------------------
|
|
491
|
+
|
|
492
|
+
async function main() {
|
|
493
|
+
const opts = parseArgs(process.argv.slice(2));
|
|
494
|
+
const paths = stagePaths(opts.buildDir, opts.r1cs);
|
|
495
|
+
|
|
496
|
+
await waitForR1cs(opts.r1cs, opts.pollMinutes);
|
|
497
|
+
|
|
498
|
+
const r1csSha256 = sha256File(opts.r1cs);
|
|
499
|
+
log(`r1cs sha256: ${r1csSha256}`);
|
|
500
|
+
const priorState = readState(opts.buildDir);
|
|
501
|
+
const artifactsComplete =
|
|
502
|
+
existsSync(paths.vkJson) &&
|
|
503
|
+
existsSync(paths.vkBytes) &&
|
|
504
|
+
existsSync(paths.zkeyFinal);
|
|
505
|
+
|
|
506
|
+
if (opts.force || priorState?.r1csSha256 !== r1csSha256) {
|
|
507
|
+
const reason = opts.force
|
|
508
|
+
? "--force"
|
|
509
|
+
: priorState
|
|
510
|
+
? `r1cs changed (${priorState.r1csSha256} → ${r1csSha256})`
|
|
511
|
+
: "no prior setup state";
|
|
512
|
+
const removed = purgeStageArtifacts(paths);
|
|
513
|
+
if (removed.length > 0) {
|
|
514
|
+
log(
|
|
515
|
+
`${reason}: purged ${removed.length} stale circuit-specific artifact(s); ` +
|
|
516
|
+
`ptau reused (r1cs-independent)`,
|
|
517
|
+
);
|
|
518
|
+
}
|
|
519
|
+
} else if (artifactsComplete) {
|
|
520
|
+
// Idempotent fast path: artifacts complete AND bound to this exact r1cs.
|
|
521
|
+
const vk = vkFromSnarkjs(JSON.parse(readFileSync(paths.vkJson, "utf8")), {
|
|
522
|
+
expectedIc: opts.expectedIc,
|
|
523
|
+
});
|
|
524
|
+
log(
|
|
525
|
+
`setup already complete for r1cs ${r1csSha256} — ` +
|
|
526
|
+
`verification_key.json IC count ${vk.ic.length}, vk_bytes.json present. Nothing to do.`,
|
|
527
|
+
);
|
|
528
|
+
return;
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
const header = readR1csHeader(opts.r1cs);
|
|
532
|
+
readConstraintMetadata(opts.buildDir, opts.r1cs);
|
|
533
|
+
log(
|
|
534
|
+
`r1cs: ${header.nConstraints} constraints, ${header.nWires} wires, ` +
|
|
535
|
+
`${header.nPubIn} pub-in, ${header.nPubOut} pub-out`,
|
|
536
|
+
);
|
|
537
|
+
const impliedIc = 1 + header.nPubIn + header.nPubOut;
|
|
538
|
+
if (impliedIc !== opts.expectedIc) {
|
|
539
|
+
log(
|
|
540
|
+
`WARNING: r1cs implies IC length ${impliedIc} (1 + ${header.nPubIn} + ${header.nPubOut}) ` +
|
|
541
|
+
`but --expected-ic is ${opts.expectedIc}; export will fail if the vk disagrees`,
|
|
542
|
+
);
|
|
543
|
+
}
|
|
544
|
+
|
|
545
|
+
const power =
|
|
546
|
+
opts.power ??
|
|
547
|
+
(header.nConstraints < PTAU_18_MAX_CONSTRAINTS ? 18 : 19);
|
|
548
|
+
if (2 ** power <= header.nConstraints) {
|
|
549
|
+
throw new Error(
|
|
550
|
+
`constraint count ${header.nConstraints} does not fit in 2^${power} powers-of-tau`,
|
|
551
|
+
);
|
|
552
|
+
}
|
|
553
|
+
log(
|
|
554
|
+
`constraint count ${header.nConstraints} → powers-of-tau 2^${power}` +
|
|
555
|
+
(opts.power ? " (forced via --power)" : ""),
|
|
556
|
+
);
|
|
557
|
+
|
|
558
|
+
const ptau = await acquirePtau(power, opts.ptauDir, { localOnly: opts.localPtau });
|
|
559
|
+
log(`ptau provenance: ${ptau.provenance} (${(ptau.size / 1024 / 1024).toFixed(1)}MB)`);
|
|
560
|
+
|
|
561
|
+
runCeremony(opts.r1cs, ptau.path, paths, opts.force);
|
|
562
|
+
|
|
563
|
+
const vkBytes = exportVkBytes(paths, opts.expectedIc, {
|
|
564
|
+
type: "single-party local (DEVELOPMENT ONLY — production needs a multi-party ceremony)",
|
|
565
|
+
ptau: ptau.provenance,
|
|
566
|
+
ptauBytes: ptau.size,
|
|
567
|
+
r1csSha256,
|
|
568
|
+
constraintCount: header.nConstraints,
|
|
569
|
+
powerOfTau: power,
|
|
570
|
+
contribution: "enigma-dev-1 (random entropy) + random beacon (10 iterations)",
|
|
571
|
+
});
|
|
572
|
+
writeState(opts.buildDir, {
|
|
573
|
+
r1csSha256,
|
|
574
|
+
constraintCount: header.nConstraints,
|
|
575
|
+
powerOfTau: power,
|
|
576
|
+
ptau: ptau.provenance,
|
|
577
|
+
zkeyFinal: path.basename(paths.zkeyFinal),
|
|
578
|
+
icCount: vkBytes.icCount,
|
|
579
|
+
completedAt: new Date().toISOString(),
|
|
580
|
+
});
|
|
581
|
+
log(`verification_key.json: ${paths.vkJson}`);
|
|
582
|
+
log(`vk_bytes.json: ${paths.vkBytes}`);
|
|
583
|
+
log(`IC count in exported vk: ${vkBytes.icCount} (expected ${opts.expectedIc})`);
|
|
584
|
+
log("setup complete.");
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
main().catch((err) => {
|
|
588
|
+
if (err instanceof BlockingError) {
|
|
589
|
+
console.error(`\n${err.message}`);
|
|
590
|
+
process.exit(err.exitCode);
|
|
591
|
+
}
|
|
592
|
+
console.error(`\nsetup.mjs FAILED: ${err.stack ?? err.message ?? err}`);
|
|
593
|
+
process.exit(1);
|
|
594
|
+
});
|