Skip to content

Expose general-purpose encrypt/decrypt on the GPU (Paillier, Lookup, BFV) #11

Description

@liwenXtrace

Context

The repo has been repurposed from the XTrace vector-DB SDK into cuhepy, a
homomorphic-encryption library. Full history is preserved at the tags
archive/xtrace-sdk (old staging, including all of your BFV work) and
archive/xtrace-sdk-main.

Since main and staging were rewritten: push anything local, then re-clone
rather than pulling.

The code now separates primitives from the application built on them:

cuhepy/paillier/  scheme.py  lookup.py                       primitives
cuhepy/bfv/       scheme.py  evaluator.py  rns.py  native.py  private.py
cuhepy/hamming/   base.py  paillier.py  paillier_lookup.py  bfv.py
                  bfv_{security,assurance,guarded,verified,attested,nitro}.py

Imports run application → primitive only. Your BFV modules moved but were not
otherwise changed; git log --follow works, and the commits are in the archive
tags.

The gap

Today the GPU accelerates only Hamming-specialised Paillier. There is no entry
point that encrypts an arbitrary integer on the GPU — encrypt_kernel takes
const uint8_t *all_bits and builds the plaintext from the bit-pair padding
on-device. For most people evaluating an HE library, general encrypt/decrypt
is the feature; encrypted Hamming search is the demo.

general encrypt/decrypt over arbitrary ints state
Paillier CPU paillier/scheme.py works; no batching wrapper, no scalar multiply
Paillier GPU encrypt is bits-only; decrypt_only_kernel exists but unexposed
Lookup CPU paillier/lookup.py works
Lookup GPU encrypt_cts / decrypt_cts ⚠️ already written in C++, not surfaced in Python
BFV CPU bfv/scheme.py works
BFV GPU ❌ your in-progress work

Suggested order

  1. Surface Lookup GPU general enc/dec. PaillierGPULookupClient::encrypt_cts
    (accepts py::int_, range-checks against n) and decrypt_cts already do
    the right thing. This is a Python wrapper, not a CUDA change — cheapest win.
  2. Paillier GPU. Needs an encrypt entry taking limbs rather than bits;
    decrypt_only_kernel and modmul_pointwise_kernel are already general
    (modmul_pointwise is homomorphic addition).
  3. BFV GPU — yours.

Design note

The Hamming specialisation can stay; it is a real contribution. But it should
sit on top of the general kernels rather than beside them:

  • Evaluate needs nothing — modmul_pointwise_kernel is already general.
  • Encrypt should move the bit-pair interleave host-side. The general path
    uploads the packed plaintext (2·embed_len bits = 128 B/vector) instead of raw
    bits (512 B/vector), so it is ~4× less PCIe traffic, not more.
  • Decode is the only place the specialisation clearly earns its keep: the
    fused decode-and-popcount returns ~4 B/vector instead of ~128 B. Worth
    measuring fused vs unfused before assuming it matters — for 10k vectors the
    difference is a few hundred µs of transfer plus ~10 ms of host popcount,
    which is small next to the modexp work. If it is negligible, the
    Hamming-specific CUDA surface can go to zero.

Smaller items

  • encrypt_cts converts each py::int_ via a decimal string
    (py::str(obj)mpz(s, 10)). Base-10 parsing of a 1024-bit integer;
    mpz_import from int.to_bytes() would be much faster.
  • paillier/scheme.py has no plaintext-scalar multiply (E(m)^k = E(k·m)).
    multiply correctly raises for ct×ct, but the scalar case is the most-used
    Paillier operation in federated learning and is a few lines.
  • alpha_len default is now 280 (was 50), matching the compiled
    ALPHA_LEN, with a 256-bit floor enforced at key generation. At 50 bits the
    secret exponent was recoverable from the public key in ~3.5 min on a laptop —
    see docs/research/paillier-security.md (PL-01) and
    attacks/pl01_alpha_recovery.py.

Before any release

  • CI/CD was removed and needs redesigning. Two findings from its last run:
    auditwheel cannot repair the BFV extension to manylinux_2_31 ("too-recent
    versioned symbols") — needs an older toolchain or a newer manylinux target;
    and msgpack had been dropped from dependencies while hamming/bfv_security
    imports it (fixed).
  • The GPU and C++ backends have not been built since the restructure. Paths
    in build_gpu_binaries.sh, both Makefiles, hatch_build.py and the
    Dockerfile.dockerignore were corrected by inspection, not by running them.
    A CUDA build and make -C src/cuhepy/bfv/_cpu_ext are the real test.
  • B023/E731 in benchmarks/bfv_nitro.py are false positives (every lambda is
    invoked immediately inside time_call); benchmarks/ and experiments/ are
    outside ruff's default scope. Noting so nobody re-litigates it.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions