Metadata-Version: 2.4
Name: implicant
Version: 0.3.0
Summary: Python client SDK for the Implicant FHE inference platform
Author: Implicant
License: Apache-2.0
License-File: LICENSE
Requires-Python: >=3.10
Requires-Dist: httpx>=0.27
Requires-Dist: implicant-fhe<0.3,>=0.2.2
Requires-Dist: numpy>=1.26
Requires-Dist: pydantic>=2.6
Requires-Dist: typer>=0.12
Provides-Extra: app
Requires-Dist: keyring>=24; extra == 'app'
Requires-Dist: pyside6>=6.6; extra == 'app'
Provides-Extra: dev
Requires-Dist: pytest-cov>=5; extra == 'dev'
Requires-Dist: pytest-qt>=4; extra == 'dev'
Requires-Dist: pytest>=8; extra == 'dev'
Description-Content-Type: text/markdown

# Implicant SDK

Python **client** for the Implicant FHE inference platform. Encrypts one row
locally under BGV, sends the ciphertext to the platform for homomorphic
evaluation, and decrypts the result. The server never sees plaintext; the
secret key never leaves the process.

The classifier head runs **server-side under FHE** (Variant B): the platform
returns one ciphertext with the class scores packed contiguously, which the
client decrypts (unsigned) and decodes with `decode_class_scores` before
threshold/argmax. `W` / `b` never reach the client.

Pure Python — all crypto comes from [`implicant-fhe`](https://github.com/implicant/implicant-fhe)
(`helut.client`). Contracts: [`docs/architecture.md`](docs/architecture.md)
and `platform/docs/FHE_INTERFACE_SPEC.md`.

## Install (developers)

`implicant-fhe` (the `helut` crypto wheel) is not on a public index — resolve it
from the bundled `./wheels/`. Wheels ship for **cp310–cp313** (macOS-arm64 +
manylinux-x86_64) only; Python 3.14 has no wheel, so use a 3.10–3.13 interpreter.

```bash
python3.13 -m venv .venv313
.venv313/bin/pip install -e ".[app,dev]" --find-links wheels/
.venv313/bin/pytest tests/ -v      # 105 tests (102 pass, 3 e2e skip w/o demo bundles)
```

## Desktop app (end users)

Non-technical users install a double-click app instead of using Python:

- **macOS (Apple chip):** open the `.dmg` and drag Implicant to Applications.
- **Linux (Intel/AMD chip):** run the `.AppImage`.

Other platforms are not supported yet; the app says so on launch. Building the
installers is documented in `docs/INSTALL_SMOKE_TEST.md`.

## Running an inference (CLI)

The `implicant` CLI is the client-side workflow: configure once, then run
encrypted predictions. Everything stays local except the ciphertext and the
public keys — the secret key never leaves your machine.

### 1. Point the client at the platform

```bash
implicant init --api-url https://api.implicant.example
```

Writes `~/.implicant/config.toml`. Run `implicant status` to confirm the
configured `api_url` and list any locally cached keys.

### 2. Set your API token

The bearer token is read from the environment, never stored on disk:

```bash
export IMPLICANT_API_KEY="imp_..."
```

### 3. Prepare the input row

One row of raw feature values, as a JSON object (or a single-row CSV). The keys
are the feature names the model expects:

```json
{
  "mean radius": 14.13,
  "mean texture": 19.29,
  "mean perimeter": 91.97,
  "mean area": 654.89
}
```

See `examples/cancer_row.json` and `examples/diabetes_row.json` for full rows.

### 4. Predict

```bash
implicant predict --model breast-cancer --input examples/cancer_row.json
```

This fetches the model manifest, generates (or reloads) your keys, uploads the
**public** keys on first use, encrypts the row locally, sends the ciphertext,
then decrypts and decodes the returned class scores:

```json
{
  "key_id": "bgv-n32768-L4-a1b2c3d4e5f6",
  "label_index": 0,
  "label": "0",
  "scores": [123, -45]
}
```

Add `--no-persist-key` to use an ephemeral secret key for a single run (nothing
written to disk; keys are regenerated and re-uploaded next time).

### Managing keys

The first prediction for a `key_id` persists your secret key to
`~/.implicant/keys/<key_id>/secret_key.bin` (mode `0600`) so later runs skip
keygen. Inspect and clean up the local store:

```bash
implicant keys list            # list key_ids; flags which have a persisted SK
implicant keys rm <key_id>     # delete one stored key (secret + public)
implicant keys purge --yes     # delete all stored keys
```

## Use (Python)

The same flow is available programmatically:

```python
from implicant import ImplicantClient
from implicant.transport import HttpxTransport

client = ImplicantClient(
    HttpxTransport(base_url="https://api.implicant.example", api_key="imp_..."),
    key_cache_dir="~/.implicant/keys",
)
result = client.predict(
    "breast-cancer",
    {"mean radius": 14.13, "mean texture": 19.29},
    class_names=("benign", "malignant"),
)
print(result.prediction.label)
```

## Demo mode

Demo mode skips FHE key generation by loading a pre-generated keypair shipped
inside the package, and skips the public-key upload (the platform already holds
the matching public bundle). It exists so a prediction can run immediately in a
live demo without the ~250 s keygen delay.

Activate with an environment variable (applies to the whole session):

```bash
export IMPLICANT_DEMO=1
implicant predict -m cancer -i row.json
```

Or per-command:

```bash
implicant predict -m cancer -i row.json --demo
```

Only the provisioned demo models (`cancer`, `diabetes`) have bundled keys; other
model IDs raise an error in demo mode.

> **Security warning — demo mode is not private.** The demo secret key is
> shipped inside the package and is therefore public: anyone with the wheel can
> decrypt anything encrypted in demo mode. **Never use demo mode for real or
> sensitive data.** Normal mode (the default) generates a secret key that never
> leaves your machine.

## License

Apache-2.0.
