@atlasauth/pca-mpc 0.1.0 → 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 +50 -15
- package/dist/ec.d.ts +38 -18
- package/dist/ec.js +187 -18
- package/dist/ec.js.map +1 -1
- 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/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 +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/kem-ot.d.ts +167 -12
- package/dist/kem-ot.js +347 -12
- package/dist/kem-ot.js.map +1 -1
- package/package.json +31 -4
|
@@ -0,0 +1,209 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TRUE post-quantum, maliciously-secure base OT — the ENDEMIC OT of Masny–Rindal (ePrint 2019/706)
|
|
3
|
+
* instantiated over Module-LWE (Kyber-768 K-PKE), the RECOMMENDED / default PQ base OT for this stack.
|
|
4
|
+
*
|
|
5
|
+
* ─── WHY THIS EXISTS ────────────────────────────────────────────────────────────────────────────────
|
|
6
|
+
* The semi-honest ML-KEM base OT (`kem-ot.ts`) has an INTRINSIC residue against a malicious receiver:
|
|
7
|
+
* a receiver can run KEM keygen twice and keep BOTH secret keys, learning both messages, and the
|
|
8
|
+
* decisional-MLWE indistinguishability that gives it choice privacy makes that cheat undetectable to
|
|
9
|
+
* the sender. `hybrid-ot.ts` masks the residue with a *classical* EC half, but a receiver that is
|
|
10
|
+
* SIMULTANEOUSLY quantum AND malicious defeats the EC half with Shor. This module closes the residue
|
|
11
|
+
* in ONE post-quantum primitive: the receiver provably cannot form two decryptable branches, because
|
|
12
|
+
* one branch's public key is forced to be a UNIFORM ring element through a random oracle.
|
|
13
|
+
*
|
|
14
|
+
* ─── THE CONSTRUCTION (faithful to libOTe's `MasnyRindal`, group → lattice) ──────────────────────────
|
|
15
|
+
* libOTe's battle-tested `MasnyRindal` base OT works in a group `G` with a hash-to-group RO `H`:
|
|
16
|
+
* • sender publishes `S = s·G`;
|
|
17
|
+
* • receiver (choice `c`) picks `r` and a random point `N`, sets the CHOICE point `C = r·G − H(N)`,
|
|
18
|
+
* places `C` at slot `c` and `N` at slot `1−c`, and sends the pair;
|
|
19
|
+
* • sender derives, per slot `b`, `shared_b = s·(P_b + H(P_{1−b}))`, so `shared_c = s·r·G = r·S`
|
|
20
|
+
* (which the receiver recomputes) while `shared_{1−c} = s·(N + H(C))` needs the discrete log of a
|
|
21
|
+
* fresh RO point — a CDH the receiver cannot solve.
|
|
22
|
+
* We keep this EXACT additive structure but replace the group's Diffie–Hellman with Kyber K-PKE, where
|
|
23
|
+
* the "group" is the public-key ring-vector space `R_q^k` (an additive group) and `H` hashes to a
|
|
24
|
+
* UNIFORM ring vector (the standard FIPS-203 `SampleNTT` sampler — the one Kyber uses for its matrix A):
|
|
25
|
+
*
|
|
26
|
+
* RECEIVER (choice `c`, transfer `i`), with session nonce `rn` and `sid = H(rn)`:
|
|
27
|
+
* • real K-PKE keygen -> public key `(t̂_real ‖ rho)`, secret key `sk`;
|
|
28
|
+
* • sample a UNIFORM ring vector `N` (the non-chosen slot's value);
|
|
29
|
+
* • `C = t̂_real − Hpk(sid, i, N)` (ring subtraction, `Hpk` = hash-to-uniform-ring);
|
|
30
|
+
* • place `C` at slot `c`, `N` at slot `1−c`; send the ordered pair `(P_0, P_1)` and `rho`.
|
|
31
|
+
* SENDER (random payloads `ρ_0, ρ_1 ∈ {0,1}^256`), per transfer:
|
|
32
|
+
* • effective public key per slot: `t̂_b = P_b + Hpk(sid, i, P_{1−b})`, `pk_b = (t̂_b ‖ rho)`;
|
|
33
|
+
* -> `t̂_c = C + Hpk(sid,i,N) = t̂_real` (a REAL key, the receiver holds its `sk`), while
|
|
34
|
+
* `t̂_{1−c} = N + Hpk(sid,i,C)` is `N +` a FRESH uniform RO value = UNIFORM (no secret exists);
|
|
35
|
+
* • K-PKE CPA-encrypt `ρ_b` under `pk_b` -> `ct_b`; pad `k_b = Hpad(sid,i,b,ρ_b)`; send `(ct_0,ct_1)`.
|
|
36
|
+
* RECEIVER recovers ONLY slot `c`: `ρ_c = Dec(sk, ct_c)`, `k_c = Hpad(sid,i,c,ρ_c)`.
|
|
37
|
+
* (The chosen-message wrapper one-time-pads `m_b` under `k_b` and adds an RO commitment, exactly like
|
|
38
|
+
* the EC `baseOT`, so a malicious sender's inconsistent ciphertext is caught — `EndemicLweOtAbort`.)
|
|
39
|
+
*
|
|
40
|
+
* ─── SECURITY ACHIEVED (precise, post-quantum, honest) ───────────────────────────────────────────────
|
|
41
|
+
* • SENDER PRIVACY — the ENDEMIC property: a (even malicious) receiver cannot learn `m_{1−c}`.
|
|
42
|
+
* Its branch `1−c` has a UNIFORM public key `t̂_{1−c}`; recovering the payload `ρ_{1−c}` from
|
|
43
|
+
* `ct_{1−c}` is exactly breaking the semantic (IND-CPA) security of K-PKE encryption under a
|
|
44
|
+
* UNIFORM public key — which is the standard Kyber IND-CPA "hybrid-1" game and REDUCES TO
|
|
45
|
+
* DECISIONAL MODULE-LWE. Concretely: for a uniform `t̂`, the ciphertext `(u = Aᵀr+e₁, v = t̂ᵀr+e₂+ρ)`
|
|
46
|
+
* is pseudorandom under dMLWE on the encryption randomness `r` (with the uniform `t̂` supplying the
|
|
47
|
+
* extra row), so `ρ_{1−c}` — hence `k_{1−c}`, hence `m_{1−c}` — is hidden. And a malicious receiver
|
|
48
|
+
* CANNOT make BOTH branches decryptable: fixing slot `c` to a real key determines `P_c`, so
|
|
49
|
+
* `Hpk(sid,i,P_c)` is a FRESH uniform RO value and `t̂_{1−c}=P_{1−c}+Hpk(sid,i,P_c)` is uniform;
|
|
50
|
+
* finding a low-norm secret for a uniform target is Module-SIS-hard. (This is the residue the
|
|
51
|
+
* opaque ML-KEM base OT could not close.)
|
|
52
|
+
* • RECEIVER (CHOICE) PRIVACY — COMPUTATIONAL under decisional Module-LWE, even against a malicious
|
|
53
|
+
* or QUANTUM sender. The wire carries `(P_0, P_1, rho)`; the sender derives `t̂_0, t̂_1`, exactly ONE
|
|
54
|
+
* of which is a real MLWE sample `A∘ŝ+ê` (the chosen branch) and the other uniform. Telling which
|
|
55
|
+
* index is the real key is precisely decisional Module-LWE. (Unlike the group/DDH instantiation,
|
|
56
|
+
* this is computational, not statistical — a real lattice key is not uniform; we do NOT overclaim.)
|
|
57
|
+
* • POST-QUANTUM: both guarantees rest only on Module-LWE (ML-KEM-768, NIST category 3) + a random
|
|
58
|
+
* oracle (SHAKE/SHA3). No discrete log anywhere.
|
|
59
|
+
*
|
|
60
|
+
* ─── COMPOSITION WITH KOS (how this becomes many malicious OTs) ──────────────────────────────────────
|
|
61
|
+
* `OtChannel` consumes this as its `κ = 128` setup base OTs, with ROLES INVERTED: the extension SENDER
|
|
62
|
+
* plays base-RECEIVER holding the secret selector `s`, and the extension RECEIVER plays base-SENDER
|
|
63
|
+
* providing the `κ` seed pairs. The two endemic guarantees are exactly what the KOS layer needs:
|
|
64
|
+
* • base receiver-privacy (dMLWE) hides the extension sender's selector `s` from a malicious
|
|
65
|
+
* extension receiver — the property IKNP relies on for the unchosen messages to stay hidden; and
|
|
66
|
+
* • the endemic "learn ≤ one" property means the extension sender learns exactly one seed per pair.
|
|
67
|
+
* The KOS correlation check over the sacrifice rows then upgrades the whole extension to
|
|
68
|
+
* MALICIOUS-with-abort against a cheating extension receiver (the IKNP attack). So endemic base OTs +
|
|
69
|
+
* the existing KOS check in `ot.ts` = maliciously-secure, post-quantum OT. Endemic security is a
|
|
70
|
+
* (deliberately) weaker notion in which corrupt parties may fix their own outputs; lifting it to
|
|
71
|
+
* standard malicious OT via actively-secure OT extension is precisely the Masny–Rindal result, and the
|
|
72
|
+
* KOS layer here is unchanged — only the base is swapped. The `extend`-level tests prove the composed
|
|
73
|
+
* results are IDENTICAL to the EC and ML-KEM bases.
|
|
74
|
+
*
|
|
75
|
+
* ─── HONEST RESIDUAL ─────────────────────────────────────────────────────────────────────────────────
|
|
76
|
+
* The Kyber core is the vetted `pqc_kyber` reference compiled to WASM (`@atlasauth/pca-mpc-lwe-ot-wasm`);
|
|
77
|
+
* it is a PROTOTYPE and is NOT claimed constant-time (same caveat as `kem-ot.ts`/`ec.ts`, docs §7.1) —
|
|
78
|
+
* a documented side-channel boundary, not a break of the stated MLWE/ROM security. Decryption of K-PKE
|
|
79
|
+
* has a negligible (~2⁻¹³⁹ for Kyber-768) failure probability, inherited from the primitive.
|
|
80
|
+
*
|
|
81
|
+
* No hand-rolled lattice crypto: keygen / CPA-encrypt / CPA-decrypt and the uniform-ring sampler all go
|
|
82
|
+
* through the vetted crate; this module only hashes (SHA-256 RO), XORs, and marshals byte vectors.
|
|
83
|
+
*/
|
|
84
|
+
import { type BaseOtFn, type OtChannel, type OtRandom } from './ot';
|
|
85
|
+
/** Kyber-768 byte sizes, surfaced from the lattice core. */
|
|
86
|
+
export declare const PK_BYTES: number;
|
|
87
|
+
export declare const SK_BYTES: number;
|
|
88
|
+
export declare const CT_BYTES: number;
|
|
89
|
+
export declare const TVEC_BYTES: number;
|
|
90
|
+
export declare const SYM_BYTES: number;
|
|
91
|
+
/** Re-export the vetted lattice primitives (used by the hybrid combiner alternatives and the tests). */
|
|
92
|
+
export declare const kpkeKeygen: (seed: Uint8Array) => {
|
|
93
|
+
publicKey: Uint8Array;
|
|
94
|
+
secretKey: Uint8Array;
|
|
95
|
+
};
|
|
96
|
+
export declare const kpkeEnc: (publicKey: Uint8Array, message: Uint8Array, coins: Uint8Array) => Uint8Array;
|
|
97
|
+
export declare const kpkeDec: (secretKey: Uint8Array, ciphertext: Uint8Array) => Uint8Array;
|
|
98
|
+
export declare const ringAdd: (a: Uint8Array, b: Uint8Array) => Uint8Array;
|
|
99
|
+
export declare const ringSub: (a: Uint8Array, b: Uint8Array) => Uint8Array;
|
|
100
|
+
export declare const hashToRing: (input: Uint8Array) => Uint8Array;
|
|
101
|
+
/** The session id `sid = H(TAG ‖ rn)` binding every RO query to this OT instance's receiver nonce. */
|
|
102
|
+
export declare function endemicSessionId(rn: Uint8Array): Uint8Array;
|
|
103
|
+
/**
|
|
104
|
+
* The endemic random-OT pad oracle, exposed for the hybrid combiner and the security tests:
|
|
105
|
+
* `H(TAG ‖ sid ‖ i ‖ slot ‖ ρ)` expanded to `len` bytes, where `ρ` is the K-PKE payload of that slot.
|
|
106
|
+
*/
|
|
107
|
+
export declare function endemicLwePad(sid: Uint8Array, index: number, slot: number, payload: Uint8Array, len: number): Uint8Array;
|
|
108
|
+
/** Byte length of a derived endemic random-OT shared secret (= a K-PKE payload). */
|
|
109
|
+
export declare const ENDEMIC_SECRET_BYTES: number;
|
|
110
|
+
/** Raised when the endemic base OT aborts: a malicious sender's ciphertext fails its RO commitment. */
|
|
111
|
+
export declare class EndemicLweOtAbort extends Error {
|
|
112
|
+
constructor(message: string);
|
|
113
|
+
}
|
|
114
|
+
/** Receiver round-1 wire message. */
|
|
115
|
+
export interface EndemicLweReceiverMessage {
|
|
116
|
+
/** Receiver session nonce. */
|
|
117
|
+
rn: Uint8Array;
|
|
118
|
+
/** For each transfer i, the ordered ring-vector pair `[P_0, P_1]` (each `TVEC_BYTES`). */
|
|
119
|
+
points: Array<[Uint8Array, Uint8Array]>;
|
|
120
|
+
/** For each transfer i, the shared matrix seed `rho` (32 B) of that transfer's real keypair. */
|
|
121
|
+
rhos: Uint8Array[];
|
|
122
|
+
}
|
|
123
|
+
/** The receiver's retained state (it keeps only the chosen branch's secret key). */
|
|
124
|
+
export interface EndemicLweReceiverState {
|
|
125
|
+
choices: number[];
|
|
126
|
+
/** `secretKeys[i]` is the IND-CPA secret key for the receiver's real key placed at slot `choices[i]`. */
|
|
127
|
+
secretKeys: Uint8Array[];
|
|
128
|
+
rhos: Uint8Array[];
|
|
129
|
+
rn: Uint8Array;
|
|
130
|
+
sid: Uint8Array;
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* RECEIVER round 1: for each choice bit, generate a real K-PKE keypair, sample a uniform ring vector
|
|
134
|
+
* `N`, set the choice vector `C = t̂_real − Hpk(sid,i,N)`, place `C` at slot `c` and `N` at slot `1−c`,
|
|
135
|
+
* send the ordered pair + `rho`, and retain only the chosen branch's secret key.
|
|
136
|
+
*/
|
|
137
|
+
export declare function endemicLweReceive(choices: number[], rng?: OtRandom): {
|
|
138
|
+
message: EndemicLweReceiverMessage;
|
|
139
|
+
state: EndemicLweReceiverState;
|
|
140
|
+
};
|
|
141
|
+
/** Sender wire message of the RANDOM endemic OT: the two ciphertexts per transfer (sender-local pads). */
|
|
142
|
+
export interface EndemicLweRandomSenderMessage {
|
|
143
|
+
ciphertexts: Array<[Uint8Array, Uint8Array]>;
|
|
144
|
+
/** Sender-LOCAL: both per-slot pads `[k_0, k_1]` per transfer (never sent). */
|
|
145
|
+
senderPads: Array<[Uint8Array, Uint8Array]>;
|
|
146
|
+
}
|
|
147
|
+
/** TEST-ONLY malicious-sender injection (corrupt the ciphertexts on the wire). */
|
|
148
|
+
export interface EndemicLweTamper {
|
|
149
|
+
tamperCiphertexts?: (ciphertexts: Array<[Uint8Array, Uint8Array]>) => void;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* SENDER round (RANDOM variant): derive each slot's effective public key `pk_b = (P_b + Hpk(sid,i,P_{1−b}) ‖ rho)`,
|
|
153
|
+
* CPA-encrypt a fresh random payload under each, and output both per-slot pads. No messages are padded
|
|
154
|
+
* — the two pads per transfer ARE the random output (consumed by the hybrid combiner / the chosen-message
|
|
155
|
+
* wrapper below).
|
|
156
|
+
*/
|
|
157
|
+
export declare function endemicLweSendRandom(message: EndemicLweReceiverMessage, rng?: OtRandom, tamper?: EndemicLweTamper): EndemicLweRandomSenderMessage;
|
|
158
|
+
/**
|
|
159
|
+
* RECEIVER recovery (RANDOM variant): decapsulate ONLY the chosen ciphertext (the chosen branch's
|
|
160
|
+
* effective key equals the receiver's real key) and derive the chosen pad. The non-chosen slot's key
|
|
161
|
+
* is uniform, so its ciphertext is unrecoverable (the endemic property).
|
|
162
|
+
*/
|
|
163
|
+
export declare function endemicLweRecoverRandom(state: EndemicLweReceiverState, senderMessage: EndemicLweRandomSenderMessage): Uint8Array[];
|
|
164
|
+
/** Full RANDOM endemic base OT (both parties in-process); the random-OT face reused by the combiner. */
|
|
165
|
+
export interface EndemicLweRandomResult {
|
|
166
|
+
/** Sender's per-slot pads `[k_0, k_1]` (the sender learns BOTH). */
|
|
167
|
+
senderPads: Array<[Uint8Array, Uint8Array]>;
|
|
168
|
+
/** Receiver's chosen pad `k_{choices[i]}` (the honest receiver learns ONE). */
|
|
169
|
+
recvPads: Uint8Array[];
|
|
170
|
+
sid: Uint8Array;
|
|
171
|
+
message: EndemicLweReceiverMessage;
|
|
172
|
+
ciphertexts: Array<[Uint8Array, Uint8Array]>;
|
|
173
|
+
}
|
|
174
|
+
/** In-process RANDOM endemic base OT. */
|
|
175
|
+
export declare function endemicLweBaseOtRandom(choices: number[], rng?: OtRandom, tamper?: EndemicLweTamper): EndemicLweRandomResult;
|
|
176
|
+
/** A full chosen-message endemic base-OT transcript, exposed for inspection/tests. */
|
|
177
|
+
export interface EndemicLweTranscript {
|
|
178
|
+
rn: Uint8Array;
|
|
179
|
+
points: Array<[Uint8Array, Uint8Array]>;
|
|
180
|
+
rhos: Uint8Array[];
|
|
181
|
+
ciphertexts: Array<[Uint8Array, Uint8Array]>;
|
|
182
|
+
/** For each transfer i, `[E_0, E_1]` with `E_b = m_b ⊕ k_b`. */
|
|
183
|
+
encrypted: Array<[Uint8Array, Uint8Array]>;
|
|
184
|
+
/** For each transfer i, `[com_0, com_1]`. */
|
|
185
|
+
commitments: Array<[Uint8Array, Uint8Array]>;
|
|
186
|
+
}
|
|
187
|
+
export interface EndemicLweResult {
|
|
188
|
+
received: Uint8Array[];
|
|
189
|
+
transcript: EndemicLweTranscript;
|
|
190
|
+
}
|
|
191
|
+
/**
|
|
192
|
+
* In-process CHOSEN-MESSAGE endemic base OT: `messages[i] = [m0, m1]` (the two must be equal length);
|
|
193
|
+
* `choices[i] ∈ {0,1}`. The sender one-time-pads each message under the endemic random-OT pads and
|
|
194
|
+
* commits to each; the receiver recovers `m_{choices[i]}` and checks the commitment, aborting
|
|
195
|
+
* (`EndemicLweOtAbort`) on any inconsistency. A drop-in for `OtChannel`'s `baseOtFn`.
|
|
196
|
+
*/
|
|
197
|
+
export declare function endemicLweBaseOT(messages: Array<[Uint8Array, Uint8Array]>, choices: number[], rng?: OtRandom, tamper?: EndemicLweTamper): EndemicLweResult;
|
|
198
|
+
/**
|
|
199
|
+
* The chosen-message endemic base OT as a `BaseOtFn` (only `received` is part of the contract).
|
|
200
|
+
*/
|
|
201
|
+
export declare const endemicLweBaseOtFn: BaseOtFn;
|
|
202
|
+
/**
|
|
203
|
+
* Wire the endemic ML-KEM base OT into the KOS OT-extension — the RECOMMENDED post-quantum,
|
|
204
|
+
* maliciously-secure base. Everything above the base OT (the IKNP matrix, the KOS correlation check,
|
|
205
|
+
* the correlation-robust hash) is unchanged; only the `κ` setup base OTs run the endemic protocol.
|
|
206
|
+
*
|
|
207
|
+
* const ch = new OtChannel(secureOtRandom(), withEndemicLweBaseOt());
|
|
208
|
+
*/
|
|
209
|
+
export declare function withEndemicLweBaseOt(): ConstructorParameters<typeof OtChannel>[1];
|
|
@@ -0,0 +1,405 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* TRUE post-quantum, maliciously-secure base OT — the ENDEMIC OT of Masny–Rindal (ePrint 2019/706)
|
|
4
|
+
* instantiated over Module-LWE (Kyber-768 K-PKE), the RECOMMENDED / default PQ base OT for this stack.
|
|
5
|
+
*
|
|
6
|
+
* ─── WHY THIS EXISTS ────────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
* The semi-honest ML-KEM base OT (`kem-ot.ts`) has an INTRINSIC residue against a malicious receiver:
|
|
8
|
+
* a receiver can run KEM keygen twice and keep BOTH secret keys, learning both messages, and the
|
|
9
|
+
* decisional-MLWE indistinguishability that gives it choice privacy makes that cheat undetectable to
|
|
10
|
+
* the sender. `hybrid-ot.ts` masks the residue with a *classical* EC half, but a receiver that is
|
|
11
|
+
* SIMULTANEOUSLY quantum AND malicious defeats the EC half with Shor. This module closes the residue
|
|
12
|
+
* in ONE post-quantum primitive: the receiver provably cannot form two decryptable branches, because
|
|
13
|
+
* one branch's public key is forced to be a UNIFORM ring element through a random oracle.
|
|
14
|
+
*
|
|
15
|
+
* ─── THE CONSTRUCTION (faithful to libOTe's `MasnyRindal`, group → lattice) ──────────────────────────
|
|
16
|
+
* libOTe's battle-tested `MasnyRindal` base OT works in a group `G` with a hash-to-group RO `H`:
|
|
17
|
+
* • sender publishes `S = s·G`;
|
|
18
|
+
* • receiver (choice `c`) picks `r` and a random point `N`, sets the CHOICE point `C = r·G − H(N)`,
|
|
19
|
+
* places `C` at slot `c` and `N` at slot `1−c`, and sends the pair;
|
|
20
|
+
* • sender derives, per slot `b`, `shared_b = s·(P_b + H(P_{1−b}))`, so `shared_c = s·r·G = r·S`
|
|
21
|
+
* (which the receiver recomputes) while `shared_{1−c} = s·(N + H(C))` needs the discrete log of a
|
|
22
|
+
* fresh RO point — a CDH the receiver cannot solve.
|
|
23
|
+
* We keep this EXACT additive structure but replace the group's Diffie–Hellman with Kyber K-PKE, where
|
|
24
|
+
* the "group" is the public-key ring-vector space `R_q^k` (an additive group) and `H` hashes to a
|
|
25
|
+
* UNIFORM ring vector (the standard FIPS-203 `SampleNTT` sampler — the one Kyber uses for its matrix A):
|
|
26
|
+
*
|
|
27
|
+
* RECEIVER (choice `c`, transfer `i`), with session nonce `rn` and `sid = H(rn)`:
|
|
28
|
+
* • real K-PKE keygen -> public key `(t̂_real ‖ rho)`, secret key `sk`;
|
|
29
|
+
* • sample a UNIFORM ring vector `N` (the non-chosen slot's value);
|
|
30
|
+
* • `C = t̂_real − Hpk(sid, i, N)` (ring subtraction, `Hpk` = hash-to-uniform-ring);
|
|
31
|
+
* • place `C` at slot `c`, `N` at slot `1−c`; send the ordered pair `(P_0, P_1)` and `rho`.
|
|
32
|
+
* SENDER (random payloads `ρ_0, ρ_1 ∈ {0,1}^256`), per transfer:
|
|
33
|
+
* • effective public key per slot: `t̂_b = P_b + Hpk(sid, i, P_{1−b})`, `pk_b = (t̂_b ‖ rho)`;
|
|
34
|
+
* -> `t̂_c = C + Hpk(sid,i,N) = t̂_real` (a REAL key, the receiver holds its `sk`), while
|
|
35
|
+
* `t̂_{1−c} = N + Hpk(sid,i,C)` is `N +` a FRESH uniform RO value = UNIFORM (no secret exists);
|
|
36
|
+
* • K-PKE CPA-encrypt `ρ_b` under `pk_b` -> `ct_b`; pad `k_b = Hpad(sid,i,b,ρ_b)`; send `(ct_0,ct_1)`.
|
|
37
|
+
* RECEIVER recovers ONLY slot `c`: `ρ_c = Dec(sk, ct_c)`, `k_c = Hpad(sid,i,c,ρ_c)`.
|
|
38
|
+
* (The chosen-message wrapper one-time-pads `m_b` under `k_b` and adds an RO commitment, exactly like
|
|
39
|
+
* the EC `baseOT`, so a malicious sender's inconsistent ciphertext is caught — `EndemicLweOtAbort`.)
|
|
40
|
+
*
|
|
41
|
+
* ─── SECURITY ACHIEVED (precise, post-quantum, honest) ───────────────────────────────────────────────
|
|
42
|
+
* • SENDER PRIVACY — the ENDEMIC property: a (even malicious) receiver cannot learn `m_{1−c}`.
|
|
43
|
+
* Its branch `1−c` has a UNIFORM public key `t̂_{1−c}`; recovering the payload `ρ_{1−c}` from
|
|
44
|
+
* `ct_{1−c}` is exactly breaking the semantic (IND-CPA) security of K-PKE encryption under a
|
|
45
|
+
* UNIFORM public key — which is the standard Kyber IND-CPA "hybrid-1" game and REDUCES TO
|
|
46
|
+
* DECISIONAL MODULE-LWE. Concretely: for a uniform `t̂`, the ciphertext `(u = Aᵀr+e₁, v = t̂ᵀr+e₂+ρ)`
|
|
47
|
+
* is pseudorandom under dMLWE on the encryption randomness `r` (with the uniform `t̂` supplying the
|
|
48
|
+
* extra row), so `ρ_{1−c}` — hence `k_{1−c}`, hence `m_{1−c}` — is hidden. And a malicious receiver
|
|
49
|
+
* CANNOT make BOTH branches decryptable: fixing slot `c` to a real key determines `P_c`, so
|
|
50
|
+
* `Hpk(sid,i,P_c)` is a FRESH uniform RO value and `t̂_{1−c}=P_{1−c}+Hpk(sid,i,P_c)` is uniform;
|
|
51
|
+
* finding a low-norm secret for a uniform target is Module-SIS-hard. (This is the residue the
|
|
52
|
+
* opaque ML-KEM base OT could not close.)
|
|
53
|
+
* • RECEIVER (CHOICE) PRIVACY — COMPUTATIONAL under decisional Module-LWE, even against a malicious
|
|
54
|
+
* or QUANTUM sender. The wire carries `(P_0, P_1, rho)`; the sender derives `t̂_0, t̂_1`, exactly ONE
|
|
55
|
+
* of which is a real MLWE sample `A∘ŝ+ê` (the chosen branch) and the other uniform. Telling which
|
|
56
|
+
* index is the real key is precisely decisional Module-LWE. (Unlike the group/DDH instantiation,
|
|
57
|
+
* this is computational, not statistical — a real lattice key is not uniform; we do NOT overclaim.)
|
|
58
|
+
* • POST-QUANTUM: both guarantees rest only on Module-LWE (ML-KEM-768, NIST category 3) + a random
|
|
59
|
+
* oracle (SHAKE/SHA3). No discrete log anywhere.
|
|
60
|
+
*
|
|
61
|
+
* ─── COMPOSITION WITH KOS (how this becomes many malicious OTs) ──────────────────────────────────────
|
|
62
|
+
* `OtChannel` consumes this as its `κ = 128` setup base OTs, with ROLES INVERTED: the extension SENDER
|
|
63
|
+
* plays base-RECEIVER holding the secret selector `s`, and the extension RECEIVER plays base-SENDER
|
|
64
|
+
* providing the `κ` seed pairs. The two endemic guarantees are exactly what the KOS layer needs:
|
|
65
|
+
* • base receiver-privacy (dMLWE) hides the extension sender's selector `s` from a malicious
|
|
66
|
+
* extension receiver — the property IKNP relies on for the unchosen messages to stay hidden; and
|
|
67
|
+
* • the endemic "learn ≤ one" property means the extension sender learns exactly one seed per pair.
|
|
68
|
+
* The KOS correlation check over the sacrifice rows then upgrades the whole extension to
|
|
69
|
+
* MALICIOUS-with-abort against a cheating extension receiver (the IKNP attack). So endemic base OTs +
|
|
70
|
+
* the existing KOS check in `ot.ts` = maliciously-secure, post-quantum OT. Endemic security is a
|
|
71
|
+
* (deliberately) weaker notion in which corrupt parties may fix their own outputs; lifting it to
|
|
72
|
+
* standard malicious OT via actively-secure OT extension is precisely the Masny–Rindal result, and the
|
|
73
|
+
* KOS layer here is unchanged — only the base is swapped. The `extend`-level tests prove the composed
|
|
74
|
+
* results are IDENTICAL to the EC and ML-KEM bases.
|
|
75
|
+
*
|
|
76
|
+
* ─── HONEST RESIDUAL ─────────────────────────────────────────────────────────────────────────────────
|
|
77
|
+
* The Kyber core is the vetted `pqc_kyber` reference compiled to WASM (`@atlasauth/pca-mpc-lwe-ot-wasm`);
|
|
78
|
+
* it is a PROTOTYPE and is NOT claimed constant-time (same caveat as `kem-ot.ts`/`ec.ts`, docs §7.1) —
|
|
79
|
+
* a documented side-channel boundary, not a break of the stated MLWE/ROM security. Decryption of K-PKE
|
|
80
|
+
* has a negligible (~2⁻¹³⁹ for Kyber-768) failure probability, inherited from the primitive.
|
|
81
|
+
*
|
|
82
|
+
* No hand-rolled lattice crypto: keygen / CPA-encrypt / CPA-decrypt and the uniform-ring sampler all go
|
|
83
|
+
* through the vetted crate; this module only hashes (SHA-256 RO), XORs, and marshals byte vectors.
|
|
84
|
+
*/
|
|
85
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
86
|
+
exports.endemicLweBaseOtFn = exports.EndemicLweOtAbort = exports.ENDEMIC_SECRET_BYTES = exports.hashToRing = exports.ringSub = exports.ringAdd = exports.kpkeDec = exports.kpkeEnc = exports.kpkeKeygen = exports.SYM_BYTES = exports.TVEC_BYTES = exports.CT_BYTES = exports.SK_BYTES = exports.PK_BYTES = void 0;
|
|
87
|
+
exports.endemicSessionId = endemicSessionId;
|
|
88
|
+
exports.endemicLwePad = endemicLwePad;
|
|
89
|
+
exports.endemicLweReceive = endemicLweReceive;
|
|
90
|
+
exports.endemicLweSendRandom = endemicLweSendRandom;
|
|
91
|
+
exports.endemicLweRecoverRandom = endemicLweRecoverRandom;
|
|
92
|
+
exports.endemicLweBaseOtRandom = endemicLweBaseOtRandom;
|
|
93
|
+
exports.endemicLweBaseOT = endemicLweBaseOT;
|
|
94
|
+
exports.withEndemicLweBaseOt = withEndemicLweBaseOt;
|
|
95
|
+
const node_crypto_1 = require("node:crypto");
|
|
96
|
+
const node_module_1 = require("node:module");
|
|
97
|
+
const node_path_1 = require("node:path");
|
|
98
|
+
const csprng_1 = require("./csprng");
|
|
99
|
+
/** Narrow an opaque module to the `LatticeCore` surface without `any` — every member must be present. */
|
|
100
|
+
function asLatticeCore(mod) {
|
|
101
|
+
if (typeof mod !== 'object' || mod === null)
|
|
102
|
+
return null;
|
|
103
|
+
const m = mod;
|
|
104
|
+
const fns = ['kpkeKeygen', 'kpkeEnc', 'kpkeDec', 'ringAdd', 'ringSub', 'hashToRing'];
|
|
105
|
+
for (const name of fns)
|
|
106
|
+
if (typeof m[name] !== 'function')
|
|
107
|
+
return null;
|
|
108
|
+
const nums = ['PK_BYTES', 'SK_BYTES', 'CT_BYTES', 'TVEC_BYTES', 'SYM_BYTES'];
|
|
109
|
+
for (const name of nums)
|
|
110
|
+
if (typeof m[name] !== 'number')
|
|
111
|
+
return null;
|
|
112
|
+
return mod;
|
|
113
|
+
}
|
|
114
|
+
function loadLatticeCore() {
|
|
115
|
+
const require = (0, node_module_1.createRequire)(__filename);
|
|
116
|
+
const candidates = [
|
|
117
|
+
'@atlasauth/pca-mpc-lwe-ot-wasm',
|
|
118
|
+
(0, node_path_1.join)(__dirname, '..', '..', 'pca-mpc-lwe-ot-wasm', 'dist', 'index.js'),
|
|
119
|
+
];
|
|
120
|
+
for (const spec of candidates) {
|
|
121
|
+
try {
|
|
122
|
+
const loaded = asLatticeCore(require(spec));
|
|
123
|
+
if (loaded !== null)
|
|
124
|
+
return loaded;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
// try the next candidate
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
throw new Error('endemic-ot: could not load @atlasauth/pca-mpc-lwe-ot-wasm (the Kyber lattice core is required; ' +
|
|
131
|
+
'build it with `pnpm --filter @atlasauth/pca-mpc-lwe-ot-wasm build:wasm && ... build`)');
|
|
132
|
+
}
|
|
133
|
+
const core = loadLatticeCore();
|
|
134
|
+
/** Kyber-768 byte sizes, surfaced from the lattice core. */
|
|
135
|
+
exports.PK_BYTES = core.PK_BYTES;
|
|
136
|
+
exports.SK_BYTES = core.SK_BYTES;
|
|
137
|
+
exports.CT_BYTES = core.CT_BYTES;
|
|
138
|
+
exports.TVEC_BYTES = core.TVEC_BYTES;
|
|
139
|
+
exports.SYM_BYTES = core.SYM_BYTES;
|
|
140
|
+
/** Re-export the vetted lattice primitives (used by the hybrid combiner alternatives and the tests). */
|
|
141
|
+
exports.kpkeKeygen = core.kpkeKeygen.bind(core);
|
|
142
|
+
exports.kpkeEnc = core.kpkeEnc.bind(core);
|
|
143
|
+
exports.kpkeDec = core.kpkeDec.bind(core);
|
|
144
|
+
exports.ringAdd = core.ringAdd.bind(core);
|
|
145
|
+
exports.ringSub = core.ringSub.bind(core);
|
|
146
|
+
exports.hashToRing = core.hashToRing.bind(core);
|
|
147
|
+
// ===================================================================================================
|
|
148
|
+
// Random-oracle helpers (SHA-256 based, domain-separated). The hash-to-uniform-ring oracle lives in
|
|
149
|
+
// the wasm core; here we build its input and the pad / commitment / session-id oracles.
|
|
150
|
+
// ===================================================================================================
|
|
151
|
+
const TAG_SID = new TextEncoder().encode('atlas-pca-mpc/endemic-lwe-ot-sid');
|
|
152
|
+
const TAG_HPK = new TextEncoder().encode('atlas-pca-mpc/endemic-lwe-ot-hpk');
|
|
153
|
+
const TAG_N = new TextEncoder().encode('atlas-pca-mpc/endemic-lwe-ot-N');
|
|
154
|
+
const TAG_PAD = new TextEncoder().encode('atlas-pca-mpc/endemic-lwe-ot-pad');
|
|
155
|
+
const TAG_COMMIT = new TextEncoder().encode('atlas-pca-mpc/endemic-lwe-ot-commit');
|
|
156
|
+
function sha256(...chunks) {
|
|
157
|
+
const h = (0, node_crypto_1.createHash)('sha256');
|
|
158
|
+
for (const c of chunks)
|
|
159
|
+
h.update(c);
|
|
160
|
+
return new Uint8Array(h.digest());
|
|
161
|
+
}
|
|
162
|
+
function u32(x) {
|
|
163
|
+
const b = new Uint8Array(4);
|
|
164
|
+
b[0] = (x >>> 24) & 0xff;
|
|
165
|
+
b[1] = (x >>> 16) & 0xff;
|
|
166
|
+
b[2] = (x >>> 8) & 0xff;
|
|
167
|
+
b[3] = x & 0xff;
|
|
168
|
+
return b;
|
|
169
|
+
}
|
|
170
|
+
function concat(...parts) {
|
|
171
|
+
let n = 0;
|
|
172
|
+
for (const p of parts)
|
|
173
|
+
n += p.length;
|
|
174
|
+
const out = new Uint8Array(n);
|
|
175
|
+
let o = 0;
|
|
176
|
+
for (const p of parts) {
|
|
177
|
+
out.set(p, o);
|
|
178
|
+
o += p.length;
|
|
179
|
+
}
|
|
180
|
+
return out;
|
|
181
|
+
}
|
|
182
|
+
function xorBytes(a, b) {
|
|
183
|
+
if (a.length !== b.length)
|
|
184
|
+
throw new Error('endemic-ot: XOR length mismatch');
|
|
185
|
+
const out = new Uint8Array(a.length);
|
|
186
|
+
for (let i = 0; i < a.length; i++)
|
|
187
|
+
out[i] = a[i] ^ b[i];
|
|
188
|
+
return out;
|
|
189
|
+
}
|
|
190
|
+
function ctEqual(a, b) {
|
|
191
|
+
if (a.length !== b.length)
|
|
192
|
+
return false;
|
|
193
|
+
let diff = 0;
|
|
194
|
+
for (let i = 0; i < a.length; i++)
|
|
195
|
+
diff |= a[i] ^ b[i];
|
|
196
|
+
return diff === 0;
|
|
197
|
+
}
|
|
198
|
+
/** The session id `sid = H(TAG ‖ rn)` binding every RO query to this OT instance's receiver nonce. */
|
|
199
|
+
function endemicSessionId(rn) {
|
|
200
|
+
return sha256(TAG_SID, rn);
|
|
201
|
+
}
|
|
202
|
+
/** `Hpk(sid, i, other)` — the uniform ring vector the branch's effective key is offset by; `other` is
|
|
203
|
+
* the OTHER slot's value (mirrors libOTe keying `H` by the opposite point). */
|
|
204
|
+
function hpk(sid, i, other) {
|
|
205
|
+
return core.hashToRing(concat(TAG_HPK, sid, u32(i), other));
|
|
206
|
+
}
|
|
207
|
+
/** The one-time pad / random-OT output for a slot: `H(TAG ‖ sid ‖ i ‖ slot ‖ ctr ‖ ρ)` to `len` bytes. */
|
|
208
|
+
function padBytes(sid, i, slot, payload, len) {
|
|
209
|
+
const out = new Uint8Array(len);
|
|
210
|
+
let produced = 0;
|
|
211
|
+
let ctr = 0;
|
|
212
|
+
while (produced < len) {
|
|
213
|
+
const block = sha256(TAG_PAD, sid, u32(i), Uint8Array.of(slot & 1), u32(ctr), payload);
|
|
214
|
+
for (let k = 0; k < block.length && produced < len; k++)
|
|
215
|
+
out[produced++] = block[k];
|
|
216
|
+
ctr++;
|
|
217
|
+
}
|
|
218
|
+
return out;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* The endemic random-OT pad oracle, exposed for the hybrid combiner and the security tests:
|
|
222
|
+
* `H(TAG ‖ sid ‖ i ‖ slot ‖ ρ)` expanded to `len` bytes, where `ρ` is the K-PKE payload of that slot.
|
|
223
|
+
*/
|
|
224
|
+
function endemicLwePad(sid, index, slot, payload, len) {
|
|
225
|
+
return padBytes(sid, index, slot, payload, len);
|
|
226
|
+
}
|
|
227
|
+
/** Per-message RO commitment `com = H(TAG ‖ sid ‖ i ‖ slot ‖ msg ‖ pad)`. */
|
|
228
|
+
function commitBytes(sid, i, slot, msg, pad) {
|
|
229
|
+
return sha256(TAG_COMMIT, sid, u32(i), Uint8Array.of(slot & 1), msg, pad);
|
|
230
|
+
}
|
|
231
|
+
// ===================================================================================================
|
|
232
|
+
// Protocol, as explicit rounds (matching the in-process, transcript-returning style of kem-ot.ts).
|
|
233
|
+
// ===================================================================================================
|
|
234
|
+
/** Byte length of a derived endemic random-OT shared secret (= a K-PKE payload). */
|
|
235
|
+
exports.ENDEMIC_SECRET_BYTES = exports.SYM_BYTES;
|
|
236
|
+
/** Raised when the endemic base OT aborts: a malicious sender's ciphertext fails its RO commitment. */
|
|
237
|
+
class EndemicLweOtAbort extends Error {
|
|
238
|
+
constructor(message) {
|
|
239
|
+
super(message);
|
|
240
|
+
this.name = 'EndemicLweOtAbort';
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
exports.EndemicLweOtAbort = EndemicLweOtAbort;
|
|
244
|
+
/**
|
|
245
|
+
* RECEIVER round 1: for each choice bit, generate a real K-PKE keypair, sample a uniform ring vector
|
|
246
|
+
* `N`, set the choice vector `C = t̂_real − Hpk(sid,i,N)`, place `C` at slot `c` and `N` at slot `1−c`,
|
|
247
|
+
* send the ordered pair + `rho`, and retain only the chosen branch's secret key.
|
|
248
|
+
*/
|
|
249
|
+
function endemicLweReceive(choices, rng = (0, csprng_1.secureOtRandom)()) {
|
|
250
|
+
const rn = rng.bytes(exports.SYM_BYTES);
|
|
251
|
+
const sid = endemicSessionId(rn);
|
|
252
|
+
const points = [];
|
|
253
|
+
const rhos = [];
|
|
254
|
+
const secretKeys = [];
|
|
255
|
+
const retained = [];
|
|
256
|
+
for (let i = 0; i < choices.length; i++) {
|
|
257
|
+
const c = choices[i] & 1;
|
|
258
|
+
const { publicKey, secretKey } = core.kpkeKeygen(rng.bytes(exports.SYM_BYTES));
|
|
259
|
+
const tReal = publicKey.slice(0, exports.TVEC_BYTES);
|
|
260
|
+
const rho = publicKey.slice(exports.TVEC_BYTES);
|
|
261
|
+
// A uniform ring vector for the non-chosen slot (RO of fresh receiver randomness).
|
|
262
|
+
const nSlot = core.hashToRing(concat(TAG_N, sid, u32(i), rng.bytes(exports.SYM_BYTES)));
|
|
263
|
+
const cPoint = core.ringSub(tReal, hpk(sid, i, nSlot));
|
|
264
|
+
points.push(c === 0 ? [cPoint, nSlot] : [nSlot, cPoint]);
|
|
265
|
+
rhos.push(rho);
|
|
266
|
+
secretKeys.push(secretKey);
|
|
267
|
+
retained.push(c);
|
|
268
|
+
}
|
|
269
|
+
return { message: { rn, points, rhos }, state: { choices: retained, secretKeys, rhos, rn, sid } };
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* SENDER round (RANDOM variant): derive each slot's effective public key `pk_b = (P_b + Hpk(sid,i,P_{1−b}) ‖ rho)`,
|
|
273
|
+
* CPA-encrypt a fresh random payload under each, and output both per-slot pads. No messages are padded
|
|
274
|
+
* — the two pads per transfer ARE the random output (consumed by the hybrid combiner / the chosen-message
|
|
275
|
+
* wrapper below).
|
|
276
|
+
*/
|
|
277
|
+
function endemicLweSendRandom(message, rng = (0, csprng_1.secureOtRandom)(), tamper) {
|
|
278
|
+
const sid = endemicSessionId(message.rn);
|
|
279
|
+
const { points, rhos } = message;
|
|
280
|
+
const ciphertexts = [];
|
|
281
|
+
const senderPads = [];
|
|
282
|
+
for (let i = 0; i < points.length; i++) {
|
|
283
|
+
const [p0, p1] = points[i];
|
|
284
|
+
const rho = rhos[i];
|
|
285
|
+
const effT0 = core.ringAdd(p0, hpk(sid, i, p1));
|
|
286
|
+
const effT1 = core.ringAdd(p1, hpk(sid, i, p0));
|
|
287
|
+
const pk0 = concat(effT0, rho);
|
|
288
|
+
const pk1 = concat(effT1, rho);
|
|
289
|
+
const r0 = rng.bytes(exports.SYM_BYTES);
|
|
290
|
+
const r1 = rng.bytes(exports.SYM_BYTES);
|
|
291
|
+
const ct0 = core.kpkeEnc(pk0, r0, rng.bytes(exports.SYM_BYTES));
|
|
292
|
+
const ct1 = core.kpkeEnc(pk1, r1, rng.bytes(exports.SYM_BYTES));
|
|
293
|
+
ciphertexts.push([ct0, ct1]);
|
|
294
|
+
senderPads.push([
|
|
295
|
+
padBytes(sid, i, 0, r0, exports.ENDEMIC_SECRET_BYTES),
|
|
296
|
+
padBytes(sid, i, 1, r1, exports.ENDEMIC_SECRET_BYTES),
|
|
297
|
+
]);
|
|
298
|
+
}
|
|
299
|
+
if (tamper?.tamperCiphertexts)
|
|
300
|
+
tamper.tamperCiphertexts(ciphertexts);
|
|
301
|
+
return { ciphertexts, senderPads };
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* RECEIVER recovery (RANDOM variant): decapsulate ONLY the chosen ciphertext (the chosen branch's
|
|
305
|
+
* effective key equals the receiver's real key) and derive the chosen pad. The non-chosen slot's key
|
|
306
|
+
* is uniform, so its ciphertext is unrecoverable (the endemic property).
|
|
307
|
+
*/
|
|
308
|
+
function endemicLweRecoverRandom(state, senderMessage) {
|
|
309
|
+
const { choices, secretKeys, sid } = state;
|
|
310
|
+
const { ciphertexts } = senderMessage;
|
|
311
|
+
const recvPads = [];
|
|
312
|
+
for (let i = 0; i < choices.length; i++) {
|
|
313
|
+
const c = choices[i] & 1;
|
|
314
|
+
const payload = core.kpkeDec(secretKeys[i], ciphertexts[i][c]);
|
|
315
|
+
recvPads.push(padBytes(sid, i, c, payload, exports.ENDEMIC_SECRET_BYTES));
|
|
316
|
+
}
|
|
317
|
+
return recvPads;
|
|
318
|
+
}
|
|
319
|
+
/** In-process RANDOM endemic base OT. */
|
|
320
|
+
function endemicLweBaseOtRandom(choices, rng = (0, csprng_1.secureOtRandom)(), tamper) {
|
|
321
|
+
const { message, state } = endemicLweReceive(choices, rng);
|
|
322
|
+
const senderMessage = endemicLweSendRandom(message, rng, tamper);
|
|
323
|
+
const recvPads = endemicLweRecoverRandom(state, senderMessage);
|
|
324
|
+
return {
|
|
325
|
+
senderPads: senderMessage.senderPads,
|
|
326
|
+
recvPads,
|
|
327
|
+
sid: state.sid,
|
|
328
|
+
message,
|
|
329
|
+
ciphertexts: senderMessage.ciphertexts,
|
|
330
|
+
};
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* In-process CHOSEN-MESSAGE endemic base OT: `messages[i] = [m0, m1]` (the two must be equal length);
|
|
334
|
+
* `choices[i] ∈ {0,1}`. The sender one-time-pads each message under the endemic random-OT pads and
|
|
335
|
+
* commits to each; the receiver recovers `m_{choices[i]}` and checks the commitment, aborting
|
|
336
|
+
* (`EndemicLweOtAbort`) on any inconsistency. A drop-in for `OtChannel`'s `baseOtFn`.
|
|
337
|
+
*/
|
|
338
|
+
function endemicLweBaseOT(messages, choices, rng = (0, csprng_1.secureOtRandom)(), tamper) {
|
|
339
|
+
if (messages.length !== choices.length)
|
|
340
|
+
throw new Error('endemicLweBaseOT: messages/choices length mismatch');
|
|
341
|
+
const { message, state } = endemicLweReceive(choices, rng);
|
|
342
|
+
const sid = state.sid;
|
|
343
|
+
// Sender: derive effective keys, encrypt a random payload per slot, then one-time-pad + commit each
|
|
344
|
+
// message under the pad expanded to the message length.
|
|
345
|
+
const ciphertexts = [];
|
|
346
|
+
const encrypted = [];
|
|
347
|
+
const commitments = [];
|
|
348
|
+
for (let i = 0; i < messages.length; i++) {
|
|
349
|
+
const [m0, m1] = messages[i];
|
|
350
|
+
if (m0.length !== m1.length) {
|
|
351
|
+
throw new Error(`endemicLweBaseOT (index ${i}): the two messages must be equal length`);
|
|
352
|
+
}
|
|
353
|
+
const [p0, p1] = message.points[i];
|
|
354
|
+
const rho = message.rhos[i];
|
|
355
|
+
const effT0 = core.ringAdd(p0, hpk(sid, i, p1));
|
|
356
|
+
const effT1 = core.ringAdd(p1, hpk(sid, i, p0));
|
|
357
|
+
const r0 = rng.bytes(exports.SYM_BYTES);
|
|
358
|
+
const r1 = rng.bytes(exports.SYM_BYTES);
|
|
359
|
+
ciphertexts.push([
|
|
360
|
+
core.kpkeEnc(concat(effT0, rho), r0, rng.bytes(exports.SYM_BYTES)),
|
|
361
|
+
core.kpkeEnc(concat(effT1, rho), r1, rng.bytes(exports.SYM_BYTES)),
|
|
362
|
+
]);
|
|
363
|
+
const pad0 = padBytes(sid, i, 0, r0, m0.length);
|
|
364
|
+
const pad1 = padBytes(sid, i, 1, r1, m1.length);
|
|
365
|
+
encrypted.push([xorBytes(m0, pad0), xorBytes(m1, pad1)]);
|
|
366
|
+
commitments.push([commitBytes(sid, i, 0, m0, pad0), commitBytes(sid, i, 1, m1, pad1)]);
|
|
367
|
+
}
|
|
368
|
+
if (tamper?.tamperCiphertexts)
|
|
369
|
+
tamper.tamperCiphertexts(encrypted);
|
|
370
|
+
// Receiver: decrypt the chosen ciphertext, unmask the chosen message, check the commitment.
|
|
371
|
+
const received = [];
|
|
372
|
+
for (let i = 0; i < messages.length; i++) {
|
|
373
|
+
const c = choices[i] & 1;
|
|
374
|
+
const payload = core.kpkeDec(state.secretKeys[i], ciphertexts[i][c]);
|
|
375
|
+
const e = encrypted[i][c];
|
|
376
|
+
const pad = padBytes(sid, i, c, payload, e.length);
|
|
377
|
+
const m = xorBytes(e, pad);
|
|
378
|
+
if (!ctEqual(commitBytes(sid, i, c, m, pad), commitments[i][c])) {
|
|
379
|
+
throw new EndemicLweOtAbort(`endemic base OT (index ${i}): sender ciphertext inconsistent with its commitment; aborting`);
|
|
380
|
+
}
|
|
381
|
+
received.push(m);
|
|
382
|
+
}
|
|
383
|
+
return {
|
|
384
|
+
received,
|
|
385
|
+
transcript: { rn: message.rn, points: message.points, rhos: message.rhos, ciphertexts, encrypted, commitments },
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
/**
|
|
389
|
+
* The chosen-message endemic base OT as a `BaseOtFn` (only `received` is part of the contract).
|
|
390
|
+
*/
|
|
391
|
+
const endemicLweBaseOtFn = (messages, choices, rng) => ({
|
|
392
|
+
received: endemicLweBaseOT(messages, choices, rng).received,
|
|
393
|
+
});
|
|
394
|
+
exports.endemicLweBaseOtFn = endemicLweBaseOtFn;
|
|
395
|
+
/**
|
|
396
|
+
* Wire the endemic ML-KEM base OT into the KOS OT-extension — the RECOMMENDED post-quantum,
|
|
397
|
+
* maliciously-secure base. Everything above the base OT (the IKNP matrix, the KOS correlation check,
|
|
398
|
+
* the correlation-robust hash) is unchanged; only the `κ` setup base OTs run the endemic protocol.
|
|
399
|
+
*
|
|
400
|
+
* const ch = new OtChannel(secureOtRandom(), withEndemicLweBaseOt());
|
|
401
|
+
*/
|
|
402
|
+
function withEndemicLweBaseOt() {
|
|
403
|
+
return { baseOtFn: exports.endemicLweBaseOtFn };
|
|
404
|
+
}
|
|
405
|
+
//# sourceMappingURL=endemic-ot.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"endemic-ot.js","sourceRoot":"","sources":["../src/endemic-ot.ts"],"names":[],"mappings":"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"}
|