{ "info": { "author": "Weiliang Li", "author_email": "to.be.impressive@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: Implementation :: CPython", "Topic :: Security :: Cryptography" ], "description": "# eciespy\n\n[![Codacy Badge](https://api.codacy.com/project/badge/Grade/2a11aeb9939244019d2c64bce3ff3c4e)](https://www.codacy.com/app/ecies/py)\n[![CI](https://img.shields.io/circleci/project/github/ecies/py.svg)](https://circleci.com/gh/ecies/py)\n[![Codecov](https://img.shields.io/codecov/c/github/ecies/py.svg)](https://codecov.io/gh/ecies/py)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/eciespy.svg)](https://pypi.org/project/eciespy/)\n[![PyPI](https://img.shields.io/pypi/v/eciespy.svg)](https://pypi.org/project/eciespy/)\n[![License](https://img.shields.io/github/license/ecies/py.svg)](https://github.com/ecies/py)\n\nElliptic Curve Integrated Encryption Scheme for secp256k1 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\nYou can also check a flask web backend demo [here](https://github.com/kigawas/eciespy-demo).\n\n## Install\n\nInstall with `pip install eciespy` under Python 3.5+.\n\n## Quick Start\n\n```python\n>>> from ecies.utils import generate_eth_key, generate_key\n>>> from ecies import encrypt, decrypt\n>>> eth_k = generate_eth_key()\n>>> prvhex = eth_k.to_hex()\n>>> pubhex = eth_k.public_key.to_hex()\n>>> data = b'this is a test'\n>>> decrypt(prvhex, encrypt(pubhex, data))\nb'this is a test'\n>>> secp_k = generate_key()\n>>> prvhex = secp_k.to_hex()\n>>> pubhex = secp_k.public_key.format(True).hex()\n>>> decrypt(prvhex, encrypt(pubhex, data))\nb'this is a test'\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], msg: bytes) -> bytes`\n\nParameters:\n\n- **receiver_pk** - Receiver's public key (hex str or bytes)\n- **msg** - Data to encrypt\n\nReturns: **bytes**\n\n### `ecies.decrypt(receiver_sk: Union[str, bytes], msg: bytes) -> bytes`\n\nParameters:\n\n- **receiver_sk** - Receiver's private key (hex str or bytes)\n- **msg** - Data to decrypt\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] [-D [DATA]] [-O [OUT]]\n\nElliptic Curve Integrated Encryption Scheme for secp256k1 in Python\n\noptional arguments:\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 ethereum key pair\n -k KEY, --key KEY public or private key file\n -D [DATA], --data [DATA]\n file to encrypt or decrypt, if not specified, it will\n read from stdin\n -O [OUT], --out [OUT]\n encrypted or decrypted file, if not specified, it will\n 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' > prv\n$ echo '0x98afe4f150642cd05cc9d2fa36458ce0a58567daeaf5fde7333ba9b403011140a4e28911fcf83ab1f457a30b4959efc4b9306f514a4c3711a16a80e3b47eb58b' > pub\n$ echo 'helloworld' | eciespy -e -k pub | eciespy -d -k prv\nhelloworld\n$ echo 'data to encrypt' > data\n$ eciespy -e -k pub -D data -O enc_data\n$ eciespy -d -k prv -D enc_data\ndata to encrypt\n$ rm data enc_data\n```\n\n## Mechanism and implementation details\n\nThis library combines `secp256k1` and `AES-256-GCM` (powered by [`coincurve`](https://github.com/ofek/coincurve) and [`pycryptodome`](https://github.com/Legrandin/pycryptodome)) to provide an API of encrypting with `secp256k1` public key and decrypting with `secp256k1`'s private key. It has two parts generally:\n\n1. Use [ECDH](https://en.wikipedia.org/wiki/Elliptic-curve_Diffie\u2013Hellman) to exchange an AES session key;\n\n > Notice that the sender public key is generated every time when `ecies.encrypt` is invoked, thus, the AES session key varies.\n\n2. Use this AES session key to encrypt/decrypt the data under `AES-256-GCM`.\n\nBasically the encrypted data will be like this:\n\n```plaintext\n+-------------------------------+----------+----------+-----------------+\n| 65 Bytes | 16 Bytes | 16 Bytes | == data size |\n+-------------------------------+----------+----------+-----------------+\n| Sender Public Key (ephemeral) | Nonce/IV | Tag/MAC | Encrypted data |\n+-------------------------------+----------+----------+-----------------+\n| sender_pk | nonce | tag | encrypted_data |\n+-------------------------------+----------+----------+-----------------+\n| Secp256k1 | AES-256-GCM |\n+-------------------------------+---------------------------------------+\n```\n\n### Secp256k1\n\n#### Glance at ecdh\n\nSo, **how** do we calculate the ECDH key under `secp256k1`? If you use a library like [`coincurve`](https://github.com/ofek/coincurve), you might just simply call `k1.ecdh(k2.public_key.format())`, then uh-huh, you got it! Let's see how to do it in simple Python snippets:\n\n```python\n>>> from coincurve import PrivateKey\n>>> k1 = PrivateKey(b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x01')\n>>> k2 = PrivateKey(b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x02')\n>>> k1.public_key.format(False).hex() # 65 bytes, False means uncompressed key\n'0479be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8'\n>>> k2.public_key.format(False).hex() # 65 bytes\n'04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a'\n>>> k1.ecdh(k2.public_key.format()).hex()\n'b1c9938f01121e159887ac2c8d393a22e4476ff8212de13fe1939de2a236f0a7'\n>>> k2.ecdh(k1.public_key.format()).hex()\n'b1c9938f01121e159887ac2c8d393a22e4476ff8212de13fe1939de2a236f0a7'\n```\n\n#### Calculate your ecdh key manually\n\nHowever, as a hacker like you with strong desire to learn something, you must be curious about the magic under the ground.\n\nIn one sentence, the `secp256k1`'s ECDH key of `k1` and `k2` is nothing but `sha256(k2.public_key.multiply(k1))`.\n\n```python\n>>> k1.to_int()\n1\n>>> shared_pub = k2.public_key.multiply(bytes.fromhex(k1.to_hex()))\n>>> shared_pub.point()\n(89565891926547004231252920425935692360644145829622209833684329913297188986597,\n 12158399299693830322967808612713398636155367887041628176798871954788371653930)\n>>> import hashlib\n>>> h = hashlib.sha256()\n>>> h.update(shared_pub.format())\n>>> h.hexdigest() # here you got the ecdh key same as above!\n'b1c9938f01121e159887ac2c8d393a22e4476ff8212de13fe1939de2a236f0a7'\n```\n\n> Warning: **NEVER** use small integers as private keys on any production systems or storing any valuable assets.\n>\n> Warning: **ALWAYS** use safe methods like [`os.urandom`](https://docs.python.org/3/library/os.html#os.urandom) to generate private keys.\n\n#### Math on ecdh\n\nLet's discuss in details. The word _multiply_ here means multiplying a **point** of a public key on elliptic curve (like `(x, y)`) with a **scalar** (like `k`). Here `k` is the integer format of a private key, for instance, it can be `1` for `k1` here, and `(x, y)` here is an extremely large number pair like `(89565891926547004231252920425935692360644145829622209833684329913297188986597, 12158399299693830322967808612713398636155367887041628176798871954788371653930)`.\n\n> Warning: 1 \\* (x, y) == (x, y) is always true, since 1 is the **identity element** for multiplication.\n\nMathematically, the elliptic curve cryptography is based on the fact that you can easily multiply point `A` (aka [base point](https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Signature_generation_algorithm), or public key in ECDH) and scalar `k` (aka private key) to get another point `B` (aka public key), but it's almost impossible to calculate `A` from `B` reversely (easy to multiply, hard to divide).\n\n#### Compressed and uncompressed keys\n\nA point multiplying a scalar can be regarded that this point adds itself multiple times, and the point `B` can be converted to a readable public key in a compressed or uncompressed format.\n\n- Compressed format (`x` coordinate only)\n\n```python\n>>> point = (89565891926547004231252920425935692360644145829622209833684329913297188986597, 12158399299693830322967808612713398636155367887041628176798871954788371653930)\n>>> prefix = '02' if point[1] % 2 == 0 else '03'\n>>> compressed_key_hex = prefix + hex(point[0])[2:]\n>>> compressed_key = bytes.fromhex(compressed_key_hex)\n>>> compressed_key.hex()\n'02c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee5'\n```\n\n- Uncompressed format (`(x, y)` coordinate)\n\n```python\n>>> uncompressed_key_hex = '04' + hex(point[0])[2:] + hex(point[1])[2:]\n>>> uncompressed_key = bytes.fromhex(uncompressed_key_hex)\n>>> uncompressed_key.hex()\n'04c6047f9441ed7d6d3045406e95c07cd85c778e4b8cef3ca7abac09b95c709ee51ae168fea63dc339a3c58419466ceaeef7f632653266d0e1236431a950cfe52a'\n```\n\nThe format is depicted by the image below from the [bitcoin book](https://github.com/bitcoinbook/bitcoinbook).\n\n![EC public key format](https://raw.githubusercontent.com/bitcoinbook/bitcoinbook/develop/images/mbc2_0407.png)\n\n> If you want to convert the compressed format to uncompressed, basically, you need to calculate `y` from `x` by solving the equation using [Cipolla's Algorithm](https://en.wikipedia.org/wiki/Cipolla's_algorithm):\n>\n> ![y^2=(x^3 + 7) mod p, where p=2^{256}-2^{32}-2^{9}-2^{8}-2^{7}-2^{6}-2^{4}-1](https://tex.s2cms.ru/svg/%20y%5E2%3D(x%5E3%20%2B%207)%20%5Cbmod%20p%2C%5C%20where%5C%20p%3D2%5E%7B256%7D-2%5E%7B32%7D-2%5E%7B9%7D-2%5E%7B8%7D-2%5E%7B7%7D-2%5E%7B6%7D-2%5E%7B4%7D-1%20)\n>\n> You can check the [bitcoin wiki](https://en.bitcoin.it/wiki/Secp256k1) and this thread on [bitcointalk.org](https://bitcointalk.org/index.php?topic=644919.msg7205689#msg7205689) for more details.\n\nThen, the shared key between `k1` and `k2` is the `sha256` hash of the **compressed** key. It's better to use the compressed format, since you can always get `x` from `x` or `(x, y)` without any calculation.\n\n```python\n>>> h = hashlib.sha256()\n>>> h.update(compressed_key)\n>>> h.hexdigest()\n'b1c9938f01121e159887ac2c8d393a22e4476ff8212de13fe1939de2a236f0a7'\n```\n\nYou may want to ask, what if no hash? Briefly, hash can:\n\n1. Make the shared key's length fixed;\n2. Make it safer since hash functions can remove \"weak bits\" in the original computed key. Check the introduction section of this [paper](http://cacr.uwaterloo.ca/techreports/1998/corr98-05.pdf) for more details.\n\n> Warning: Accoring to some recent research, although widely used, the `sha256` key derivation function is [not secure enough](https://github.com/ecies/py/issues/82).\n\n### AES\n\nNow we have the shared key, and we can use the `nonce` and `tag` to decrypt. This is quite straight, and the example derives from `pycryptodome`'s [documentation](https://pycryptodome.readthedocs.io/en/latest/src/examples.html#encrypt-data-with-aes).\n\n```python\n>>> from Cryptodome.Cipher import AES\n>>> key = b'\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00\\x00'\n>>> iv = b'\\xf3\\xe1\\xba\\x81\\r,\\x89\\x00\\xb1\\x13\\x12\\xb7\\xc7%V_'\n>>> tag = b'\\xec;q\\xe1|\\x11\\xdb\\xe3\\x14\\x84\\xda\\x94P\\xed\\xcfl'\n>>> data = b'\\x02\\xd2\\xff\\xed\\x93\\xb8V\\xf1H\\xb9'\n>>> decipher = AES.new(key, AES.MODE_GCM, nonce=iv)\n>>> decipher.decrypt_and_verify(data, tag)\nb'helloworld'\n```\n\n> Strictly speaking, `nonce` != `iv`, but this is a little bit off topic, if you are curious, you can check [the comment in `utils.py`](https://github.com/ecies/py/blob/master/ecies/utils.py#L223).\n\n## Release Notes\n\n### 0.3.0\n\n- API change: use `HKDF` to derive shared keys instead of `sha256`\n\n### 0.2.0\n\n- API change: `ecies.encrypt` and `ecies.decrypt` now can take both hex str and raw bytes\n- Bump dependency versions\n- Update documentation\n\n### 0.1.1 ~ 0.1.9\n\n- Bump dependency versions\n- Update documentation\n- Switch to Circle CI\n- Change license to MIT\n\n### 0.1.0\n\n- First beta version release\n\n\n", "description_content_type": "text/markdown", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/ecies/py", "keywords": "secp256k1,crypto,elliptic curves,ecies,bitcoin,ethereum,cryptocurrency", "license": "MIT", "maintainer": "", "maintainer_email": "", "name": "eciespy", "package_url": "https://pypi.org/project/eciespy/", "platform": "", "project_url": "https://pypi.org/project/eciespy/", "project_urls": { "Homepage": "https://github.com/ecies/py" }, "release_url": "https://pypi.org/project/eciespy/0.3.0/", "requires_dist": [ "eth-keys", "pysha3", "pycryptodomex", "coincurve" ], "requires_python": ">=3.5", "summary": "Elliptic Curve Integrated Encryption Scheme for secp256k1 in Python", "version": "0.3.0" }, "last_serial": 5747627, "releases": { "0.1.0": [ { "comment_text": "", "digests": { "md5": "2d9c80742f40a5684e8b6acbc15649aa", "sha256": "36e5cf4a8ee2b5ac568abf3c7dac8e761053c72fdbeef9a210f91985f5fb7022" }, "downloads": -1, "filename": "eciespy-0.1.0-py3-none-any.whl", "has_sig": false, "md5_digest": "2d9c80742f40a5684e8b6acbc15649aa", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8154, "upload_time": "2018-06-22T07:14:17", "url": "https://files.pythonhosted.org/packages/d9/54/e36c5e7860d05effe16935e6656644e0e9ed27fbc41aa39fb9349433d95d/eciespy-0.1.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ff5e458ea006b81524a410c07160d63f", "sha256": "28215f8296b09985eccff75d381891120b779b62da3f26f58b1079b88ff7e68e" }, "downloads": -1, "filename": "eciespy-0.1.0.tar.gz", "has_sig": false, "md5_digest": "ff5e458ea006b81524a410c07160d63f", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7210, "upload_time": "2018-06-22T07:14:18", "url": "https://files.pythonhosted.org/packages/c1/a7/63d18972d155f318d3679a1ba7d5b665b2df57d0973de4400f61752516d2/eciespy-0.1.0.tar.gz" } ], "0.1.1": [ { "comment_text": "", "digests": { "md5": "6ac55f1d1e390e3430a48078c86f1076", "sha256": "9ff8df77107eea7d3ade63c0af1020e9e3d0d1683ce38a92e2bd9fa5e57bee20" }, "downloads": -1, "filename": "eciespy-0.1.1-py3-none-any.whl", "has_sig": false, "md5_digest": "6ac55f1d1e390e3430a48078c86f1076", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 8206, "upload_time": "2018-06-22T07:38:22", "url": "https://files.pythonhosted.org/packages/46/25/826d76605895f352b78396aedf7f0dad35de1338ae62d30dc3e258ad8276/eciespy-0.1.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e8cdb9cec37edd761f0c256a905d0cc1", "sha256": "8f54e652279140107d9302da53a7f9cd37d398ecd52e4a779dc1212099a7b557" }, "downloads": -1, "filename": "eciespy-0.1.1.tar.gz", "has_sig": false, "md5_digest": "e8cdb9cec37edd761f0c256a905d0cc1", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 7291, "upload_time": "2018-06-22T07:38:23", "url": "https://files.pythonhosted.org/packages/09/c4/8f17aae0f6f7a2c7cba96e6ac57194398d8aa5ac0b1681f76dc761ae247c/eciespy-0.1.1.tar.gz" } ], "0.1.2": [ { "comment_text": "", "digests": { "md5": "d9ed93c302851bad92e397ba51b31c8d", "sha256": "3651b9279732e3bf446d38411ceb81d3ae919416d1fe6246e8e331d9ccb8f268" }, "downloads": -1, "filename": "eciespy-0.1.2-py3-none-any.whl", "has_sig": false, "md5_digest": "d9ed93c302851bad92e397ba51b31c8d", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 9432, "upload_time": "2018-07-17T05:11:13", "url": "https://files.pythonhosted.org/packages/01/bb/923a7d66465379266b7c6721a50f2cfd8b6eb23167e301a1bb6dfa5277bd/eciespy-0.1.2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "29575e8db8c60ffafd7bc5584b8cff13", "sha256": "ab332492f041e90a6244a9af8bd0ec58ee0a6cfd030002c1cdaf2b1148a7cc00" }, "downloads": -1, "filename": "eciespy-0.1.2.tar.gz", "has_sig": false, "md5_digest": "29575e8db8c60ffafd7bc5584b8cff13", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9687, "upload_time": "2018-07-17T05:11:15", "url": "https://files.pythonhosted.org/packages/ef/6d/a80710e87a6f05392f6c2af78ab55d81e33dc69b4c34a4ab2419e967b6fb/eciespy-0.1.2.tar.gz" } ], "0.1.3": [ { "comment_text": "", "digests": { "md5": "6619026da5ace8750e46f1dbc4e2f617", "sha256": "9b24e89d8b45d340953c82c236545a033dbe211590c14aa1c877a51498df41c2" }, "downloads": -1, "filename": "eciespy-0.1.3-py3-none-any.whl", "has_sig": false, "md5_digest": "6619026da5ace8750e46f1dbc4e2f617", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 13584, "upload_time": "2018-10-17T09:02:16", "url": "https://files.pythonhosted.org/packages/fd/d1/a536ddecf2cba1809c6a84201610289b4f5b458e8713d3c22545ef1fe9f3/eciespy-0.1.3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "00ed12181d6db8e9070395f395d424c9", "sha256": "e0f98488da0d611f24371fa494ea3937efaece02ecfb9f8d40f1d39b80998e64" }, "downloads": -1, "filename": "eciespy-0.1.3.tar.gz", "has_sig": false, "md5_digest": "00ed12181d6db8e9070395f395d424c9", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 9726, "upload_time": "2018-10-17T09:02:17", "url": "https://files.pythonhosted.org/packages/98/7c/6ef0c8f3b25b46f8af3122d99d5a73c13a1ecf7cab05d4f58ea2f1407142/eciespy-0.1.3.tar.gz" } ], "0.1.4": [ { "comment_text": "", "digests": { "md5": "a4bceb3e70298fa1a06b262527d74018", "sha256": "060d0e352b007cd00697d10a506fd7d3f17799acba606b4cb9a500bc1dbc274d" }, "downloads": -1, "filename": "eciespy-0.1.4-py3-none-any.whl", "has_sig": false, "md5_digest": "a4bceb3e70298fa1a06b262527d74018", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 10491, "upload_time": "2018-11-27T07:45:23", "url": "https://files.pythonhosted.org/packages/88/73/a40ae3714ca3cbb0cc782027eb2aacba4829bca52d59752ea4d64e258c38/eciespy-0.1.4-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "bbd74f63d0aca5bb6e4f5c319c4dc7a8", "sha256": "c15296a243b52a7eda941e647f2ba18c19dff85132a5ee148086b48d0538e1bd" }, "downloads": -1, "filename": "eciespy-0.1.4.tar.gz", "has_sig": false, "md5_digest": "bbd74f63d0aca5bb6e4f5c319c4dc7a8", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 10011, "upload_time": "2018-11-27T07:45:25", "url": "https://files.pythonhosted.org/packages/6e/91/d14463e100ba84466d47cb8763cd76075e19fc75cc693988e9ce32cd3ec5/eciespy-0.1.4.tar.gz" } ], "0.1.5": [ { "comment_text": "", "digests": { "md5": "de048d36c804dd31970186fd471a908b", "sha256": "35663aa7986c01921d936d177ede8b37fcecbab7b45ed20007faf966792dcca9" }, "downloads": -1, "filename": "eciespy-0.1.5-py3-none-any.whl", "has_sig": false, "md5_digest": "de048d36c804dd31970186fd471a908b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3", "size": 10562, "upload_time": "2018-12-27T06:51:10", "url": "https://files.pythonhosted.org/packages/8d/66/905c552baeb1cc98d429ee03ae34b1535aa88f45a03e9b5c81e5b19ee7e2/eciespy-0.1.5-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "e57570690ca0cb3655e7759ad2b73eed", "sha256": "6433bc02ba7444f145a9815219808cb3a60eaa4a9b135f254fa515612723e499" }, "downloads": -1, "filename": "eciespy-0.1.5.tar.gz", "has_sig": false, "md5_digest": "e57570690ca0cb3655e7759ad2b73eed", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 10344, "upload_time": "2018-12-27T06:51:12", "url": "https://files.pythonhosted.org/packages/f9/bf/7aa77b00172ebadf7cf3ff9de2cf5d10e245b3c07732dcd13ba59c6f0000/eciespy-0.1.5.tar.gz" } ], "0.1.6": [ { "comment_text": "", "digests": { "md5": "0d53db57d69c438467c8c16724ac2db5", "sha256": "78ddb63ad66f85c742df571858c9336e9ca23703aded52b9c1b9c74b9624c467" }, "downloads": -1, "filename": "eciespy-0.1.6-py3-none-any.whl", "has_sig": false, "md5_digest": "0d53db57d69c438467c8c16724ac2db5", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3", "size": 10566, "upload_time": "2019-05-30T06:21:47", "url": "https://files.pythonhosted.org/packages/ac/56/1e6fd6ae25b1fe92d37db50d140f2cd0f2c3c2ff7b19c7bef69efdc22e47/eciespy-0.1.6-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "2422eb85442d16c9989e534a6971eaa6", "sha256": "1196277e6d5c0547f58efcd9a9c31e3808c0e3527ed9f97e2b5eb1760159e707" }, "downloads": -1, "filename": "eciespy-0.1.6.tar.gz", "has_sig": false, "md5_digest": "2422eb85442d16c9989e534a6971eaa6", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3", "size": 10353, "upload_time": "2019-05-30T06:21:48", "url": "https://files.pythonhosted.org/packages/4b/07/bc448a306fa200e36d62efc2f4982fd33ee09465391b2f88ac5155c8f3ed/eciespy-0.1.6.tar.gz" } ], "0.1.7": [ { "comment_text": "", "digests": { "md5": "cee74adfe40a963a08eaa6d8c780b355", "sha256": "bb85a96c2f517e4fca93ccc6a6c8b6cc9be7b7dc88a6766306b5fe9fa25cff1d" }, "downloads": -1, "filename": "eciespy-0.1.7-py3-none-any.whl", "has_sig": false, "md5_digest": "cee74adfe40a963a08eaa6d8c780b355", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 10978, "upload_time": "2019-06-12T03:57:52", "url": "https://files.pythonhosted.org/packages/38/97/10f0f6e8c6639caef4233682f80c3fefdfd4cc41ee08f9bb33803c20455b/eciespy-0.1.7-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "0c04ef9bb6216a2a6d64201f494c31fc", "sha256": "74085740f9ca607fa7f47dd327565cd41820dfe7b0820c8dff26b294cfd65869" }, "downloads": -1, "filename": "eciespy-0.1.7.tar.gz", "has_sig": false, "md5_digest": "0c04ef9bb6216a2a6d64201f494c31fc", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 10869, "upload_time": "2019-06-12T03:57:54", "url": "https://files.pythonhosted.org/packages/78/6f/d0d7d0e0619650869d7f1d6b9110acca90ae949bd4cb260e57efc92f1b46/eciespy-0.1.7.tar.gz" } ], "0.1.8": [ { "comment_text": "", "digests": { "md5": "b3f1563e0a589b2c358d6cb061edfe16", "sha256": "6850bbe97421161b5a29ef77e611cf2057ae0375f0567003da925f721cc3d987" }, "downloads": -1, "filename": "eciespy-0.1.8-py3-none-any.whl", "has_sig": false, "md5_digest": "b3f1563e0a589b2c358d6cb061edfe16", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 11066, "upload_time": "2019-06-26T09:19:12", "url": "https://files.pythonhosted.org/packages/f2/0d/746671dc99697ad6fc28a139769f5ddaaffd4002fb60fe9090b9f18060db/eciespy-0.1.8-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c6210ee26102a6095001ba37bd060661", "sha256": "dc0a8be08da27b120adeebc9e39da1ba7e8d6187600a8f836695c4fd94e5d70b" }, "downloads": -1, "filename": "eciespy-0.1.8.tar.gz", "has_sig": false, "md5_digest": "c6210ee26102a6095001ba37bd060661", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 11043, "upload_time": "2019-06-26T09:19:13", "url": "https://files.pythonhosted.org/packages/f6/1e/1c14c463abfba619dbc0e011f17b091462e905cfe04a9fece1fd4d8bc2d1/eciespy-0.1.8.tar.gz" } ], "0.1.9": [ { "comment_text": "", "digests": { "md5": "0f23431b6cef947f124049671991254b", "sha256": "25e0322210b0c0da4e89f14a08a63ede35e6bb8a5e3b8d0297f7bf20388688c2" }, "downloads": -1, "filename": "eciespy-0.1.9-py3-none-any.whl", "has_sig": false, "md5_digest": "0f23431b6cef947f124049671991254b", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 11068, "upload_time": "2019-07-13T02:03:51", "url": "https://files.pythonhosted.org/packages/dd/51/fdecc6a309334246182b4da2ab985ce688ebb425acf579fa5ce9d4b85539/eciespy-0.1.9-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "c048e818e817c0da28f2375799f18793", "sha256": "1563e062e022038320602e81a25b3a03b456a0ef2e719be9477f92c42ec7b6a2" }, "downloads": -1, "filename": "eciespy-0.1.9.tar.gz", "has_sig": false, "md5_digest": "c048e818e817c0da28f2375799f18793", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 11043, "upload_time": "2019-07-13T02:03:52", "url": "https://files.pythonhosted.org/packages/d4/58/12310183ef02300251d003378f28ca58052141bcef3a9246fe31e2f50c0c/eciespy-0.1.9.tar.gz" } ], "0.2.0": [ { "comment_text": "", "digests": { "md5": "68a3376c4622055344fe243e61a47344", "sha256": "57f2659d57b7f4566b7d23a3dc81464157ccb287b31eba5999eb4177bcb8a6d3" }, "downloads": -1, "filename": "eciespy-0.2.0-py3-none-any.whl", "has_sig": false, "md5_digest": "68a3376c4622055344fe243e61a47344", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 11574, "upload_time": "2019-08-10T00:42:18", "url": "https://files.pythonhosted.org/packages/2d/b5/1cd84d710e28fc7892b2aa90d78c27d4bf42734a09a9fd3ee030d3ba6141/eciespy-0.2.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4d13d313f2183837f4437cd82e3da2cc", "sha256": "5190e6dc7e55c878890f2c6dfdd26a08f26fbb8e9b1e5cf6dc2cd70cad1b8719" }, "downloads": -1, "filename": "eciespy-0.2.0.tar.gz", "has_sig": false, "md5_digest": "4d13d313f2183837f4437cd82e3da2cc", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 11524, "upload_time": "2019-08-10T00:42:19", "url": "https://files.pythonhosted.org/packages/0f/8d/f9ee1e3321d9df5983dd684d77a1cdc02256ecfc9a7c682770e9a691de3a/eciespy-0.2.0.tar.gz" } ], "0.3.0": [ { "comment_text": "", "digests": { "md5": "48a183032ff333cd8a5fe6c0364ea920", "sha256": "82a0aa52e5847e4417919624402c93d15b944591e3d0f503535961b12d7920fd" }, "downloads": -1, "filename": "eciespy-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "48a183032ff333cd8a5fe6c0364ea920", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 11916, "upload_time": "2019-08-29T02:09:19", "url": "https://files.pythonhosted.org/packages/a6/22/d5a0cfb248943611323952e74f06b239ad6616e202c251d0921684221f0c/eciespy-0.3.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6bec6b985fe4907ca68edbdc660a9329", "sha256": "39e6751fef3c52044f9e2f1b1c1a86ca273fce52b667d1a0c5c842d85c9be89c" }, "downloads": -1, "filename": "eciespy-0.3.0.tar.gz", "has_sig": false, "md5_digest": "6bec6b985fe4907ca68edbdc660a9329", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 13803, "upload_time": "2019-08-29T02:09:21", "url": "https://files.pythonhosted.org/packages/89/0c/ef3ba667278d40df3c2c72924b0d07806e29d149665633c270518c8e25d2/eciespy-0.3.0.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "48a183032ff333cd8a5fe6c0364ea920", "sha256": "82a0aa52e5847e4417919624402c93d15b944591e3d0f503535961b12d7920fd" }, "downloads": -1, "filename": "eciespy-0.3.0-py3-none-any.whl", "has_sig": false, "md5_digest": "48a183032ff333cd8a5fe6c0364ea920", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.5", "size": 11916, "upload_time": "2019-08-29T02:09:19", "url": "https://files.pythonhosted.org/packages/a6/22/d5a0cfb248943611323952e74f06b239ad6616e202c251d0921684221f0c/eciespy-0.3.0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "6bec6b985fe4907ca68edbdc660a9329", "sha256": "39e6751fef3c52044f9e2f1b1c1a86ca273fce52b667d1a0c5c842d85c9be89c" }, "downloads": -1, "filename": "eciespy-0.3.0.tar.gz", "has_sig": false, "md5_digest": "6bec6b985fe4907ca68edbdc660a9329", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.5", "size": 13803, "upload_time": "2019-08-29T02:09:21", "url": "https://files.pythonhosted.org/packages/89/0c/ef3ba667278d40df3c2c72924b0d07806e29d149665633c270518c8e25d2/eciespy-0.3.0.tar.gz" } ] }