@xmbl/simulator 0.1.11 → 0.1.13

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/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.1.13
4
+
5
+ ### Patch Changes
6
+
7
+ - **SECURITY — the AIR zero-knowledge path leaked the entire secret trace.** Reported against
8
+ 0.1.12 and reproduced: the batching challenges `alpha` and `beta` are public and the composition
9
+ `C(x) = alpha*u + beta*v` is an `F_p^4` element over two base-field unknowns, so every FRI opening
10
+ was four equations in two unknowns. Solving two limbs for `v` gives `col'(x)` directly, and the
11
+ `2*nq` layer-0 openings interpolate the blinded trace column — row 0 IS the witness. It returned
12
+ the secret exactly, in about a second. The `(x^T - 1)` blind could not help: it is sized for the
13
+ `2*nc` direct openings and vanishes on the trace domain by construction.
14
+
15
+ The composition is now MASKED before FRI sees it: a uniformly random extension-valued polynomial
16
+ `M` of degree `< K` is committed first, `gamma` is drawn from a transcript that includes its root,
17
+ and FRI runs on `C + gamma*M`. Each opening is four equations in six unknowns. The verifier opens
18
+ `M` against its own root at the consistency points. A mask that is not of degree `< K` would pin
19
+ `gamma` to one value out of ~2^124, so masking cannot hide a false statement.
20
+
21
+ `setup` now doubles `K` until it exceeds everything the transcript reveals
22
+ (`nq*(log2 K + 1) + nc`, plus margin): `K = 2048`, `N = 16384`. `nc` is raised 16 -> 40, because
23
+ each consistency point is `-log2(K/N) = 3` bits and `nc = 16` was a ~48-bit check behind a
24
+ ~100-bit FRI. Coset evaluation is now an NTT, so proving is faster than 0.1.12 despite the larger
25
+ domain. **PROOFS FROM 0.1.12 DO NOT VERIFY ON 0.1.13** — the proof carries new commitments
26
+ (`rootM`, `rootD`) and the derived parameters moved.
27
+
28
+ `xzk` (the cube-curve statement) was attacked the same way and survives: the committed curve is
29
+ fully recoverable from its FRI openings, but `Pt = P + Z_R*B` with `B` uniform of degree 18 over a
30
+ witness quotient of degree 1, so the same proof is carried by a 2-parameter family of witnesses.
31
+
32
+ The attack is now a permanent check in `air.test.mjs` and `xzk.test.mjs`.
33
+
34
+ ## 0.1.12
35
+
3
36
  ## 0.1.11
4
37
 
5
38
  ### Patch Changes
@@ -18,7 +51,7 @@
18
51
  never under the xid it claims (a datum fails `validateXid` precisely when that xid is somebody else's), and
19
52
  the anchor dedup key claimed before validation is released on every failure. Both doors are closed on BOTH
20
53
  entry points — `addTransaction` and `addSealedBatch`, the path a finalized transaction actually takes — and
21
- one invalid entry in a batch no longer discards the honest transactions behind it.
54
+ one invalid entry in a batch no longer discards the genuine transactions behind it.
22
55
  - consensus: a content-addressed type-6 value tx is admitted on its content address (it carries no in-body
23
56
  signature by design); a malformed anchor is refused at the door by the ledger's own `validateTransaction`;
24
57
  `finalizeTransaction` preserves the signed `id`.
@@ -28,7 +61,7 @@
28
61
  - networking: self-elected circuit-relay server; NO_FATAL transport tolerance; throttled bootstrap warnings.
29
62
  - storage-compute: `CoordinateDelivery` (broken: `require` in ESM, keyed on the public key) is removed.
30
63
  - core: ships the node daemon as the `xmbl-node` bin; the control socket implements the coordinator
31
- contract (`xsc`, `submit_batch`, `ledger_capabilities`, `identity_status`, a signed `chain` claim, honest
64
+ contract (`xsc`, `submit_batch`, `ledger_capabilities`, `identity_status`, a signed `chain` claim, genuine
32
65
  `submit_tx` rejections) and reports the RUNNING versions; boot waits for the stores.
33
66
  - every package exports a load-time `VERSION`.
34
67
  - PROTOCOL (operator, 2026-09-16): every transaction is typed by its xid (tokens.json type codes; `micromineTx`/
@@ -5,7 +5,7 @@ opts into ledger-side signature verification — it wires **both** `xid` and
5
5
  `getPublicKeyByAddress` into the `Ledger` — which is precisely the caller configuration that
6
6
  exercises defects no production code path currently reaches. Two of the three defects below are
7
7
  now **FIXED**; the third is a genuine signature-domain decision left for the audit and documented
8
- honestly rather than papered over. All are covered by `src/devnet.test.mjs`.
8
+ accurately rather than papered over. All are covered by `src/devnet.test.mjs`.
9
9
 
10
10
  ## Where ledger-side verification runs
11
11
 
@@ -92,7 +92,7 @@ architectural choices, **which is an audit-level signature-domain / block-identi
92
92
  Both touch `block.js`, ledger dedup, and cross-node determinism, so neither rides in on a tooling
93
93
  commit. Until one is made and audited, **ledger-side re-verification stays OFF in production**
94
94
  (the `getPublicKeyByAddress` lookup is deliberately not wired into the `Ledger`), and consensus
95
- remains the single verification point. This is the honest, current posture — not a silent gap.
95
+ remains the single verification point. This is the genuine, current posture — not a silent gap.
96
96
 
97
97
  ## Why the devnet drives the direct path
98
98
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xmbl/simulator",
3
- "version": "0.1.11",
3
+ "version": "0.1.13",
4
4
  "type": "module",
5
5
  "main": "index.js",
6
6
  "description": "XMBL Simulator",
@@ -2,7 +2,7 @@
2
2
  // zk / homomorphic-encryption / signature primitives in-page (they need node:crypto; an MV3 page
3
3
  // CSP and WebCrypto's async sha256 make a faithful in-page port impossible), so the devnet node
4
4
  // process — which already loads the REAL modules — runs each primitive end-to-end and returns a
5
- // JSON-safe verdict. Each runner does the honest thing and its NEGATIVE control in one call: it
5
+ // JSON-safe verdict. Each runner does the right thing and its NEGATIVE control in one call: it
6
6
  // proves the capability verifies true input AND rejects tampered input, so a green card on screen
7
7
  // is backed by a real refusal, not a fabricated pass. Every flow mirrors the headless
8
8
  // reproductions in @xmbl/contracts (reproductions/contract-zk.mjs, contract-he.mjs,
@@ -25,7 +25,7 @@ const CUBE_CONTEXT = {
25
25
 
26
26
  // ── Coordinate / curve zero-knowledge (@xmbl/zero-knowledge, FRI, ⛔ UNAUDITED) ──
27
27
  // A prover shows a coordinate (derivedX, derivedY) lies on a curve through secret points, and a
28
- // verifier checks it WITHOUT the secret points. We prove the honest coordinate and reject a
28
+ // verifier checks it WITHOUT the secret points. We prove the genuine coordinate and reject a
29
29
  // tampered y (derivedY+1) — the exact pair reproductions/contract-zk.mjs gates a Verkle write on.
30
30
  export function zkProof({ derivedX = 99 } = {}) {
31
31
  const ctx = setup();
@@ -34,14 +34,14 @@ export function zkProof({ derivedX = 99 } = {}) {
34
34
  const dX = bi(derivedX);
35
35
  const { Pt, derivedY } = blindedCurve(ctx, { publicPoints, secretPoints, derivedX: dX });
36
36
  const proof = prove(ctx, { Pt, publicPoints, derivedX: dX, derivedY });
37
- const honest = zkVerify(ctx, { proof, publicPoints, derivedX: dX, derivedY });
37
+ const genuine = zkVerify(ctx, { proof, publicPoints, derivedX: dX, derivedY });
38
38
  const tampered = zkVerify(ctx, { proof, publicPoints, derivedX: dX, derivedY: derivedY + 1n });
39
39
  return {
40
- ok: honest === true && tampered === false,
40
+ ok: genuine === true && tampered === false,
41
41
  scheme: 'xzk (FRI coordinate/curve proof, UNAUDITED)',
42
42
  derivedX: str(dX), derivedY: str(derivedY),
43
43
  publicAnchors: publicPoints.length,
44
- honestVerifies: honest, tamperedRejected: tampered === false,
44
+ genuineVerifies: genuine, tamperedRejected: tampered === false,
45
45
  note: 'proof checked without the secret points; a coordinate off the curve is rejected',
46
46
  };
47
47
  }
package/src/devnet-rpc.js CHANGED
@@ -17,7 +17,7 @@
17
17
  // It ALSO serves the node-side capability surface the extension cannot run in-page — each a REAL
18
18
  // primitive run end-to-end in this node process, verdict returned JSON-safe (see capabilities.js):
19
19
  // getStateRoot {type} → { root, pooled, landed } // live ledger state root
20
- // zkProof {type, derivedX?} → { ok, derivedX, derivedY, honestVerifies, tamperedRejected, … }
20
+ // zkProof {type, derivedX?} → { ok, derivedX, derivedY, genuineVerifies, tamperedRejected, … }
21
21
  // heAdd {type, a?, b?} → { ok, a, b, sum, expected, … } // homomorphic add
22
22
  // sigVerify {type, message?} → { ok, signedVerifies, tamperedRejected, … } // Cubic-SIG
23
23
  // seal {type, secret?} → { ok, roundTrip, … } // PQ KEM seal
@@ -69,7 +69,7 @@ export class DevnetRpc {
69
69
  }
70
70
  default: {
71
71
  // Node-side capability surface (zk / HE / signature / seal): a real primitive run to a
72
- // verdict in this process. Unknown types still fall through to an honest error.
72
+ // verdict in this process. Unknown types still fall through to a genuine error.
73
73
  const cap = CAPABILITIES[message && message.type];
74
74
  if (cap) return cap(message || {});
75
75
  return { error: `Unknown message type: ${message && message.type}` };
@@ -54,7 +54,7 @@ try {
54
54
 
55
55
  // ── node-side capability surface: each a REAL primitive verified + negative-controlled ──
56
56
  const zk = await call({ type: 'zkProof', derivedX: 99 });
57
- ok('zkProof verifies the honest coordinate and rejects the tampered one', zk.ok === true && zk.honestVerifies === true && zk.tamperedRejected === true, JSON.stringify(zk));
57
+ ok('zkProof verifies the genuine coordinate and rejects the tampered one', zk.ok === true && zk.genuineVerifies === true && zk.tamperedRejected === true, JSON.stringify(zk));
58
58
 
59
59
  const he1 = await call({ type: 'heAdd', a: 1, b: 0 });
60
60
  ok('heAdd: ENC(1) ⊞ ENC(0) decrypts to 1 (blind add)', he1.ok === true && he1.sum === 1, JSON.stringify(he1));
package/src/simulator.js CHANGED
@@ -613,7 +613,7 @@ export class SystemSimulator extends EventEmitter {
613
613
  // Compute operations can trigger state changes. This used to call a fake
614
614
  // xvsm.executeTransaction with a comment string as "WASM"; that path is gone (real
615
615
  // contract execution is @xmbl/contracts' ContractHost over @xmbl/storage-compute). The
616
- // simulator's honest job here is just to drive a state change, so it uses the real
616
+ // simulator's genuine job here is just to drive a state change, so it uses the real
617
617
  // state-diff path directly.
618
618
  if (this.modules.xvsm && chance.bool({ likelihood: 70 })) {
619
619
  setTimeout(() => {