@atlasauth/pca-mpc-lwe-ot-wasm
v0.4.1
Published
Post-quantum endemic (Masny-Rindal) base-OT lattice core for @atlasauth/pca-mpc: Kyber-768 IND-CPA (K-PKE) from the vetted pqc_kyber reference crate compiled to WebAssembly, plus the ring arithmetic + uniform-ring random oracle the additive endemic constr
Maintainers
Readme
@atlasauth/pca-mpc-lwe-ot-wasm
The post-quantum, maliciously-secure endemic base-OT lattice core for @atlasauth/pca-mpc.
@atlasauth/pca-mpc's its ML-KEM base-OT module is a semi-honest ML-KEM base OT: a malicious receiver can keep
both ML-KEM secret keys and learn both messages, and an opaque KEM cannot detect it. This package
removes that residue by exposing exactly the Kyber-768 IND-CPA (K-PKE) primitives the endemic
OT of Masny–Rindal (ePrint 2019/706) needs, so that the non-chosen branch's public key is forced to
be a uniform ring element — provably undecryptable under decisional Module-LWE. The full
protocol lives in @atlasauth/pca-mpc's its endemic-OT module; this package is just the lattice core.
Install
npm i @atlasauth/pca-mpc-lwe-ot-wasmThis is the lattice core @atlasauth/pca-mpc uses for its post-quantum base OT; you normally get it as a dependency of @atlasauth/pca-mpc.
Node >= 20. The .wasm file ships inside the package and is loaded relative to the installed dist/ directory; no build step or Rust toolchain is needed to use it.
The vetted boundary (no hand-rolled Kyber)
Every Module-LWE / Kyber operation — K-PKE key generation, CPA encryption, CPA decryption, and
therefore the NTT, matrix expansion, CBD noise, polynomial multiplication, compression and modular
reduction — runs through the audited pqc_kyber reference implementation (crates.io 0.7.1),
reached via its hazmat / indcpa surface and compiled to WebAssembly (crate/). The FO transform
is bypassed, which is exactly what an endemic OT requires.
This crate adds only three non-cryptographic pieces pqc_kyber does not re-export:
- 12-bit (de)serialization of a public-key ring vector
t̂(a byte-for-byte copy of the Kyber referencepoly_{to,from}bytespacking); - coefficient-wise
t̂addition / subtraction modulo the public primeq = 3329(plain modular vector arithmetic — NTT linearity makes this the ring sum, used for the additive endemic trick); - a random oracle into the ring: SHAKE128 + the standard FIPS-203 / Kyber
SampleNTTrejection sampler, yielding a uniformt̂vector.
None of these is the Kyber PKE, its NTT, its noise sampler or its compression.
crate/vendor/pqc_kyberispqc_kyber0.7.1 with a manifest-only change (crate-type = ["rlib"], so cargo does not try to build a std-lesscdylibforwasm32-unknown-unknown). The algorithm source is byte-identical to the crates.io release; the[patch.crates-io]incrate/Cargo.tomlwires it in. The package still pinspqc_kyber = "0.7.1"as the dependency of record.
API
import {
kpkeKeygen, kpkeEnc, kpkeDec, // Kyber-768 K-PKE (IND-CPA): deterministic keygen, CPA enc/dec
ringAdd, ringSub, // (a ± b) mod q over a serialized t̂
hashToRing, // SHAKE128 -> uniform ring vector
PK_BYTES, SK_BYTES, CT_BYTES, TVEC_BYTES, SYM_BYTES, // 1184 / 1152 / 1088 / 1152 / 32
} from '@atlasauth/pca-mpc-lwe-ot-wasm';The WASM is no_std, allocator-free, instantiates with an empty import object, and is driven
through fixed static buffers in linear memory (mirrors @atlasauth/pca-mpc-wasm).
Build & test
pnpm build:wasm # cargo build --release --target wasm32-unknown-unknown + copy artifact + cargo clean
pnpm build # tsc
pnpm test # vitest (parity / KATs through the wasm binding)Native KATs for the Kyber arithmetic (decryption correctness, deterministic regression vector, the
ring homomorphism, the uniform-branch endemic property) live in crate/src/lib.rs
(cargo test --features hoststd).
Security achieved
- Sender privacy (endemic): a (even malicious) receiver cannot learn
m_{1−c}— its branch has a uniform public key, so recovering the payload reduces to IND-CPA of K-PKE under a uniform key, i.e. decisional Module-LWE; and it cannot make both branches decryptable (Module-SIS). - Receiver choice privacy: computational under decisional Module-LWE, even vs a quantum sender.
- Post-quantum: rests only on Module-LWE (ML-KEM-768, NIST category 3) + a random oracle.
Composed with the KOS correlation check in @atlasauth/pca-mpc, κ endemic base OTs become
many maliciously-secure, post-quantum OTs.
Honest residual: the Kyber core is a prototype and is not claimed constant-time (a documented side-channel boundary, not a break of the MLWE/ROM security); K-PKE has a negligible (~2⁻¹³⁹) decryption-failure probability inherited from the primitive.
Status
Experimental. The Kyber core is a prototype use of a non-FO primitive and has not been independently audited.
What is validated. The K-PKE encrypt and decrypt core is checked against NIST's official ACVP vectors for ML-KEM-768 (FIPS 203): all 25 encapsulation vectors (ciphertext and shared secret reproduced exactly) and all 10 decapsulation vectors, including the implicit-rejection cases, by composing this core with the FIPS 203 wrapper hashes. It is also cross-checked against an independent implementation (kyber-py 1.2.0): encryption is byte-identical, decryption interoperates in both directions, and hashToRing matches an independent transcription of the FIPS 203 SampleNTT algorithm.
Known difference from ML-KEM. The underlying library derives K-PKE keys from the seed as G(d), while FIPS 203 uses G(d || k). kpkeKeygen therefore does not reproduce the official ML-KEM key-generation vectors and is not an ML-KEM key generator; the keys it produces are valid K-PKE keys (they interoperate with kyber-py in both directions). The Fujisaki-Okamoto transform is intentionally bypassed, so this package is not an ML-KEM implementation and offers no chosen-ciphertext security on its own. Constant-time behavior and the endemic-OT construction built on top are not covered by these tests.
Build provenance
The shipped wasm/pca_mpc_lwe_ot_wasm.wasm is built from the Rust source in crate/ (with its Cargo.lock) and is bit-for-bit reproducible.
| | |
| --- | --- |
| artifact | wasm/pca_mpc_lwe_ot_wasm.wasm |
| sha256 | a1498859a453eea725113f95c5da43f9b37cc83dc3f4b75e0e4a958bfd94c5ef |
| target | wasm32-unknown-unknown, --release --locked via crate/build-wasm.sh (path-remapped; opt-level s, LTO, panic = "abort", stripped) |
| toolchain | rustc 1.99.0 (b940084d7 2026-09-28), cargo 1.99.0 |
| locked crates | pqc_kyber 0.7.1 (vendored, manifest-only change), sha3 0.10.9, rand_core 0.6.4 |
Verify: bash crate/build-wasm.sh && shasum -a 256 wasm/pca_mpc_lwe_ot_wasm.wasm (needs rustup target add wasm32-unknown-unknown). The script passes --remap-path-prefix for the crate, home, cargo registry and rustc sysroot and -Cdebuginfo=0, so the build is path-independent: no host path is embedded, and the same sha256 results from any checkout location.
License
MIT - see LICENSE.
