@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.
Files changed (85) hide show
  1. package/README.md +81 -3
  2. package/dist/beaver.js +4 -0
  3. package/dist/beaver.js.map +1 -1
  4. package/dist/compose.d.ts +9 -2
  5. package/dist/compose.js +24 -1
  6. package/dist/compose.js.map +1 -1
  7. package/dist/ec.d.ts +6 -3
  8. package/dist/ec.js +27 -9
  9. package/dist/ec.js.map +1 -1
  10. package/dist/enc.d.ts +46 -0
  11. package/dist/enc.js +88 -0
  12. package/dist/enc.js.map +1 -0
  13. package/dist/endemic-ot.js +24 -1
  14. package/dist/endemic-ot.js.map +1 -1
  15. package/dist/hybrid-ot.js +3 -0
  16. package/dist/hybrid-ot.js.map +1 -1
  17. package/dist/kem-ot.js +2 -0
  18. package/dist/kem-ot.js.map +1 -1
  19. package/dist/mascot.d.ts +81 -30
  20. package/dist/mascot.js +232 -113
  21. package/dist/mascot.js.map +1 -1
  22. package/dist/net/certs.d.ts +14 -0
  23. package/dist/net/certs.js +30 -0
  24. package/dist/net/certs.js.map +1 -0
  25. package/dist/net/faults.d.ts +49 -0
  26. package/dist/net/faults.js +222 -0
  27. package/dist/net/faults.js.map +1 -0
  28. package/dist/net/forensics.d.ts +81 -0
  29. package/dist/net/forensics.js +181 -0
  30. package/dist/net/forensics.js.map +1 -0
  31. package/dist/net/gadget.d.ts +44 -0
  32. package/dist/net/gadget.js +102 -0
  33. package/dist/net/gadget.js.map +1 -0
  34. package/dist/net/index.d.ts +11 -0
  35. package/dist/net/index.js +28 -0
  36. package/dist/net/index.js.map +1 -0
  37. package/dist/net/launch-local.d.ts +53 -0
  38. package/dist/net/launch-local.js +190 -0
  39. package/dist/net/launch-local.js.map +1 -0
  40. package/dist/net/launch-support.d.ts +6 -0
  41. package/dist/net/launch-support.js +65 -0
  42. package/dist/net/launch-support.js.map +1 -0
  43. package/dist/net/mesh.d.ts +135 -0
  44. package/dist/net/mesh.js +491 -0
  45. package/dist/net/mesh.js.map +1 -0
  46. package/dist/net/offline-net.d.ts +58 -0
  47. package/dist/net/offline-net.js +485 -0
  48. package/dist/net/offline-net.js.map +1 -0
  49. package/dist/net/ot-net.d.ts +42 -0
  50. package/dist/net/ot-net.js +219 -0
  51. package/dist/net/ot-net.js.map +1 -0
  52. package/dist/net/pa.d.ts +65 -0
  53. package/dist/net/pa.js +118 -0
  54. package/dist/net/pa.js.map +1 -0
  55. package/dist/net/party-main.d.ts +48 -0
  56. package/dist/net/party-main.js +146 -0
  57. package/dist/net/party-main.js.map +1 -0
  58. package/dist/net/prep.d.ts +40 -0
  59. package/dist/net/prep.js +12 -0
  60. package/dist/net/prep.js.map +1 -0
  61. package/dist/net/protocol.d.ts +126 -0
  62. package/dist/net/protocol.js +655 -0
  63. package/dist/net/protocol.js.map +1 -0
  64. package/dist/net/wire.d.ts +89 -0
  65. package/dist/net/wire.js +242 -0
  66. package/dist/net/wire.js.map +1 -0
  67. package/dist/ot.d.ts +176 -17
  68. package/dist/ot.js +479 -252
  69. package/dist/ot.js.map +1 -1
  70. package/dist/otx.d.ts +76 -0
  71. package/dist/otx.js +238 -0
  72. package/dist/otx.js.map +1 -0
  73. package/dist/runner.d.ts +1 -1
  74. package/dist/runner.js +6 -1
  75. package/dist/runner.js.map +1 -1
  76. package/dist/sharing.d.ts +2 -0
  77. package/dist/sharing.js +7 -4
  78. package/dist/sharing.js.map +1 -1
  79. package/dist/spdz-runner.d.ts +20 -3
  80. package/dist/spdz-runner.js +21 -3
  81. package/dist/spdz-runner.js.map +1 -1
  82. package/dist/spdz.d.ts +96 -22
  83. package/dist/spdz.js +196 -47
  84. package/dist/spdz.js.map +1 -1
  85. package/package.json +15 -6
package/dist/ot.d.ts CHANGED
@@ -47,7 +47,14 @@
47
47
  * random weights `χ_j ∈ GF(2^κ)` (one per row, bound to `u` by a Fiat–Shamir hash here), the
48
48
  * receiver reveals `x = Σ_j b_j·χ_j` and `t = Σ_j χ_j·t_j`, and the sender checks
49
49
  * `Σ_j χ_j·q_j == t ⊕ x·s` in GF(2^κ). Honestly this always holds (`q_j = t_j ⊕ b_j·s`); a receiver
50
- * who deviated in `u` satisfies it with probability ≤ `2^{-κ} = 2^{-128}`, so a deviation ABORTS.
50
+ * who deviated in `u` is caught, so a deviation ABORTS. The honest statement of the bound is the KOS
51
+ * STATISTICAL parameter `s = SSEC = 128`, NOT `2^{-κ}`: a receiver that deviates in a few columns passes by
52
+ * guessing the matching bits of the selector `s`, and the 2015 proof (ePrint 2015/546) was additionally shown
53
+ * to rest on an incorrect lemma (Roy, CRYPTO 2022). Roy's attacks give the receiver success
54
+ * about `2^{-s}` with `s` extra rows, and the KOS proof is still open (Roy leaves a sound proof to future work), so
55
+ * this module sets `s = SSEC = 128` extra rows (was 64): the best KNOWN attack then succeeds with probability about
56
+ * `2^{-128}`. That is an argument from the attack analysis, NOT a proof; we did not implement SoftSpokenOT's own
57
+ * (different, small-field VOLE) consistency check, whose parameters we could not verify from the paper.
51
58
  * The check is run over `m + κ + SSEC` rows — the extra `κ + SSEC` random "sacrifice" OT rows mask
52
59
  * the revealed combination (receiver privacy) and give statistical soundness. This makes the OT
53
60
  * extension **malicious-secure**, not just semi-honest.
@@ -64,9 +71,12 @@ export declare const KAPPA = 128;
64
71
  /**
65
72
  * KOS statistical-security parameter: the number of EXTRA random check-OT rows (beyond the `κ` that
66
73
  * mask the revealed combination) appended to every extension round. Together `κ + SSEC` padding rows
67
- * give the correlation check its receiver-privacy and statistical soundness margin.
74
+ * give the correlation check its receiver-privacy and statistical soundness margin. Roy (CRYPTO 2022, ePrint
75
+ * 2022/192) shows the KOS proof is flawed and that the attacks succeed with probability about 2^-s for `s` extra
76
+ * rows; `s = 128` (raised from 64, a WIRE CHANGE: the matrix has 64 more rows per round) makes the best known attack
77
+ * about 2^-128. Not a proof.
68
78
  */
69
- export declare const SSEC = 64;
79
+ export declare const SSEC = 128;
70
80
  /** Raised when the KOS correlation check fails: a cheating OT-extension receiver is detected → ABORT. */
71
81
  export declare class MalOtAbort extends Error {
72
82
  constructor(message: string);
@@ -82,6 +92,47 @@ export interface OtRandom {
82
92
  export declare function splitMix64(seed: bigint): () => bigint;
83
93
  /** Build an OtRandom from a SplitMix64-style 64-bit stream (deterministic; CSPRNG in production). */
84
94
  export declare function otRandom(next64: () => bigint): OtRandom;
95
+ /**
96
+ * Session binding of one base OT: who runs it, in which session and round. It is folded into the sender's
97
+ * Schnorr challenge AND into every pad, so neither a proof nor a pad carries over to another session,
98
+ * party pair or round. `senderIndex` is the base-OT SENDER (the party that publishes S).
99
+ */
100
+ export interface BaseOtBinding {
101
+ /** 8..64 bytes, unique per session (the network runner uses its session id). */
102
+ sessionId: Uint8Array;
103
+ senderIndex: number;
104
+ receiverIndex: number;
105
+ /** Non-empty label of the protocol round / use, at most 64 bytes. */
106
+ round: string;
107
+ }
108
+ /** Canonical, length-prefixed encoding of a binding (the Schnorr context and part of every KDF input). */
109
+ export declare function bindingBytes(b: BaseOtBinding): Uint8Array;
110
+ /** A fresh binding for an in-process OT (both roles simulated): random session id from `rng`. */
111
+ export declare function randomBinding(rng: OtRandom, round: string, senderIndex?: number, receiverIndex?: number): BaseOtBinding;
112
+ /**
113
+ * Hash of the WHOLE base-OT transcript: binding, the sender's S and every receiver point R_i, in order.
114
+ * Every pad is derived under this hash, so changing the session, S or ANY R_j changes EVERY key.
115
+ */
116
+ export declare function baseOtTranscriptHash(binding: BaseOtBinding, S: Point, R: readonly Point[]): Uint8Array;
117
+ /**
118
+ * Key derivation from a group point, Chou–Orlandi / Simplest-OT style but over the full transcript:
119
+ * `H("ot-kdf" ‖ H(transcript) ‖ index ‖ R_i ‖ P)` → SEED_BYTES bytes.
120
+ */
121
+ export declare function baseOtKdf(transcriptHash: Uint8Array, index: number, Ri: Point, p: Point): Uint8Array;
122
+ /**
123
+ * Derive the KOS row-weights χ_j ∈ GF(2^128) for one extension round (Fiat–Shamir). The sender and
124
+ * receiver both derive the SAME χ from the FULL `u` matrix on the wire, so a cheating receiver cannot
125
+ * pick `u` after seeing χ. In the real protocol χ comes from a secure coin-flip after the receiver
126
+ * commits to `u`; the transcript hash here models that round.
127
+ *
128
+ * The weights are the output of SHAKE256 (an extendable-output function, `node:crypto`) over
129
+ * `TAG ‖ channel binding ‖ round ‖ mExt ‖ every bit of every column of u`, 16 bytes per row — a vetted
130
+ * XOF seeded by the whole transcript, not a fast non-cryptographic stream. (An earlier version expanded a
131
+ * 128-bit digest with SplitMix64, and hashed only the low 128 bits of each column; both are gone.)
132
+ */
133
+ export declare function kosChallenges(binding: Uint8Array, round: number, u: bigint[], mExt: number): bigint[];
134
+ /** The same weights as little-endian u32 words (4 per row), the form the typed kernels consume. */
135
+ export declare function kosChiWords(binding: Uint8Array, round: number, u: bigint[], mExt: number, colBytesList?: Uint8Array[]): Uint32Array;
85
136
  /** Raised when a base OT aborts: a cheating sender (bad proof / inconsistent ciphertext) is detected. */
86
137
  export declare class BaseOtAbort extends Error {
87
138
  constructor(message: string);
@@ -149,7 +200,36 @@ export interface MalRandomOtResult {
149
200
  * No messages are transferred — the pads ARE the random output. `tamper` injects malicious behaviour
150
201
  * for tests. Both parties are simulated in-process.
151
202
  */
152
- export declare function malBaseRandomOT(choices: number[], rng?: OtRandom, tamper?: BaseOtTamper): MalRandomOtResult;
203
+ export declare function malBaseRandomOT(choices: number[], rng?: OtRandom, tamper?: BaseOtTamper, binding?: BaseOtBinding): MalRandomOtResult;
204
+ /** SENDER step 1: S = y·B, T = y·S, and a Schnorr proof of knowledge of y. `y`/`T` stay sender-local. */
205
+ export declare function malBaseOtSenderSetup(rng: OtRandom, binding: BaseOtBinding): {
206
+ y: bigint;
207
+ T: Point;
208
+ S: Point;
209
+ proof: SchnorrProof;
210
+ };
211
+ /**
212
+ * RECEIVER step: validate the sender's point + proof BEFORE forming any R (malicious-sender guard), then
213
+ * choose x_i, form R_i = x_i·B (+ S if c_i=1) and derive recvPad_i = H(x_i·S). Throws `BaseOtAbort`/
214
+ * `PointValidationError` on a bad S or proof.
215
+ */
216
+ export declare function malBaseOtReceiverRespond(S: Point, proof: SchnorrProof, choices: number[], rng: OtRandom, binding: BaseOtBinding): {
217
+ R: Point[];
218
+ recvPads: Uint8Array[];
219
+ };
220
+ /** SENDER step 2: validate every received R_i (malicious-receiver / small-subgroup guard), derive both pads. */
221
+ export declare function malBaseOtSenderDerive(y: bigint, T: Point, R: Point[], S: Point, binding: BaseOtBinding): Array<[Uint8Array, Uint8Array]>;
222
+ /** SENDER step 3 (chosen-message wrapper): one-time-pad each message under its pad and commit to it. */
223
+ export declare function baseOtSenderEncrypt(messages: Array<[Uint8Array, Uint8Array]>, senderPads: Array<[Uint8Array, Uint8Array]>): {
224
+ ct: Array<[Uint8Array, Uint8Array]>;
225
+ com: Array<[Uint8Array, Uint8Array]>;
226
+ };
227
+ /**
228
+ * RECEIVER step 3: decrypt the chosen ciphertext with its pad, then CHECK the commitment it can open;
229
+ * `BaseOtAbort` on any inconsistency (a cheating sender). Every ciphertext/commitment must have the shape
230
+ * the receiver expects (equal-length byte strings of at most the pad width).
231
+ */
232
+ export declare function baseOtReceiverDecrypt(choices: number[], recvPads: Uint8Array[], ct: Array<[Uint8Array, Uint8Array]>, com: Array<[Uint8Array, Uint8Array]>): Uint8Array[];
153
233
  /**
154
234
  * Run `count` MALICIOUS-secure base OTs in one batch (chosen-message, over the random OT above).
155
235
  * `messages[i] = [m0, m1]` (SEED_BYTES each), the sender's pair; `choices[i] ∈ {0,1}` the receiver's
@@ -157,25 +237,99 @@ export declare function malBaseRandomOT(choices: number[], rng?: OtRandom, tampe
157
237
  * the receiver recovers `m_{i,c_i}` and checks the commitment, aborting (`BaseOtAbort`) on any
158
238
  * inconsistency. Returns the receiver's recovered messages and the full transcript.
159
239
  */
160
- export declare function baseOT(messages: Array<[Uint8Array, Uint8Array]>, choices: number[], rng?: OtRandom, tamper?: BaseOtTamper): BaseOtResult;
240
+ export declare function baseOT(messages: Array<[Uint8Array, Uint8Array]>, choices: number[], rng?: OtRandom, tamper?: BaseOtTamper, binding?: BaseOtBinding): BaseOtResult;
241
+ /** One extension round's receiver -> sender message: the u matrix and the KOS-revealed (x, t) pair. */
242
+ export interface ExtRoundMsg {
243
+ /** KAPPA columns of `mExt = m + KAPPA + SSEC` bits each. */
244
+ u: bigint[];
245
+ /** x = Σ_j b_j·χ_j in GF(2^128). */
246
+ x: bigint;
247
+ /** t = Σ_i x^i·(Σ_j t_i[j]·χ_j). */
248
+ tComb: bigint;
249
+ }
250
+ /** The receiver's private state between sending `ExtRoundMsg` and receiving the sender's ciphertexts. */
251
+ export interface ExtPending {
252
+ m: number;
253
+ choiceBits: number[];
254
+ /** The receiver's `t` matrix: COLS columns of `W` u32 words, concatenated. */
255
+ t: Uint32Array;
256
+ W: number;
257
+ /** Channel-global index of this round's first row (R4-12 hash tweak). */
258
+ rowOffset: number;
259
+ }
161
260
  /**
162
- * An IKNP OT-extension channel between a fixed RECEIVER (choice bits) and SENDER (message pairs). The
163
- * κ base OTs run lazily on the first `extend`; each later `extend(m)` is a cheap PRG+hash round. The
164
- * channel is stateful (advances per-seed PRG counters) so many rounds compose into one amortized setup.
261
+ * The OT-extension RECEIVER (holds the choice bits). In the base OT it is the SENDER: it draws κ seed pairs
262
+ * and offers them; after the base OT it expands them with the PRG.
263
+ */
264
+ export declare class OtExtReceiver {
265
+ private readonly rng;
266
+ private readonly kosBinding;
267
+ private seed0;
268
+ private seed1;
269
+ private blk0;
270
+ private blk1;
271
+ private round;
272
+ /** Rows hashed in earlier rounds (R4-12 global tweak offset); advanced by m per round, in step with the sender. */
273
+ private rowsDone;
274
+ private readonly tweakDomain;
275
+ ready: boolean;
276
+ /**
277
+ * TEST-ONLY: called with the honest `u` matrix just before it goes on the wire; may mutate it (a malicious
278
+ * receiver encoding inconsistent choices). The KOS values are computed over the tampered `u`.
279
+ */
280
+ tamperU?: (u: bigint[], round: number) => void;
281
+ constructor(rng: OtRandom, kosBinding: Uint8Array);
282
+ /** Base-OT messages: the κ seed pairs this party offers as the base-OT sender. */
283
+ makeSeeds(): Array<[Uint8Array, Uint8Array]>;
284
+ /** Round start: form u and the KOS pair for `choiceBits` (the real rows); returns the wire message + pending state. */
285
+ begin(choiceBits: number[]): {
286
+ msg: ExtRoundMsg;
287
+ pending: ExtPending;
288
+ };
289
+ /** Round end: recover the chosen messages from the sender's ciphertexts. */
290
+ finish(pending: ExtPending, y0: bigint[], y1: bigint[]): bigint[];
291
+ }
292
+ /** The OT-extension SENDER (holds the message pairs). In the base OT it is the RECEIVER with selector `s`. */
293
+ export declare class OtExtSender {
294
+ private readonly rng;
295
+ private readonly kosBinding;
296
+ private s;
297
+ private sBits;
298
+ private seeds;
299
+ private blk;
300
+ private round;
301
+ private rowsDone;
302
+ private readonly tweakDomain;
303
+ ready: boolean;
304
+ constructor(rng: OtRandom, kosBinding: Uint8Array);
305
+ /** Draw the secret selector s ∈ {0,1}^κ (the base-OT choice bits). */
306
+ makeSelector(): number[];
307
+ /** Install the κ seeds learned from the base OT. */
308
+ setSeeds(seeds: Uint8Array[]): void;
309
+ get selector(): bigint;
310
+ /**
311
+ * Verify the receiver's round message (structure + KOS correlation check) and return the ciphertexts for
312
+ * the `m` real rows. A cheating receiver is caught here: `MalOtAbort`.
313
+ */
314
+ respond(msg: ExtRoundMsg, msg0: bigint[], msg1: bigint[]): {
315
+ y0: bigint[];
316
+ y1: bigint[];
317
+ };
318
+ }
319
+ /**
320
+ * An IKNP/KOS OT-extension channel between a fixed RECEIVER (choice bits) and SENDER (message pairs), both
321
+ * simulated in-process. The κ base OTs run lazily on the first `extend`; each later `extend(m)` is a cheap
322
+ * PRG+hash round. The channel is stateful (advances per-seed PRG counters) so many rounds compose into one
323
+ * amortized setup. The two roles are the standalone `OtExtReceiver` / `OtExtSender` (used over the network).
165
324
  */
166
325
  export declare class OtChannel {
167
326
  private readonly rng;
168
327
  /** Optional post-quantum (or otherwise custom) base OT for the κ setup OTs; defaults to EC `baseOT`. */
169
328
  private readonly baseOtFn?;
329
+ private readonly bindingOpt?;
330
+ private recv?;
331
+ private send?;
170
332
  private ready;
171
- private s;
172
- private sBits;
173
- private senderSeeds;
174
- private senderBlk;
175
- private recvSeed0;
176
- private recvSeed1;
177
- private recvBlk0;
178
- private recvBlk1;
179
333
  /** The base-OT transcript (available after setup) — exposed for inspection/tests. */
180
334
  baseTranscript?: BaseOtTranscript;
181
335
  /**
@@ -186,13 +340,18 @@ export declare class OtChannel {
186
340
  * a non-trivial tamper is caught — the real malicious-receiver attack that KOS defeats.
187
341
  */
188
342
  tamperU?: (u: bigint[], round: number) => void;
189
- private round;
190
343
  /**
191
344
  * `rng` defaults to the CSPRNG (`secureOtRandom`, `node:crypto`) — production randomness. Pass a
192
345
  * deterministic `otRandom(splitMix64(seed))` ONLY to make a test bit-reproducible (docs §7.1 item c).
193
346
  */
194
347
  constructor(rng?: OtRandom, opts?: {
195
348
  baseOtFn?: BaseOtFn;
349
+ /**
350
+ * Session binding of this channel (both parties must agree on it). `senderIndex` is the EXTENSION
351
+ * RECEIVER (it plays base-OT sender), `receiverIndex` the extension sender. Omitted for an in-process
352
+ * channel: a fresh random session id is drawn from `rng`.
353
+ */
354
+ binding?: Omit<BaseOtBinding, 'round'>;
196
355
  });
197
356
  private setup;
198
357
  /** Selector s as a κ-bit bigint (sender-side secret; exposed only for tests). */