Metadata-Version: 2.4
Name: nxd
Version: 0.4.3
Summary: Encrypted compute layer for AI agents
Author: Nexplora Labs
License-Expression: LicenseRef-Nexplora-Proprietary
Project-URL: Homepage, https://github.com/Nexploraai/nxd
Project-URL: Repository, https://github.com/Nexploraai/nxd
Project-URL: Issues, https://github.com/Nexploraai/nxd/issues
Keywords: fhe,encryption,ai-agents,privacy,homomorphic-encryption
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Topic :: Security :: Cryptography
Classifier: Topic :: Software Development :: Libraries
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography>=42.0.0
Requires-Dist: mcp>=1.28.1
Requires-Dist: numpy>=1.26.0
Requires-Dist: pandas>=2.0.0
Requires-Dist: portalocker>=3.2.0
Requires-Dist: scikit-learn>=1.5.0
Provides-Extra: dev
Requires-Dist: pytest; extra == "dev"
Requires-Dist: build; extra == "dev"
Requires-Dist: twine; extra == "dev"
Provides-Extra: fhe
Requires-Dist: concrete-ml==1.9.0; extra == "fhe"
Dynamic: license-file

# NXD 0.4.3

NXD is an encrypted compute layer for AI agents. It wraps fully homomorphic encryption, credential vaulting, privacy primitives, and operator-only reveal flows behind a single Python import so developers can run agents on sensitive data without exposing client records, credentials, or proprietary code to models, clouds, or MCP servers.

## Three guarantees

1. **The agent works fully** - capability unchanged. The agent still completes its task.
2. **The agent sees nothing** - when `shield()` or `vault.safe_use()` is used correctly. The agent receives ciphertext or callback results, not the secret itself. A callback that returns a credential defeats this guarantee.
3. **The operator holds the keys** - in local mode, keys live in `~/.nxd/` under passphrase-derived Fernet protection. In hosted mode, key custody moves to HashiCorp Vault. Local machine compromise defeats local mode.

## Install

```bash
export NXD_OPERATOR_PASSPHRASE="NXD-2026-Nexplora-Secure!"
pip install nxd==0.4.3
```

Requires Python 3.10 or 3.11 for the FHE path (`concrete-ml`).

## Passphrase Requirements

`NXD_OPERATOR_PASSPHRASE` must be:

- At least 12 characters
- A mix of letters, numbers, and symbols
- Not a common word or phrase

Strong example: `NXD-2026-Nexplora-Secure!`

Weak examples rejected at startup: `nexplora2026`, `password123`

Your vault security depends entirely on passphrase strength. A weak passphrase is vulnerable to offline dictionary attacks if the vault files are obtained.

## Quick start

```python
import nxd

# 1. Shield code before any AI call
code = "api_key = 'sk_live_xxxx'"
shielded = nxd.shield(code)
recovered = nxd.unshield(shielded)
print(f"AI sees:  {shielded[:40]}...")
print(f"You see:  {recovered}")
print(f"Match:    {code == recovered}")

# 2. Redact PII before sending to AI
note = "Patient John Smith, DOB 1985-04-12, SSN 432-11-5678"
clean, mapping = nxd.redact(note)
print(f"\nAI gets:  {clean}")
print(f"Original: {nxd.deredact(clean, mapping)}")

# 3. Vault a credential and use it without returning it
vault = nxd.Vault(agent_id="my-agent")
vault.store("stripe_key", "sk_live_xxxx")
result = vault.safe_use(
    "stripe_key",
    lambda key: {"status": "charged", "auth_len": len(key)},
)
print(f"\nAgent got: {result}")
print("Key seen:  never")

# 4. Verify tamper-proof audit chain
nxd.audit.log("session", agent_id="my-agent")
print(f"\nAudit valid: {nxd.audit.verify()}")
```

## Redaction Levels

`redact()` returns both the safe text and the local restoration mapping:

```python
import nxd

safe, mapping = nxd.redact("Patient John Smith, SSN 432-11-5678")
restored = nxd.deredact(safe, mapping)
print(safe)
print(restored)
```

`redact()` catches common PII and secret formats including emails, phone numbers, SSNs, many API key families, bearer tokens, JWTs, physician names, dates, connection strings, and account numbers.

Important: `redact()` is pattern-based detection. It reduces exposure, but it is not a guaranteed wall. For complete payload protection, combine it with `shield()`.

`redact_strict()` is the guaranteed path for opaque transport. It pattern-redacts first, then shields the remaining payload so no plaintext survives in the returned value.

```python
import nxd

shielded, recovery = nxd.redact_strict(
    "John Smith SSN 432-11-5678 sk_live_real_key_here UNUSUAL_FORMAT_12345"
)
restored = nxd.deredact_strict(shielded, recovery)
print("sk_live" not in shielded)
print(restored)
```

## Security Model

### Memory Safety

NXD provides `SecureString` for credential handling that zeroes memory on deletion.

```python
import os
import nxd

vault = nxd.Vault(agent_id="memory-safe")

# Strongest pattern — load from environment and remove immediately
os.environ["API_KEY"] = "sk_live_env_secret_value_2026"
with nxd.SecureString.from_env("API_KEY") as s:
    vault.store("api_key", s.read())

# SecureString — zeroes memory on context exit
with nxd.SecureString("sk_live_example_secret_value_2026") as s:
    vault.store("api_key_copy", s.read())

# secure_store() — zeroes after storing
my_secret = bytearray(b"sk_live_buffered_secret")
vault.secure_store("buffered_key", my_secret)
print(vault.use("api_key_copy", lambda value: len(value)))
```

Honest caveat: Python string interning means zero-on-delete is still best-effort for short values. `SecureString.from_env()` is the strongest local pattern because the environment variable is removed immediately after loading.

### Callback Safety

Use `safe_use()` in production to detect accidental credential leakage in callback return values.

```python
import nxd

vault = nxd.Vault(agent_id="callback-safe")
vault.store("stripe_key", "sk_live_xxxx")

class stripe:
    @staticmethod
    def charge(key, amount):
        return {"status": "charged", "amount": amount, "auth_len": len(key)}

# safe_use() raises CredentialLeakError if callback returns credential data
result = vault.safe_use("stripe_key", lambda k: stripe.charge(k, amount=100))
print(result)

# use() when you need callback flexibility
# but callbacks must USE credentials, not RETURN them
```

### Audit Integrity

Audit chain is protected against:

- Entry modification via HMAC-signed entries
- Entry injection via sequential hash verification
- Entry reordering via chained previous-hash checks
- Entry truncation via a signed manifest with entry count and tail hash

If the manifest is lost, recover with:

```python
import nxd

nxd.audit.log("example", agent_id="recover-demo")
print(nxd.audit.verify())
print(nxd.audit.recover())
print(nxd.audit.verify())
```

CLI equivalent:

```bash
nxd audit-recover
```

Back up `~/.nxd/` regularly. Losing `master.key` means losing access to all vaulted data.

### Hosted Key Management

For deployments where local key custody is not acceptable, use the hosted backend:

```bash
export VAULT_ADDR="https://vault.example.com"
export VAULT_TOKEN="replace-me"
python3 -c "import nxd; print(type(nxd.Vault(agent_id='prod-agent', hosted=True)).__name__)"
```

Hosted mode keeps credentials out of `~/.nxd/` and delegates secret custody to HashiCorp Vault. `http://127.0.0.1:8200` remains acceptable for local development only and now emits a `SecurityWarning`.

## Import Surface

```python
import nxd

vault = nxd.Vault(agent_id="imports")

# Memory-safe credential handling
with nxd.SecureString("sk_live_example_secret_value_2026") as s:
    vault.store("key", s.read())

credential = bytearray(b"sk_live_buffer")
vault.secure_store("key", credential)    # zeroes after store
vault.safe_use("key", lambda callback_cred: {"status": "ok", "len": len(callback_cred)})  # detects callback leaks
print(nxd.CredentialLeakError.__name__)  # raised on leak detection
print(nxd.PrivacyBudgetExceededError.__name__)
shielded, recovery = nxd.redact_strict("John Smith SSN 432-11-5678")
print(nxd.deredact_strict(shielded, recovery))
import os
os.environ["IMPORT_SURFACE_SECRET"] = "import_surface_secret_value_2026"
with nxd.SecureString.from_env("IMPORT_SURFACE_SECRET") as env_secret:
    print(env_secret.read())

# Audit recovery
print(nxd.audit.recover())               # rebuild manifest
# CLI: nxd audit-recover
```

## Exact-match search

`search()` is keyed exact-match lookup over HMAC tokens and encrypted records. Query tokens are deterministic, so repeated queries and equality patterns are observable. This is not private information retrieval, oblivious RAM, or searchable symmetric encryption.

## Channel messaging

`channel()` is Fernet-based agent messaging with within-session sequence validation. It provides confidentiality and rejects replayed or out-of-order packets within a single channel instance. It does not provide forward secrecy, persistent replay protection across new channel instances, or asymmetric sender authentication.

## Recipient binding

`bind()` is a derived-key access wrapper. Data is encrypted under a key derived from recipient identity and optional purpose. It is not a formal capability system, a revocable ACL, or a proof-backed authorization framework.

## Token substitution

`tokenize()` replaces sensitive values with random opaque tokens backed by an encrypted local map. It is useful for local indirection and recovery, not HSM-backed or PCI-style tokenization.

## What each primitive actually is

| Primitive | What it is | What it is not |
|-----------|------------|----------------|
| `score` / `match` / `aggregate` | FHE via Concrete ML | Custom FHE |
| `shield` / `seal` | Fernet symmetric encryption | New primitive |
| `vault` | Fernet + PBKDF2 + agent tokens | HSM or KMS |
| `sign` / `verify_signature` | Ed25519 via `cryptography` | Custom signing |
| `handoff` | Fernet + replay store | Ratchet protocol |
| `channel` | Fernet + session sequence checks | Forward-secret messaging |
| `search` | HMAC token lookup + Fernet records | PIR or SSE |
| `tokenize` | Random token map + Fernet | HSM tokenization |
| `bind` | HKDF-derived key + Fernet | Capability system |
| `split` | Shamir secret sharing | Verifiable secret sharing |
| `blur` | Laplace mechanism | Formally certified DP |
| `audit` | HMAC-backed chain + manifest | Append-only ledger |
| `redact` | Pattern detection + optional shielding | Guaranteed semantic wall |

## Handoff tokens

Handoff tokens are single-use. A token that has already been unpacked raises `ReplayError` if it is unpacked again.

Replay state is kept in a bounded local seen-token store. Entries older than 30 days are pruned during normal operation. If that seen-token state is lost or corrupted, previously used tokens can become reusable until the store is rebuilt.

```python
import nxd

handoff = nxd.Handoff()
token = handoff.pack({"client": "Jane Doe", "balance": 50000})
payload = handoff.unpack(token)
print(payload)
```

For multi-agent workflows where the same context is needed by multiple agents, pack a separate token for each agent.

## Audit export

```python
import nxd

nxd.audit.log("docs-example", agent_id="my-agent")
nxd.audit.export("audit_report.json")
print("export works")
```

## Benchmarks (MacBook Air, Python 3.11, Concrete ML 1.9.0)

| Operation | Latency | Notes |
|-----------|---------|-------|
| FHE score (1 record) | ~183 ms | First-call cold start |
| FHE score (1k records, parallel) | 1.6 s | 8 cores, ~1.6 ms/record |
| FHE match (single pair) | 352 ms | Cross-system comparison |
| FHE aggregate (1k records, parallel) | 1.8 s | ~0.009% quantization error |
| Credential vault use | <1 ms | Decrypt in memory only |
| Proof suite | 114/114 passed | `python3 prove.py` |
| Real-world simulation | 34/34 passed | `python3 realworld.py` |
| Pytest suite | 72 passed | `pytest -q` |

## What NXD does not protect against

NXD protects credentials and sensitive data from AI providers, model context, and ordinary cloud exposure. It does not remove the need for normal endpoint security and key management discipline.

- Local deployments still inherit host risk. `Vault(hosted=True)` removes local key custody, but `Vault(hosted=False)` still stores encrypted key material on the operator machine.
- `split()` and `blur()` are still pending external cryptographic review. They now ship with import-time self-tests, split self-verification, and privacy-budget guards, but that is not a substitute for independent review.
- `search()` is deterministic exact-match lookup. It leaks equality and access patterns and should not be described as PIR or private search.
- `channel()` uses a long-term key derived from the operator master key. It does not provide forward secrecy, and replay protection is only session-scoped.
- `redact()` remains best-effort pattern detection. Use `redact_strict()` when you need guaranteed opaque output.
- `SecureString`, `secure_store()`, and `SecureString.from_env()` are stronger patterns than raw strings, but CPython memory behavior means zeroing remains best-effort for short secrets.
- NXD uses FHE for specific compute operations such as `score`, `match`, and `aggregate`. It does not run the full LLM context window under FHE.
- NXD does not protect against a trusted operator with physical access, because that operator holds the keys by design.
- Current encryption choices are not presented as quantum-resistant. Post-quantum primitives are not part of the current release.

## Operator workflow

Set `NXD_OPERATOR_PASSPHRASE` before using the vault, audit chain, signatures, or any operator-only reveal flow. NXD stores ciphertext at rest, and local key files are wrapped with a PBKDF2-derived key from that operator passphrase.

When you use `nxd init`, NXD can vault `.env` secrets, replace them with `NXD_VAULT::NAME` references, and write an encrypted `.env.backup.nxd` recovery file.

On the MCP path, decrypt-style tools such as `nxd_unshield`, `nxd_unseal_text`, and `nxd_detokenize` no longer return plaintext to the agent. They queue an operator-only reveal:

```bash
nxd reveal <reveal_id>
```

## Roadmap

### v0.3.x (shipped)

- ✅ Agent vault isolation
- ✅ Concurrent vault safety
- ✅ Passphrase strength enforcement
- ✅ API key redaction coverage
- ✅ Audit truncation detection
- ✅ Uniform error messages (`VaultError`)
- ✅ `SecureString` memory safety
- ✅ `safe_use()` leak detection
- ✅ Audit manifest recovery
- ✅ HashiCorp Vault hosted mode
- ✅ `redact_strict()` guaranteed opaque transport
- ✅ `SecureString.from_env()` and `SecurityWarning`
- ✅ `split()` self-tests and runtime self-verification
- ✅ `blur()` privacy-budget enforcement and import self-test

### v0.4.0 (shipped)

- Managed backend expansion (`AWS KMS`, Vault transit patterns, stronger auth flows)
- Production hosted deployment ergonomics

### v0.5.0 (next)

- Forward secrecy for `channel()` via explicit X25519 session handshake design
- Discrete Laplace or snapping mechanism in `blur()` to avoid floating-point ambiguity
- External cryptographic audit of `split()` and `blur()`

### v0.6.0

- Hardware-accelerated FHE on GPU/TPU
- Sub-10 ms encrypted inference
- Stronger search privacy via evaluation of SSE or related schemes

## Development

```bash
git clone https://github.com/Nexploraai/nxd
cd nxd
pip install -e ".[dev]"
python3 prove.py
pytest -q
python3 realworld.py
```

## License

Proprietary - Nexplora Labs. Free to use in projects, but the source may not be modified, redistributed, resold, or used to build a competing encryption or agent-protection product. See [LICENSE](LICENSE).
