# eciespy
[](https://app.codacy.com/gh/ecies/py/dashboard)
[](https://github.com/ecies/py)
[](https://pypi.org/project/eciespy/)
[](https://pypistats.org/packages/eciespy)
[](https://pypi.org/project/eciespy/)
[](https://github.com/ecies/py/actions)
[](https://codecov.io/gh/ecies/py)
Elliptic Curve Integrated Encryption Scheme for secp256k1/curve25519 in Python.
Other language versions:
- [TypeScript](https://github.com/ecies/js)
- [Rust](https://github.com/ecies/rs)
- [Golang](https://github.com/ecies/go)
- [WASM](https://github.com/ecies/rs-wasm)
- [Java](https://github.com/ecies/java)
- [Dart](https://github.com/ecies/dart)
You can also check a [web backend demo](https://github.com/ecies/py-demo).
## Install
`pip install eciespy`
Or `pip install 'eciespy[eth]'` to install `eth-keys` as well.
## Quick Start
### Secp256k1
```python
>>> from ecies.keys import PrivateKey
>>> from ecies import encrypt, decrypt
>>> data = 'hello world🌍'.encode()
>>> sk = PrivateKey('secp256k1')
>>> sk_bytes = sk.secret # bytes
>>> pk_bytes = sk.public_key.to_bytes(True) # bytes
>>> decrypt(sk_bytes, encrypt(pk_bytes, data)).decode()
'hello world🌍'
>>> sk_hex = sk.to_hex() # hex str
>>> pk_hex = sk.public_key.to_hex(True) # hex str
>>> decrypt(sk_hex, encrypt(pk_hex, data)).decode()
'hello world🌍'
```
### X25519/Ed25519
```python
>>> from ecies.keys import PrivateKey
>>> from ecies import encrypt, decrypt
>>> from ecies.config import ECIES_CONFIG
>>> ECIES_CONFIG.elliptic_curve = 'x25519' # or 'ed25519'
>>> data = 'hello world🌍'.encode()
>>> sk = PrivateKey('x25519') # or 'ed25519'
>>> decrypt(sk.secret, encrypt(sk.public_key.to_bytes(), data)).decode()
'hello world🌍'
```
Or just use a builtin command `eciespy` in your favorite [command line](#command-line-interface).
## API
### `ecies.encrypt(receiver_pk: Union[str, bytes], data: bytes, config: Config = ECIES_CONFIG) -> bytes`
Parameters:
- `receiver_pk` - Receiver's public key (hex `str` or `bytes`)
- `data` - Data to encrypt
- `config` - Optional configuration object
Returns: `bytes`
### `ecies.decrypt(receiver_sk: Union[str, bytes], data: bytes, config: Config = ECIES_CONFIG) -> bytes`
Parameters:
- `receiver_sk` - Receiver's private key (hex `str` or `bytes`)
- `data` - Data to decrypt
- `config` - Optional configuration object
Returns: `bytes`
## Command Line Interface
### Show help
```console
$ eciespy -h
usage: eciespy [-h] [-e] [-d] [-g] [-k KEY] [-c {secp256k1,x25519,ed25519}] [-D [DATA]] [-O [OUT]]
Elliptic Curve Integrated Encryption Scheme for secp256k1/curve25519 in Python
options:
-h, --help show this help message and exit
-e, --encrypt encrypt with public key, exclusive with -d
-d, --decrypt decrypt with private key, exclusive with -e
-g, --generate generate key pair, for secp256k1, ethereum public key and address will be printed
-k, --key KEY public or private key file
-c, --curve {secp256k1,x25519,ed25519}
elliptic curve, default: secp256k1
-D, --data [DATA] file to encrypt or decrypt, if not specified, it will read from stdin
-O, --out [OUT] encrypted or decrypted file, if not specified, it will write to stdout
```
### Generate eth key
```console
$ eciespy -g
Private: 0x95d3c5e483e9b1d4f5fc8e79b2deaf51362980de62dbb082a9a4257eef653d7d
Public: 0x98afe4f150642cd05cc9d2fa36458ce0a58567daeaf5fde7333ba9b403011140a4e28911fcf83ab1f457a30b4959efc4b9306f514a4c3711a16a80e3b47eb58b
Address: 0x47e801184B3a8ea8E6A4A7A4CFEfEcC76809Da72
```
### Encrypt with public key and decrypt with private key
```console
$ echo '0x95d3c5e483e9b1d4f5fc8e79b2deaf51362980de62dbb082a9a4257eef653d7d' > sk
$ echo '0x98afe4f150642cd05cc9d2fa36458ce0a58567daeaf5fde7333ba9b403011140a4e28911fcf83ab1f457a30b4959efc4b9306f514a4c3711a16a80e3b47eb58b' > pk
$ echo 'hello ecies' | eciespy -e -k pk | eciespy -d -k sk
hello ecies
$ echo 'data to encrypt' > data
$ eciespy -e -k pk -D data -O enc_data
$ eciespy -d -k sk -D enc_data
data to encrypt
$ rm sk pk data enc_data
```
## Configuration
Following configurations are available.
- Elliptic curve: secp256k1 or curve25519 (x25519/ed25519)
- Ephemeral key format in the payload: compressed or uncompressed (only for secp256k1)
- Shared elliptic curve key format in the key derivation: compressed or uncompressed (only for secp256k1)
- Symmetric cipher algorithm: AES-256-GCM or XChaCha20-Poly1305
- Symmetric nonce length: 12 or 16 bytes (only for AES-256-GCM)
For compatibility, make sure different applications share the same configuration.
```py
EllipticCurve = Literal["secp256k1", "x25519", "ed25519"]
SymmetricAlgorithm = Literal["aes-256-gcm", "xchacha20"]
NonceLength = Literal[12, 16] # only for aes-256-gcm, xchacha20 will always be 24
@dataclass()
class Config:
elliptic_curve: EllipticCurve = "secp256k1"
is_ephemeral_key_compressed: bool = False
is_hkdf_key_compressed: bool = False
symmetric_algorithm: SymmetricAlgorithm = "aes-256-gcm"
symmetric_nonce_length: NonceLength = 16
@property
def ephemeral_key_size(self):
if self.elliptic_curve == "secp256k1":
return (
COMPRESSED_PUBLIC_KEY_SIZE
if self.is_ephemeral_key_compressed
else UNCOMPRESSED_PUBLIC_KEY_SIZE
)
elif self.elliptic_curve in ("x25519", "ed25519"):
return CURVE25519_PUBLIC_KEY_SIZE
else:
raise NotImplementedError
ECIES_CONFIG = Config()
```
On `ECIES_CONFIG.elliptic_curve = "x25519"` or `"ed25519"`, x25519 (key exchange function on curve25519) or ed25519 (signature algorithm on curve25519) will be used for key exchange instead of secp256k1.
In this case, the payload would always be: `32 Bytes + Ciphered`.
> If you don't know how to choose between x25519 and ed25519, just use the dedicated key exchange function x25519 for efficiency.
>
> Because any 32-byte data is a valid curve25519 public key, the payload would seem random. This property is excellent for circumventing censorship by adversaries.
### Secp256k1-specific configuration
On `is_ephemeral_key_compressed = True`, the payload would be like: `33 Bytes + Ciphered` instead of `65 Bytes + Ciphered`.
On `is_hkdf_key_compressed = True`, the hkdf key would be derived from `ephemeral public key (compressed) + shared public key (compressed)` instead of `ephemeral public key (uncompressed) + shared public key (uncompressed)`.
### Symmetric cipher configuration
On `symmetric_algorithm = "xchacha20"`, plaintext data would be encrypted with XChaCha20-Poly1305.
On `symmetric_nonce_length = 12`, then the nonce of AES-256-GCM would be 12 bytes. XChaCha20-Poly1305's nonce is always 24 bytes.
### Which configuration should I choose?
For compatibility with other [ecies libraries](https://github.com/orgs/ecies/repositories), start with the default (secp256k1 with AES-256-GCM).
For speed and security, pick x25519 with XChaCha20-Poly1305.
## Technical details
See [DETAILS.md](./DETAILS.md).
## Changelog
See [CHANGELOG.md](./CHANGELOG.md).
Raw data
{
"_id": null,
"home_page": "https://github.com/ecies/py",
"name": "eciespy",
"maintainer": "Weiliang Li",
"docs_url": null,
"requires_python": "<4.0,>=3.9",
"maintainer_email": "to.be.impressive@gmail.com",
"keywords": "secp256k1, crypto, elliptic curves, ecies, bitcoin, ethereum, cryptocurrency",
"author": "Weiliang Li",
"author_email": "to.be.impressive@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/39/d1/29e6cab7060dd41d8f8cada139da58d843f3f4a950e3747691c56c196fd3/eciespy-0.4.6.tar.gz",
"platform": null,
"description": "# eciespy\n\n[](https://app.codacy.com/gh/ecies/py/dashboard)\n[](https://github.com/ecies/py)\n[](https://pypi.org/project/eciespy/)\n[](https://pypistats.org/packages/eciespy)\n[](https://pypi.org/project/eciespy/)\n[](https://github.com/ecies/py/actions)\n[](https://codecov.io/gh/ecies/py)\n\nElliptic Curve Integrated Encryption Scheme for secp256k1/curve25519 in Python.\n\nOther language versions:\n\n- [TypeScript](https://github.com/ecies/js)\n- [Rust](https://github.com/ecies/rs)\n- [Golang](https://github.com/ecies/go)\n- [WASM](https://github.com/ecies/rs-wasm)\n- [Java](https://github.com/ecies/java)\n- [Dart](https://github.com/ecies/dart)\n\nYou can also check a [web backend demo](https://github.com/ecies/py-demo).\n\n## Install\n\n`pip install eciespy`\n\nOr `pip install 'eciespy[eth]'` to install `eth-keys` as well.\n\n## Quick Start\n\n### Secp256k1\n\n```python\n>>> from ecies.keys import PrivateKey\n>>> from ecies import encrypt, decrypt\n>>> data = 'hello world\ud83c\udf0d'.encode()\n>>> sk = PrivateKey('secp256k1')\n>>> sk_bytes = sk.secret # bytes\n>>> pk_bytes = sk.public_key.to_bytes(True) # bytes\n>>> decrypt(sk_bytes, encrypt(pk_bytes, data)).decode()\n'hello world\ud83c\udf0d'\n>>> sk_hex = sk.to_hex() # hex str\n>>> pk_hex = sk.public_key.to_hex(True) # hex str\n>>> decrypt(sk_hex, encrypt(pk_hex, data)).decode()\n'hello world\ud83c\udf0d'\n```\n\n### X25519/Ed25519\n\n```python\n>>> from ecies.keys import PrivateKey\n>>> from ecies import encrypt, decrypt\n>>> from ecies.config import ECIES_CONFIG\n>>> ECIES_CONFIG.elliptic_curve = 'x25519' # or 'ed25519'\n>>> data = 'hello world\ud83c\udf0d'.encode()\n>>> sk = PrivateKey('x25519') # or 'ed25519'\n>>> decrypt(sk.secret, encrypt(sk.public_key.to_bytes(), data)).decode()\n'hello world\ud83c\udf0d'\n```\n\nOr just use a builtin command `eciespy` in your favorite [command line](#command-line-interface).\n\n## API\n\n### `ecies.encrypt(receiver_pk: Union[str, bytes], data: bytes, config: Config = ECIES_CONFIG) -> bytes`\n\nParameters:\n\n- `receiver_pk` - Receiver's public key (hex `str` or `bytes`)\n- `data` - Data to encrypt\n- `config` - Optional configuration object\n\nReturns: `bytes`\n\n### `ecies.decrypt(receiver_sk: Union[str, bytes], data: bytes, config: Config = ECIES_CONFIG) -> bytes`\n\nParameters:\n\n- `receiver_sk` - Receiver's private key (hex `str` or `bytes`)\n- `data` - Data to decrypt\n- `config` - Optional configuration object\n\nReturns: `bytes`\n\n## Command Line Interface\n\n### Show help\n\n```console\n$ eciespy -h\nusage: eciespy [-h] [-e] [-d] [-g] [-k KEY] [-c {secp256k1,x25519,ed25519}] [-D [DATA]] [-O [OUT]]\n\nElliptic Curve Integrated Encryption Scheme for secp256k1/curve25519 in Python\n\noptions:\n -h, --help show this help message and exit\n -e, --encrypt encrypt with public key, exclusive with -d\n -d, --decrypt decrypt with private key, exclusive with -e\n -g, --generate generate key pair, for secp256k1, ethereum public key and address will be printed\n -k, --key KEY public or private key file\n -c, --curve {secp256k1,x25519,ed25519}\n elliptic curve, default: secp256k1\n -D, --data [DATA] file to encrypt or decrypt, if not specified, it will read from stdin\n -O, --out [OUT] encrypted or decrypted file, if not specified, it will write to stdout\n```\n\n### Generate eth key\n\n```console\n$ eciespy -g\nPrivate: 0x95d3c5e483e9b1d4f5fc8e79b2deaf51362980de62dbb082a9a4257eef653d7d\nPublic: 0x98afe4f150642cd05cc9d2fa36458ce0a58567daeaf5fde7333ba9b403011140a4e28911fcf83ab1f457a30b4959efc4b9306f514a4c3711a16a80e3b47eb58b\nAddress: 0x47e801184B3a8ea8E6A4A7A4CFEfEcC76809Da72\n```\n\n### Encrypt with public key and decrypt with private key\n\n```console\n$ echo '0x95d3c5e483e9b1d4f5fc8e79b2deaf51362980de62dbb082a9a4257eef653d7d' > sk\n$ echo '0x98afe4f150642cd05cc9d2fa36458ce0a58567daeaf5fde7333ba9b403011140a4e28911fcf83ab1f457a30b4959efc4b9306f514a4c3711a16a80e3b47eb58b' > pk\n$ echo 'hello ecies' | eciespy -e -k pk | eciespy -d -k sk\nhello ecies\n$ echo 'data to encrypt' > data\n$ eciespy -e -k pk -D data -O enc_data\n$ eciespy -d -k sk -D enc_data\ndata to encrypt\n$ rm sk pk data enc_data\n```\n\n## Configuration\n\nFollowing configurations are available.\n\n- Elliptic curve: secp256k1 or curve25519 (x25519/ed25519)\n- Ephemeral key format in the payload: compressed or uncompressed (only for secp256k1)\n- Shared elliptic curve key format in the key derivation: compressed or uncompressed (only for secp256k1)\n- Symmetric cipher algorithm: AES-256-GCM or XChaCha20-Poly1305\n- Symmetric nonce length: 12 or 16 bytes (only for AES-256-GCM)\n\nFor compatibility, make sure different applications share the same configuration.\n\n```py\nEllipticCurve = Literal[\"secp256k1\", \"x25519\", \"ed25519\"]\nSymmetricAlgorithm = Literal[\"aes-256-gcm\", \"xchacha20\"]\nNonceLength = Literal[12, 16] # only for aes-256-gcm, xchacha20 will always be 24\n\n\n@dataclass()\nclass Config:\n elliptic_curve: EllipticCurve = \"secp256k1\"\n is_ephemeral_key_compressed: bool = False\n is_hkdf_key_compressed: bool = False\n symmetric_algorithm: SymmetricAlgorithm = \"aes-256-gcm\"\n symmetric_nonce_length: NonceLength = 16\n\n @property\n def ephemeral_key_size(self):\n if self.elliptic_curve == \"secp256k1\":\n return (\n COMPRESSED_PUBLIC_KEY_SIZE\n if self.is_ephemeral_key_compressed\n else UNCOMPRESSED_PUBLIC_KEY_SIZE\n )\n elif self.elliptic_curve in (\"x25519\", \"ed25519\"):\n return CURVE25519_PUBLIC_KEY_SIZE\n else:\n raise NotImplementedError\n\n\nECIES_CONFIG = Config()\n```\n\nOn `ECIES_CONFIG.elliptic_curve = \"x25519\"` or `\"ed25519\"`, x25519 (key exchange function on curve25519) or ed25519 (signature algorithm on curve25519) will be used for key exchange instead of secp256k1.\n\nIn this case, the payload would always be: `32 Bytes + Ciphered`.\n\n> If you don't know how to choose between x25519 and ed25519, just use the dedicated key exchange function x25519 for efficiency.\n>\n> Because any 32-byte data is a valid curve25519 public key, the payload would seem random. This property is excellent for circumventing censorship by adversaries.\n\n### Secp256k1-specific configuration\n\nOn `is_ephemeral_key_compressed = True`, the payload would be like: `33 Bytes + Ciphered` instead of `65 Bytes + Ciphered`.\n\nOn `is_hkdf_key_compressed = True`, the hkdf key would be derived from `ephemeral public key (compressed) + shared public key (compressed)` instead of `ephemeral public key (uncompressed) + shared public key (uncompressed)`.\n\n### Symmetric cipher configuration\n\nOn `symmetric_algorithm = \"xchacha20\"`, plaintext data would be encrypted with XChaCha20-Poly1305.\n\nOn `symmetric_nonce_length = 12`, then the nonce of AES-256-GCM would be 12 bytes. XChaCha20-Poly1305's nonce is always 24 bytes.\n\n### Which configuration should I choose?\n\nFor compatibility with other [ecies libraries](https://github.com/orgs/ecies/repositories), start with the default (secp256k1 with AES-256-GCM).\n\nFor speed and security, pick x25519 with XChaCha20-Poly1305.\n\n## Technical details\n\nSee [DETAILS.md](./DETAILS.md).\n\n## Changelog\n\nSee [CHANGELOG.md](./CHANGELOG.md).\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "Elliptic Curve Integrated Encryption Scheme for secp256k1/curve25519 in Python",
"version": "0.4.6",
"project_urls": {
"Homepage": "https://github.com/ecies/py",
"Repository": "https://github.com/ecies/py"
},
"split_keywords": [
"secp256k1",
" crypto",
" elliptic curves",
" ecies",
" bitcoin",
" ethereum",
" cryptocurrency"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "36d2a1ffc809daae895ba6abfcbcdc2336f72169150ed6538d24c328392c4deb",
"md5": "c0c4406390214ad35d6b045f25194208",
"sha256": "5329e6f4a79e67eb060f03474fa04ebc76da1a277ff9cec0a71a5f7f4efdfd01"
},
"downloads": -1,
"filename": "eciespy-0.4.6-py3-none-any.whl",
"has_sig": false,
"md5_digest": "c0c4406390214ad35d6b045f25194208",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": "<4.0,>=3.9",
"size": 15107,
"upload_time": "2025-07-21T05:28:13",
"upload_time_iso_8601": "2025-07-21T05:28:13.499870Z",
"url": "https://files.pythonhosted.org/packages/36/d2/a1ffc809daae895ba6abfcbcdc2336f72169150ed6538d24c328392c4deb/eciespy-0.4.6-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "39d129e6cab7060dd41d8f8cada139da58d843f3f4a950e3747691c56c196fd3",
"md5": "51ec03519a294318ce0adf59e7bf6c1c",
"sha256": "aa981bf3da70de8cdca477ab65e9c9e2d133fd60ec84fa9d3187999bcb958f9c"
},
"downloads": -1,
"filename": "eciespy-0.4.6.tar.gz",
"has_sig": false,
"md5_digest": "51ec03519a294318ce0adf59e7bf6c1c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": "<4.0,>=3.9",
"size": 12373,
"upload_time": "2025-07-21T05:28:14",
"upload_time_iso_8601": "2025-07-21T05:28:14.913163Z",
"url": "https://files.pythonhosted.org/packages/39/d1/29e6cab7060dd41d8f8cada139da58d843f3f4a950e3747691c56c196fd3/eciespy-0.4.6.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-07-21 05:28:14",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ecies",
"github_project": "py",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "eciespy"
}