@atlasauth/pca-mpc 0.0.0-stage → 0.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/LICENSE +21 -0
- package/README.md +65 -2
- package/dist/beaver.d.ts +49 -0
- package/dist/beaver.js +72 -0
- package/dist/beaver.js.map +1 -0
- package/dist/compose.d.ts +21 -0
- package/dist/compose.js +33 -0
- package/dist/compose.js.map +1 -0
- package/dist/csprng.d.ts +46 -0
- package/dist/csprng.js +86 -0
- package/dist/csprng.js.map +1 -0
- package/dist/ec.d.ts +130 -0
- package/dist/ec.js +475 -0
- package/dist/ec.js.map +1 -0
- package/dist/endemic-ot.d.ts +209 -0
- package/dist/endemic-ot.js +405 -0
- package/dist/endemic-ot.js.map +1 -0
- package/dist/field.d.ts +34 -0
- package/dist/field.js +65 -0
- package/dist/field.js.map +1 -0
- package/dist/gf128.d.ts +23 -0
- package/dist/gf128.js +59 -0
- package/dist/gf128.js.map +1 -0
- package/dist/hybrid-ot.d.ts +153 -0
- package/dist/hybrid-ot.js +241 -0
- package/dist/hybrid-ot.js.map +1 -0
- package/dist/index.d.ts +29 -0
- package/dist/index.js +46 -0
- package/dist/index.js.map +1 -0
- package/dist/kem-ot.d.ts +292 -0
- package/dist/kem-ot.js +559 -0
- package/dist/kem-ot.js.map +1 -0
- package/dist/mascot.d.ts +189 -0
- package/dist/mascot.js +322 -0
- package/dist/mascot.js.map +1 -0
- package/dist/ot.d.ts +212 -0
- package/dist/ot.js +536 -0
- package/dist/ot.js.map +1 -0
- package/dist/party.d.ts +38 -0
- package/dist/party.js +40 -0
- package/dist/party.js.map +1 -0
- package/dist/runner.d.ts +56 -0
- package/dist/runner.js +97 -0
- package/dist/runner.js.map +1 -0
- package/dist/sharing.d.ts +40 -0
- package/dist/sharing.js +97 -0
- package/dist/sharing.js.map +1 -0
- package/dist/spdz-runner.d.ts +50 -0
- package/dist/spdz-runner.js +107 -0
- package/dist/spdz-runner.js.map +1 -0
- package/dist/spdz.d.ts +136 -0
- package/dist/spdz.js +243 -0
- package/dist/spdz.js.map +1 -0
- package/dist/thermometer.d.ts +22 -0
- package/dist/thermometer.js +41 -0
- package/dist/thermometer.js.map +1 -0
- package/package.json +58 -3
package/dist/index.js
ADDED
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* @atlasauth/pca-mpc — PCA evolution B5 reference prototype.
|
|
4
|
+
*
|
|
5
|
+
* A multi-stakeholder Policy VM composed under secure multi-party computation, so user + org +
|
|
6
|
+
* regulator decide allow / threshold jointly WITHOUT any party revealing its own policy. Two layers:
|
|
7
|
+
* - SEMI-HONEST: additive secret sharing over a prime field + Beaver-triple multiplication
|
|
8
|
+
* (`sharing.ts`, `beaver.ts`, `runner.ts`).
|
|
9
|
+
* - MALICIOUS-WITH-ABORT (dishonest-majority): SPDZ-style authenticated sharing with
|
|
10
|
+
* information-theoretic MACs + a commit-then-open MAC-check that ABORTS on any deviation
|
|
11
|
+
* (`spdz.ts`, `spdz-runner.ts`). Result is correct, or an abort — never a silent wrong answer.
|
|
12
|
+
* See docs/specs/pca-mpc-policy-vm.md for the security model and the trusted-dealer / no-dealer boundary.
|
|
13
|
+
*/
|
|
14
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
15
|
+
if (k2 === undefined) k2 = k;
|
|
16
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
17
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
18
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
19
|
+
}
|
|
20
|
+
Object.defineProperty(o, k2, desc);
|
|
21
|
+
}) : (function(o, m, k, k2) {
|
|
22
|
+
if (k2 === undefined) k2 = k;
|
|
23
|
+
o[k2] = m[k];
|
|
24
|
+
}));
|
|
25
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
26
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
27
|
+
};
|
|
28
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
|
+
__exportStar(require("./field"), exports);
|
|
30
|
+
__exportStar(require("./sharing"), exports);
|
|
31
|
+
__exportStar(require("./beaver"), exports);
|
|
32
|
+
__exportStar(require("./thermometer"), exports);
|
|
33
|
+
__exportStar(require("./party"), exports);
|
|
34
|
+
__exportStar(require("./compose"), exports);
|
|
35
|
+
__exportStar(require("./runner"), exports);
|
|
36
|
+
__exportStar(require("./spdz"), exports);
|
|
37
|
+
__exportStar(require("./spdz-runner"), exports);
|
|
38
|
+
__exportStar(require("./ec"), exports);
|
|
39
|
+
__exportStar(require("./gf128"), exports);
|
|
40
|
+
__exportStar(require("./csprng"), exports);
|
|
41
|
+
__exportStar(require("./ot"), exports);
|
|
42
|
+
__exportStar(require("./kem-ot"), exports);
|
|
43
|
+
__exportStar(require("./hybrid-ot"), exports);
|
|
44
|
+
__exportStar(require("./mascot"), exports);
|
|
45
|
+
__exportStar(require("./endemic-ot"), exports);
|
|
46
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;GAWG;;;;;;;;;;;;;;;;AAEH,0CAAwB;AACxB,4CAA0B;AAC1B,2CAAyB;AACzB,gDAA8B;AAC9B,0CAAwB;AACxB,4CAA0B;AAC1B,2CAAyB;AACzB,yCAAuB;AACvB,gDAA8B;AAC9B,uCAAqB;AACrB,0CAAwB;AACxB,2CAAyB;AACzB,uCAAqB;AACrB,2CAAyB;AACzB,8CAA4B;AAC5B,2CAAyB;AACzB,+CAA6B"}
|
package/dist/kem-ot.d.ts
ADDED
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Post-quantum base OT from ML-KEM — a 1-of-2 oblivious transfer whose hardness rests on Module-LWE
|
|
3
|
+
* (ML-KEM-768, FIPS 203) instead of the curve25519 discrete log. This is the end-game plan's P3
|
|
4
|
+
* ("KEM-based OT from ML-KEM") so the MPC base OT no longer has a classical, quantum-breakable root.
|
|
5
|
+
*
|
|
6
|
+
* ─── THE CONSTRUCTION (be precise and honest) ──────────────────────────────────────────────────────
|
|
7
|
+
* This is the folklore semi-honest 1-of-2 OT from a key-encapsulation mechanism — the "dual-public-key
|
|
8
|
+
* KEM-OT" (closely related to endemic/Masny–Rindal-style OT, but WITHOUT any oblivious-key derivation):
|
|
9
|
+
*
|
|
10
|
+
* RECEIVER, choice bit c, per transfer:
|
|
11
|
+
* • generates TWO *real* ML-KEM keypairs, (pk_c, sk_c) and (pk', sk');
|
|
12
|
+
* • places pk_c at wire index c and pk' at wire index 1−c, and sends the ordered pair (pk_0, pk_1);
|
|
13
|
+
* • KEEPS sk_c and DISCARDS the other secret sk' (this discard is the whole semi-honest assumption).
|
|
14
|
+
* SENDER, messages (m_0, m_1), per transfer:
|
|
15
|
+
* • encapsulates under each received key: (ct_b, ss_b) ← Encaps(pk_b) for b ∈ {0,1};
|
|
16
|
+
* • one-time-pads each message under a random-oracle key: E_b = m_b ⊕ H(b ‖ ss_b), and sends
|
|
17
|
+
* (ct_0, E_0), (ct_1, E_1).
|
|
18
|
+
* RECEIVER recovers ONLY m_c: ss_c ← Decaps(ct_c, sk_c); m_c = E_c ⊕ H(c ‖ ss_c).
|
|
19
|
+
* It cannot recover m_{1−c}: it discarded sk_{1−c}, so ss_{1−c} is hidden by ML-KEM IND-CCA security
|
|
20
|
+
* and H(1−c ‖ ss_{1−c}) is a pseudorandom pad.
|
|
21
|
+
*
|
|
22
|
+
* ─── WHY *THIS* CONSTRUCTION (soundness) ───────────────────────────────────────────────────────────
|
|
23
|
+
* A tempting alternative is an "oblivious public key": derive pk_{1−c} by HASHING some public value so
|
|
24
|
+
* the receiver provably cannot invert it. That is sound for group-based KEMs where a public key is a
|
|
25
|
+
* group element you can hash-to. It is NOT soundly implementable for ML-KEM with the primitive we have:
|
|
26
|
+
* an ML-KEM public key is a structured Module-LWE object (a matrix seed ρ plus t = A·s + e); a hash
|
|
27
|
+
* output is not a valid encapsulation target, and there is no black-box "hash → valid pk whose secret is
|
|
28
|
+
* unknown-to-everyone" for ML-KEM without a trusted setup or a specialised lattice gadget. Rolling one
|
|
29
|
+
* by hand would be exactly the hand-rolled lattice crypto this module forbids. So we use the two-real-
|
|
30
|
+
* keypairs/discard-one-secret variant, which is sound with `ml_kem768` as an opaque IND-CCA KEM.
|
|
31
|
+
*
|
|
32
|
+
* ─── SECURITY MODEL (exactly what is and is not achieved) ──────────────────────────────────────────
|
|
33
|
+
* • Receiver-choice privacy — UNCONDITIONAL, and holds even against a *malicious* sender. The wire
|
|
34
|
+
* message (pk_0, pk_1) is two i.i.d. honest ML-KEM public keys; the choice c only decides which
|
|
35
|
+
* secret the receiver keeps *locally*. The two orderings are therefore identically distributed, so
|
|
36
|
+
* the sender's view is independent of c with probability 1 (no assumption, no abort needed).
|
|
37
|
+
* • Sender privacy (receiver learns nothing about m_{1−c}) — SEMI-HONEST only, under ML-KEM IND-CCA
|
|
38
|
+
* security + H modelled as a random oracle. An honest-but-curious receiver discards sk_{1−c}; given
|
|
39
|
+
* only pk_{1−c} and ct_{1−c} it cannot distinguish ss_{1−c} from random (IND-CCA), so the pad hides
|
|
40
|
+
* m_{1−c}. A MALICIOUS receiver that *keeps both* secrets learns BOTH messages — this base OT does
|
|
41
|
+
* not stop that by itself.
|
|
42
|
+
* • POST-QUANTUM: both guarantees are PQ. Choice privacy is information-theoretic; sender privacy
|
|
43
|
+
* rests on Module-LWE (ML-KEM-768, NIST security level ~3) and a hash in the ROM — no classical
|
|
44
|
+
* discrete-log anywhere, which is the entire point of P3.
|
|
45
|
+
*
|
|
46
|
+
* ─── MALICIOUS-RECEIVER HARDENING (`kemBaseOtMal`, below) ──────────────────────────────────────────
|
|
47
|
+
* The semi-honest base OT above leaves two malicious-receiver surfaces. The committed variant
|
|
48
|
+
* `kemBaseOtMal` closes the one that CAN be closed from an opaque KEM, and documents — precisely,
|
|
49
|
+
* rather than faking a defence — the one that cannot:
|
|
50
|
+
*
|
|
51
|
+
* CLOSED (by an RO-commitment + session binding, mirroring the EC `baseOT`'s commit round):
|
|
52
|
+
* • ADAPTIVE / MALLEABLE / REPLAYED key material. The receiver first sends only a RO-commitment
|
|
53
|
+
* `com = H(rn ‖ pk_0 ‖ pk_1)` to its ordered public keys (and a receiver nonce `rn`); the sender
|
|
54
|
+
* replies with a fresh nonce `sn`; the parties set `sid = H(rn ‖ sn)`; only THEN does the receiver
|
|
55
|
+
* open `(pk_0, pk_1)` and the sender encapsulate, binding every pad to `(sid, com)`. The sender
|
|
56
|
+
* recomputes `com` from the opened keys and ABORTS on any mismatch. So the receiver must fix its
|
|
57
|
+
* keys BEFORE it learns `sn` (no adaptive/precomputed/related-key choice, no cross-session replay),
|
|
58
|
+
* and cannot open keys other than the ones it committed to — exactly the non-malleability the EC
|
|
59
|
+
* base OT gets from `R` being a single committed group element.
|
|
60
|
+
*
|
|
61
|
+
* NOT CLOSABLE from an OPAQUE ML-KEM, and WHY (an impossibility, not a shortcut):
|
|
62
|
+
* • A receiver that simply runs keygen TWICE and keeps BOTH secret keys learns both messages. To
|
|
63
|
+
* stop it the protocol would have to force one slot to a public key whose secret NOBODY knows
|
|
64
|
+
* (the Masny–Rindal "endemic OT" idea: `pk_{1−c}` derived in the public-key space from a random
|
|
65
|
+
* oracle / a common reference). That needs either (i) sampling / adding in ML-KEM's structured
|
|
66
|
+
* public-key space — reaching into the Module-LWE internals this module forbids (no hand-rolled
|
|
67
|
+
* lattice crypto), or (ii) a trusted setup / CRS. Crucially, the SAME decisional-Module-LWE
|
|
68
|
+
* indistinguishability that makes choice privacy hold (a real `pk` ≈ a uniform one) is what makes
|
|
69
|
+
* a cheating "both-keys-real" receiver UNDETECTABLE to the sender: it cannot tell a secretless
|
|
70
|
+
* slot from a real one. So this residue is intrinsic to the opaque primitive.
|
|
71
|
+
*
|
|
72
|
+
* ─── LIFTING THE RESIDUE (how this plugs into the stack) ───────────────────────────────────────────
|
|
73
|
+
* The residue is closed exactly where the EC stack closes its analogue: the KOS OT-extension (`ot.ts`).
|
|
74
|
+
* KOS runs the base OTs with ROLES INVERTED (the extension *sender* is the base *receiver*, holding the
|
|
75
|
+
* secret selector s) and adds the correlation check over sacrifice rows. A base receiver keeping both
|
|
76
|
+
* secrets maps to the extension *sender* learning the extension *receiver*'s seed pairs; the KOS
|
|
77
|
+
* consistency machinery + correlation-robust hash constrain that, raising the overall extension to
|
|
78
|
+
* malicious-with-abort against a cheating extension receiver — the attack IKNP is vulnerable to. So
|
|
79
|
+
* `kemBaseOtMal` is the right base layer: it hardens everything the opaque KEM allows (commitment /
|
|
80
|
+
* binding), and defers only the intrinsic residue to the layer that already handles it.
|
|
81
|
+
*
|
|
82
|
+
* No hand-rolled lattice crypto: all PQ operations go through `ml_kem768` (keygen/encapsulate/
|
|
83
|
+
* decapsulate) as a black box. Randomness follows the module policy — a CSPRNG (`secureOtRandom`) by
|
|
84
|
+
* default, a seeded deterministic stream ONLY when a test passes one.
|
|
85
|
+
*/
|
|
86
|
+
import { type OtChannel, type OtRandom } from './ot';
|
|
87
|
+
/**
|
|
88
|
+
* The random-oracle pad for one slot: `H(TAG ‖ i ‖ b ‖ sharedSecret)` expanded (SHA-256 counter mode)
|
|
89
|
+
* to exactly `len` bytes. `i` binds the transfer index and `b` the slot, so the two pads of one transfer
|
|
90
|
+
* — and the pads across transfers — are domain-separated.
|
|
91
|
+
*/
|
|
92
|
+
export declare function kemOtPad(index: number, slot: number, sharedSecret: Uint8Array, len: number): Uint8Array;
|
|
93
|
+
/** Receiver round-1 wire message: the ordered public-key pairs the sender encapsulates under. */
|
|
94
|
+
export interface KemOtReceiverMessage {
|
|
95
|
+
/** For each transfer i, [pk_0, pk_1]; the chosen key sits at index `choices[i]`. */
|
|
96
|
+
publicKeys: Array<[Uint8Array, Uint8Array]>;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* The receiver's RETAINED state after round 1. An honest receiver keeps ONLY the chosen secret key per
|
|
100
|
+
* transfer (`secretKeys[i]` is `sk_{choices[i]}`); the other secret has been discarded. This is exactly
|
|
101
|
+
* the state the semi-honest model assumes, and the one the tests assert over ("the non-chosen ciphertext
|
|
102
|
+
* does not decrypt under the receiver's state").
|
|
103
|
+
*/
|
|
104
|
+
export interface KemOtReceiverState {
|
|
105
|
+
/** The choice bits, one per transfer. */
|
|
106
|
+
choices: number[];
|
|
107
|
+
/** The chosen secret key per transfer (sk for slot `choices[i]`); the non-chosen secret is discarded. */
|
|
108
|
+
secretKeys: Uint8Array[];
|
|
109
|
+
}
|
|
110
|
+
/** Sender round wire message: the two ciphertexts + two padded messages per transfer. */
|
|
111
|
+
export interface KemOtSenderMessage {
|
|
112
|
+
/** For each transfer i, the ML-KEM ciphertexts [ct_0, ct_1] under [pk_0, pk_1]. */
|
|
113
|
+
ciphertexts: Array<[Uint8Array, Uint8Array]>;
|
|
114
|
+
/** For each transfer i, the one-time-padded messages [E_0, E_1] = [m_0 ⊕ H(0‖ss_0), m_1 ⊕ H(1‖ss_1)]. */
|
|
115
|
+
encrypted: Array<[Uint8Array, Uint8Array]>;
|
|
116
|
+
}
|
|
117
|
+
/** A full KEM base-OT transcript (receiver message + sender message), exposed for inspection/tests. */
|
|
118
|
+
export interface KemBaseOtTranscript extends KemOtReceiverMessage, KemOtSenderMessage {
|
|
119
|
+
}
|
|
120
|
+
export interface KemBaseOtResult {
|
|
121
|
+
/** Receiver's recovered messages m_{i, choices[i]}. */
|
|
122
|
+
received: Uint8Array[];
|
|
123
|
+
transcript: KemBaseOtTranscript;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* RECEIVER round 1: for each choice bit, generate two real ML-KEM keypairs, send both public keys
|
|
127
|
+
* (chosen one at wire index `c`), and retain only the chosen secret key. Returns the wire message AND
|
|
128
|
+
* the retained receiver state.
|
|
129
|
+
*/
|
|
130
|
+
export declare function kemBaseOtReceive(choices: number[], rng?: OtRandom): {
|
|
131
|
+
message: KemOtReceiverMessage;
|
|
132
|
+
state: KemOtReceiverState;
|
|
133
|
+
};
|
|
134
|
+
/**
|
|
135
|
+
* SENDER round: encapsulate under each received public key and one-time-pad each message under
|
|
136
|
+
* `H(slot ‖ sharedSecret)`. `messages[i] = [m_0, m_1]`; the two messages of one transfer must be equal
|
|
137
|
+
* length (padding is derived to that length). Returns the sender wire message.
|
|
138
|
+
*/
|
|
139
|
+
export declare function kemBaseOtSend(messages: Array<[Uint8Array, Uint8Array]>, receiverMessage: KemOtReceiverMessage, rng?: OtRandom): KemOtSenderMessage;
|
|
140
|
+
/**
|
|
141
|
+
* RECEIVER recovery: decapsulate ONLY the chosen ciphertext with the retained secret key and unmask the
|
|
142
|
+
* chosen message. The receiver never touches the non-chosen slot (it has no secret for it). Returns
|
|
143
|
+
* `received[i] = m_{i, choices[i]}`.
|
|
144
|
+
*/
|
|
145
|
+
export declare function kemBaseOtOpen(state: KemOtReceiverState, senderMessage: KemOtSenderMessage): Uint8Array[];
|
|
146
|
+
/**
|
|
147
|
+
* In-process combined simulator (both parties in one call), matching the shape of `baseOT` in `ot.ts`:
|
|
148
|
+
* run `count = choices.length` KEM base OTs and return the receiver's recovered messages plus the full
|
|
149
|
+
* transcript. This is the drop-in the KOS extension consumes (see `OtChannel`'s `baseOtFn` option).
|
|
150
|
+
*/
|
|
151
|
+
export declare function kemBaseOT(messages: Array<[Uint8Array, Uint8Array]>, choices: number[], rng?: OtRandom): KemBaseOtResult;
|
|
152
|
+
/**
|
|
153
|
+
* Wire the ML-KEM base OT into the existing KOS OT-extension: returns the constructor option bag for
|
|
154
|
+
* `OtChannel` that makes it run its κ setup base OTs over `kemBaseOT` (post-quantum) instead of the
|
|
155
|
+
* classical EC Chou–Orlandi `baseOT`. Everything above the base OT (the IKNP matrix, the KOS correlation
|
|
156
|
+
* check, the correlation-robust hash) is unchanged.
|
|
157
|
+
*
|
|
158
|
+
* const ch = new OtChannel(secureOtRandom(), withKemBaseOt());
|
|
159
|
+
*/
|
|
160
|
+
export declare function withKemBaseOt(): ConstructorParameters<typeof OtChannel>[1];
|
|
161
|
+
/** Raised when the committed KEM base OT aborts: a cheating receiver (opened keys ≠ commitment) is caught. */
|
|
162
|
+
export declare class KemBaseOtAbort extends Error {
|
|
163
|
+
constructor(message: string);
|
|
164
|
+
}
|
|
165
|
+
/** Receiver round-1 message: a nonce + the per-transfer commitments (public keys NOT yet revealed). */
|
|
166
|
+
export interface KemMalCommitMessage {
|
|
167
|
+
/** Receiver nonce `rn`, bound into every commitment and into `sid`. */
|
|
168
|
+
rn: Uint8Array;
|
|
169
|
+
/** Per-transfer RO-commitment `com_i = H(rn ‖ i ‖ pk_0 ‖ pk_1)`. */
|
|
170
|
+
commitments: Uint8Array[];
|
|
171
|
+
}
|
|
172
|
+
/** Receiver round-3 message: the opening of the committed public keys. */
|
|
173
|
+
export interface KemMalOpenMessage {
|
|
174
|
+
/** For each transfer i, the ordered public keys `[pk_0, pk_1]` the sender encapsulates under. */
|
|
175
|
+
publicKeys: Array<[Uint8Array, Uint8Array]>;
|
|
176
|
+
}
|
|
177
|
+
/** Sender round-2 message: the sender nonce `sn` completing the session id. */
|
|
178
|
+
export interface KemMalSenderNonce {
|
|
179
|
+
sn: Uint8Array;
|
|
180
|
+
}
|
|
181
|
+
/** Sender round-4 message: ciphertexts + `(sid, com)`-bound padded messages. */
|
|
182
|
+
export interface KemMalSenderMessage {
|
|
183
|
+
ciphertexts: Array<[Uint8Array, Uint8Array]>;
|
|
184
|
+
encrypted: Array<[Uint8Array, Uint8Array]>;
|
|
185
|
+
}
|
|
186
|
+
/** The receiver's retained state across the committed flow. */
|
|
187
|
+
export interface KemMalReceiverState {
|
|
188
|
+
choices: number[];
|
|
189
|
+
/** The chosen secret key per transfer (`sk_{choices[i]}`); the non-chosen secret is discarded. */
|
|
190
|
+
secretKeys: Uint8Array[];
|
|
191
|
+
/** The ordered public keys (opened in round 3). */
|
|
192
|
+
publicKeys: Array<[Uint8Array, Uint8Array]>;
|
|
193
|
+
rn: Uint8Array;
|
|
194
|
+
}
|
|
195
|
+
/** A full committed KEM base-OT transcript, exposed for inspection/tests. */
|
|
196
|
+
export interface KemMalTranscript extends KemMalCommitMessage, KemMalOpenMessage, KemMalSenderNonce, KemMalSenderMessage {
|
|
197
|
+
}
|
|
198
|
+
export interface KemBaseOtMalResult {
|
|
199
|
+
received: Uint8Array[];
|
|
200
|
+
transcript: KemMalTranscript;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* TEST-ONLY injection points modelling a malicious RECEIVER in the committed flow. Each hook mutates a
|
|
204
|
+
* value exactly where it crosses the wire, so the honest sender's checks run against the adversarial
|
|
205
|
+
* value.
|
|
206
|
+
*/
|
|
207
|
+
export interface KemMalTamper {
|
|
208
|
+
/** Malicious receiver: open public keys DIFFERENT from the committed ones (→ sender abort). */
|
|
209
|
+
tamperOpenedKeys?: (publicKeys: Array<[Uint8Array, Uint8Array]>) => void;
|
|
210
|
+
/** Malicious receiver/MITM: tamper the sender nonce the receiver binds `sid` with (→ pad mismatch). */
|
|
211
|
+
tamperReceiverSid?: (sid: Uint8Array) => Uint8Array;
|
|
212
|
+
}
|
|
213
|
+
/**
|
|
214
|
+
* RECEIVER round 1: generate the keypairs (keeping only the chosen secret), draw a nonce `rn`, and send
|
|
215
|
+
* only the COMMITMENTS to the ordered public keys. Returns the round-1 wire message plus the retained
|
|
216
|
+
* state (which holds the not-yet-revealed public keys for the round-3 opening).
|
|
217
|
+
*/
|
|
218
|
+
export declare function kemBaseOtMalCommit(choices: number[], rng?: OtRandom): {
|
|
219
|
+
message: KemMalCommitMessage;
|
|
220
|
+
state: KemMalReceiverState;
|
|
221
|
+
};
|
|
222
|
+
/** SENDER round 2: draw the sender nonce `sn` completing the session id. */
|
|
223
|
+
export declare function kemBaseOtMalSenderNonce(rng?: OtRandom): KemMalSenderNonce;
|
|
224
|
+
/** RECEIVER round 3: open the committed public keys (the sender will re-check them against `com`). */
|
|
225
|
+
export declare function kemBaseOtMalOpen(state: KemMalReceiverState): KemMalOpenMessage;
|
|
226
|
+
/**
|
|
227
|
+
* SENDER round 4: VERIFY the opened keys against the round-1 commitments (ABORT on mismatch), then
|
|
228
|
+
* encapsulate under each and one-time-pad each message with a `(sid, com)`-bound pad.
|
|
229
|
+
*/
|
|
230
|
+
export declare function kemBaseOtMalSend(messages: Array<[Uint8Array, Uint8Array]>, commit: KemMalCommitMessage, senderNonce: KemMalSenderNonce, opening: KemMalOpenMessage, rng?: OtRandom): KemMalSenderMessage;
|
|
231
|
+
/**
|
|
232
|
+
* RECEIVER round 5: decapsulate ONLY the chosen ciphertext and unmask with the `(sid, com)`-bound pad.
|
|
233
|
+
*/
|
|
234
|
+
export declare function kemBaseOtMalRecover(state: KemMalReceiverState, senderNonce: KemMalSenderNonce, senderMessage: KemMalSenderMessage, tamper?: KemMalTamper): Uint8Array[];
|
|
235
|
+
/**
|
|
236
|
+
* In-process combined simulator for the MALICIOUS-HARDENED committed KEM base OT, matching the shape of
|
|
237
|
+
* `kemBaseOT` so it is a drop-in for `OtChannel`'s `baseOtFn` (`withKemBaseOtMal`). Runs all five
|
|
238
|
+
* rounds; a cheating receiver (opened keys ≠ commitment) makes the sender throw `KemBaseOtAbort`. The
|
|
239
|
+
* `tamper` hook injects malicious-receiver behaviour for tests.
|
|
240
|
+
*/
|
|
241
|
+
export declare function kemBaseOtMal(messages: Array<[Uint8Array, Uint8Array]>, choices: number[], rng?: OtRandom, tamper?: KemMalTamper): KemBaseOtMalResult;
|
|
242
|
+
/**
|
|
243
|
+
* Wire the MALICIOUS-HARDENED committed ML-KEM base OT into the KOS OT-extension — the recommended
|
|
244
|
+
* post-quantum base. Like `withKemBaseOt`, but the κ setup base OTs run the committed/session-bound
|
|
245
|
+
* protocol (and abort on a cheating receiver). Everything above the base OT is unchanged.
|
|
246
|
+
*
|
|
247
|
+
* const ch = new OtChannel(secureOtRandom(), withKemBaseOtMal());
|
|
248
|
+
*/
|
|
249
|
+
export declare function withKemBaseOtMal(): ConstructorParameters<typeof OtChannel>[1];
|
|
250
|
+
/** Byte length of a derived committed-KEM random-OT shared secret. */
|
|
251
|
+
export declare const KEM_OT_SECRET_BYTES = 32;
|
|
252
|
+
/** Sender round-4 message of the committed KEM RANDOM OT: ciphertexts (wire) + both per-slot secrets (sender-local). */
|
|
253
|
+
export interface KemMalRandomSenderMessage {
|
|
254
|
+
/** For each transfer i, the ML-KEM ciphertexts `[ct_0, ct_1]` (the only part that crosses the wire). */
|
|
255
|
+
ciphertexts: Array<[Uint8Array, Uint8Array]>;
|
|
256
|
+
/** Sender-LOCAL: the two session-bound shared secrets `[ss_0, ss_1]` per transfer (never sent). */
|
|
257
|
+
senderSecrets: Array<[Uint8Array, Uint8Array]>;
|
|
258
|
+
}
|
|
259
|
+
/** A full committed KEM RANDOM-OT transcript + the two parties' shared-secret outputs. */
|
|
260
|
+
export interface KemBaseOtMalRandomResult {
|
|
261
|
+
/** Sender's per-slot shared secrets `[ss_0, ss_1]` per transfer (the sender learns BOTH). */
|
|
262
|
+
senderSecrets: Array<[Uint8Array, Uint8Array]>;
|
|
263
|
+
/** Receiver's chosen shared secret `ss_{choices[i]}` per transfer (the honest receiver learns ONE). */
|
|
264
|
+
recvSecrets: Uint8Array[];
|
|
265
|
+
/** The session id `sid = H(rn ‖ sn)` the secrets are bound to (public; both parties derive it). */
|
|
266
|
+
sid: Uint8Array;
|
|
267
|
+
transcript: {
|
|
268
|
+
rn: Uint8Array;
|
|
269
|
+
commitments: Uint8Array[];
|
|
270
|
+
sn: Uint8Array;
|
|
271
|
+
publicKeys: Array<[Uint8Array, Uint8Array]>;
|
|
272
|
+
ciphertexts: Array<[Uint8Array, Uint8Array]>;
|
|
273
|
+
};
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* SENDER round 4 (RANDOM variant): VERIFY the opened keys against the round-1 commitments (ABORT on
|
|
277
|
+
* mismatch), encapsulate under each, and derive BOTH per-slot session-bound shared secrets. No messages
|
|
278
|
+
* are padded — the two secrets per transfer ARE the random output.
|
|
279
|
+
*/
|
|
280
|
+
export declare function kemBaseOtMalRandomSend(commit: KemMalCommitMessage, senderNonce: KemMalSenderNonce, opening: KemMalOpenMessage, rng?: OtRandom): KemMalRandomSenderMessage;
|
|
281
|
+
/**
|
|
282
|
+
* RECEIVER round 5 (RANDOM variant): decapsulate ONLY the chosen ciphertext and derive the chosen
|
|
283
|
+
* session-bound shared secret. The receiver never touches the non-chosen slot (it kept no secret for it).
|
|
284
|
+
*/
|
|
285
|
+
export declare function kemBaseOtMalRandomRecover(state: KemMalReceiverState, senderNonce: KemMalSenderNonce, senderMessage: KemMalRandomSenderMessage, tamper?: KemMalTamper): Uint8Array[];
|
|
286
|
+
/**
|
|
287
|
+
* In-process combined simulator for the committed KEM RANDOM OT. Runs the same five rounds as
|
|
288
|
+
* `kemBaseOtMal` (commit → sender nonce → open → verify+encapsulate → recover) but outputs per-slot
|
|
289
|
+
* shared secrets instead of padded messages. A cheating receiver (opened keys ≠ commitment) makes the
|
|
290
|
+
* sender throw `KemBaseOtAbort`. The `tamper` hook injects malicious-receiver behaviour for tests.
|
|
291
|
+
*/
|
|
292
|
+
export declare function kemBaseOtMalRandom(choices: number[], rng?: OtRandom, tamper?: KemMalTamper): KemBaseOtMalRandomResult;
|