@nekzus/liop 1.2.0 → 1.3.0-alpha.1
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 +49 -46
- package/dist/bridge/stream.js +14 -6
- package/dist/client/index.js +7 -7
- package/dist/crypto/verifier.d.ts +1 -1
- package/dist/crypto/verifier.js +2 -1
- package/dist/sandbox/guardian.js +27 -4
- package/dist/sandbox/wasi.js +1 -0
- package/dist/security/zk.d.ts +1 -1
- package/dist/security/zk.js +11 -1
- package/dist/workers/logic-execution.js +4 -2
- package/dist/workers/zk-verifier.d.ts +2 -0
- package/dist/workers/zk-verifier.js +15 -1
- package/package.json +3 -3
package/README.md
CHANGED
|
@@ -4,19 +4,19 @@
|
|
|
4
4
|
<img alt="Logic-Injection-on-Origin Protocol Logo" src="https://res.cloudinary.com/dsvsl0b0b/image/upload/v1774702621/Neural-Mesh-Protocol/hoanw0m6tybpz5fbl12n.svg?v=20260328" width="700">
|
|
5
5
|
</picture>
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
<h1>Logic-Injection-on-Origin Protocol (LIOP) — TypeScript SDK</h1>
|
|
8
8
|
<p align="center">
|
|
9
|
-
<a href="https://github.com/Nekzus/
|
|
9
|
+
<a href="https://github.com/Nekzus/LIOP/actions/workflows/ci.yml"><img src="https://github.com/Nekzus/LIOP/actions/workflows/ci.yml/badge.svg?event=push" alt="Github Workflow"></a>
|
|
10
10
|
<a href="https://www.npmjs.com/package/@nekzus/liop"><img src="https://img.shields.io/npm/v/@nekzus/liop.svg" alt="npm version"></a>
|
|
11
11
|
<a href="https://www.npmjs.com/package/@nekzus/liop"><img src="https://img.shields.io/npm/dm/@nekzus/liop.svg" alt="npm-month"></a>
|
|
12
12
|
<a href="https://www.npmjs.com/package/@nekzus/liop"><img src="https://img.shields.io/npm/dt/@nekzus/liop.svg?style=flat" alt="npm-total"></a>
|
|
13
|
-
<a href="https://github.com/Nekzus/
|
|
14
|
-
<a href="https://
|
|
13
|
+
<a href="https://github.com/Nekzus/LIOP/blob/main/LICENSE"><img src="https://img.shields.io/github/license/Nekzus/LIOP.svg" alt="License"></a>
|
|
14
|
+
<a href="https://nekzus-32.mintlify.app/"><img src="https://img.shields.io/badge/docs-mintlify-0D9373?style=flat" alt="Docs"></a>
|
|
15
15
|
<a href="https://deepwiki.com/Nekzus/LIOP"><img src="https://deepwiki.com/badge.svg" alt="Ask DeepWiki"></a>
|
|
16
16
|
<a href="https://paypal.me/maseortega"><img src="https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square" alt="Donate"></a>
|
|
17
17
|
</p>
|
|
18
18
|
|
|
19
|
-
|
|
19
|
+
<p><strong>The official TypeScript SDK for the Logic-Injection-on-Origin Protocol.</strong></p>
|
|
20
20
|
<p>Deploy Logic-on-Origin with WebAssembly sandboxing, gRPC-speed execution, and full MCP backward compatibility.</p>
|
|
21
21
|
</div>
|
|
22
22
|
|
|
@@ -30,19 +30,19 @@ This fundamentally solves the data privacy, bandwidth, and latency challenges of
|
|
|
30
30
|
|
|
31
31
|
### Key Capabilities
|
|
32
32
|
|
|
33
|
-
| Feature
|
|
34
|
-
|
|
35
|
-
| **Logic-Injection-on-Origin** | LLMs send code, not queries. Data never leaves the origin server.
|
|
36
|
-
| **MCP Drop-in Replacement**
|
|
37
|
-
| **Guardian AST**
|
|
38
|
-
| **WASI Sandbox**
|
|
39
|
-
| **PII Shield**
|
|
40
|
-
| **ZK-Receipts**
|
|
41
|
-
| **Worker Pool**
|
|
42
|
-
| **Cross-AI Adapters
|
|
43
|
-
| **MCP Bridge**
|
|
44
|
-
| **Post-Quantum Ready**
|
|
45
|
-
| **P2P Mesh**
|
|
33
|
+
| Feature | Description |
|
|
34
|
+
| :---------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------------- |
|
|
35
|
+
| **Logic-Injection-on-Origin** | LLMs send code, not queries. Data never leaves the origin server. |
|
|
36
|
+
| **MCP Drop-in Replacement** | `LiopServer` mirrors the Anthropic MCP `Server` API — tools, resources, and prompts with `Zod` schemas. |
|
|
37
|
+
| **Guardian AST** | Zero-time heuristic inspection blocks sandbox escapes (`require`, `fs`, `eval`, `fetch`, prototype pollution). |
|
|
38
|
+
| **WASI Sandbox** | JavaScript payloads execute inside V8 isolates with CPU fuel limits and no access to Node.js globals. |
|
|
39
|
+
| **PII Shield** | Multi-layer egress filter with Regional Presets (Email, Credit Card with Luhn, IP, Phone, SSN, IBAN Mod-97, Passport MRZ) and custom keys. |
|
|
40
|
+
| **ZK-Receipts** | Cryptographic proof (SHA-256 ImageID + HMAC-SHA256 seal) that the returned result was computed honestly from the injected logic. |
|
|
41
|
+
| **Worker Pool** | Heavy computation (crypto, sandboxing) dispatched to OS threads via `piscina`, unblocking the V8 event loop. |
|
|
42
|
+
| **Cross-AI Adapters** | Zero-Shot system prompts automatically adapt instructions for Claude (XML-heavy) vs OpenAI/Gemini (JSON-schema). |
|
|
43
|
+
| **MCP Bridge** | `LiopMcpBridge` adapts any `LiopServer` to the JSON-RPC 2.0 / stdio protocol used by Claude Desktop, Cursor, etc. |
|
|
44
|
+
| **Post-Quantum Ready** | ML-KEM-768 (Kyber) handshake + AES-256-GCM symmetric encryption for transport-layer security. |
|
|
45
|
+
| **P2P Mesh** | Kademlia DHT discovery via `libp2p` with TCP + WebSocket + Yamux multiplexing and Noise encryption. |
|
|
46
46
|
|
|
47
47
|
---
|
|
48
48
|
|
|
@@ -91,6 +91,7 @@ To use the Neural Mesh inside Claude Desktop, update your `claude_desktop_config
|
|
|
91
91
|
### Persistence & Identity
|
|
92
92
|
|
|
93
93
|
The agent automatically manages your P2P identity:
|
|
94
|
+
|
|
94
95
|
- **Identity Path**: `~/.liop/identity.json`. This file contains your unique PeerID. Keep it safe if you want to maintain a consistent identity in the mesh.
|
|
95
96
|
- **Bootstrap Nodes**: By default, the agent connects to the **LIOP Alpha Nexus**. You can provide custom bootstrap addresses as CLI arguments:
|
|
96
97
|
```bash
|
|
@@ -197,24 +198,24 @@ new LiopServer(
|
|
|
197
198
|
|
|
198
199
|
#### Methods
|
|
199
200
|
|
|
200
|
-
| Method
|
|
201
|
-
|
|
202
|
-
| `tool()`
|
|
203
|
-
| `prompt()`
|
|
204
|
-
| `resource()`
|
|
205
|
-
| `dataDictionary()`
|
|
206
|
-
| `setSandboxData()`
|
|
207
|
-
| `enableZeroShotAutonomy()` | `()`
|
|
208
|
-
| `callTool()`
|
|
209
|
-
| `listTools()`
|
|
210
|
-
| `listPrompts()`
|
|
211
|
-
| `getPrompt()`
|
|
212
|
-
| `listResources()`
|
|
213
|
-
| `readResource()`
|
|
214
|
-
| `getServerInfo()`
|
|
215
|
-
| `connectToMesh()`
|
|
216
|
-
| `clearAstCache()`
|
|
217
|
-
| `close()`
|
|
201
|
+
| Method | Signature | Description |
|
|
202
|
+
| :--------------------------- | :------------------------------------------------- | :---------------------------------------------------------------------------------- |
|
|
203
|
+
| `tool()` | `(name, description, zodSchema, handler)` | Registers a callable tool with Zod input validation. |
|
|
204
|
+
| `prompt()` | `(name, description, args, handler)` | Registers a dynamic prompt template. |
|
|
205
|
+
| `resource()` | `(name, uri, description?, mimeType?, content?)` | Registers a readable resource. |
|
|
206
|
+
| `dataDictionary()` | `(schema, name?, uri?, description?)` | Broadcasts a data schema so LLMs can write accurate Logic-Injection-on-Origin code. |
|
|
207
|
+
| `setSandboxData()` | `(records: Record[])` | Injects data into the sandbox as `env.records` for Logic-on-Origin tools. |
|
|
208
|
+
| `enableZeroShotAutonomy()` | `()` | Registers the "Blind Analyst" prompt for autonomous code generation. |
|
|
209
|
+
| `callTool()` | `(request: CallToolRequest)` | Invokes a registered tool (used locally or via MCP Bridge). |
|
|
210
|
+
| `listTools()` | `()` | Returns all registered tools. |
|
|
211
|
+
| `listPrompts()` | `()` | Returns all registered prompts. |
|
|
212
|
+
| `getPrompt()` | `(request: GetPromptRequest)` | Returns a specific prompt by name. |
|
|
213
|
+
| `listResources()` | `()` | Returns all registered resources. |
|
|
214
|
+
| `readResource()` | `(uri: string)` | Reads a resource by URI. |
|
|
215
|
+
| `getServerInfo()` | `()` | Returns the server's name and version. |
|
|
216
|
+
| `connectToMesh()` | `()` | Connects to the libp2p Kademlia DHT. |
|
|
217
|
+
| `clearAstCache()` | `()` | Invalidates the Guardian AST logic cache. |
|
|
218
|
+
| `close()` | `()` | Destroys the worker pool and releases threads. |
|
|
218
219
|
|
|
219
220
|
### `LiopMcpBridge`
|
|
220
221
|
|
|
@@ -226,6 +227,7 @@ await bridge.connect();
|
|
|
226
227
|
```
|
|
227
228
|
|
|
228
229
|
**Supported JSON-RPC methods:**
|
|
230
|
+
|
|
229
231
|
- `initialize` — Returns server capabilities and info
|
|
230
232
|
- `tools/list` — Lists available tools
|
|
231
233
|
- `tools/call` — Calls a tool (with ZK-Receipt verification)
|
|
@@ -255,7 +257,7 @@ await bridge.connect();
|
|
|
255
257
|
├─────────────────────────────────────────────────────┤
|
|
256
258
|
│ Layer 4: ZK-Receipt (Integrity Verification) │
|
|
257
259
|
│ SHA-256 ImageID + SHA-512 RISC0-style Seal │
|
|
258
|
-
│ LiopMcpBridge verifies before forwarding to LLM
|
|
260
|
+
│ LiopMcpBridge verifies before forwarding to LLM │
|
|
259
261
|
└─────────────────────────────────────────────────────┘
|
|
260
262
|
```
|
|
261
263
|
|
|
@@ -388,26 +390,27 @@ await server.connectToMesh();
|
|
|
388
390
|
|
|
389
391
|
This package is continuously tested across multiple platforms and Node.js versions via CI/CD:
|
|
390
392
|
|
|
391
|
-
- **
|
|
393
|
+
- **209+ tests** spanning unit, integration, conformance, and crossnet suites
|
|
392
394
|
- **Multi-OS matrix:** Ubuntu, Windows, macOS
|
|
393
395
|
- **Node.js versions:** 22.x, 24.x
|
|
394
396
|
- **Code quality:** Enforced by [Biome.js](https://biomejs.dev/) (linting + formatting)
|
|
397
|
+
- **Security:** Verified defense-in-depth architecture — see [Security Architecture](https://nekzus-32.mintlify.app/typescript-sdk/security)
|
|
395
398
|
|
|
396
|
-
> To run tests locally or contribute, clone the [repository](https://github.com/Nekzus/
|
|
399
|
+
> To run tests locally or contribute, clone the [repository](https://github.com/Nekzus/LIOP) and follow the [Contributing Guide](https://github.com/Nekzus/LIOP/blob/main/CONTRIBUTING.md).
|
|
397
400
|
|
|
398
401
|
---
|
|
399
402
|
|
|
400
403
|
## Related
|
|
401
404
|
|
|
402
|
-
- [LIOP Documentation](https://
|
|
403
|
-
- [LIOP Specification](https://github.com/Nekzus/
|
|
404
|
-
- [LIOP Manifesto](https://github.com/Nekzus/
|
|
405
|
-
- [Contributing Guide](https://github.com/Nekzus/
|
|
406
|
-
- [Rust Mesh Node](https://github.com/Nekzus/
|
|
407
|
-
- [LIOP CLI](https://github.com/Nekzus/
|
|
405
|
+
- [LIOP Documentation](https://nekzus-32.mintlify.app/) — Full conceptual and API documentation
|
|
406
|
+
- [LIOP Specification](https://github.com/Nekzus/LIOP/blob/main/protocol/SPECIFICATION.md) — Technical specification
|
|
407
|
+
- [LIOP Manifesto](https://github.com/Nekzus/LIOP/blob/main/MANIFESTO.md) — Project philosophy
|
|
408
|
+
- [Contributing Guide](https://github.com/Nekzus/LIOP/blob/main/CONTRIBUTING.md) — How to contribute
|
|
409
|
+
- [Rust Mesh Node](https://github.com/Nekzus/LIOP/tree/main/servers/liop-node) — Native high-performance backend
|
|
410
|
+
- [LIOP CLI](https://github.com/Nekzus/LIOP/tree/main/tools/liop-cli) — Developer diagnostics
|
|
408
411
|
|
|
409
412
|
---
|
|
410
413
|
|
|
411
414
|
## License
|
|
412
415
|
|
|
413
|
-
[MIT](https://github.com/Nekzus/
|
|
416
|
+
[MIT](https://github.com/Nekzus/LIOP/blob/main/LICENSE) © [Nekzus](https://github.com/Nekzus)
|
package/dist/bridge/stream.js
CHANGED
|
@@ -120,16 +120,24 @@ export class LiopStreamBridge {
|
|
|
120
120
|
}
|
|
121
121
|
setupRoutes() {
|
|
122
122
|
this.app.use("*", cors());
|
|
123
|
+
// Initialize strict zero-trust token if not provided
|
|
124
|
+
if (!process.env.ZERO_TRUST_TOKEN) {
|
|
125
|
+
process.env.ZERO_TRUST_TOKEN = randomUUID();
|
|
126
|
+
log.info("=".repeat(60));
|
|
127
|
+
log.info("⚠️ STRICT ZERO-TRUST MODE ENABLED ⚠️");
|
|
128
|
+
log.info("No ZERO_TRUST_TOKEN found in environment.");
|
|
129
|
+
log.info("A secure ephemeral token has been generated for this session:");
|
|
130
|
+
log.info(`Token: ${process.env.ZERO_TRUST_TOKEN}`);
|
|
131
|
+
log.info("=".repeat(60));
|
|
132
|
+
}
|
|
123
133
|
// ZTA (Zero-Trust Architecture) Security Middleware
|
|
124
134
|
this.app.use("/mcp", async (c, next) => {
|
|
125
135
|
const auth = c.req.header("Authorization");
|
|
126
136
|
const expectedToken = process.env.ZERO_TRUST_TOKEN;
|
|
127
|
-
if (
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
return c.json({ error: "Unauthorized: LIOP Zero-Trust Policy Enforced" }, 401);
|
|
132
|
-
}
|
|
137
|
+
if (!auth?.startsWith("Bearer ") ||
|
|
138
|
+
auth.split(" ")[1] !== expectedToken) {
|
|
139
|
+
log.info("[LIOP-StreamBridge] ALERT: Access denied - Invalid Zero-Trust token.");
|
|
140
|
+
return c.json({ error: "Unauthorized: LIOP Zero-Trust Policy Enforced" }, 401);
|
|
133
141
|
}
|
|
134
142
|
await next();
|
|
135
143
|
});
|
package/dist/client/index.js
CHANGED
|
@@ -147,19 +147,19 @@ export class LiopClient {
|
|
|
147
147
|
const _safePayload = _wasmPayload || Buffer.from("");
|
|
148
148
|
// Encrypt WASM binary
|
|
149
149
|
const { ciphertext: encryptedWasm, nonce: aesNonce } = AesGcmWrapper.encryptPayload(_safePayload, sharedSecret);
|
|
150
|
-
// Encrypt inputs using
|
|
150
|
+
// Encrypt inputs using a fresh random nonce per input to prevent AES-GCM nonce reuse
|
|
151
151
|
const encryptedInputs = {};
|
|
152
|
+
const crypto = await import("node:crypto");
|
|
152
153
|
for (const [key, value] of Object.entries(request.arguments || {})) {
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
const crypto = await import("node:crypto");
|
|
156
|
-
const cipher = crypto.createCipheriv("aes-256-gcm", sharedSecret, aesNonce);
|
|
154
|
+
const inputNonce = crypto.randomBytes(12);
|
|
155
|
+
const cipher = crypto.createCipheriv("aes-256-gcm", sharedSecret, inputNonce);
|
|
157
156
|
const encrypted = Buffer.concat([
|
|
158
157
|
cipher.update(JSON.stringify(value)),
|
|
159
158
|
cipher.final(),
|
|
160
159
|
]);
|
|
161
160
|
const authTag = cipher.getAuthTag();
|
|
162
|
-
|
|
161
|
+
// Prepend the 12-byte nonce to the ciphertext
|
|
162
|
+
encryptedInputs[key] = Buffer.concat([inputNonce, encrypted, authTag]);
|
|
163
163
|
}
|
|
164
164
|
// 4. Assemble and Execute gRPC LogicRequest
|
|
165
165
|
const logicRequest = {
|
|
@@ -183,7 +183,7 @@ export class LiopClient {
|
|
|
183
183
|
hasReceivedData = true;
|
|
184
184
|
log.info("[LiopClient] Logic Executed. Verification in progress...");
|
|
185
185
|
try {
|
|
186
|
-
const isValid = await this.verifier.verifyZkReceipt(_safePayload, Buffer.from(response.cryptographic_proof).toString("hex"), Buffer.from(response.zk_receipt));
|
|
186
|
+
const isValid = await this.verifier.verifyZkReceipt(_safePayload, Buffer.from(response.cryptographic_proof).toString("hex"), Buffer.from(response.zk_receipt), Buffer.from(sharedSecret));
|
|
187
187
|
if (!isValid) {
|
|
188
188
|
reject(new Error("PROTOCOL INTEGRITY VIOLATION: ZK-Receipt verification failed."));
|
|
189
189
|
return;
|
|
@@ -15,7 +15,7 @@ export declare class LiopVerifier {
|
|
|
15
15
|
* @param remoteImageIdHex The ImageID reported by the provider (must match our local calculation).
|
|
16
16
|
* @param zkReceipt The mathematical proof (Seal + Journal) from the zkVM.
|
|
17
17
|
*/
|
|
18
|
-
verifyZkReceipt(logicPayload: Buffer, remoteImageIdHex: string, zkReceipt: Buffer): Promise<boolean>;
|
|
18
|
+
verifyZkReceipt(logicPayload: Buffer, remoteImageIdHex: string, zkReceipt: Buffer, sessionSecret?: Buffer): Promise<boolean>;
|
|
19
19
|
/**
|
|
20
20
|
* Verifies if a node is running inside an authenticated TEE (e.g. AWS Nitro).
|
|
21
21
|
*
|
package/dist/crypto/verifier.js
CHANGED
|
@@ -49,7 +49,7 @@ export class LiopVerifier {
|
|
|
49
49
|
* @param remoteImageIdHex The ImageID reported by the provider (must match our local calculation).
|
|
50
50
|
* @param zkReceipt The mathematical proof (Seal + Journal) from the zkVM.
|
|
51
51
|
*/
|
|
52
|
-
async verifyZkReceipt(logicPayload, remoteImageIdHex, zkReceipt) {
|
|
52
|
+
async verifyZkReceipt(logicPayload, remoteImageIdHex, zkReceipt, sessionSecret) {
|
|
53
53
|
const pool = this.getZkPool();
|
|
54
54
|
if (!pool)
|
|
55
55
|
throw new Error("Worker pool initialization failed");
|
|
@@ -58,6 +58,7 @@ export class LiopVerifier {
|
|
|
58
58
|
logicPayload: new Uint8Array(logicPayload),
|
|
59
59
|
remoteImageIdHex,
|
|
60
60
|
zkReceipt: new Uint8Array(zkReceipt),
|
|
61
|
+
sessionSecret: sessionSecret ? new Uint8Array(sessionSecret) : undefined,
|
|
61
62
|
});
|
|
62
63
|
if (result.verified) {
|
|
63
64
|
log.info(`[LiopVerifier] ${result.message}`);
|
package/dist/sandbox/guardian.js
CHANGED
|
@@ -20,13 +20,36 @@ export const ASTGuardian = {
|
|
|
20
20
|
analyze(module) {
|
|
21
21
|
const imports = WebAssembly.Module.imports(module);
|
|
22
22
|
let _importCount = 0;
|
|
23
|
+
const ALLOWED_WASI_FUNCTIONS = new Set([
|
|
24
|
+
"fd_write",
|
|
25
|
+
"fd_read",
|
|
26
|
+
"fd_close",
|
|
27
|
+
"fd_seek",
|
|
28
|
+
"environ_get",
|
|
29
|
+
"environ_sizes_get",
|
|
30
|
+
"args_get",
|
|
31
|
+
"args_sizes_get",
|
|
32
|
+
"clock_time_get",
|
|
33
|
+
"random_get",
|
|
34
|
+
"proc_exit",
|
|
35
|
+
"fd_prestat_get",
|
|
36
|
+
"fd_prestat_dir_name",
|
|
37
|
+
"fd_fdstat_get",
|
|
38
|
+
]);
|
|
23
39
|
for (const imp of imports) {
|
|
24
|
-
// Strict Sandbox Validation: Only allow WASI preview 1
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
40
|
+
// Strict Sandbox Validation: Only allow WASI preview 1 specific whitelisted functions.
|
|
41
|
+
if (imp.module === "wasi_snapshot_preview1") {
|
|
42
|
+
if (!ALLOWED_WASI_FUNCTIONS.has(imp.name)) {
|
|
43
|
+
throw new GuardianError(`Banned WASI Import Detected: ${imp.module}/${imp.name}`);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
throw new GuardianError(`Banned Host Import Module Detected: ${imp.module}`);
|
|
28
48
|
}
|
|
29
49
|
_importCount++;
|
|
50
|
+
if (_importCount > 128) {
|
|
51
|
+
throw new GuardianError("Import limit exceeded. Possible resource exhaustion attack.");
|
|
52
|
+
}
|
|
30
53
|
}
|
|
31
54
|
// In Node.js / V8, the maximum module size and function limits
|
|
32
55
|
// are natively enforced by the engine during compilation.
|
package/dist/sandbox/wasi.js
CHANGED
|
@@ -116,6 +116,7 @@ export class WasiSandbox {
|
|
|
116
116
|
sandboxEnv.queueMicrotask = undefined;
|
|
117
117
|
sandboxEnv.eval = undefined;
|
|
118
118
|
sandboxEnv.Function = undefined;
|
|
119
|
+
sandboxEnv.SharedArrayBuffer = undefined;
|
|
119
120
|
// Inject strictly monitored globals
|
|
120
121
|
sandboxEnv.records = JSON.parse(JSON.stringify(records)); // Deep copy safety
|
|
121
122
|
sandboxEnv.env = JSON.parse(JSON.stringify(env));
|
package/dist/security/zk.d.ts
CHANGED
|
@@ -26,7 +26,7 @@ export declare const ZkVerifier: {
|
|
|
26
26
|
* @throws ZkVerificationError if the proof is invalid or image IDs mismatch
|
|
27
27
|
* @returns true if the proof mathematically verifies the execution
|
|
28
28
|
*/
|
|
29
|
-
verify(receipt: ZkReceipt, expectedImageId: Buffer): boolean;
|
|
29
|
+
verify(receipt: ZkReceipt, expectedImageId: Buffer, sessionSecret?: Buffer): boolean;
|
|
30
30
|
/**
|
|
31
31
|
* Derives a predictable ImageID (usually a Hash) from a raw WASM binary.
|
|
32
32
|
*
|
package/dist/security/zk.js
CHANGED
|
@@ -22,7 +22,7 @@ export const ZkVerifier = {
|
|
|
22
22
|
* @throws ZkVerificationError if the proof is invalid or image IDs mismatch
|
|
23
23
|
* @returns true if the proof mathematically verifies the execution
|
|
24
24
|
*/
|
|
25
|
-
verify(receipt, expectedImageId) {
|
|
25
|
+
verify(receipt, expectedImageId, sessionSecret) {
|
|
26
26
|
// 1. Verify Image ID (Ensures the host executed the exact logic we sent, not a malicious one)
|
|
27
27
|
if (!receipt.imageId.equals(expectedImageId)) {
|
|
28
28
|
throw new ZkVerificationError("ImageID mismatch. The remote origin executed a different WASM payload.");
|
|
@@ -52,6 +52,16 @@ export const ZkVerifier = {
|
|
|
52
52
|
catch (_e) {
|
|
53
53
|
throw new ZkVerificationError("Failed to parse journal data.");
|
|
54
54
|
}
|
|
55
|
+
// 4. Mathematical Verification (HMAC-SHA256)
|
|
56
|
+
if (sessionSecret && sessionSecret.length > 0) {
|
|
57
|
+
const expectedSeal = crypto
|
|
58
|
+
.createHmac("sha256", sessionSecret)
|
|
59
|
+
.update(journal)
|
|
60
|
+
.digest();
|
|
61
|
+
if (!crypto.timingSafeEqual(seal, expectedSeal)) {
|
|
62
|
+
throw new ZkVerificationError("Invalid seal: HMAC verification failed.");
|
|
63
|
+
}
|
|
64
|
+
}
|
|
55
65
|
return true;
|
|
56
66
|
},
|
|
57
67
|
/**
|
|
@@ -30,9 +30,11 @@ export default async function processLogicExecution(data) {
|
|
|
30
30
|
// 3. Decrypt Inputs
|
|
31
31
|
for (const [key, encValue] of Object.entries(inputs || {})) {
|
|
32
32
|
const valBuffer = Buffer.from(encValue);
|
|
33
|
+
// Extract 12-byte prepended nonce, ciphertext, and 16-byte AuthTag
|
|
34
|
+
const inputNonce = valBuffer.subarray(0, 12);
|
|
33
35
|
const valTag = valBuffer.subarray(-16);
|
|
34
|
-
const valData = valBuffer.subarray(
|
|
35
|
-
const valDecipher = crypto.createDecipheriv("aes-256-gcm", aesKey,
|
|
36
|
+
const valData = valBuffer.subarray(12, -16);
|
|
37
|
+
const valDecipher = crypto.createDecipheriv("aes-256-gcm", aesKey, inputNonce);
|
|
36
38
|
valDecipher.setAuthTag(valTag);
|
|
37
39
|
let valDecrypted = valDecipher.update(valData);
|
|
38
40
|
valDecrypted = Buffer.concat([valDecrypted, valDecipher.final()]);
|
|
@@ -10,6 +10,8 @@ export interface ZkVerificationPayload {
|
|
|
10
10
|
remoteImageIdHex: string;
|
|
11
11
|
/** Cbor-encoded or raw buffer containing the execution Receipt (Journal + Seal) */
|
|
12
12
|
zkReceipt: Uint8Array;
|
|
13
|
+
/** Kyber-derived session secret to verify HMAC signature */
|
|
14
|
+
sessionSecret?: Uint8Array;
|
|
13
15
|
}
|
|
14
16
|
/**
|
|
15
17
|
* Main worker entry point for Piscina.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import crypto from "node:crypto";
|
|
1
2
|
import { parentPort } from "node:worker_threads";
|
|
2
3
|
import { deriveLogicImageDigest } from "../crypto/logic-image-id.js";
|
|
3
4
|
// Ensure this worker is used via Piscina pool
|
|
@@ -12,7 +13,7 @@ function deriveImageId(logicPayload) {
|
|
|
12
13
|
* In a real environment, this delegates to @risc0/verifier or SP1 FFI bindings.
|
|
13
14
|
*/
|
|
14
15
|
async function verifyZkReceipt(payload) {
|
|
15
|
-
const { logicPayload, remoteImageIdHex, zkReceipt } = payload;
|
|
16
|
+
const { logicPayload, remoteImageIdHex, zkReceipt, sessionSecret } = payload;
|
|
16
17
|
// 1. Calculate local ImageID (Integrity Check)
|
|
17
18
|
const localImageId = deriveImageId(logicPayload);
|
|
18
19
|
const localImageIdHex = localImageId.toString("hex");
|
|
@@ -60,6 +61,19 @@ async function verifyZkReceipt(payload) {
|
|
|
60
61
|
catch (_e) {
|
|
61
62
|
return { verified: false, message: "Failed to parse journal data." };
|
|
62
63
|
}
|
|
64
|
+
// 4. Mathematical Verification (HMAC-SHA256)
|
|
65
|
+
if (sessionSecret && sessionSecret.length > 0) {
|
|
66
|
+
const expectedSeal = crypto
|
|
67
|
+
.createHmac("sha256", sessionSecret)
|
|
68
|
+
.update(journal)
|
|
69
|
+
.digest();
|
|
70
|
+
if (!crypto.timingSafeEqual(seal, expectedSeal)) {
|
|
71
|
+
return {
|
|
72
|
+
verified: false,
|
|
73
|
+
message: "Invalid seal: HMAC verification failed.",
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
}
|
|
63
77
|
return {
|
|
64
78
|
verified: true,
|
|
65
79
|
message: "HMAC Commitment Verified: Integrity intact.",
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nekzus/liop",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.3.0-alpha.1",
|
|
4
4
|
"description": "Official SDK for Logic-Injection-on-Origin Protocol (LIOP). Deploy Logic-on-Origin with WebAssembly at gRPC speed and bidirectional MCP compatibility.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -88,10 +88,10 @@
|
|
|
88
88
|
"type": "module",
|
|
89
89
|
"repository": {
|
|
90
90
|
"type": "git",
|
|
91
|
-
"url": "git+https://github.com/Nekzus/
|
|
91
|
+
"url": "git+https://github.com/Nekzus/LIOP.git"
|
|
92
92
|
},
|
|
93
93
|
"bugs": {
|
|
94
|
-
"url": "https://github.com/Nekzus/
|
|
94
|
+
"url": "https://github.com/Nekzus/LIOP/issues"
|
|
95
95
|
},
|
|
96
96
|
"homepage": "https://nekzus-32.mintlify.app/",
|
|
97
97
|
"publishConfig": {
|