@nekzus/liop 1.2.0-alpha.9 → 1.2.0
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 +12 -3
- package/dist/bin/agent.js +222 -51
- package/dist/bridge/index.js +7 -6
- package/dist/bridge/stream.js +11 -11
- package/dist/client/index.js +46 -35
- package/dist/crypto/logic-image-id.d.ts +3 -0
- package/dist/crypto/logic-image-id.js +27 -0
- package/dist/crypto/verifier.js +7 -19
- package/dist/economy/estimator.d.ts +53 -0
- package/dist/economy/estimator.js +69 -0
- package/dist/economy/index.d.ts +5 -0
- package/dist/economy/index.js +3 -0
- package/dist/economy/otel.d.ts +38 -0
- package/dist/economy/otel.js +100 -0
- package/dist/economy/telemetry.d.ts +77 -0
- package/dist/economy/telemetry.js +224 -0
- package/dist/errors.d.ts +14 -0
- package/dist/errors.js +19 -0
- package/dist/gateway/hybrid.d.ts +3 -1
- package/dist/gateway/hybrid.js +38 -13
- package/dist/gateway/router.d.ts +25 -9
- package/dist/gateway/router.js +484 -133
- package/dist/index.d.ts +3 -0
- package/dist/index.js +3 -0
- package/dist/mesh/node.d.ts +16 -0
- package/dist/mesh/node.js +394 -113
- package/dist/prompts/adapters.d.ts +16 -0
- package/dist/prompts/adapters.js +55 -0
- package/dist/rpc/proto.js +2 -1
- package/dist/rpc/server.d.ts +1 -1
- package/dist/rpc/server.js +4 -3
- package/dist/rpc/tls.js +3 -2
- package/dist/sandbox/wasi.d.ts +1 -1
- package/dist/sandbox/wasi.js +43 -3
- package/dist/security/guardian.js +3 -2
- package/dist/security/zk.d.ts +2 -3
- package/dist/security/zk.js +22 -9
- package/dist/server/index.d.ts +53 -4
- package/dist/server/index.js +362 -49
- package/dist/server/pii.d.ts +12 -0
- package/dist/server/pii.js +90 -0
- package/dist/types.d.ts +16 -0
- package/dist/utils/logger.d.ts +21 -0
- package/dist/utils/logger.js +70 -0
- package/dist/utils/mcpCompact.d.ts +11 -0
- package/dist/utils/mcpCompact.js +29 -0
- package/dist/workers/logic-execution.d.ts +1 -1
- package/dist/workers/logic-execution.js +38 -20
- package/dist/workers/zk-verifier.js +37 -33
- package/package.json +14 -2
package/dist/server/pii.js
CHANGED
|
@@ -26,6 +26,35 @@ function isLuhnValid(cardNumber) {
|
|
|
26
26
|
}
|
|
27
27
|
return sum % 10 === 0;
|
|
28
28
|
}
|
|
29
|
+
/**
|
|
30
|
+
* Validates an International Bank Account Number (IBAN) using ISO 7064 Modulo 97.
|
|
31
|
+
* Uses BigInt algebra to avoid JS floating point truncation with 30-digit numbers.
|
|
32
|
+
*/
|
|
33
|
+
function isIbanValid(iban) {
|
|
34
|
+
const sanitized = iban.replace(/\s+/g, "").toUpperCase();
|
|
35
|
+
if (!/^[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}$/.test(sanitized))
|
|
36
|
+
return false;
|
|
37
|
+
const rearranged = sanitized.substring(4) + sanitized.substring(0, 4);
|
|
38
|
+
let numericString = "";
|
|
39
|
+
for (let i = 0; i < rearranged.length; i++) {
|
|
40
|
+
const charCode = rearranged.charCodeAt(i);
|
|
41
|
+
if (charCode >= 65 && charCode <= 90) {
|
|
42
|
+
numericString += (charCode - 55).toString();
|
|
43
|
+
}
|
|
44
|
+
else if (charCode >= 48 && charCode <= 57) {
|
|
45
|
+
numericString += rearranged.charAt(i);
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
try {
|
|
52
|
+
return BigInt(numericString) % 97n === 1n;
|
|
53
|
+
}
|
|
54
|
+
catch (_e) {
|
|
55
|
+
return false;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
29
58
|
export const PII_PATTERNS = {
|
|
30
59
|
EMAIL: {
|
|
31
60
|
name: "EMAIL",
|
|
@@ -65,6 +94,67 @@ export const PII_PATTERNS = {
|
|
|
65
94
|
return true;
|
|
66
95
|
},
|
|
67
96
|
},
|
|
97
|
+
SSN: {
|
|
98
|
+
name: "SSN",
|
|
99
|
+
pattern: /\b\d{3}[- ]?\d{2}[- ]?\d{4}\b/g,
|
|
100
|
+
validator: (match) => {
|
|
101
|
+
const digits = match.replace(/\D/g, "");
|
|
102
|
+
if (digits.length !== 9)
|
|
103
|
+
return false;
|
|
104
|
+
const area = parseInt(digits.substring(0, 3), 10);
|
|
105
|
+
if (area === 0 || area === 666 || area >= 900)
|
|
106
|
+
return false;
|
|
107
|
+
const group = parseInt(digits.substring(3, 5), 10);
|
|
108
|
+
if (group === 0)
|
|
109
|
+
return false;
|
|
110
|
+
const serial = parseInt(digits.substring(5, 9), 10);
|
|
111
|
+
if (serial === 0)
|
|
112
|
+
return false;
|
|
113
|
+
if (/^(\d)\1+$/.test(digits) || digits === "123456789")
|
|
114
|
+
return false;
|
|
115
|
+
return true;
|
|
116
|
+
},
|
|
117
|
+
},
|
|
118
|
+
IBAN: {
|
|
119
|
+
name: "IBAN",
|
|
120
|
+
pattern: /\b[A-Z]{2}[0-9]{2}[A-Z0-9]{1,30}\b/gi,
|
|
121
|
+
validator: isIbanValid,
|
|
122
|
+
},
|
|
123
|
+
PASSPORT_MRZ: {
|
|
124
|
+
name: "PASSPORT_MRZ",
|
|
125
|
+
// Machina Readable Zone line match for standard international passports
|
|
126
|
+
pattern: /\bP[A-Z<][A-Z<]{3}[A-Z0-9<]{39}(?:\b|\s|$)/g,
|
|
127
|
+
},
|
|
128
|
+
};
|
|
129
|
+
/**
|
|
130
|
+
* Regional and Cultural Security Presets for Out-Of-The-Box compliance.
|
|
131
|
+
* Developers can override, merge, or omit these based on local laws.
|
|
132
|
+
*/
|
|
133
|
+
export const PII_PRESETS = {
|
|
134
|
+
GLOBAL_STRICT: [
|
|
135
|
+
PII_PATTERNS.EMAIL,
|
|
136
|
+
PII_PATTERNS.CREDIT_CARD,
|
|
137
|
+
PII_PATTERNS.IP_ADDRESS,
|
|
138
|
+
PII_PATTERNS.PHONE,
|
|
139
|
+
PII_PATTERNS.PASSPORT_MRZ,
|
|
140
|
+
PII_PATTERNS.IBAN,
|
|
141
|
+
],
|
|
142
|
+
US_COMPLIANT: [
|
|
143
|
+
PII_PATTERNS.EMAIL,
|
|
144
|
+
PII_PATTERNS.CREDIT_CARD,
|
|
145
|
+
PII_PATTERNS.IP_ADDRESS,
|
|
146
|
+
PII_PATTERNS.PHONE,
|
|
147
|
+
PII_PATTERNS.SSN,
|
|
148
|
+
PII_PATTERNS.PASSPORT_MRZ,
|
|
149
|
+
],
|
|
150
|
+
EU_GDPR: [
|
|
151
|
+
PII_PATTERNS.EMAIL,
|
|
152
|
+
PII_PATTERNS.CREDIT_CARD,
|
|
153
|
+
PII_PATTERNS.IP_ADDRESS,
|
|
154
|
+
PII_PATTERNS.PHONE,
|
|
155
|
+
PII_PATTERNS.IBAN,
|
|
156
|
+
PII_PATTERNS.PASSPORT_MRZ,
|
|
157
|
+
],
|
|
68
158
|
};
|
|
69
159
|
export class PiiScanner {
|
|
70
160
|
patterns;
|
package/dist/types.d.ts
CHANGED
|
@@ -127,3 +127,19 @@ export interface ServerInfo {
|
|
|
127
127
|
logging?: Record<string, unknown>;
|
|
128
128
|
};
|
|
129
129
|
}
|
|
130
|
+
export interface McpRequest {
|
|
131
|
+
method: string;
|
|
132
|
+
params?: unknown;
|
|
133
|
+
id?: string | number | null;
|
|
134
|
+
jsonrpc?: "2.0";
|
|
135
|
+
}
|
|
136
|
+
export interface McpResponse {
|
|
137
|
+
jsonrpc: "2.0";
|
|
138
|
+
id?: string | number | null;
|
|
139
|
+
result?: unknown;
|
|
140
|
+
error?: {
|
|
141
|
+
code: number;
|
|
142
|
+
message: string;
|
|
143
|
+
data?: unknown;
|
|
144
|
+
};
|
|
145
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export type LogLevel = "silent" | "error" | "warn" | "info" | "debug";
|
|
2
|
+
/**
|
|
3
|
+
* LiopLogger - Structured Logging Abstraction
|
|
4
|
+
* Configurable via `process.env.LIOP_LOG_LEVEL`.
|
|
5
|
+
* Emits strictly to stderr to comply with MCP stdio protocols.
|
|
6
|
+
*/
|
|
7
|
+
export declare class LiopLogger {
|
|
8
|
+
private static instance;
|
|
9
|
+
private level;
|
|
10
|
+
private constructor();
|
|
11
|
+
static getInstance(): LiopLogger;
|
|
12
|
+
private setLevelFromEnv;
|
|
13
|
+
setLevel(level: LogLevel): void;
|
|
14
|
+
private shouldLog;
|
|
15
|
+
private formatMessage;
|
|
16
|
+
error(message: string, ...args: unknown[]): void;
|
|
17
|
+
warn(message: string, ...args: unknown[]): void;
|
|
18
|
+
info(message: string, ...args: unknown[]): void;
|
|
19
|
+
debug(message: string, ...args: unknown[]): void;
|
|
20
|
+
}
|
|
21
|
+
export declare const log: LiopLogger;
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LiopLogger - Structured Logging Abstraction
|
|
3
|
+
* Configurable via `process.env.LIOP_LOG_LEVEL`.
|
|
4
|
+
* Emits strictly to stderr to comply with MCP stdio protocols.
|
|
5
|
+
*/
|
|
6
|
+
export class LiopLogger {
|
|
7
|
+
static instance;
|
|
8
|
+
level = "info";
|
|
9
|
+
constructor() {
|
|
10
|
+
this.setLevelFromEnv();
|
|
11
|
+
}
|
|
12
|
+
static getInstance() {
|
|
13
|
+
if (!LiopLogger.instance) {
|
|
14
|
+
LiopLogger.instance = new LiopLogger();
|
|
15
|
+
}
|
|
16
|
+
return LiopLogger.instance;
|
|
17
|
+
}
|
|
18
|
+
setLevelFromEnv() {
|
|
19
|
+
const envLevel = process.env.LIOP_LOG_LEVEL?.toLowerCase();
|
|
20
|
+
if (envLevel === "silent" ||
|
|
21
|
+
envLevel === "error" ||
|
|
22
|
+
envLevel === "warn" ||
|
|
23
|
+
envLevel === "info" ||
|
|
24
|
+
envLevel === "debug") {
|
|
25
|
+
this.level = envLevel;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
// Default level: info
|
|
29
|
+
this.level = "info";
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
setLevel(level) {
|
|
33
|
+
this.level = level;
|
|
34
|
+
}
|
|
35
|
+
shouldLog(targetLevel) {
|
|
36
|
+
const levels = {
|
|
37
|
+
silent: 0,
|
|
38
|
+
error: 1,
|
|
39
|
+
warn: 2,
|
|
40
|
+
info: 3,
|
|
41
|
+
debug: 4,
|
|
42
|
+
};
|
|
43
|
+
return levels[this.level] >= levels[targetLevel];
|
|
44
|
+
}
|
|
45
|
+
formatMessage(level, message) {
|
|
46
|
+
const ts = new Date().toISOString();
|
|
47
|
+
return `[${ts}] [${level}] ${message}`;
|
|
48
|
+
}
|
|
49
|
+
error(message, ...args) {
|
|
50
|
+
if (this.shouldLog("error")) {
|
|
51
|
+
console.error(this.formatMessage("ERROR", message), ...args);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
warn(message, ...args) {
|
|
55
|
+
if (this.shouldLog("warn")) {
|
|
56
|
+
console.error(this.formatMessage("WARN", message), ...args);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
info(message, ...args) {
|
|
60
|
+
if (this.shouldLog("info")) {
|
|
61
|
+
console.error(this.formatMessage("INFO", message), ...args);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
debug(message, ...args) {
|
|
65
|
+
if (this.shouldLog("debug")) {
|
|
66
|
+
console.error(this.formatMessage("DEBUG", message), ...args);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
export const log = LiopLogger.getInstance();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP UX: optional compact tool descriptions for clients (e.g. cloud models)
|
|
3
|
+
* that over-trigger on long "envelope / injection" wording in tools/list.
|
|
4
|
+
*
|
|
5
|
+
* Full LIOP payload format remains in prompts/get → liop_blind_analyst.
|
|
6
|
+
*/
|
|
7
|
+
export declare function mcpCompactToolDescriptions(): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Removes SDK-appended LIOP specification blocks from a registered tool description.
|
|
10
|
+
*/
|
|
11
|
+
export declare function stripVerboseLiopToolDescription(description: string): string;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* MCP UX: optional compact tool descriptions for clients (e.g. cloud models)
|
|
3
|
+
* that over-trigger on long "envelope / injection" wording in tools/list.
|
|
4
|
+
*
|
|
5
|
+
* Full LIOP payload format remains in prompts/get → liop_blind_analyst.
|
|
6
|
+
*/
|
|
7
|
+
export function mcpCompactToolDescriptions() {
|
|
8
|
+
const v = process.env.LIOP_MCP_COMPACT_TOOL_DESCRIPTIONS?.toLowerCase().trim();
|
|
9
|
+
return v === "1" || v === "true" || v === "yes";
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Removes SDK-appended LIOP specification blocks from a registered tool description.
|
|
13
|
+
*/
|
|
14
|
+
export function stripVerboseLiopToolDescription(description) {
|
|
15
|
+
let d = description;
|
|
16
|
+
const markers = [
|
|
17
|
+
"\n\n[LIOP-PROTO-V1:",
|
|
18
|
+
"\r\n\r\n[LIOP-PROTO-V1:",
|
|
19
|
+
"\n[LIOP-PROTO-V1:", // rare
|
|
20
|
+
];
|
|
21
|
+
for (const m of markers) {
|
|
22
|
+
const i = d.indexOf(m);
|
|
23
|
+
if (i !== -1) {
|
|
24
|
+
d = d.slice(0, i);
|
|
25
|
+
break;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return d.trimEnd();
|
|
29
|
+
}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { Buffer } from "node:buffer";
|
|
2
2
|
import crypto from "node:crypto";
|
|
3
3
|
import { createMlKem768 } from "mlkem";
|
|
4
|
+
import { deriveLogicImageDigest, normalizeLogicSource, } from "../crypto/logic-image-id.js";
|
|
4
5
|
import { ASTGuardian } from "../sandbox/guardian.js";
|
|
5
6
|
import { WasiSandbox } from "../sandbox/wasi.js";
|
|
6
7
|
export default async function processLogicExecution(data) {
|
|
7
8
|
const { ciphertext, secretKeyObj, wasmBinary, inputs, aesNonce, records, isEncrypted = true, } = data;
|
|
8
9
|
let decryptedPayload;
|
|
9
10
|
const decryptedInputs = {};
|
|
11
|
+
let sessionSecret = Buffer.alloc(32); // Fallback if plain text (no PQC)
|
|
10
12
|
if (isEncrypted) {
|
|
11
13
|
// 1. Decapsulate Kyber secret
|
|
12
14
|
const sk = new Uint8Array(secretKeyObj);
|
|
@@ -14,6 +16,7 @@ export default async function processLogicExecution(data) {
|
|
|
14
16
|
const kem = await createMlKem768();
|
|
15
17
|
const sharedSecret = kem.decap(ct, sk);
|
|
16
18
|
const aesKey = Buffer.from(sharedSecret);
|
|
19
|
+
sessionSecret = aesKey;
|
|
17
20
|
// 2. Decrypt Main Payload (WASM/JS Code)
|
|
18
21
|
// LIOP Serialization: Ciphertext = EncryptedData + 16-byte AuthTag
|
|
19
22
|
const wasmBuffer = Buffer.from(wasmBinary);
|
|
@@ -63,33 +66,48 @@ export default async function processLogicExecution(data) {
|
|
|
63
66
|
else if (decryptedPayload instanceof Buffer && !isWasm) {
|
|
64
67
|
decryptedPayload = decryptedPayload.toString("utf-8");
|
|
65
68
|
}
|
|
66
|
-
//
|
|
69
|
+
// Strip only a whole-document LIOP envelope (see logic-image-id.ts).
|
|
67
70
|
if (typeof decryptedPayload === "string") {
|
|
68
|
-
decryptedPayload = decryptedPayload
|
|
69
|
-
.replace(/^\s*LIOP_MAGIC:.*?\n/g, "")
|
|
70
|
-
.replace(/^\s*MANIFEST:.*?\n/g, "")
|
|
71
|
-
.replace(/\s*---BEGIN_LOGIC---\n?/g, "")
|
|
72
|
-
.replace(/\n?---END_LOGIC---\s*$/g, "")
|
|
73
|
-
.trim();
|
|
71
|
+
decryptedPayload = normalizeLogicSource(decryptedPayload);
|
|
74
72
|
}
|
|
75
73
|
// 4. Instantiate and Execute WASI Sandbox (or V8 Fallback)
|
|
76
74
|
const sandbox = new WasiSandbox();
|
|
77
75
|
await sandbox.init();
|
|
78
76
|
try {
|
|
79
77
|
const result = await sandbox.execute(decryptedPayload, records, decryptedInputs);
|
|
80
|
-
// 5. Generate
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const imageId =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
78
|
+
// 5. Generate Cryptographic Proof of Execution (HMAC-SHA256 Commitment)
|
|
79
|
+
let logicBytes;
|
|
80
|
+
if (typeof decryptedPayload === "string") {
|
|
81
|
+
logicBytes = Buffer.from(decryptedPayload, "utf-8");
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
logicBytes = new Uint8Array(decryptedPayload);
|
|
85
|
+
}
|
|
86
|
+
const imageId = deriveLogicImageDigest(logicBytes).toString("hex");
|
|
87
|
+
const journal = Buffer.from(JSON.stringify({
|
|
88
|
+
image_id: imageId,
|
|
89
|
+
output_hash: crypto
|
|
90
|
+
.createHash("sha256")
|
|
91
|
+
.update(typeof result.output === "string"
|
|
92
|
+
? result.output
|
|
93
|
+
: JSON.stringify(result.output))
|
|
94
|
+
.digest("hex"),
|
|
95
|
+
fuel: result.fuelConsumed,
|
|
96
|
+
ts: Date.now(),
|
|
97
|
+
}));
|
|
98
|
+
const seal = crypto
|
|
99
|
+
.createHmac("sha256", sessionSecret)
|
|
100
|
+
.update(journal)
|
|
101
|
+
.digest();
|
|
102
|
+
const journalLen = Buffer.alloc(2);
|
|
103
|
+
journalLen.writeUInt16BE(journal.length);
|
|
104
|
+
const receiptBuf = Buffer.concat([
|
|
105
|
+
Buffer.from([0x01]), // Receipt format v1
|
|
106
|
+
journalLen,
|
|
107
|
+
journal,
|
|
108
|
+
seal, // 32 bytes HMAC
|
|
109
|
+
]);
|
|
110
|
+
const zkReceipt = receiptBuf.toString("base64");
|
|
93
111
|
return {
|
|
94
112
|
image_id: imageId,
|
|
95
113
|
zk_receipt: zkReceipt,
|
|
@@ -1,35 +1,11 @@
|
|
|
1
|
-
import * as crypto from "node:crypto";
|
|
2
1
|
import { parentPort } from "node:worker_threads";
|
|
2
|
+
import { deriveLogicImageDigest } from "../crypto/logic-image-id.js";
|
|
3
3
|
// Ensure this worker is used via Piscina pool
|
|
4
4
|
if (!parentPort) {
|
|
5
5
|
// Not fatal in Piscina, but handled appropriately
|
|
6
6
|
}
|
|
7
|
-
/**
|
|
8
|
-
* Derives the ImageID of a logic payload following the LIOP v1 Standard.
|
|
9
|
-
*/
|
|
10
7
|
function deriveImageId(logicPayload) {
|
|
11
|
-
|
|
12
|
-
let processed = Buffer.from(logicPayload);
|
|
13
|
-
const isWasm = logicPayload[0] === 0x00 && logicPayload[1] === 0x61; // \0asm
|
|
14
|
-
if (!isWasm) {
|
|
15
|
-
const text = Buffer.from(logicPayload).toString("utf-8");
|
|
16
|
-
const regex = /\s*LIOP_MAGIC:0x00FF\s*\n?\s*MANIFEST:(?<manifest>\{[\s\S]*?\})\s*\n?\s*---BEGIN_LOGIC---\n?(?<logic>[\s\S]*?)\n?---END_LOGIC---/m;
|
|
17
|
-
const match = text.match(regex);
|
|
18
|
-
if (match?.groups?.logic) {
|
|
19
|
-
processed = Buffer.from(match.groups.logic.trim());
|
|
20
|
-
}
|
|
21
|
-
else {
|
|
22
|
-
// Fallback string manipulation if no explicit full envelope
|
|
23
|
-
const clean = text
|
|
24
|
-
.replace(/^LIOP_MAGIC:.*?\n/g, "")
|
|
25
|
-
.replace(/^MANIFEST:.*?\n/g, "")
|
|
26
|
-
.replace(/---BEGIN_LOGIC---\n?/g, "")
|
|
27
|
-
.replace(/\n?---END_LOGIC---/g, "")
|
|
28
|
-
.trim();
|
|
29
|
-
processed = Buffer.from(clean);
|
|
30
|
-
}
|
|
31
|
-
}
|
|
32
|
-
return crypto.createHash("sha256").update(processed).digest();
|
|
8
|
+
return deriveLogicImageDigest(logicPayload);
|
|
33
9
|
}
|
|
34
10
|
/**
|
|
35
11
|
* Simulates heavy ZK-Proof cryptographic verification.
|
|
@@ -46,19 +22,47 @@ async function verifyZkReceipt(payload) {
|
|
|
46
22
|
message: `Integrity Violation: Local (${localImageIdHex.slice(0, 8)}) != Remote (${remoteImageIdHex.slice(0, 8)})`,
|
|
47
23
|
};
|
|
48
24
|
}
|
|
49
|
-
// 2. Structural
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
25
|
+
// 2. Structural Verification: Deserialize Binary Receipt
|
|
26
|
+
const receiptBuf = Buffer.from(zkReceipt);
|
|
27
|
+
if (receiptBuf.length < 35) {
|
|
28
|
+
// 1 version + 2 len + 32 seal minimum
|
|
29
|
+
return {
|
|
30
|
+
verified: false,
|
|
31
|
+
message: "Receipt too short for binary format.",
|
|
32
|
+
};
|
|
33
|
+
}
|
|
34
|
+
const version = receiptBuf[0];
|
|
35
|
+
if (version !== 0x01) {
|
|
54
36
|
return {
|
|
55
37
|
verified: false,
|
|
56
|
-
message:
|
|
38
|
+
message: `Unknown receipt version: ${version}`,
|
|
57
39
|
};
|
|
58
40
|
}
|
|
41
|
+
const journalLen = receiptBuf.readUInt16BE(1);
|
|
42
|
+
const journal = receiptBuf.subarray(3, 3 + journalLen);
|
|
43
|
+
const seal = receiptBuf.subarray(3 + journalLen);
|
|
44
|
+
if (seal.length !== 32) {
|
|
45
|
+
return {
|
|
46
|
+
verified: false,
|
|
47
|
+
message: "Invalid seal length (expected 32 bytes HMAC-SHA256).",
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
// 3. Parse journal and verify imageId
|
|
51
|
+
try {
|
|
52
|
+
const journalData = JSON.parse(journal.toString());
|
|
53
|
+
if (journalData.image_id !== localImageIdHex) {
|
|
54
|
+
return {
|
|
55
|
+
verified: false,
|
|
56
|
+
message: `Journal ImageID mismatch: ${journalData.image_id.slice(0, 8)} != ${localImageIdHex.slice(0, 8)}`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
catch (_e) {
|
|
61
|
+
return { verified: false, message: "Failed to parse journal data." };
|
|
62
|
+
}
|
|
59
63
|
return {
|
|
60
64
|
verified: true,
|
|
61
|
-
message: "
|
|
65
|
+
message: "HMAC Commitment Verified: Integrity intact.",
|
|
62
66
|
};
|
|
63
67
|
}
|
|
64
68
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@nekzus/liop",
|
|
3
|
-
"version": "1.2.0
|
|
3
|
+
"version": "1.2.0",
|
|
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",
|
|
@@ -56,7 +56,16 @@
|
|
|
56
56
|
"demo:client-quickstart": "pnpm --filter @liop/example-client-quickstart start",
|
|
57
57
|
"demo:server-quickstart": "pnpm --filter @liop/example-server-quickstart start",
|
|
58
58
|
"demo:server": "pnpm --filter @liop/example-server start",
|
|
59
|
-
"demo:client": "pnpm --filter @liop/example-client start"
|
|
59
|
+
"demo:client": "pnpm --filter @liop/example-client start",
|
|
60
|
+
"test:crossnet": "tsx tests/infra/cli/crossnet.ts",
|
|
61
|
+
"test:crossnet:burn": "tsx tests/infra/cli/crossnet-burn.ts",
|
|
62
|
+
"demo:build": "tsx tests/infra/cli/demo-build.ts",
|
|
63
|
+
"demo:start": "tsx tests/infra/cli/demo-start.ts",
|
|
64
|
+
"demo:start:rebuild": "tsx tests/infra/cli/demo-start-rebuild.ts",
|
|
65
|
+
"demo:stop": "tsx tests/infra/cli/demo-stop.ts",
|
|
66
|
+
"demo:clean": "tsx tests/infra/cli/demo-clean.ts",
|
|
67
|
+
"demo:claude": "tsx tests/infra/cli/demo-claude.ts",
|
|
68
|
+
"demo:inspector": "tsx tests/infra/cli/demo-inspector.ts"
|
|
60
69
|
},
|
|
61
70
|
"keywords": [
|
|
62
71
|
"liop",
|
|
@@ -95,6 +104,7 @@
|
|
|
95
104
|
},
|
|
96
105
|
"devDependencies": {
|
|
97
106
|
"@biomejs/biome": "^2.4.4",
|
|
107
|
+
"@opentelemetry/sdk-metrics": "^2.7.0",
|
|
98
108
|
"@types/node": "^25.3.1",
|
|
99
109
|
"@vitest/coverage-v8": "^4.0.18",
|
|
100
110
|
"tsx": "^4.21.0",
|
|
@@ -120,6 +130,8 @@
|
|
|
120
130
|
"@libp2p/websockets": "^10.1.7",
|
|
121
131
|
"@modelcontextprotocol/sdk": "^1.28.0",
|
|
122
132
|
"@multiformats/multiaddr": "^13.0.1",
|
|
133
|
+
"@opentelemetry/api": "^1.9.1",
|
|
134
|
+
"gpt-tokenizer": "^3.4.0",
|
|
123
135
|
"hono": "^4.12.5",
|
|
124
136
|
"it-pipe": "^3.0.1",
|
|
125
137
|
"libp2p": "^3.1.3",
|