Official Python SDK for FHEnom for AI™ - Confidential AI with fully encrypted models and data
Project description
FHEnom AI Python Client Library
Official Python SDK for FHEnom for AI™ - Confidential AI with fully encrypted models and data.
🚀 Quick Start
Installation
pip install fhenomai
Or install from source:
CLI Configuration
First, configure the CLI with your TEE server details:
# Initialize configuration (interactive)
fhenomai config init \
--admin-host YOUR_TEE_IP \
--admin-port 9099 \
--user-host YOUR_TEE_IP \
--user-port 9999 \
--sftp-host YOUR_TEE_IP \
--sftp-username admin \
--sftp-password YOUR_PASSWORD
# Verify configuration
fhenomai config show
# Test connectivity
fhenomai test connection
Basic CLI Usage
# List models
fhenomai model list --show-status
# Upload model via SFTP (upload/ prefix added automatically)
fhenomai sftp upload ./my-model my-model --recursive
# Encrypt model (paths normalized automatically)
fhenomai model encrypt my-model my-model-encrypted \
--encrypted-model-id my-model-encrypted \
--wait --show-progress
# Download encrypted model (download/ prefix added automatically)
fhenomai sftp download my-model-encrypted ./encrypted/my-model --recursive
# Start serving
fhenomai serve start my-model-encrypted \
--server-url http://YOUR_VLLM_SERVER_IP:8000 \
--display-model-name my-model
# Stop serving
fhenomai serve stop my-model-encrypted
# --- Sovereign split inference ---
# Split the model: keep the first/last layers in the TEE, run the middle
# layers on your own server.
fhenomai model split my-model-encrypted --first-layers 1 --last-layers 1
# Start the split model: the TEE connects out to your sovereign server
# (no --server-url for sovereign mode).
fhenomai serve start my-model-encrypted \
--display-model-name my-model-sovereign \
--sovereign-server-host 172.19.0.1 \
--sovereign-server-port 8000
Basic Python SDK Usage
from fhenomai import FHEnomClient, FHEnomConfig
# Load configuration from file
config = FHEnomConfig.from_file() # Reads from ~/.fhenomai/config.yaml
# Initialize client
client = FHEnomClient(config)
# List available models
models = client.admin.list_models()
print(f"Available models: {models}")
# Encrypt a model (paths auto-prefixed with /models/upload/ and /models/download/)
job_id = client.admin.encrypt_model(
model_name_or_path="llama-3-8b", # Becomes /models/upload/llama-3-8b
out_encrypted_model_path="llama-3-8b-encrypted", # Becomes /models/download/llama-3-8b-encrypted
encrypted_model_id="llama-3-8b-encrypted"
)
# Wait for completion
result = client.admin.wait_for_job(job_id, timeout=3600)
# Start serving
client.admin.start_serving(
encrypted_model_id="llama-3-8b-encrypted",
server_url="http://YOUR_VLLM_SERVER_IP:8000", # vLLM server IP/hostname
display_model_name="llama-3-8b-instruct" # Optional: for vLLM --served-model-name
)
Sovereign Split Inference
In sovereign mode the security-critical first/last layers stay inside the TEE while the structurally-inert middle layers run on your own server. Split the model once, then start it pointing the TEE at your sovereign server.
# Split: keep 1 leading + 1 trailing layer in the TEE, middle layers go sovereign
job_id = client.admin.split_model(
encrypted_model_id="llama-3-8b-encrypted",
first_layers=1,
last_layers=1,
)
client.admin.wait_for_job(job_id, timeout=3600)
# Start sovereign serving — the TEE connects OUT to your sovereign server,
# so no server_url is passed.
client.admin.start_serving(
encrypted_model_id="llama-3-8b-encrypted",
display_model_name="llama-3-8b-sovereign",
sovereign_server_host="172.19.0.1", # reachable from inside the TEE
sovereign_server_port=8000,
)
📚 Features
Core Capabilities
- CLI Tool: Full-featured command-line interface for all operations
- Python SDK: Programmatic access via
FHEnomClientandAdminAPI - Model Encryption: Encrypt models on TEE server with progress tracking
- Dataset Encryption: Encrypt datasets using encrypted models
- SFTP Integration: Upload/download with automatic path normalization
- Job Monitoring: Real-time progress updates and status checking
- Serving Control: Start/stop model serving with vLLM integration
CLI Commands
- config:
init,show,validate,test - model:
list,encrypt,encrypt-dataset,info,upload,download,delete - serve:
start,stop,list - sftp:
upload,download,list,clear - job:
status,wait - health:
check,admin,sftp - test:
connection,admin,sftp
Advanced Features
- Progress Bars: Rich terminal UI with real-time progress
- Auto Path Normalization: Automatic
upload/anddownload/prefix handling - Duplicate Detection: Warns about existing model names
- Directory Management: Bulk operations on TEE directories
- Health Monitoring: Test connectivity to all services
- Context Manager: Automatic resource cleanup
- TEE Attestation: Generate and verify TEE attestation reports with built-in verification
TEE Attestation Support (v1.0.7)
!!! info "New in v1.0.7" Enhanced attestation with automatic file management, format inference, and built-in verification. Report formatting is now integrated into fhenomai for stability.
FHEnom AI includes integrated TEE attestation with AMD SEV-SNP and Intel TDX support:
# Install fhenomai (includes dk-tee-attestation for verification)
pip install fhenomai
# Generate attestation report (creates 3 files)
fhenomai admin attestation --output report.html
# Creates: report.html, report.bin, report.nonce
# Verify attestation (nonce auto-loads from report.nonce)
fhenomai admin verify-attestation --report report.bin
# Generate detailed PDF with hex dump
fhenomai admin attestation --format detailed --output analysis.pdf
# Verify with detailed output
fhenomai admin verify-attestation --report report.bin --format detailed
What's New in v1.0.7:
- ✨ Triple file output: All attestation commands create .html/.pdf/.txt + .bin + .nonce
- ✨ Format inference: File extension determines output type (.html, .pdf, .txt)
- ✨ Changed
--formatbehavior: Now controls display style (standard/detailed) not output type - ✨ Auto-load nonce: Verification automatically loads .nonce file if not provided
- ✨ Built-in verification: New
verify-attestationcommand with color-coded output - ✨ Parsed reports: CPU info, TCB details, and signatures cleanly displayed
- ✨ Integrated formatter: Report formatting moved from dk-tee-attestation to fhenomai for API stability
Python SDK usage:
from fhenomai import FHEnomClient, AttestationReportFormatter
client = FHEnomClient.from_config()
# Generate attestation (nonce auto-generated)
report = client.admin.attestation()
# Save report
with open("report.bin", "wb") as f:
f.write(report)
# Verify attestation
result = client.admin.verify_attestation(
report=report,
engine_type="amd_sev_snp"
)
if result['verified']:
print(f"✓ Verified - Platform: {result['platform']}")
print(f" CPU: {result['cpu_info']}")
# Use the formatter directly for custom output
formatter = AttestationReportFormatter()
html_report = formatter.format_html(report)
with open("custom_report.html", "w") as f:
f.write(html_report)
Verification Features:
- ✅ ECDSA P-384 signature validation
- ✅ Nonce binding verification
- ✅ TCB (Trusted Computing Base) parsing
- ✅ CPU identification
- ✅ Color-coded hex dumps
- ✅ HTML/PDF report generation
- ✅ Platform detection (AMD SEV-SNP, Intel TDX)
📖 Documentation
Admin API Operations
# Model discovery
models = client.admin.list_models()
online_models = client.admin.list_online_models()
model_info = client.admin.get_model_info(model_id)
# Model encryption (paths auto-normalized)
job_id = client.admin.encrypt_model(
model_name_or_path="model-name", # Auto-prefixed with /models/upload/
out_encrypted_model_path="model-name-encrypted", # Auto-prefixed with /models/download/
encrypted_model_id="model-name-encrypted", # Custom model ID
encryption_impl="decoder-only-llm",
dtype="bfloat16",
server_ip="fhenom_ai_server",
server_port=9100
)
# Dataset encryption (paths auto-normalized)
dataset_job = client.admin.encrypt_dataset(
encrypted_model_id="my-encrypted-model",
dataset_name_or_path="my-dataset", # Auto-prefixed with /models/upload/
out_encrypted_dataset_path="my-dataset-encrypted", # Auto-prefixed with /models/download/
dataset_encryption_impl="numeric",
text_fields=["text"],
server_ip="fhenom_ai_server",
server_port=9100
)
Implementation-selector parameters
The encryption methods accept several string parameters that select an implementation strategy. The canonical list lives in fhenomai/impl_choices.py and is enforced at runtime by the SDK and CLI — passing an unrecognized value raises ValueError immediately.
| Parameter | Default | Allowed values |
|---|---|---|
encryption_impl (model) |
decoder-only-llm |
decoder-only-llm, moe-llm, nomic-bert-text-embedding, llama-bidirectional-embedding |
preprocessing_impl (model) |
default |
default, lora, bert-model, final-linear |
inference_mode (model) |
double_tokenizer |
double_tokenizer, embedding_only_double_tokenizer |
driver_mode (model) |
safetensor |
safetensor |
dtype (model) |
bfloat16 |
bfloat16, float16, float32 |
dataset_encryption_impl (dataset) |
numeric |
numeric |
To inspect at runtime:
from fhenomai import ENCRYPTION_IMPL, ALL_CHOICES
print(ENCRYPTION_IMPL.values_tuple) # ('decoder-only-llm', 'moe-llm', ...)
for choice in ALL_CHOICES:
print(choice.name, choice.values_tuple)
Reusing keying material across related models
encrypt_model() accepts an optional related_encrypted_model_id argument. When set, the TEE retrieves the tokenizer / embedding keying material from that previously-encrypted model and reuses it for the new one. Typical use: encrypting a LoRA adapter or embedding head on top of an already-encrypted base model, or batching a family of fine-tuned variants that must share a vocabulary.
# SDK
client.admin.encrypt_model(
model_name_or_path="my-lora-adapter",
out_encrypted_model_path="my-lora-encrypted",
encryption_impl="llama-bidirectional-embedding",
preprocessing_impl="final-linear",
inference_mode="embedding_only_double_tokenizer",
related_encrypted_model_id="9a2504c671064c5087120ed7c1ae3cb0",
)
# CLI
fhenomai model encrypt my-lora-adapter my-lora-encrypted \
--encryption-impl llama-bidirectional-embedding \
--preprocessing-impl final-linear \
--inference-mode embedding_only_double_tokenizer \
--related-encrypted-model-id 9a2504c671064c5087120ed7c1ae3cb0
Channel security (encrypted token channel)
encrypt_model() accepts an optional secure_channel flag (default False). When enabled, the TEE provisions a TPM-protected pre-shared key at encryption time and uses an AES-GCM-encrypted token channel for inference and dataset encryption, so token IDs never travel in cleartext. The choice is baked into the model at encryption time. Note that return_token_ids is not supported at inference time when channel security is enabled.
# SDK
client.admin.encrypt_model(
model_name_or_path="llama-3-8b",
out_encrypted_model_path="llama-3-8b-secure",
secure_channel=True,
)
# CLI
fhenomai model encrypt llama-3-8b llama-3-8b-secure --secure-channel
# Serving control
client.admin.start_serving(
encrypted_model_id=model_id,
server_url="http://YOUR_VLLM_SERVER_IP:8000", # vLLM server IP/hostname
api_key=None, # Optional
display_model_name="my-model" # Optional: custom name for vLLM
)
client.admin.stop_serving(model_id)
# Job management
status = client.admin.get_job_status(job_id)
result = client.admin.wait_for_job(
job_id,
poll_interval=5,
timeout=3600,
callback=lambda s: print(f"Progress: {s.get('progress', 0)*100:.1f}%")
)
Provisioning & License Management
CLI: Standard Provisioning
Provision (or re-provision) a TEE node with client configuration and license:
# Initial provisioning with client parameters
fhenomai provision \
--client-id "my-client" \
--num-encryptable 100 \
--admin-token "my-admin-token" \
--rotation-token "my-rotation-token"
# With SSL client certificates and optional out-of-band license
fhenomai provision \
--client-id "my-client" \
--num-encryptable 100 \
--admin-token "my-admin-token" \
--client-ssl-cert-hex <hex-encoded-cert> \
--client-ssl-key-hex <hex-encoded-key> \
--root-cert-hex <hex-encoded-root-ca> \
--instance-cert-hex <hex-encoded-instance-cert> \
--instance-key-hex <hex-encoded-instance-key>
CLI: License Reuse (After Deprovision)
Fast re-provisioning using the cached license from p2p-auth:
# 1. Deprovision (factory-reset, clears provisioned state)
fhenomai admin deprovision --force --yes-i-understand
# 2. Re-provision using cached internal license (no parameters needed)
fhenomai provision --reuse-license
This workflow reuses the license certificate stored in p2p-auth (TEE), avoiding License Manager contact. Works only if the license is not expired.
SDK: Standard Provisioning
=== "Signature"
python def provision( client_id: str, num_encryptable: int, admin_token: Optional[str] = None, rotation_token: Optional[str] = None, client_ssl_cert_hex: Optional[str] = None, client_ssl_key_hex: Optional[str] = None, root_cert_hex: Optional[str] = None, instance_cert_hex: Optional[str] = None, instance_key_hex: Optional[str] = None, ) -> Dict[str, Any]
=== "Example" ```python from fhenomai import FHEnomClient, FHEnomConfig
config = FHEnomConfig.from_file()
client = FHEnomClient(config)
# Provision with client config (contacts License Manager)
result = client.provisioning.provision(
client_id="my-client",
num_encryptable=100,
admin_token="my-token",
rotation_token="my-rotation-token"
)
print(f"Status: {result['status']}") # "Provisioned"
```
Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
client_id |
str | Yes | Unique client identifier |
num_encryptable |
int | Yes | Number of models allowed to encrypt |
admin_token |
str | No | Admin authentication token |
rotation_token |
str | No | Token for credential rotation |
client_ssl_cert_hex |
str | No | Client SSL cert (hex); requires client_ssl_key_hex |
client_ssl_key_hex |
str | No | Client SSL key (hex); requires client_ssl_cert_hex |
root_cert_hex |
str | No | Root CA cert (hex); requires both instance certs |
instance_cert_hex |
str | No | Instance cert (hex); requires all out-of-band params |
instance_key_hex |
str | No | Instance key (hex); requires all out-of-band params |
Returns: Dict[str, Any] - Provisioning response with status field
Exceptions:
| Exception | Condition |
|---|---|
ValueError |
SSL or out-of-band license parameters incomplete |
ConnectionError |
Cannot connect to TEE server |
HTTPError |
Server returns an error |
Note: Without a valid License Manager certificate, only limited endpoints available on the node.
SDK: Deprovision and License Reuse
from fhenomai import FHEnomClient, FHEnomConfig
config = FHEnomConfig.from_file()
client = FHEnomClient(config)
# Check current license status
license_info = client.admin.get_license_info()
print(f"Status: {license_info['status']}")
print(f"Client: {license_info['client_id']}")
print(f"Models: {license_info['locally_encrypted_models']} / {license_info['available_to_encrypt']}")
# Deprovision the node (destructive factory-reset)
result = client.admin.deprovision()
print(f"Deprovisioned: {result['response']}")
# Wait for node to restart after deprovision
import time
time.sleep(5)
# Re-provision using the cached license from p2p-auth
# (requires node to be in PROVISIONING state after deprovision)
result = client.provisioning.reuse_license()
print(f"Re-provisioned: {result['status']}")
# Verify license was restored (if node is ready)
try:
license_info = client.admin.get_license_info()
print(f"Status: {license_info['status']}")
except Exception:
print("Node still restarting after license reuse")
!!! note "Security" - Private keys remain protected in TPM throughout the process - The license certificate is reused internally from p2p-auth (not portable) - License Manager is not contacted during reuse - Provisioning is always attestation-based
SFTP Operations
# Get SFTP manager
sftp = client.get_sftp_manager()
# Upload model (upload/ prefix added automatically)
sftp.upload_directory(
local_path="./llama-3-8b",
remote_path="llama-3-8b" # Becomes upload/llama-3-8b
)
# Download encrypted model (download/ prefix added automatically)
sftp.download_directory(
remote_path="llama-3-8b-encrypted", # Becomes download/llama-3-8b-encrypted
local_path="./encrypted/llama-3-8b"
)
# List files in upload directory
files = sftp.list_upload_directory()
for file in files:
print(f"{file.name}: {file.size_mb:.2f} MB")
# Clear download directory
sftp.clear_download_directory()
# Get directory size
size_gb = sftp.get_directory_size("upload")
print(f"Upload directory: {size_gb:.2f} GB")
# Check if file exists (via Admin API's SFTP manager)
exists = client.admin.sftp.file_exists("upload/my-model/config.json")
Health & Testing
# Test connectivity (via CLI)
# fhenomai health check
# fhenomai test connection
# In Python - test admin API
try:
models = client.admin.list_models()
print(f"✓ Admin API connected ({len(models)} models)")
except Exception as e:
print(f"✗ Admin API failed: {e}")
# Test SFTP connection
try:
sftp = client.get_sftp_manager()
files = sftp.list_upload_directory()
print(f"✓ SFTP connected ({len(files)} files in upload/)")
except Exception as e:
print(f"✗ SFTP failed: {e}")
User Inference (via OpenAI SDK)
For inference, use the standard OpenAI Python SDK:
from openai import OpenAI
# Connect to FHEnom User API (port 9999)
client = OpenAI(
base_url="http://your-tee-ip:9999/v1",
api_key="not-needed" # TEE doesn't require API key
)
# Standard OpenAI-compatible inference
response = client.chat.completions.create(
model="your-model-name",
messages=[
{"role": "user", "content": "Explain quantum computing"}
],
max_tokens=200
)
print(response.choices[0].message.content)
🛠️ Advanced Usage
Context Manager Usage
from fhenomai import FHEnomClient, FHEnomConfig
# Load config
config = FHEnomConfig.from_file()
# Context manager handles connection lifecycle
with FHEnomClient(config) as client:
# SFTP connection auto-managed
sftp = client.get_sftp_manager()
# Upload model (upload/ prefix added automatically)
sftp.upload_directory("./model", "model")
# Encrypt (paths auto-normalized)
job_id = client.admin.encrypt_model(
model_name_or_path="model",
out_encrypted_model_path="model-enc",
encrypted_model_id="model-enc"
)
# Wait for completion
result = client.admin.wait_for_job(job_id)
if result.get('status') == 'done':
# Download encrypted model (download/ prefix added automatically)
sftp.download_directory(
"model-enc",
"./encrypted/model"
)
# Connection automatically closed
Job Monitoring with Callbacks
import time
# Encrypt with progress callback (paths auto-normalized)
job_id = client.admin.encrypt_model(
model_name_or_path="large-model",
out_encrypted_model_path="large-model-enc",
encrypted_model_id="large-model-enc"
)
# Define callback for progress updates
def progress_callback(status):
progress = status.get('progress', 0) * 100
message = status.get('message', 'Processing')
print(f"\r{message}: {progress:.1f}%", end='', flush=True)
# Wait with callback
result = client.admin.wait_for_job(
job_id,
timeout=3600,
poll_interval=5,
callback=progress_callback
)
print(f"\nCompleted: {result.get('status')}")
## 📋 Configuration
### Configuration File
Create `~/.fhenomai/config.yaml`:
```yaml
# Admin API Configuration
admin:
host: "your-tee-ip"
port: 9099
url: "http://your-tee-ip:9099" # Alternative to host+port
# User API Configuration (for inference)
user:
host: "your-tee-ip"
port: 9999
url: "http://your-tee-ip:9999/v1" # Alternative to host+port
# SFTP Configuration
sftp:
host: "your-tee-ip"
port: 22
username: "admin"
password: "your-password" # Or use key_path
# key_path: "~/.ssh/id_rsa" # Alternative to password
base_path: "/var/lib/fhenomai/FHEnomAI-server/admin" # Optional
# Optional settings
timeout: 30
max_retries: 3
verify_ssl: true
auth_token: "default-auth-token-2026" # X-Auth-Token header
Environment Variables
export FHENOM_ADMIN_HOST="your-tee-ip"
export FHENOM_ADMIN_PORT="9099"
export FHENOM_SFTP_HOST="your-tee-ip"
export FHENOM_SFTP_USERNAME="admin"
export FHENOM_SFTP_PASSWORD="your-password"
Then use without parameters:
from fhenomai import FHEnomClient, FHEnomConfig
# Load from environment
config = FHEnomConfig.from_env()
client = FHEnomClient(config)
# Or load from file
config = FHEnomConfig.from_file() # Reads ~/.fhenomai/config.yaml
client = FHEnomClient(config)
🔧 API Reference
FHEnomClient
Main client class for FHEnom AI operations.
Key Methods:
admin- Access AdminAPI instance for model/serving operationsget_sftp_manager()- Get SFTPManager for file operations- Context manager support with
__enter__and__exit__
AdminAPI
Admin operations (accessible via client.admin):
Model Operations:
list_models()- List all encrypted modelslist_online_models()- List currently served modelsget_model_info(model_id)- Get model detailsencrypt_model(...)- Encrypt a plaintext modelencrypt_dataset(...)- Encrypt a datasetsplit_model(encrypted_model_id, first_layers, last_layers)- Split a model for sovereign inference
Serving Operations:
start_serving(encrypted_model_id, server_url=..., ...)- Start external servingstart_serving(encrypted_model_id, sovereign_server_host=..., sovereign_server_port=...)- Start sovereign split inferencestop_serving(encrypted_model_id)- Stop serving
Job Operations:
get_job_status(job_id)- Check job statuswait_for_job(job_id, timeout, callback)- Wait for completion
SFTP Operations (via admin.sftp):
- Access to SFTPManager for TEE directory operations
SFTPManager
High-level SFTP operations (accessible via client.get_sftp_manager() or client.admin.sftp):
Directory Operations:
upload_directory(local_path, remote_path)- Upload directorydownload_directory(remote_path, local_path)- Download directorylist_upload_directory()- List files in upload/list_download_directory()- List files in download/clear_upload_directory()- Clear upload directoryclear_download_directory()- Clear download directory
File Operations:
upload_file(local_file, remote_file)- Upload single filedownload_file(remote_file, local_file)- Download single filefile_exists(remote_path)- Check if file existsget_directory_size(directory)- Get size in GB
🤝 Contributing
Contributions are welcome! Please contact DataKrypto for contribution guidelines.
📄 License
This project is licensed under the MIT License - see LICENSE file.
🔗 Links
- Repository: Azure DevOps
- Documentation: https://docs.datakrypto.ai
- Website: https://datakrypto.ai
- LinkedIn: DataKrypto
- Support: support@datakrypto.ai
📞 Contact
DataKrypto
United States
533 Airport Blvd. Ste 400
Burlingame, CA 94010
+1 (650) 373-2083
Italy
Via Marche, 54
00187 Rome - Italy
+39 (06) 88923849
© 2026 DataKrypto. All rights reserved.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file fhenomai-1.2.0.tar.gz.
File metadata
- Download URL: fhenomai-1.2.0.tar.gz
- Upload date:
- Size: 105.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
244550656d6660abcb4fa84bbe3d981884a09427cf34095cc1ee8d431860bb72
|
|
| MD5 |
3c95b24112a958974740d3871c0638a5
|
|
| BLAKE2b-256 |
ee3e77913db1a59ec68597307e120acb2cf7d8efc377a0bee1b315c0d9a9a18a
|
File details
Details for the file fhenomai-1.2.0-py3-none-any.whl.
File metadata
- Download URL: fhenomai-1.2.0-py3-none-any.whl
- Upload date:
- Size: 94.4 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.2
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6fed271b36ea34f3e99f35a5468de8d2719906eb4ce0b999b5d9a79e6cfc25b1
|
|
| MD5 |
75f9d9e018967c3b7ab428ea6dc385a5
|
|
| BLAKE2b-256 |
09aa2037e7b0ddf53018c1619ac8fa6896eea9c00a2d447940dcea545bed76c0
|