This repo has been merge into https://github.com/cedoor/squid
poulpy-js is a JavaScript library for browser-usable FHE, built on Poulpy via Squid (an ergonomic Rust wrapper). It ships a WebAssembly client (poulpy-js/client) and a napi-rs Node evaluator (poulpy-js/server) — see packages/poulpy-js/README.md for install and API docs.
This repo is the Cargo + pnpm monorepo that builds the library, plus a client/server demo showing it end-to-end: the browser generates its own (secret_key, evaluation_key) pair, ships only the evaluation key and ciphertexts to the server, and decrypts results locally. The server never sees plaintexts and never holds secret-key material.
poulpy-js/
├─ Cargo.toml # Rust workspace
├─ pnpm-workspace.yaml
├─ package.json # root scripts
├─ crates/
│ ├─ poulpy-wasm/ # wasm-bindgen bindings (browser)
│ └─ poulpy-napi/ # napi-rs bindings (Node server)
├─ packages/
│ └─ poulpy-js/ # dual entry point:
│ # `poulpy-js/client` (browser, wasm worker + PoulpyClient)
│ # `poulpy-js/server` (Node, napi-backed Evaluator)
├─ demo/ # Next.js FHE demo
└─ tests/ # Playwright end-to-end tests
- Rust nightly (pinned in
rust-toolchain.toml), with thewasm32-unknown-unknowntarget wasm-pack(cargo install wasm-pack)- Node.js 20+ and pnpm 9+
pnpm install
pnpm build # build:poulpy (wasm + napi + ts) → build:demo
pnpm dev # Next.js demo on :3000
pnpm test # Playwright: installs Chromium (pretest), runs demo flowIndividual steps are also available (pnpm build:poulpy, pnpm build:demo). build:poulpy compiles the wasm crate via wasm-pack, the napi crate via @napi-rs/cli, and the TS wrappers via tsc — all into packages/poulpy-js/.
GitHub Actions (.github/workflows/e2e.yml) runs pnpm install, pnpm build, and pnpm test on pushes and pull requests to main / master.
- Browser.
PoulpyClient.create({ paramsSet })spins up a module worker that loads wasm and callsSession::new_random(paramsSet). Squid resolves the name withParams::by_name(e.g."test"or"unsecure"), thenContext::keygen_with_seedsruns under that parameter set. The client exposesevaluationKeyplus asyncencryptU32,decryptU32, andexportSeeds(all in the worker). The sameparamsSetmust be used on the server (POULPY_PARAMS_SETin the demo). - Client → server handshake. The browser POSTs raw evaluation-key bytes (
Content-Type: application/octet-stream) toPOST /session. The server deserializes into apoulpy_napi::Evaluatorand stores it in an in-memoryMapkeyed by a UUID. - Compute. The browser POSTs packed ciphertext bytes to
POST /session/:id/add. The server deserializes both, runs homomorphic add, and returns the serialized result ciphertext. - Decrypt. Browser
awaitsclient.decryptU32(result); secret-key material never leaves the worker/page.
- Parameter sets —
paramsSetis a Squid name (currently"test"or"unsecure"). The demo defaults to"test"; that set uses the same layout bundle as Poulpy’sbdd_arithmetictest_suite and is smaller/faster than"unsecure". Neither is a vetted production security level. - Sessions are in-memory and unauthenticated (single-process demo only).
- Keygen runs in the wasm worker until it finishes; the demo UI stays on “Booting wasm…” until the worker reports ready (the main thread stays responsive).