Metadata-Version: 2.4
Name: proxy-recrypt
Version: 1.0.0
Summary: Unidirectional proxy re-encryption (AFGH PRE1) for Python, built on the JHU-MIT Proxy Re-encryption Library and MIRACL
Author-email: Myagmartseren <myagmartseren7@gmail.com>
License: Apache-2.0
Project-URL: Homepage, https://github.com/myagmartseren/pypre
Project-URL: Source, https://github.com/myagmartseren/pypre
Keywords: proxy re-encryption,PRE,AFGH,pairing,cryptography
Classifier: Development Status :: 4 - Beta
Classifier: Intended Audience :: Developers
Classifier: Operating System :: POSIX :: Linux
Classifier: Programming Language :: C++
Classifier: Programming Language :: Python :: 3
Classifier: Topic :: Security :: Cryptography
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: cryptography
Dynamic: license-file

# proxy-recrypt

Unidirectional proxy re-encryption for Python. `proxy-recrypt` wraps the
[JHU-MIT Proxy Re-encryption Library (proxylib)](http://spar.isi.jhu.edu/~mgreen/prl/)
— the reference implementation of the AFGH "PRE1" scheme (Ateniese, Fu,
Green, Hohenberger — NDSS'05) over the MIRACL pairing library — and adds a
Pythonic high-level API plus a hybrid (KEM/DEM) layer so you can encrypt data
of any size: Alice encrypts once, hands a *re-encryption key* to a
semi-trusted proxy, and the proxy transforms her ciphertexts so Bob can
decrypt them — without the proxy ever seeing plaintexts or secret keys.

## Install

Linux x86-64 only. Requirements: `g++`, `ar`, Python ≥ 3.9 with `setuptools`
and the CPython development headers.

```sh
./build_native.sh      # builds miracl.a + proxylib.a (with -fPIC) and the extension
python -m pip install .
```

`build_native.sh` also leaves an in-place build in `proxy_recrypt/`, so the
tests and example run from the source tree without installing:

```sh
python3 tests/test_proxy_recrypt.py    # or: pytest tests/test_proxy_recrypt.py
python3 example/example.py
```

If `Python.h` is not in your compiler's default include path, either export
`CPATH` (e.g. `export CPATH=$HOME/.local/include/python3.12`) before
building, or place the headers in `~/.local/include/pythonX.Y/` — `setup.py`
picks that directory up automatically. The high-level hybrid API depends on
[`cryptography`](https://pypi.org/project/cryptography/) (installed
automatically by `pip install .`).

## Quick start

```python
import proxy_recrypt as prc

# One-time setup: parameters shared by all users.
params = prc.generate_params()

alice_pk, alice_sk = prc.generate_keypair(params)
bob_pk, bob_sk = prc.generate_keypair(params)

# Alice encrypts data of any size for herself:
#   capsule = tiny re-encryptable encryption of a fresh 32-byte data key
#   payload = AES-256-GCM encryption of the data under that key
data = b"any amount of data" * 10_000
capsule, payload = prc.encrypt_data(params, alice_pk, data)

# Alice delegates to Bob: the proxy gets this key (works Alice->Bob only).
rekey = prc.generate_reencryption_key(params, bob_pk, alice_sk)

# The proxy transforms ONLY the capsule; the payload is untouched.
capsule_bob = prc.reencrypt_capsule(params, capsule, rekey)

# Bob decrypts with his own secret key.
assert prc.decrypt_data(params, bob_sk, capsule_bob, payload) == data
```

Short messages (≤ 63 bytes) can skip the hybrid layer:
`encrypt_message(params, pk, msg, level=2)` / `reencrypt(params, ct, rekey)` /
`decrypt_message(params, sk, ct)`.

Everything serializes to bytes: `params.to_bytes()`, `pk.to_bytes()`,
`sk.to_bytes()`, `ct.to_bytes()` with matching `*_from_bytes()` functions;
re-encryption keys, capsules and payloads already are bytes. In a fresh
process, always load `CurveParams` first.

## API

### High-level

| Function | Description |
| --- | --- |
| `generate_params() -> CurveParams` | Generate the shared curve parameters. |
| `generate_keypair(params) -> (PK_PRE1, SK_PRE1)` | Generate a keypair. |
| `encrypt_data(params, pk, data, aad=None) -> (capsule, payload)` | Hybrid encryption of arbitrary-size data (level-2 KEM capsule + AES-256-GCM payload). |
| `decrypt_data(params, sk, capsule, payload, aad=None) -> bytes` | Decrypt as owner *or* delegatee (handles re-encrypted capsules). |
| `reencrypt_capsule(params, capsule, rekey) -> bytes` | Proxy-side capsule transform, bytes in / bytes out. |
| `encrypt_message(params, pk, message, level=2) -> Ciphertext_PRE1` | Direct PRE1 encryption of ≤ 63 bytes (level 1 = not re-encryptable, 2 = re-encryptable). |
| `decrypt_message(params, sk, ciphertext) -> bytes` | Direct PRE1 decryption. |
| `generate_reencryption_key(params, delegatee_pk, delegator_sk) -> bytes` | Unidirectional re-encryption key delegator→delegatee. |
| `reencrypt(params, ciphertext, rekey) -> Ciphertext_PRE1` | Proxy-side transform of a second-level ciphertext. |

### Low-level (mapping to proxylib)

| proxy_recrypt | proxylib (C++) |
| --- | --- |
| `PRE1_generate_params(params)` | `PRE1_generate_params(CurveParams&)` |
| `PRE1_keygen(params, pk, sk)` | `PRE1_keygen(...)` |
| `PRE1_level1_encrypt(params, msg, pk)` | `encodePlaintextAsBig` + `PRE1_level1_encrypt(...)` |
| `PRE1_level2_encrypt(params, msg, pk)` | `encodePlaintextAsBig` + `PRE1_level2_encrypt(...)` |
| `PRE1_delegate(params, delegatee_pk, delegator_sk)` | `PRE1_delegate(...)` + `SerializeDelegationKey_PRE1` |
| `PRE1_reencrypt(params, ct, rekey)` | `DeserializeDelegationKey_PRE1` + `PRE1_reencrypt(...)` |
| `PRE1_decrypt(params, ct, sk)` | `PRE1_decrypt(...)` + plaintext decode |
| `X.to_bytes()` / `X_from_bytes(b)` | `serialize()` / `deserialize()` with `SERIALIZE_BINARY` |
| `Ciphertext_PRE1.type` | `CIPHERTEXT_TYPE` (`CIPH_FIRST_LEVEL`/`CIPH_SECOND_LEVEL`/`CIPH_REENCRYPTED`) |

Errors: bad arguments and malformed serialized data raise `ValueError`;
proxylib failures raise `RuntimeError`; GCM authentication failures (tamper,
wrong key, `aad` mismatch) raise `cryptography.exceptions.InvalidTag`; an RNG
seeding failure at import raises `ImportError`.

## Caveats

* **Legacy parameters.** proxylib (2007) uses a 512-bit prime-field pairing
  curve with a 160-bit group order — far below current security
  recommendations for pairing-based crypto. Treat this package as a research
  and prototyping tool, not production-grade cryptography.
* **Not wire-compatible with the JavaScript `proxy-recrypt` package.** The
  hybrid capsule/payload *structure* mirrors it, but the curve, ciphertext
  serialization and KDF differ, so blobs cannot be exchanged between the two.
* **Direct-message encoding.** `encrypt_message` plaintexts are encoded as
  big integers, so leading `b"\x00"` bytes are not preserved by
  `decrypt_message` (the hybrid API is not affected).
* **Single parameter set per process; not thread-safe.** MIRACL/proxylib
  keep the active curve and scratch state in globals — use one `CurveParams`
  at a time and keep all calls on one thread.
* **License.** proxylib is published for research and non-commercial use
  (see the headers in `external/proxylib/`); this package inherits those
  constraints.
