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,365 @@
|
|
|
1
|
+
// intent-witness.mjs — client-side witness builder for
|
|
2
|
+
// circuits/intent_attestation.circom — IntentAttestation(NOTE_DEPTH=20, ALLOW_DEPTH=16).
|
|
3
|
+
//
|
|
4
|
+
// Binding spec: "verifiable agent intent" — a Groth16 proof that an x402
|
|
5
|
+
// payment action is consistent with a policy committed in the shared note
|
|
6
|
+
// tree. RECONCILIATION POINT: circuits/intent_attestation.circom is built
|
|
7
|
+
// concurrently (IntentCircuitBuild); every signal name below is taken VERBATIM
|
|
8
|
+
// from the circuit spec, and intent-witness.test.mjs re-reads the .circom
|
|
9
|
+
// file (when present) and asserts the names match exactly.
|
|
10
|
+
//
|
|
11
|
+
// Public signals (exact order/names): noteRoot, actionHash, nullifier, currentSlot.
|
|
12
|
+
// Private signals: ownerKey, rho, maxAmount, allowlistRoot, validAfterSlot,
|
|
13
|
+
// notePathElements[20], notePathIndices[20] (LSB-first),
|
|
14
|
+
// rLo, rHi, mintLo, mintHi, amount, nonce (x402 descriptor limbs, each < 2^128),
|
|
15
|
+
// allowPathElements[16], allowPathIndices[16].
|
|
16
|
+
//
|
|
17
|
+
// In-circuit semantics mirrored here:
|
|
18
|
+
// payloadCommit = Poseidon4(DOMAIN_POLICY, maxAmount, allowlistRoot, validAfterSlot)
|
|
19
|
+
// note = Poseidon3(ownerKey, rho, payloadCommit) (member of noteRoot)
|
|
20
|
+
// payeeLeaf = Poseidon3(DOMAIN_ALLOW, rLo, rHi) (member of allowlistRoot)
|
|
21
|
+
// actionHash = Poseidon7(DOMAIN_ACTION, rLo, rHi, mintLo, mintHi, amount, nonce)
|
|
22
|
+
// nullifier = Poseidon3(DOMAIN_INTENT_NF, ownerKey, actionHash)
|
|
23
|
+
// amount <= maxAmount (u64), validAfterSlot <= currentSlot (< 2^48)
|
|
24
|
+
//
|
|
25
|
+
// x402 descriptor limbs (deterministic, each < 2^128, little-endian):
|
|
26
|
+
// recipient (32B) = rLo (LE bytes 0..16) | rHi (LE bytes 16..32)
|
|
27
|
+
// mint (32B) = mintLo | mintHi (same split)
|
|
28
|
+
// amount = u64 LE lamports
|
|
29
|
+
// nonce = 16 bytes LE
|
|
30
|
+
//
|
|
31
|
+
// All field elements are emitted as DECIMAL STRINGS (snarkjs JSON convention).
|
|
32
|
+
|
|
33
|
+
import bs58 from "bs58";
|
|
34
|
+
|
|
35
|
+
import {
|
|
36
|
+
NoteTree,
|
|
37
|
+
buildZeros,
|
|
38
|
+
computeProof,
|
|
39
|
+
computeRoot,
|
|
40
|
+
poseidon,
|
|
41
|
+
verifyMerkleProof,
|
|
42
|
+
} from "./zk-tree.mjs";
|
|
43
|
+
|
|
44
|
+
/** Note tree depth (matches the shared note tree / NoteTree default). */
|
|
45
|
+
export const NOTE_DEPTH = 20;
|
|
46
|
+
/** Allowlist tree depth. */
|
|
47
|
+
export const ALLOW_DEPTH = 16;
|
|
48
|
+
|
|
49
|
+
// Domain separators ("enigma_policy" / "enigma_allow" / "enigma_action" /
|
|
50
|
+
// "enigma_intent" ASCII, decimal — the circuit binds these exact values).
|
|
51
|
+
export const DOMAIN_POLICY = 8036215190653564880547136234361n;
|
|
52
|
+
export const DOMAIN_ALLOW = 31391465588490487750162411383n;
|
|
53
|
+
export const DOMAIN_ACTION = 8036215190653564864003056430958n;
|
|
54
|
+
export const DOMAIN_INTENT_NF = 8036215190653564872846393831028n;
|
|
55
|
+
|
|
56
|
+
/** Public signal names in exact on-chain/circuit order. */
|
|
57
|
+
export const INTENT_PUBLIC_SIGNALS = Object.freeze([
|
|
58
|
+
"noteRoot",
|
|
59
|
+
"actionHash",
|
|
60
|
+
"nullifier",
|
|
61
|
+
"currentSlot",
|
|
62
|
+
]);
|
|
63
|
+
|
|
64
|
+
const TWO_64 = 1n << 64n;
|
|
65
|
+
const TWO_128 = 1n << 128n;
|
|
66
|
+
const TWO_48 = 1n << 48n;
|
|
67
|
+
|
|
68
|
+
// ---------------------------------------------------------------------------
|
|
69
|
+
// Byte/limb helpers
|
|
70
|
+
// ---------------------------------------------------------------------------
|
|
71
|
+
|
|
72
|
+
/** Little-endian bytes → bigint. */
|
|
73
|
+
export function bytesToBigIntLE(bytes) {
|
|
74
|
+
let v = 0n;
|
|
75
|
+
for (let i = bytes.length - 1; i >= 0; i--) v = (v << 8n) | BigInt(bytes[i]);
|
|
76
|
+
return v;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** base58 → exactly `len` bytes (Solana pubkey / fixed-size buffer). */
|
|
80
|
+
function decodeBase58Fixed(b58, len, what) {
|
|
81
|
+
if (typeof b58 !== "string" || b58.length === 0) {
|
|
82
|
+
throw new TypeError(`${what}: expected a non-empty base58 string`);
|
|
83
|
+
}
|
|
84
|
+
const bytes = bs58.decode(b58);
|
|
85
|
+
if (bytes.length !== len) {
|
|
86
|
+
throw new Error(`${what}: expected ${len} bytes, got ${bytes.length}`);
|
|
87
|
+
}
|
|
88
|
+
return bytes;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Split the x402 payment descriptor into circuit limbs.
|
|
93
|
+
* recipient/mint: base58-encoded 32-byte Solana pubkeys.
|
|
94
|
+
* amountLamports: u64. nonceBytes: exactly 16 bytes.
|
|
95
|
+
* Returns { rLo, rHi, mintLo, mintHi, amount, nonce } — bigints, each < 2^128.
|
|
96
|
+
*/
|
|
97
|
+
export function splitDescriptor({ recipient, mint, amountLamports, nonceBytes }) {
|
|
98
|
+
const rBytes = decodeBase58Fixed(recipient, 32, "recipient");
|
|
99
|
+
const mBytes = decodeBase58Fixed(mint, 32, "mint");
|
|
100
|
+
const amount = BigInt(amountLamports);
|
|
101
|
+
if (amount < 0n || amount >= TWO_64) {
|
|
102
|
+
throw new RangeError(`amountLamports ${amount} out of u64 range`);
|
|
103
|
+
}
|
|
104
|
+
const nonce = bytesToBigIntLE(nonceBytes);
|
|
105
|
+
if (!(nonceBytes instanceof Uint8Array) || nonceBytes.length !== 16) {
|
|
106
|
+
throw new Error(`nonceBytes: expected exactly 16 bytes, got ${nonceBytes?.length}`);
|
|
107
|
+
}
|
|
108
|
+
if (nonce >= TWO_128) throw new RangeError("nonce limb overflow"); // unreachable for 16B
|
|
109
|
+
return {
|
|
110
|
+
rLo: bytesToBigIntLE(rBytes.subarray(0, 16)),
|
|
111
|
+
rHi: bytesToBigIntLE(rBytes.subarray(16, 32)),
|
|
112
|
+
mintLo: bytesToBigIntLE(mBytes.subarray(0, 16)),
|
|
113
|
+
mintHi: bytesToBigIntLE(mBytes.subarray(16, 32)),
|
|
114
|
+
amount,
|
|
115
|
+
nonce,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
// ---------------------------------------------------------------------------
|
|
120
|
+
// Poseidon commitments (mirror the circuit exactly)
|
|
121
|
+
// ---------------------------------------------------------------------------
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* actionHash = Poseidon7(DOMAIN_ACTION, rLo, rHi, mintLo, mintHi, amount, nonce).
|
|
125
|
+
* @returns {{ actionHash: bigint, rLo: bigint, rHi: bigint, mintLo: bigint,
|
|
126
|
+
* mintHi: bigint, amount: bigint, nonce: bigint }}
|
|
127
|
+
*/
|
|
128
|
+
export function computeActionHash({ recipientPubkeyBase58, mintBase58, amountLamports, nonceBytes }) {
|
|
129
|
+
const limbs = splitDescriptor({
|
|
130
|
+
recipient: recipientPubkeyBase58,
|
|
131
|
+
mint: mintBase58,
|
|
132
|
+
amountLamports,
|
|
133
|
+
nonceBytes,
|
|
134
|
+
});
|
|
135
|
+
const actionHash = poseidon([
|
|
136
|
+
DOMAIN_ACTION,
|
|
137
|
+
limbs.rLo,
|
|
138
|
+
limbs.rHi,
|
|
139
|
+
limbs.mintLo,
|
|
140
|
+
limbs.mintHi,
|
|
141
|
+
limbs.amount,
|
|
142
|
+
limbs.nonce,
|
|
143
|
+
]);
|
|
144
|
+
return { actionHash, ...limbs };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/** payloadCommit = Poseidon4(DOMAIN_POLICY, maxAmount, allowlistRoot, validAfterSlot). */
|
|
148
|
+
export function computePayloadCommit({ maxAmount, allowlistRoot, validAfterSlot }) {
|
|
149
|
+
return poseidon([
|
|
150
|
+
DOMAIN_POLICY,
|
|
151
|
+
BigInt(maxAmount),
|
|
152
|
+
BigInt(allowlistRoot),
|
|
153
|
+
BigInt(validAfterSlot),
|
|
154
|
+
]);
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/** nullifier = Poseidon3(DOMAIN_INTENT_NF, ownerKey, actionHash). */
|
|
158
|
+
export function computeIntentNullifier(ownerKey, actionHash) {
|
|
159
|
+
return poseidon([DOMAIN_INTENT_NF, BigInt(ownerKey), BigInt(actionHash)]);
|
|
160
|
+
}
|
|
161
|
+
/** Policy note leaf = Poseidon3(ownerKey, rho, payloadCommit) — insert into NoteTree. */
|
|
162
|
+
export function computeIntentNote(ownerKey, rho, payloadCommit) {
|
|
163
|
+
return poseidon([BigInt(ownerKey), BigInt(rho), BigInt(payloadCommit)]);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// AllowlistTree — depth-16 Poseidon Merkle tree of allowlisted payees.
|
|
168
|
+
// leaf = Poseidon3(DOMAIN_ALLOW, rLo, rHi); append-only, same sparse-prefix
|
|
169
|
+
// machinery as the note tree (computeRoot/computeProof accept a depth param).
|
|
170
|
+
// ---------------------------------------------------------------------------
|
|
171
|
+
|
|
172
|
+
export class AllowlistTree {
|
|
173
|
+
constructor(depth = ALLOW_DEPTH) {
|
|
174
|
+
this.depth = depth;
|
|
175
|
+
this.zeros = buildZeros(depth);
|
|
176
|
+
/** @type {{rLo: bigint, rHi: bigint, leaf: bigint}[]} */
|
|
177
|
+
this.payees = [];
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
get leaves() {
|
|
181
|
+
return this.payees.map((p) => p.leaf);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
get nextIndex() {
|
|
185
|
+
return this.payees.length;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
root() {
|
|
189
|
+
return computeRoot(this.leaves, this.zeros, this.depth);
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/** Proof for any index (filled leaf or zero slot) against the current root. */
|
|
193
|
+
getProof(index) {
|
|
194
|
+
return computeProof(this.leaves, index, this.zeros, this.depth);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
/**
|
|
198
|
+
* Append a payee by base58 recipient pubkey. Returns
|
|
199
|
+
* { index, leaf, pathElements, pathIndices } — the proof of the inserted
|
|
200
|
+
* leaf against the POST-insert root (what the intent circuit consumes).
|
|
201
|
+
*/
|
|
202
|
+
insert(recipientBase58) {
|
|
203
|
+
const index = this.payees.length;
|
|
204
|
+
if (index >= 2 ** this.depth) throw new RangeError("allowlist tree full");
|
|
205
|
+
const { rLo, rHi } = splitDescriptor({
|
|
206
|
+
recipient: recipientBase58,
|
|
207
|
+
mint: recipientBase58, // unused limbs; recipient drives rLo/rHi
|
|
208
|
+
amountLamports: 0n,
|
|
209
|
+
nonceBytes: new Uint8Array(16),
|
|
210
|
+
});
|
|
211
|
+
const leaf = poseidon([DOMAIN_ALLOW, rLo, rHi]);
|
|
212
|
+
this.payees.push({ rLo, rHi, leaf });
|
|
213
|
+
const { pathElements, pathIndices } = this.getProof(index);
|
|
214
|
+
return { index, leaf, pathElements, pathIndices };
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Index of the payee leaf for (rLo, rHi), or -1 if not allowlisted. */
|
|
218
|
+
indexOf(rLo, rHi) {
|
|
219
|
+
for (let i = 0; i < this.payees.length; i++) {
|
|
220
|
+
if (this.payees[i].rLo === rLo && this.payees[i].rHi === rHi) return i;
|
|
221
|
+
}
|
|
222
|
+
return -1;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
verifyProof(leaf, pathElements, pathIndices, root = this.root()) {
|
|
226
|
+
return verifyMerkleProof(leaf, pathElements, pathIndices, root, this.depth);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// ---------------------------------------------------------------------------
|
|
231
|
+
// Witness builder
|
|
232
|
+
// ---------------------------------------------------------------------------
|
|
233
|
+
|
|
234
|
+
/** Recursively convert bigints → decimal strings for snarkjs input JSON. */
|
|
235
|
+
function toDec(x) {
|
|
236
|
+
if (typeof x === "bigint") return x.toString(10);
|
|
237
|
+
if (Array.isArray(x)) return x.map(toDec);
|
|
238
|
+
if (typeof x === "number") return String(x);
|
|
239
|
+
if (typeof x === "object" && x !== null) {
|
|
240
|
+
return Object.fromEntries(Object.entries(x).map(([k, v]) => [k, toDec(v)]));
|
|
241
|
+
}
|
|
242
|
+
return x;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
function need(value, name) {
|
|
246
|
+
if (value === undefined || value === null) {
|
|
247
|
+
throw new TypeError(`buildIntentWitness: missing ${name}`);
|
|
248
|
+
}
|
|
249
|
+
return BigInt(value);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Build the snarkjs input for one intent attestation.
|
|
254
|
+
*
|
|
255
|
+
* @param {object} args
|
|
256
|
+
* @param {NoteTree} args.noteTree shared note tree at the current on-chain note_root
|
|
257
|
+
* @param {number} args.noteIndex index of the policy note in noteTree
|
|
258
|
+
* @param {bigint|number|string} args.ownerKey note opening
|
|
259
|
+
* @param {bigint|number|string} args.rho note opening
|
|
260
|
+
* @param {bigint|number|string} args.maxAmount policy cap (u64 lamports)
|
|
261
|
+
* @param {AllowlistTree} args.allowlist payee allowlist tree (contains recipient)
|
|
262
|
+
* @param {bigint|number|string} args.validAfterSlot policy time lock (slot, < 2^48)
|
|
263
|
+
* @param {string} args.recipient x402 payee, base58 32B pubkey
|
|
264
|
+
* @param {string} args.mint x402 mint, base58 32B pubkey
|
|
265
|
+
* @param {bigint|number|string} args.amountLamports payment amount (u64)
|
|
266
|
+
* @param {Uint8Array} args.nonceBytes 16-byte action nonce (LE limb)
|
|
267
|
+
* @param {bigint|number|string} args.currentSlot current slot (< 2^48, <= Clock on-chain)
|
|
268
|
+
* @returns {object} snarkjs input JSON (all values decimal strings); public
|
|
269
|
+
* signals are INTENT_PUBLIC_SIGNALS in order.
|
|
270
|
+
*/
|
|
271
|
+
export function buildIntentWitness(args) {
|
|
272
|
+
const { noteTree, allowlist, noteIndex } = args;
|
|
273
|
+
if (!(noteTree instanceof NoteTree)) throw new TypeError("noteTree must be a NoteTree");
|
|
274
|
+
if (!(allowlist instanceof AllowlistTree)) {
|
|
275
|
+
throw new TypeError("allowlist must be an AllowlistTree");
|
|
276
|
+
}
|
|
277
|
+
if (!Number.isInteger(noteIndex) || noteIndex < 0 || noteIndex >= noteTree.nextIndex) {
|
|
278
|
+
throw new RangeError(`noteIndex ${noteIndex} not present in note tree`);
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const ownerKey = need(args.ownerKey, "ownerKey");
|
|
282
|
+
const rho = need(args.rho, "rho");
|
|
283
|
+
const maxAmount = need(args.maxAmount, "maxAmount");
|
|
284
|
+
const validAfterSlot = need(args.validAfterSlot, "validAfterSlot");
|
|
285
|
+
const currentSlot = need(args.currentSlot, "currentSlot");
|
|
286
|
+
|
|
287
|
+
if (maxAmount < 0n || maxAmount >= TWO_64) {
|
|
288
|
+
throw new RangeError(`maxAmount ${maxAmount} out of u64 range`);
|
|
289
|
+
}
|
|
290
|
+
if (validAfterSlot < 0n || validAfterSlot >= TWO_48) {
|
|
291
|
+
throw new RangeError(`validAfterSlot ${validAfterSlot} out of 48-bit range`);
|
|
292
|
+
}
|
|
293
|
+
if (currentSlot < 0n || currentSlot >= TWO_48) {
|
|
294
|
+
throw new RangeError(`currentSlot ${currentSlot} out of 48-bit range`);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
// x402 descriptor limbs + public actionHash.
|
|
298
|
+
if (args.recipient === undefined || args.recipient === null) {
|
|
299
|
+
throw new TypeError("buildIntentWitness: missing recipient");
|
|
300
|
+
}
|
|
301
|
+
if (args.mint === undefined || args.mint === null) {
|
|
302
|
+
throw new TypeError("buildIntentWitness: missing mint");
|
|
303
|
+
}
|
|
304
|
+
const { actionHash, rLo, rHi, mintLo, mintHi, amount, nonce } = computeActionHash({
|
|
305
|
+
recipientPubkeyBase58: args.recipient,
|
|
306
|
+
mintBase58: args.mint,
|
|
307
|
+
amountLamports: args.amountLamports,
|
|
308
|
+
nonceBytes: args.nonceBytes,
|
|
309
|
+
});
|
|
310
|
+
|
|
311
|
+
// Client-side policy checks (the circuit enforces the same constraints;
|
|
312
|
+
// failing early gives a usable error instead of a wasm assertion trap).
|
|
313
|
+
if (amount > maxAmount) {
|
|
314
|
+
throw new Error(`amount ${amount} exceeds policy maxAmount ${maxAmount}`);
|
|
315
|
+
}
|
|
316
|
+
if (validAfterSlot > currentSlot) {
|
|
317
|
+
throw new Error(`policy not yet valid: validAfterSlot ${validAfterSlot} > currentSlot ${currentSlot}`);
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
// Policy commitment + note opening; the note must sit at noteIndex.
|
|
321
|
+
const allowlistRoot = allowlist.root();
|
|
322
|
+
const payloadCommit = computePayloadCommit({ maxAmount, allowlistRoot, validAfterSlot });
|
|
323
|
+
const note = computeIntentNote(ownerKey, rho, payloadCommit);
|
|
324
|
+
if (noteTree.leaves[noteIndex] !== note) {
|
|
325
|
+
throw new Error("note opening does not match the leaf at noteIndex");
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
// Note membership proof vs the current (pre-submission) note root.
|
|
329
|
+
const noteProof = noteTree.getProof(noteIndex);
|
|
330
|
+
const noteRoot = noteTree.root();
|
|
331
|
+
|
|
332
|
+
// Payee allowlist membership.
|
|
333
|
+
const payeeIndex = allowlist.indexOf(rLo, rHi);
|
|
334
|
+
if (payeeIndex === -1) {
|
|
335
|
+
throw new Error("recipient is not in the allowlist");
|
|
336
|
+
}
|
|
337
|
+
const allowProof = allowlist.getProof(payeeIndex);
|
|
338
|
+
|
|
339
|
+
// Non-replay nullifier bound to (ownerKey, actionHash).
|
|
340
|
+
const nullifier = computeIntentNullifier(ownerKey, actionHash);
|
|
341
|
+
|
|
342
|
+
return toDec({
|
|
343
|
+
// public (exact contract order/names)
|
|
344
|
+
noteRoot,
|
|
345
|
+
actionHash,
|
|
346
|
+
nullifier,
|
|
347
|
+
currentSlot,
|
|
348
|
+
// private
|
|
349
|
+
ownerKey,
|
|
350
|
+
rho,
|
|
351
|
+
maxAmount,
|
|
352
|
+
allowlistRoot,
|
|
353
|
+
validAfterSlot,
|
|
354
|
+
notePathElements: noteProof.pathElements,
|
|
355
|
+
notePathIndices: noteProof.pathIndices,
|
|
356
|
+
rLo,
|
|
357
|
+
rHi,
|
|
358
|
+
mintLo,
|
|
359
|
+
mintHi,
|
|
360
|
+
amount,
|
|
361
|
+
nonce,
|
|
362
|
+
allowPathElements: allowProof.pathElements,
|
|
363
|
+
allowPathIndices: allowProof.pathIndices,
|
|
364
|
+
});
|
|
365
|
+
}
|