@atlasauth/pca-mpc 0.3.0 → 0.4.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 +81 -3
- package/dist/beaver.js +4 -0
- package/dist/beaver.js.map +1 -1
- package/dist/compose.d.ts +9 -2
- package/dist/compose.js +24 -1
- package/dist/compose.js.map +1 -1
- package/dist/ec.d.ts +6 -3
- package/dist/ec.js +27 -9
- package/dist/ec.js.map +1 -1
- package/dist/enc.d.ts +46 -0
- package/dist/enc.js +88 -0
- package/dist/enc.js.map +1 -0
- package/dist/endemic-ot.js +24 -1
- package/dist/endemic-ot.js.map +1 -1
- package/dist/hybrid-ot.js +3 -0
- package/dist/hybrid-ot.js.map +1 -1
- package/dist/kem-ot.js +2 -0
- package/dist/kem-ot.js.map +1 -1
- package/dist/mascot.d.ts +81 -30
- package/dist/mascot.js +232 -113
- package/dist/mascot.js.map +1 -1
- package/dist/net/certs.d.ts +14 -0
- package/dist/net/certs.js +30 -0
- package/dist/net/certs.js.map +1 -0
- package/dist/net/faults.d.ts +49 -0
- package/dist/net/faults.js +222 -0
- package/dist/net/faults.js.map +1 -0
- package/dist/net/forensics.d.ts +81 -0
- package/dist/net/forensics.js +181 -0
- package/dist/net/forensics.js.map +1 -0
- package/dist/net/gadget.d.ts +44 -0
- package/dist/net/gadget.js +102 -0
- package/dist/net/gadget.js.map +1 -0
- package/dist/net/index.d.ts +11 -0
- package/dist/net/index.js +28 -0
- package/dist/net/index.js.map +1 -0
- package/dist/net/launch-local.d.ts +53 -0
- package/dist/net/launch-local.js +190 -0
- package/dist/net/launch-local.js.map +1 -0
- package/dist/net/launch-support.d.ts +6 -0
- package/dist/net/launch-support.js +65 -0
- package/dist/net/launch-support.js.map +1 -0
- package/dist/net/mesh.d.ts +135 -0
- package/dist/net/mesh.js +491 -0
- package/dist/net/mesh.js.map +1 -0
- package/dist/net/offline-net.d.ts +58 -0
- package/dist/net/offline-net.js +485 -0
- package/dist/net/offline-net.js.map +1 -0
- package/dist/net/ot-net.d.ts +42 -0
- package/dist/net/ot-net.js +219 -0
- package/dist/net/ot-net.js.map +1 -0
- package/dist/net/pa.d.ts +65 -0
- package/dist/net/pa.js +118 -0
- package/dist/net/pa.js.map +1 -0
- package/dist/net/party-main.d.ts +48 -0
- package/dist/net/party-main.js +146 -0
- package/dist/net/party-main.js.map +1 -0
- package/dist/net/prep.d.ts +40 -0
- package/dist/net/prep.js +12 -0
- package/dist/net/prep.js.map +1 -0
- package/dist/net/protocol.d.ts +126 -0
- package/dist/net/protocol.js +655 -0
- package/dist/net/protocol.js.map +1 -0
- package/dist/net/wire.d.ts +89 -0
- package/dist/net/wire.js +242 -0
- package/dist/net/wire.js.map +1 -0
- package/dist/ot.d.ts +176 -17
- package/dist/ot.js +479 -252
- package/dist/ot.js.map +1 -1
- package/dist/otx.d.ts +76 -0
- package/dist/otx.js +238 -0
- package/dist/otx.js.map +1 -0
- package/dist/runner.d.ts +1 -1
- package/dist/runner.js +6 -1
- package/dist/runner.js.map +1 -1
- package/dist/sharing.d.ts +2 -0
- package/dist/sharing.js +7 -4
- package/dist/sharing.js.map +1 -1
- package/dist/spdz-runner.d.ts +20 -3
- package/dist/spdz-runner.js +21 -3
- package/dist/spdz-runner.js.map +1 -1
- package/dist/spdz.d.ts +96 -22
- package/dist/spdz.js +196 -47
- package/dist/spdz.js.map +1 -1
- package/package.json +15 -6
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agreement on the joint choice-bit gadget seeds (R3-16): a signed commit-reveal with an echo round, so that ONE
|
|
4
|
+
* corrupt party cannot make the honest parties derive different gadgets and then blame each other.
|
|
5
|
+
*
|
|
6
|
+
* The plain commit-reveal (`gd-c` / `gd-o`) leaves each party's message to each peer unauthenticated beyond the TLS link,
|
|
7
|
+
* so a corrupt party can send a different commitment and seed to each honest peer. The honest parties then compute different
|
|
8
|
+
* gadgets, the triple sacrifice fails, and the forensic audit (which uses each verifier's OWN gadget) makes honest parties
|
|
9
|
+
* accuse each other while the corrupt one goes unnamed.
|
|
10
|
+
*
|
|
11
|
+
* Here every commitment and every opening is SIGNED by its sender with the sender's pinned TLS identity key. After the
|
|
12
|
+
* reveal each party echoes, to every peer, the signed values it received from each third party (`gd-e`). A receiver then
|
|
13
|
+
* checks each echoed statement against what it received directly:
|
|
14
|
+
*
|
|
15
|
+
* - an echoed signature that does not verify is a forgery by the echoer: blame the echoer (first-hand: I can verify
|
|
16
|
+
* the signature myself, and I need no one's word);
|
|
17
|
+
* - an echoed statement that verifies but differs from the one I received directly from the same signer means the signer
|
|
18
|
+
* signed two different values for the same round: blame the signer, with both signed statements as TRANSFERABLE evidence
|
|
19
|
+
* (any third party can verify both against the signer's pinned certificate). An honest party signs one value per
|
|
20
|
+
* round, so it can never be framed this way, and a corrupt echoer can only relay values the signer really signed.
|
|
21
|
+
*
|
|
22
|
+
* If every check passes, all honest parties hold identical seeds and so identical gadgets. A party that is silent, late
|
|
23
|
+
* or malformed is blamed by the existing receive deadline / schema checks (a local observation, see `NetAbort.deadlineMs`).
|
|
24
|
+
* With n = 2 there is no third party to equivocate towards, so the echo round is skipped.
|
|
25
|
+
*/
|
|
26
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
27
|
+
exports.gadgetStatement = exports.gadgetCommit = void 0;
|
|
28
|
+
exports.agreeGadgetSeeds = agreeGadgetSeeds;
|
|
29
|
+
const node_crypto_1 = require("node:crypto");
|
|
30
|
+
const wire_1 = require("./wire");
|
|
31
|
+
const HEX64 = /^[0-9a-f]{64}$/;
|
|
32
|
+
const HEXSIG = /^[0-9a-f]{16,200}$/;
|
|
33
|
+
const gadgetCommit = (sessionId, party, seed) => (0, node_crypto_1.createHash)('sha256').update('atlas-pca-mpc/gadget-commit').update(sessionId).update(String(party)).update(seed).digest('hex');
|
|
34
|
+
exports.gadgetCommit = gadgetCommit;
|
|
35
|
+
/** The exact bytes a party signs: domain, session, round, signer and value, length-unambiguous via JSON. */
|
|
36
|
+
const gadgetStatement = (sessionId, round, signer, value) => Buffer.from(JSON.stringify(['atlas-pca-mpc/gadget-sig/v1', sessionId, round, signer, value]), 'utf8');
|
|
37
|
+
exports.gadgetStatement = gadgetStatement;
|
|
38
|
+
const isSigned = (x, valueRe) => typeof x === 'object' && x !== null && typeof x.v === 'string' && valueRe.test(x.v) && typeof x.s === 'string' && HEXSIG.test(x.s);
|
|
39
|
+
/**
|
|
40
|
+
* Run the signed commit / reveal / echo and return every party's seed in party order (mine included).
|
|
41
|
+
* `mySeed` is injectable for tests; production passes nothing.
|
|
42
|
+
*/
|
|
43
|
+
async function agreeGadgetSeeds(net, n, io, mySeed = (0, node_crypto_1.randomBytes)(32)) {
|
|
44
|
+
const id = net.selfId;
|
|
45
|
+
const sid = net.sessionId;
|
|
46
|
+
const sign = (round, value) => ({ v: value, s: Buffer.from(net.sign((0, exports.gadgetStatement)(sid, round, id, value))).toString('hex') });
|
|
47
|
+
const check = (signer, round, m) => net.verify(signer, (0, exports.gadgetStatement)(sid, round, signer, m.v), Buffer.from(m.s, 'hex'));
|
|
48
|
+
const myCommit = (0, exports.gadgetCommit)(sid, id, mySeed);
|
|
49
|
+
const commits = await io.exchange('gd-c', () => sign('gd-c', myCommit), (p, raw) => {
|
|
50
|
+
if (!isSigned(raw, HEX64))
|
|
51
|
+
return io.bad(p, 'bad gadget commitment');
|
|
52
|
+
if (!check(p, 'gd-c', raw))
|
|
53
|
+
return io.bad(p, 'gadget commitment signature does not verify');
|
|
54
|
+
return raw;
|
|
55
|
+
});
|
|
56
|
+
const mySeedHex = Buffer.from(mySeed).toString('hex');
|
|
57
|
+
const opens = await io.exchange('gd-o', () => sign('gd-o', mySeedHex), (p, raw) => {
|
|
58
|
+
if (!isSigned(raw, HEX64))
|
|
59
|
+
return io.bad(p, 'bad gadget seed');
|
|
60
|
+
if (!check(p, 'gd-o', raw))
|
|
61
|
+
return io.bad(p, 'gadget seed signature does not verify');
|
|
62
|
+
if ((0, exports.gadgetCommit)(sid, p, Buffer.from(raw.v, 'hex')) !== commits.get(p).v) {
|
|
63
|
+
throw new wire_1.NetAbort('commitment', p, id, `party ${p} opened a gadget seed that does not match its commitment`);
|
|
64
|
+
}
|
|
65
|
+
return raw;
|
|
66
|
+
});
|
|
67
|
+
if (n >= 3) {
|
|
68
|
+
const others = [];
|
|
69
|
+
for (let i = 0; i < n; i++)
|
|
70
|
+
if (i !== id)
|
|
71
|
+
others.push(i);
|
|
72
|
+
await io.exchange('gd-e', (peer) => others.filter((j) => j !== peer).map((j) => ({ j, c: commits.get(j), o: opens.get(j) })), (p, raw) => {
|
|
73
|
+
const expect = others.filter((j) => j !== p);
|
|
74
|
+
if (!Array.isArray(raw) || raw.length !== expect.length)
|
|
75
|
+
return io.bad(p, 'bad gadget echo');
|
|
76
|
+
for (let k = 0; k < expect.length; k++) {
|
|
77
|
+
const e = raw[k];
|
|
78
|
+
const j = expect[k];
|
|
79
|
+
if (e === null || typeof e !== 'object' || e.j !== j || !isSigned(e.c, HEX64) || !isSigned(e.o, HEX64))
|
|
80
|
+
return io.bad(p, 'bad gadget echo entry');
|
|
81
|
+
// a statement that does not verify under j's pinned key was forged by the echoer p
|
|
82
|
+
if (!check(j, 'gd-c', e.c) || !check(j, 'gd-o', e.o))
|
|
83
|
+
return io.bad(p, `gadget echo carries a statement that party ${j} did not sign`);
|
|
84
|
+
const mineC = commits.get(j);
|
|
85
|
+
const mineO = opens.get(j);
|
|
86
|
+
if (e.c.v !== mineC.v || e.o.v !== mineO.v) {
|
|
87
|
+
// both statements verify under j's key and differ: j signed two values for one round
|
|
88
|
+
throw new wire_1.NetAbort('equivocation', j, id, `party ${j} signed different gadget ${e.c.v !== mineC.v ? 'commitments' : 'seeds'} for different parties (shown by party ${p}'s echo)`, undefined, undefined, {
|
|
89
|
+
evidence: {
|
|
90
|
+
signer: j,
|
|
91
|
+
round: e.c.v !== mineC.v ? 'gd-c' : 'gd-o',
|
|
92
|
+
statements: e.c.v !== mineC.v ? [mineC, e.c] : [mineO, e.o],
|
|
93
|
+
},
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return true;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
return Array.from({ length: n }, (_, p) => (p === id ? Uint8Array.from(mySeed) : Uint8Array.from(Buffer.from(opens.get(p).v, 'hex'))));
|
|
101
|
+
}
|
|
102
|
+
//# sourceMappingURL=gadget.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gadget.js","sourceRoot":"","sources":["../../src/net/gadget.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Networked runner for `@atlasauth/pca-mpc` (research prototype): mutual-TLS mesh, the distributed
|
|
3
|
+
* malicious-with-abort protocol (parties + trusted dealer), pairwise base-OT over the wire, and the
|
|
4
|
+
* multi-process launcher / fault-injection helpers used by the tests and the multi-host run.
|
|
5
|
+
*/
|
|
6
|
+
export * from './wire';
|
|
7
|
+
export * from './certs';
|
|
8
|
+
export * from './mesh';
|
|
9
|
+
export * from './protocol';
|
|
10
|
+
export * from './faults';
|
|
11
|
+
export * from './launch-local';
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Networked runner for `@atlasauth/pca-mpc` (research prototype): mutual-TLS mesh, the distributed
|
|
4
|
+
* malicious-with-abort protocol (parties + trusted dealer), pairwise base-OT over the wire, and the
|
|
5
|
+
* multi-process launcher / fault-injection helpers used by the tests and the multi-host run.
|
|
6
|
+
*/
|
|
7
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
8
|
+
if (k2 === undefined) k2 = k;
|
|
9
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
10
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
11
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
12
|
+
}
|
|
13
|
+
Object.defineProperty(o, k2, desc);
|
|
14
|
+
}) : (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
o[k2] = m[k];
|
|
17
|
+
}));
|
|
18
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
19
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
20
|
+
};
|
|
21
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
22
|
+
__exportStar(require("./wire"), exports);
|
|
23
|
+
__exportStar(require("./certs"), exports);
|
|
24
|
+
__exportStar(require("./mesh"), exports);
|
|
25
|
+
__exportStar(require("./protocol"), exports);
|
|
26
|
+
__exportStar(require("./faults"), exports);
|
|
27
|
+
__exportStar(require("./launch-local"), exports);
|
|
28
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/net/index.ts"],"names":[],"mappings":";AAAA;;;;GAIG;;;;;;;;;;;;;;;;AAEH,yCAAuB;AACvB,0CAAwB;AACxB,yCAAuB;AACvB,6CAA2B;AAC3B,2CAAyB;AACzB,iDAA+B"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Multi-process launcher: spawns the dealer and each party as its own OS process (`party-main.js`) on
|
|
3
|
+
* localhost, generates a fresh per-run identity for each, optionally routes one link through a
|
|
4
|
+
* `FaultProxy`, and collects each node's one-line JSON verdict. Used by the tests and the demo script;
|
|
5
|
+
* the real multi-host run uses the same `party-main.js` with a config per host.
|
|
6
|
+
*/
|
|
7
|
+
import { type WireFault } from './faults';
|
|
8
|
+
import type { NodeConfig } from './party-main';
|
|
9
|
+
import type { DecisionVector } from '../party';
|
|
10
|
+
export interface NodeOutput {
|
|
11
|
+
id: number;
|
|
12
|
+
role: 'party' | 'dealer';
|
|
13
|
+
exitCode: number | null;
|
|
14
|
+
json: any;
|
|
15
|
+
stderr: string;
|
|
16
|
+
}
|
|
17
|
+
export interface LaunchOptions {
|
|
18
|
+
n: number;
|
|
19
|
+
Q?: number;
|
|
20
|
+
vectors: DecisionVector[];
|
|
21
|
+
/** Path to the compiled `party-main.js`. */
|
|
22
|
+
mainJs: string;
|
|
23
|
+
recvTimeoutMs?: number;
|
|
24
|
+
/** Hard wall-clock cap for the whole run (kills stragglers; a hang is a test failure). */
|
|
25
|
+
killAfterMs?: number;
|
|
26
|
+
overrides?: Record<number, Partial<NodeConfig>>;
|
|
27
|
+
/** Route the connection `dialer -> target` through a faulty TCP proxy. */
|
|
28
|
+
wireFault?: {
|
|
29
|
+
dialer: number;
|
|
30
|
+
target: number;
|
|
31
|
+
fault: WireFault;
|
|
32
|
+
};
|
|
33
|
+
dealerSeed?: string;
|
|
34
|
+
/** `trusted-dealer` (default; spawns a dealer process) or `no-dealer` (the parties run the OT offline phase). */
|
|
35
|
+
offline?: 'trusted-dealer' | 'no-dealer';
|
|
36
|
+
}
|
|
37
|
+
export declare function freePort(): Promise<number>;
|
|
38
|
+
export declare function launchLocal(o: LaunchOptions): Promise<{
|
|
39
|
+
outputs: NodeOutput[];
|
|
40
|
+
wallMs: number;
|
|
41
|
+
proxyLog: string[];
|
|
42
|
+
}>;
|
|
43
|
+
/** Two-process base-OT run (sender = node 0, receiver = node 1) over mutual TLS on localhost. */
|
|
44
|
+
export declare function launchOtLocal(o: {
|
|
45
|
+
kind: 'ec' | 'lwe';
|
|
46
|
+
count: number;
|
|
47
|
+
mainJs: string;
|
|
48
|
+
recvTimeoutMs?: number;
|
|
49
|
+
killAfterMs?: number;
|
|
50
|
+
}): Promise<{
|
|
51
|
+
outputs: NodeOutput[];
|
|
52
|
+
wallMs: number;
|
|
53
|
+
}>;
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Multi-process launcher: spawns the dealer and each party as its own OS process (`party-main.js`) on
|
|
4
|
+
* localhost, generates a fresh per-run identity for each, optionally routes one link through a
|
|
5
|
+
* `FaultProxy`, and collects each node's one-line JSON verdict. Used by the tests and the demo script;
|
|
6
|
+
* the real multi-host run uses the same `party-main.js` with a config per host.
|
|
7
|
+
*/
|
|
8
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
9
|
+
if (k2 === undefined) k2 = k;
|
|
10
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
11
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
12
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
13
|
+
}
|
|
14
|
+
Object.defineProperty(o, k2, desc);
|
|
15
|
+
}) : (function(o, m, k, k2) {
|
|
16
|
+
if (k2 === undefined) k2 = k;
|
|
17
|
+
o[k2] = m[k];
|
|
18
|
+
}));
|
|
19
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
20
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
21
|
+
}) : function(o, v) {
|
|
22
|
+
o["default"] = v;
|
|
23
|
+
});
|
|
24
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
25
|
+
var ownKeys = function(o) {
|
|
26
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
27
|
+
var ar = [];
|
|
28
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
29
|
+
return ar;
|
|
30
|
+
};
|
|
31
|
+
return ownKeys(o);
|
|
32
|
+
};
|
|
33
|
+
return function (mod) {
|
|
34
|
+
if (mod && mod.__esModule) return mod;
|
|
35
|
+
var result = {};
|
|
36
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
37
|
+
__setModuleDefault(result, mod);
|
|
38
|
+
return result;
|
|
39
|
+
};
|
|
40
|
+
})();
|
|
41
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
42
|
+
exports.freePort = freePort;
|
|
43
|
+
exports.launchLocal = launchLocal;
|
|
44
|
+
exports.launchOtLocal = launchOtLocal;
|
|
45
|
+
const node_child_process_1 = require("node:child_process");
|
|
46
|
+
const node_fs_1 = require("node:fs");
|
|
47
|
+
const net = __importStar(require("node:net"));
|
|
48
|
+
const node_os_1 = require("node:os");
|
|
49
|
+
const node_path_1 = require("node:path");
|
|
50
|
+
const node_crypto_1 = require("node:crypto");
|
|
51
|
+
const certs_1 = require("./certs");
|
|
52
|
+
const faults_1 = require("./faults");
|
|
53
|
+
const launch_support_1 = require("./launch-support");
|
|
54
|
+
async function freePort() {
|
|
55
|
+
return new Promise((res, rej) => {
|
|
56
|
+
const s = net.createServer();
|
|
57
|
+
s.listen(0, '127.0.0.1', () => {
|
|
58
|
+
const p = s.address().port;
|
|
59
|
+
s.close(() => res(p));
|
|
60
|
+
});
|
|
61
|
+
s.on('error', rej);
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
async function launchLocal(o) {
|
|
65
|
+
const n = o.n;
|
|
66
|
+
const noDealer = o.offline === 'no-dealer';
|
|
67
|
+
const nodeCount = noDealer ? n : n + 1;
|
|
68
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'pca-mpc-net-'));
|
|
69
|
+
const sessionId = (0, node_crypto_1.randomBytes)(8).toString('hex');
|
|
70
|
+
const ports = await (0, launch_support_1.reservePorts)(nodeCount + 1); // distinct, held together; the last one is for the optional fault proxy
|
|
71
|
+
const ids = [];
|
|
72
|
+
for (let i = 0; i < nodeCount; i++)
|
|
73
|
+
ids.push((0, certs_1.generateIdentity)((0, node_path_1.join)(dir, `node${i}`), `mpc-node-${i}`));
|
|
74
|
+
let proxy = null;
|
|
75
|
+
let proxyPort = 0;
|
|
76
|
+
if (o.wireFault) {
|
|
77
|
+
proxyPort = ports[nodeCount];
|
|
78
|
+
proxy = new faults_1.FaultProxy(proxyPort, { host: '127.0.0.1', port: ports[o.wireFault.target] }, { ...o.wireFault.fault, ...(o.wireFault.fault.ms !== undefined ? { ms: (0, launch_support_1.T)(o.wireFault.fault.ms) } : {}) });
|
|
79
|
+
await proxy.listen();
|
|
80
|
+
}
|
|
81
|
+
const t0 = Date.now();
|
|
82
|
+
const procs = Array.from({ length: nodeCount }, (_, id) => {
|
|
83
|
+
const nodes = ids.map((x, j) => ({
|
|
84
|
+
id: j,
|
|
85
|
+
host: '127.0.0.1',
|
|
86
|
+
port: o.wireFault && id === o.wireFault.dialer && j === o.wireFault.target ? proxyPort : ports[j],
|
|
87
|
+
certPath: x.certPath,
|
|
88
|
+
}));
|
|
89
|
+
const cfg = {
|
|
90
|
+
role: !noDealer && id === n ? 'dealer' : 'party',
|
|
91
|
+
id,
|
|
92
|
+
n,
|
|
93
|
+
Q: o.Q,
|
|
94
|
+
offline: o.offline,
|
|
95
|
+
sessionId,
|
|
96
|
+
input: id < n ? o.vectors[id] : undefined,
|
|
97
|
+
listenHost: '127.0.0.1',
|
|
98
|
+
nodes,
|
|
99
|
+
keyPath: ids[id].keyPath,
|
|
100
|
+
certPath: ids[id].certPath,
|
|
101
|
+
recvTimeoutMs: (0, launch_support_1.T)(o.recvTimeoutMs ?? 30_000),
|
|
102
|
+
connectTimeoutMs: (0, launch_support_1.T)(120_000),
|
|
103
|
+
dealerSeed: id === n ? o.dealerSeed : undefined,
|
|
104
|
+
...(o.overrides?.[id] ?? {}),
|
|
105
|
+
};
|
|
106
|
+
const hooks = cfg.behavior !== undefined || cfg.frameFault !== undefined || cfg.dealerFault !== undefined;
|
|
107
|
+
if (hooks)
|
|
108
|
+
cfg.unsafeTestHooks = true;
|
|
109
|
+
const cfgPath = (0, node_path_1.join)(dir, `cfg${id}.json`);
|
|
110
|
+
(0, node_fs_1.writeFileSync)(cfgPath, JSON.stringify(cfg));
|
|
111
|
+
const child = (0, node_child_process_1.spawn)(process.execPath, [o.mainJs, cfgPath], {
|
|
112
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
113
|
+
env: hooks ? { ...process.env, PCA_MPC_UNSAFE_TEST_HOOKS: '1' } : { ...process.env, PCA_MPC_UNSAFE_TEST_HOOKS: undefined },
|
|
114
|
+
});
|
|
115
|
+
let so = '';
|
|
116
|
+
let se = '';
|
|
117
|
+
child.stdout.on('data', (d) => (so += d));
|
|
118
|
+
child.stderr.on('data', (d) => (se += d));
|
|
119
|
+
return new Promise((resolve) => {
|
|
120
|
+
child.on('close', (code) => {
|
|
121
|
+
const line = so.trim().split('\n').filter(Boolean).pop();
|
|
122
|
+
let json = null; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
123
|
+
try {
|
|
124
|
+
json = line ? JSON.parse(line) : null;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
/* leave null */
|
|
128
|
+
}
|
|
129
|
+
resolve({ id, role: !noDealer && id === n ? 'dealer' : 'party', exitCode: code, json, stderr: se.slice(0, 2000) });
|
|
130
|
+
});
|
|
131
|
+
const killer = setTimeout(() => child.kill('SIGKILL'), (0, launch_support_1.T)(o.killAfterMs ?? 120_000));
|
|
132
|
+
child.on('close', () => clearTimeout(killer));
|
|
133
|
+
});
|
|
134
|
+
});
|
|
135
|
+
const outputs = await Promise.all(procs);
|
|
136
|
+
proxy?.close();
|
|
137
|
+
const proxyLog = proxy?.log ?? [];
|
|
138
|
+
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
139
|
+
return { outputs, wallMs: Date.now() - t0, proxyLog };
|
|
140
|
+
}
|
|
141
|
+
/** Two-process base-OT run (sender = node 0, receiver = node 1) over mutual TLS on localhost. */
|
|
142
|
+
async function launchOtLocal(o) {
|
|
143
|
+
const dir = (0, node_fs_1.mkdtempSync)((0, node_path_1.join)((0, node_os_1.tmpdir)(), 'pca-mpc-ot-'));
|
|
144
|
+
const sessionId = (0, node_crypto_1.randomBytes)(8).toString('hex');
|
|
145
|
+
const ports = await (0, launch_support_1.reservePorts)(2);
|
|
146
|
+
const ids = [0, 1].map((i) => (0, certs_1.generateIdentity)((0, node_path_1.join)(dir, `node${i}`), `mpc-ot-${i}`));
|
|
147
|
+
const nodes = ids.map((x, j) => ({ id: j, host: '127.0.0.1', port: ports[j], certPath: x.certPath }));
|
|
148
|
+
const t0 = Date.now();
|
|
149
|
+
const procs = [0, 1].map((id) => {
|
|
150
|
+
const cfg = {
|
|
151
|
+
role: id === 0 ? 'ot-sender' : 'ot-receiver',
|
|
152
|
+
id,
|
|
153
|
+
n: 2,
|
|
154
|
+
sessionId,
|
|
155
|
+
listenHost: '127.0.0.1',
|
|
156
|
+
nodes,
|
|
157
|
+
keyPath: ids[id].keyPath,
|
|
158
|
+
certPath: ids[id].certPath,
|
|
159
|
+
recvTimeoutMs: (0, launch_support_1.T)(o.recvTimeoutMs ?? 30_000),
|
|
160
|
+
connectTimeoutMs: (0, launch_support_1.T)(120_000),
|
|
161
|
+
ot: { kind: o.kind, count: o.count },
|
|
162
|
+
};
|
|
163
|
+
const cfgPath = (0, node_path_1.join)(dir, `cfg${id}.json`);
|
|
164
|
+
(0, node_fs_1.writeFileSync)(cfgPath, JSON.stringify(cfg));
|
|
165
|
+
const child = (0, node_child_process_1.spawn)(process.execPath, [o.mainJs, cfgPath], { stdio: ['ignore', 'pipe', 'pipe'] });
|
|
166
|
+
let so = '';
|
|
167
|
+
let se = '';
|
|
168
|
+
child.stdout.on('data', (d) => (so += d));
|
|
169
|
+
child.stderr.on('data', (d) => (se += d));
|
|
170
|
+
return new Promise((resolve) => {
|
|
171
|
+
const killer = setTimeout(() => child.kill('SIGKILL'), (0, launch_support_1.T)(o.killAfterMs ?? 120_000));
|
|
172
|
+
child.on('close', (code) => {
|
|
173
|
+
clearTimeout(killer);
|
|
174
|
+
const line = so.trim().split('\n').filter(Boolean).pop();
|
|
175
|
+
let json = null; // eslint-disable-line @typescript-eslint/no-explicit-any
|
|
176
|
+
try {
|
|
177
|
+
json = line ? JSON.parse(line) : null;
|
|
178
|
+
}
|
|
179
|
+
catch {
|
|
180
|
+
/* leave null */
|
|
181
|
+
}
|
|
182
|
+
resolve({ id, role: id === 0 ? 'dealer' : 'party', exitCode: code, json, stderr: se.slice(0, 2000) });
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
const outputs = await Promise.all(procs);
|
|
187
|
+
(0, node_fs_1.rmSync)(dir, { recursive: true, force: true });
|
|
188
|
+
return { outputs, wallMs: Date.now() - t0 };
|
|
189
|
+
}
|
|
190
|
+
//# sourceMappingURL=launch-local.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launch-local.js","sourceRoot":"","sources":["../../src/net/launch-local.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAuCH,4BASC;AAED,kCAyEC;AAGD,sCAoDC;AAhLD,2DAA2C;AAC3C,qCAA6D;AAC7D,8CAAgC;AAChC,qCAAiC;AACjC,yCAAiC;AACjC,6CAA0C;AAC1C,mCAA2C;AAC3C,qCAAsD;AAGtD,qDAAmD;AA2B5C,KAAK,UAAU,QAAQ;IAC5B,OAAO,IAAI,OAAO,CAAC,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;QAC9B,MAAM,CAAC,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAC7B,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE;YAC5B,MAAM,CAAC,GAAI,CAAC,CAAC,OAAO,EAAsB,CAAC,IAAI,CAAC;YAChD,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;QACxB,CAAC,CAAC,CAAC;QACH,CAAC,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IACrB,CAAC,CAAC,CAAC;AACL,CAAC;AAEM,KAAK,UAAU,WAAW,CAAC,CAAgB;IAChD,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;IACd,MAAM,QAAQ,GAAG,CAAC,CAAC,OAAO,KAAK,WAAW,CAAC;IAC3C,MAAM,SAAS,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,GAAG,GAAG,IAAA,qBAAW,EAAC,IAAA,gBAAI,EAAC,IAAA,gBAAM,GAAE,EAAE,cAAc,CAAC,CAAC,CAAC;IACxD,MAAM,SAAS,GAAG,IAAA,yBAAW,EAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,MAAM,IAAA,6BAAY,EAAC,SAAS,GAAG,CAAC,CAAC,CAAC,CAAC,wEAAwE;IACzH,MAAM,GAAG,GAA4C,EAAE,CAAC;IACxD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,EAAE,CAAC,EAAE;QAAE,GAAG,CAAC,IAAI,CAAC,IAAA,wBAAgB,EAAC,IAAA,gBAAI,EAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,YAAY,CAAC,EAAE,CAAC,CAAC,CAAC;IACvG,IAAI,KAAK,GAAsB,IAAI,CAAC;IACpC,IAAI,SAAS,GAAG,CAAC,CAAC;IAClB,IAAI,CAAC,CAAC,SAAS,EAAE,CAAC;QAChB,SAAS,GAAG,KAAK,CAAC,SAAS,CAAE,CAAC;QAC9B,KAAK,GAAG,IAAI,mBAAU,CAAC,SAAS,EAAE,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAE,EAAE,EAAE,EAAE,GAAG,CAAC,CAAC,SAAS,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAA,kBAAC,EAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;QACrM,MAAM,KAAK,CAAC,MAAM,EAAE,CAAC;IACvB,CAAC;IACD,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,EAAE;QACxD,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC;YAC/B,EAAE,EAAE,CAAC;YACL,IAAI,EAAE,WAAW;YACjB,IAAI,EAAE,CAAC,CAAC,SAAS,IAAI,EAAE,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,IAAI,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAE;YAClG,QAAQ,EAAE,CAAC,CAAC,QAAQ;SACrB,CAAC,CAAC,CAAC;QACJ,MAAM,GAAG,GAAe;YACtB,IAAI,EAAE,CAAC,QAAQ,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO;YAChD,EAAE;YACF,CAAC;YACD,CAAC,EAAE,CAAC,CAAC,CAAC;YACN,OAAO,EAAE,CAAC,CAAC,OAAO;YAClB,SAAS;YACT,KAAK,EAAE,EAAE,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS;YACzC,UAAU,EAAE,WAAW;YACvB,KAAK;YACL,OAAO,EAAE,GAAG,CAAC,EAAE,CAAE,CAAC,OAAO;YACzB,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAE,CAAC,QAAQ;YAC3B,aAAa,EAAE,IAAA,kBAAC,EAAC,CAAC,CAAC,aAAa,IAAI,MAAM,CAAC;YAC3C,gBAAgB,EAAE,IAAA,kBAAC,EAAC,OAAO,CAAC;YAC5B,UAAU,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS;YAC/C,GAAG,CAAC,CAAC,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,CAAC;SAC7B,CAAC;QACF,MAAM,KAAK,GAAG,GAAG,CAAC,QAAQ,KAAK,SAAS,IAAI,GAAG,CAAC,UAAU,KAAK,SAAS,IAAI,GAAG,CAAC,WAAW,KAAK,SAAS,CAAC;QAC1G,IAAI,KAAK;YAAE,GAAG,CAAC,eAAe,GAAG,IAAI,CAAC;QACtC,MAAM,OAAO,GAAG,IAAA,gBAAI,EAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAC3C,IAAA,uBAAa,EAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAA,0BAAK,EAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE;YACzD,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC;YACjC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,yBAAyB,EAAE,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,GAAG,OAAO,CAAC,GAAG,EAAE,yBAAyB,EAAE,SAAS,EAAE;SAC3H,CAAC,CAAC;QACH,IAAI,EAAE,GAAG,EAAE,CAAC;QACZ,IAAI,EAAE,GAAG,EAAE,CAAC;QACZ,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,OAAO,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,EAAE;YACzC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACzB,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC;gBACzD,IAAI,IAAI,GAAQ,IAAI,CAAC,CAAC,yDAAyD;gBAC/E,IAAI,CAAC;oBACH,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBACxC,CAAC;gBAAC,MAAM,CAAC;oBACP,gBAAgB;gBAClB,CAAC;gBACD,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,QAAQ,IAAI,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;YACrH,CAAC,CAAC,CAAC;YACH,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAA,kBAAC,EAAC,CAAC,CAAC,WAAW,IAAI,OAAO,CAAC,CAAC,CAAC;YACpF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC;QAChD,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACzC,KAAK,EAAE,KAAK,EAAE,CAAC;IACf,MAAM,QAAQ,GAAG,KAAK,EAAE,GAAG,IAAI,EAAE,CAAC;IAClC,IAAA,gBAAM,EAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,QAAQ,EAAE,CAAC;AACxD,CAAC;AAED,iGAAiG;AAC1F,KAAK,UAAU,aAAa,CAAC,CAMnC;IACC,MAAM,GAAG,GAAG,IAAA,qBAAW,EAAC,IAAA,gBAAI,EAAC,IAAA,gBAAM,GAAE,EAAE,aAAa,CAAC,CAAC,CAAC;IACvD,MAAM,SAAS,GAAG,IAAA,yBAAW,EAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC;IACjD,MAAM,KAAK,GAAG,MAAM,IAAA,6BAAY,EAAC,CAAC,CAAC,CAAC;IACpC,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAA,wBAAgB,EAAC,IAAA,gBAAI,EAAC,GAAG,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC,EAAE,CAAC,CAAC,CAAC;IACtF,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,IAAI,EAAE,KAAK,CAAC,CAAC,CAAE,EAAE,QAAQ,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;IACvG,MAAM,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACtB,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE;QAC9B,MAAM,GAAG,GAAe;YACtB,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,aAAa;YAC5C,EAAE;YACF,CAAC,EAAE,CAAC;YACJ,SAAS;YACT,UAAU,EAAE,WAAW;YACvB,KAAK;YACL,OAAO,EAAE,GAAG,CAAC,EAAE,CAAE,CAAC,OAAO;YACzB,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAE,CAAC,QAAQ;YAC3B,aAAa,EAAE,IAAA,kBAAC,EAAC,CAAC,CAAC,aAAa,IAAI,MAAM,CAAC;YAC3C,gBAAgB,EAAE,IAAA,kBAAC,EAAC,OAAO,CAAC;YAC5B,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC,KAAK,EAAE;SACrC,CAAC;QACF,MAAM,OAAO,GAAG,IAAA,gBAAI,EAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,CAAC;QAC3C,IAAA,uBAAa,EAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC;QAC5C,MAAM,KAAK,GAAG,IAAA,0BAAK,EAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,CAAC,CAAC;QAClG,IAAI,EAAE,GAAG,EAAE,CAAC;QACZ,IAAI,EAAE,GAAG,EAAE,CAAC;QACZ,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC;QAC1C,OAAO,IAAI,OAAO,CAAa,CAAC,OAAO,EAAE,EAAE;YACzC,MAAM,MAAM,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,IAAA,kBAAC,EAAC,CAAC,CAAC,WAAW,IAAI,OAAO,CAAC,CAAC,CAAC;YACpF,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,EAAE;gBACzB,YAAY,CAAC,MAAM,CAAC,CAAC;gBACrB,MAAM,IAAI,GAAG,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,GAAG,EAAE,CAAC;gBACzD,IAAI,IAAI,GAAQ,IAAI,CAAC,CAAC,yDAAyD;gBAC/E,IAAI,CAAC;oBACH,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;gBACxC,CAAC;gBAAC,MAAM,CAAC;oBACP,gBAAgB;gBAClB,CAAC;gBACD,OAAO,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,CAAC,CAAC;YACxG,CAAC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACzC,IAAA,gBAAM,EAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9C,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE,CAAC;AAC9C,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Multiplier for every launcher/test timeout, from `PCA_MPC_TEST_TIMEOUT_SCALE` (default 1; raise it on a slow machine). */
|
|
2
|
+
export declare const TIMEOUT_SCALE: number;
|
|
3
|
+
/** Scale a duration (ms) by the one timeout knob. */
|
|
4
|
+
export declare const T: (ms: number) => number;
|
|
5
|
+
/** `count` DISTINCT free ephemeral ports, all held open at the same time (so they cannot collide with each other) and released together. */
|
|
6
|
+
export declare function reservePorts(count: number): Promise<number[]>;
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.T = exports.TIMEOUT_SCALE = void 0;
|
|
37
|
+
exports.reservePorts = reservePorts;
|
|
38
|
+
/**
|
|
39
|
+
* Small helpers the local multi-process launcher (`launch-local.ts`) shares with the tests: the one timeout-scale knob and
|
|
40
|
+
* distinct free loopback ports.
|
|
41
|
+
*/
|
|
42
|
+
const net = __importStar(require("node:net"));
|
|
43
|
+
const parsed = Number(process.env['PCA_MPC_TEST_TIMEOUT_SCALE'] ?? '1');
|
|
44
|
+
/** Multiplier for every launcher/test timeout, from `PCA_MPC_TEST_TIMEOUT_SCALE` (default 1; raise it on a slow machine). */
|
|
45
|
+
exports.TIMEOUT_SCALE = Number.isFinite(parsed) && parsed > 0 ? parsed : 1;
|
|
46
|
+
/** Scale a duration (ms) by the one timeout knob. */
|
|
47
|
+
const T = (ms) => Math.ceil(ms * exports.TIMEOUT_SCALE);
|
|
48
|
+
exports.T = T;
|
|
49
|
+
/** `count` DISTINCT free ephemeral ports, all held open at the same time (so they cannot collide with each other) and released together. */
|
|
50
|
+
async function reservePorts(count) {
|
|
51
|
+
const servers = [];
|
|
52
|
+
const ports = [];
|
|
53
|
+
for (let i = 0; i < count; i++) {
|
|
54
|
+
const s = net.createServer();
|
|
55
|
+
await new Promise((res, rej) => {
|
|
56
|
+
s.once('error', rej);
|
|
57
|
+
s.listen(0, '127.0.0.1', () => res());
|
|
58
|
+
});
|
|
59
|
+
servers.push(s);
|
|
60
|
+
ports.push(s.address().port);
|
|
61
|
+
}
|
|
62
|
+
await Promise.all(servers.map((s) => new Promise((r) => s.close(() => r()))));
|
|
63
|
+
return ports;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=launch-support.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"launch-support.js","sourceRoot":"","sources":["../../src/net/launch-support.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAcA,oCAcC;AA5BD;;;GAGG;AACH,8CAAgC;AAEhC,MAAM,MAAM,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,IAAI,GAAG,CAAC,CAAC;AACxE,6HAA6H;AAChH,QAAA,aAAa,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC;AAEhF,qDAAqD;AAC9C,MAAM,CAAC,GAAG,CAAC,EAAU,EAAU,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,GAAG,qBAAa,CAAC,CAAC;AAA1D,QAAA,CAAC,KAAyD;AAEvE,4IAA4I;AACrI,KAAK,UAAU,YAAY,CAAC,KAAa;IAC9C,MAAM,OAAO,GAAiB,EAAE,CAAC;IACjC,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,EAAE,CAAC,EAAE,EAAE,CAAC;QAC/B,MAAM,CAAC,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;QAC7B,MAAM,IAAI,OAAO,CAAO,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACnC,CAAC,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;YACrB,CAAC,CAAC,MAAM,CAAC,CAAC,EAAE,WAAW,EAAE,GAAG,EAAE,CAAC,GAAG,EAAE,CAAC,CAAC;QACxC,CAAC,CAAC,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAChB,KAAK,CAAC,IAAI,CAAE,CAAC,CAAC,OAAO,EAAsB,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IACD,MAAM,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,OAAO,CAAO,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IACpF,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Authenticated, confidential, fail-closed point-to-point mesh over TLS 1.3 (research prototype).
|
|
3
|
+
*
|
|
4
|
+
* - MUTUAL TLS with PINNED self-signed certificates (generated per run by `certs.ts`). A peer is
|
|
5
|
+
* identified by the SHA-256 fingerprint of its certificate, never by anything it claims; the claimed
|
|
6
|
+
* id in the hello frame must agree with the pinned fingerprint.
|
|
7
|
+
* - Strict framing + per-link sequence numbers. A malformed frame, a duplicate / replayed frame, a
|
|
8
|
+
* skipped (out-of-order) frame, a frame for the wrong round or session, or an oversize length
|
|
9
|
+
* prefix aborts the whole run with an ATTRIBUTABLE `NetAbort` naming the sender.
|
|
10
|
+
* - Timeouts on every receive (no hangs); a silent peer is blamed after `recvTimeoutMs`.
|
|
11
|
+
* - ABORT PROPAGATION: the first failure poisons the mesh, wakes every pending receive, best-effort
|
|
12
|
+
* sends an `abort` frame to every peer (so they stop immediately and learn who we blame), then
|
|
13
|
+
* closes the sockets. Once failed, nothing further is sent as protocol data (fail closed).
|
|
14
|
+
*
|
|
15
|
+
* Network faults (drop, truncate, bit-flip, reorder, duplicate at the TCP level) are all caught by TLS
|
|
16
|
+
* record authentication and surface as `disconnect` on that link. Application-level misbehaviour
|
|
17
|
+
* (replay, skipped sequence, garbage, wrong round) is caught by the framing checks here. See the tests.
|
|
18
|
+
*/
|
|
19
|
+
import { type Frame, NetAbort } from './wire';
|
|
20
|
+
export interface NodeAddr {
|
|
21
|
+
id: number;
|
|
22
|
+
host: string;
|
|
23
|
+
port: number;
|
|
24
|
+
/** The node's PUBLIC certificate (PEM): pinned trust anchor + identity. */
|
|
25
|
+
certPem: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Time source for every DECISION the mesh makes by time (receive deadlines, connect deadline, dial retry). The default is the
|
|
29
|
+
* wall clock; tests inject a virtual clock so an outcome never depends on how loaded the machine is. A deadline is always a
|
|
30
|
+
* parameter (`timeoutMs`) and is recorded on the resulting `NetAbort` (`deadlineMs`).
|
|
31
|
+
*/
|
|
32
|
+
export interface MeshClock {
|
|
33
|
+
now(): number;
|
|
34
|
+
/** Schedule `fn` after `ms` of clock time; returns a handle for `clearTimer`. */
|
|
35
|
+
setTimer(fn: () => void, ms: number): unknown;
|
|
36
|
+
clearTimer(handle: unknown): void;
|
|
37
|
+
}
|
|
38
|
+
export declare const wallClock: MeshClock;
|
|
39
|
+
export interface MeshConfig {
|
|
40
|
+
/** Time source for deadlines (default: wall clock). */
|
|
41
|
+
clock?: MeshClock;
|
|
42
|
+
selfId: number;
|
|
43
|
+
/** Every node in the session (including self). Only nodes in `linkTo` get a connection. */
|
|
44
|
+
nodes: NodeAddr[];
|
|
45
|
+
/** Node ids this node maintains a link to (default: all others). */
|
|
46
|
+
linkTo?: number[];
|
|
47
|
+
keyPem: string;
|
|
48
|
+
certPem: string;
|
|
49
|
+
sessionId: string;
|
|
50
|
+
listenHost?: string;
|
|
51
|
+
connectTimeoutMs?: number;
|
|
52
|
+
recvTimeoutMs?: number;
|
|
53
|
+
/**
|
|
54
|
+
* TEST HOOK: a (malicious) sender rewriting its own outgoing frames. Refused unless `unsafeTestHooks` is
|
|
55
|
+
* also `true`; the production entry point (`party-main`) only sets that from an explicit test environment.
|
|
56
|
+
*/
|
|
57
|
+
tamper?: (ev: TamperEvent) => Buffer[];
|
|
58
|
+
/** Explicit opt-in required for `tamper`. Leave unset in production. */
|
|
59
|
+
unsafeTestHooks?: boolean;
|
|
60
|
+
/** Most unread frames queued per link before the sender is blamed with `flood` (default 1024). */
|
|
61
|
+
maxInboxFrames?: number;
|
|
62
|
+
/** Most unread frame bytes queued per link before the sender is blamed with `flood` (default 32 MiB). */
|
|
63
|
+
maxInboxBytes?: number;
|
|
64
|
+
}
|
|
65
|
+
/** Most non-fatal observations kept in `Mesh.events`; further ones are only counted. */
|
|
66
|
+
export declare const MAX_MESH_EVENTS = 64;
|
|
67
|
+
export interface TamperEvent {
|
|
68
|
+
to: number;
|
|
69
|
+
frame: Frame;
|
|
70
|
+
/** The honest encoding of the frame. */
|
|
71
|
+
raw: Buffer;
|
|
72
|
+
}
|
|
73
|
+
export interface LinkStats {
|
|
74
|
+
peer: number;
|
|
75
|
+
appBytesOut: number;
|
|
76
|
+
appBytesIn: number;
|
|
77
|
+
framesOut: number;
|
|
78
|
+
framesIn: number;
|
|
79
|
+
tlsBytesWritten: number;
|
|
80
|
+
tlsBytesRead: number;
|
|
81
|
+
}
|
|
82
|
+
export declare class Mesh {
|
|
83
|
+
readonly selfId: number;
|
|
84
|
+
private readonly cfg;
|
|
85
|
+
private readonly links;
|
|
86
|
+
private readonly pinned;
|
|
87
|
+
private readonly ev;
|
|
88
|
+
private server;
|
|
89
|
+
private failure;
|
|
90
|
+
private finished;
|
|
91
|
+
private readonly clock;
|
|
92
|
+
private readonly recvTimeoutMs;
|
|
93
|
+
private readonly connectTimeoutMs;
|
|
94
|
+
/** Non-fatal observations (e.g. a TLS client rejected at the door) for evidence logs. */
|
|
95
|
+
readonly events: string[];
|
|
96
|
+
/** Observations beyond `MAX_MESH_EVENTS` that were counted but not stored. */
|
|
97
|
+
eventsDropped: number;
|
|
98
|
+
private readonly maxInboxFrames;
|
|
99
|
+
private readonly maxInboxBytes;
|
|
100
|
+
constructor(cfg: MeshConfig);
|
|
101
|
+
private note;
|
|
102
|
+
/** The session id every frame on this mesh carries (used to bind sub-protocols to this session). */
|
|
103
|
+
get sessionId(): string;
|
|
104
|
+
get peers(): number[];
|
|
105
|
+
get failed(): NetAbort | null;
|
|
106
|
+
/** Listen, dial every lower-numbered link target, and wait until all links are authenticated. */
|
|
107
|
+
connect(): Promise<void>;
|
|
108
|
+
private dial;
|
|
109
|
+
private onIncoming;
|
|
110
|
+
private attach;
|
|
111
|
+
private onData;
|
|
112
|
+
private onClosed;
|
|
113
|
+
private sendFrame;
|
|
114
|
+
/** Send a protocol message to one peer. Throws the mesh failure if already aborted (fail closed). */
|
|
115
|
+
send(to: number, round: string, payload: unknown): void;
|
|
116
|
+
broadcast(round: string, payload: unknown, to?: readonly number[]): void;
|
|
117
|
+
/** ECDSA-P256/SHA-256 signature over `data` with this node's TLS identity key (transferable: verifiable against the pinned certificate). */
|
|
118
|
+
sign(data: Uint8Array): Buffer;
|
|
119
|
+
/** Verify `sig` over `data` against the PINNED certificate of node `peer`. False on any failure (never throws). */
|
|
120
|
+
verify(peer: number, data: Uint8Array, sig: Uint8Array): boolean;
|
|
121
|
+
/** Receive the next message from `from`, which must belong to `round`. Times out; never hangs. */
|
|
122
|
+
recv(from: number, round: string, timeoutMs?: number): Promise<unknown>;
|
|
123
|
+
/** Receive `round` from every peer in `from` concurrently. A failure on any link rejects the whole call. */
|
|
124
|
+
collect(round: string, from?: readonly number[], timeoutMs?: number): Promise<Map<number, unknown>>;
|
|
125
|
+
/**
|
|
126
|
+
* Poison the mesh: record the first failure, tell EVERY peer except `skipPeer` (the one that just told us;
|
|
127
|
+
* forwarding the original accusation so an innocent bystander is never blamed for merely closing), close all.
|
|
128
|
+
*/
|
|
129
|
+
fail(err: NetAbort, skipPeer?: number): void;
|
|
130
|
+
private sendFrameRaw;
|
|
131
|
+
/** Normal completion: flush and close. Peers that are still reading will see EOF only after our data. */
|
|
132
|
+
finish(): Promise<void>;
|
|
133
|
+
private closeAll;
|
|
134
|
+
stats(): LinkStats[];
|
|
135
|
+
}
|