{ "info": { "author": "Foteinos Mergoupis", "author_email": "foteinosmerg@gmail.com", "bugtrack_url": null, "classifiers": [ "Development Status :: 4 - Beta", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Operating System :: OS Independent", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Topic :: Security :: Cryptography", "Topic :: Software Development :: Libraries :: Python Modules" ], "description": "# pymerkle: A Python library for constructing Merkle Trees and validating Log Proofs\n[![Build Status](https://travis-ci.com/FoteinosMerg/pymerkle.svg?branch=master)](https://travis-ci.com/FoteinosMerg/pymerkle)\n[![Docs Status](https://readthedocs.org/projects/pymerkle/badge/?version=latest)](http://pymerkle.readthedocs.org)\n[![PyPI version](https://badge.fury.io/py/pymerkle.svg)](https://pypi.org/project/pymerkle/)\n\n**Complete documentation can be found at [pymerkle.readthedocs.org](http://pymerkle.readthedocs.org/).**\n\nThis library implements\n\n- a class for _binary balanced_ Merkle-Trees (with possibly _odd_ number of leaves) capable of generating _consistency-proofs_ except for _audit-proofs_ (along with _inclusion-tests_), supporting all hashing algorithms (including _SHA3_ variations) and most encoding types provided by `Python>=3.6`\n- defense against _second-preimage attack_\n- flexible mechanisms for validating the generated proofs\n\nIt is currently the only Python library implementing all the above features, with an eye on protocols like [_Certificate Transparency_](https://tools.ietf.org/html/rfc6962) and real-life applications.\n\n## Installation\n\n```bash\npip3 install pymerkle\n```\n\n## Quick example\n\n**See also [_Usage and API_](USAGE.md)**\n\n```python\nfrom pymerkle import * # Import merkle_tree, validate_proof\n # and proof_validator\ntree = merkle_tree() # Create empty SHA256/UTF-8 Merkle-tree with\n # defense against second-preimage attack\nvalidator = proof_validator() # Create object for validating proofs\n\n# Successively update the tree with one hundred records\nfor i in range(100):\n tree.update(bytes('{}-th record'.format(i), 'utf-8'))\n\n\np = tree.audit_proof(b'12-th record') # Generate audit-proof for the given record\nq = tree.audit_proof(55) # Generate audit-proof based upon the 56-th leaf\n\n# Quick validation of the above proofs\nvalidate_proof(target_hash=tree.root_hash(), proof=p) # True\nvalidate_proof(target_hash=tree.root_hash(), proof=q) # True\n\n# Store the tree's current state (root-hash and length) for later use\ntop_hash = tree.root_hash()\nlength = tree.length()\n\n# Update the tree by encrypting a new log\ntree.encrypt_log('logs/sample_log')\n\n# Generate consistency-proof for the stage before encrypting the log\nr = tree.consistency_proof(old_hash=top_hash, sublength=length)\n\n# Validate consistency-proof and generate receipt\nvalidation_receipt = validator.validate(target_hash=tree.root_hash(), proof=r)\n```\n\n\n## Tree structure\n\nContrary to most implementations, the Merkle-tree is here always _binary balanced_, with all nodes except for the exterior ones (_leaves_) having _two_ parents. This is achieved as follows: upon appending a block of new leaves, instead of promoting a lonely leaf or duplicating it, a *bifurcation* node gets created **_so that trees with the same number of leaves have always identical structure and input clashes among growing strategies be avoided_** (independently of the configured hash and encoding types). This standardization is further crucial for:\n\n- fast generation of consistency-proof paths (based on additive decompositions in decreasing powers of _2_)\n- fast recalculation of the root-hash after appending a new leaf, since _only the hashes at the tree's left-most branch need be recalculated_\n- memory efficiency, since the height as well as total number of nodes with respect to the tree's length is controlled to the minimum. For example, a tree with _9_ leaves has _17_ nodes in the present implementation, whereas the total number of nodes in the structure described [**here**](https://crypto.stackexchange.com/questions/22669/merkle-hash-tree-updates) is _20_.\n\nThe topology is namely identical to that of a binary _Sekura tree_, depicted in Section 5.4 of [**this**](https://keccak.team/files/Sakura.pdf) paper. Follow the straightforward algorithm of the `pymerkle.merkle_tree.update` method for further insight, or the gradual development exposed in the [`tests/test_tree_structure.py`](https://github.com/FoteinosMerg/pymerkle/blob/master/tests/test_tree_structure.py) file inside the project's repository.\n\n\n\n### Deviation from bitcoin specification\n\nIn contrast to the [_bitcoin_](https://en.bitcoin.it/wiki/Protocol_documentation#Merkle_Trees) specification for Merkle-trees, lonely leaves are not duplicated in order for the tree to remain genuinely binary. Instead, creating bifurcation nodes at the rightmost branch allows the tree remains balanced upon any update. As a consequence, even if security against second-preimage attack (see below) were deactivated, the current implementation by structure invulnerable to the kind of attack that is described [**here**](https://github.com/bitcoin/bitcoin/blob/bccb4d29a8080bf1ecda1fc235415a11d903a680/src/consensus/merkle.cpp).\n\n\n\n## Defense against second-preimage attack\n\n\nDefense against second-preimage attack is by default activated. Roughly speaking, it consists in the following security measures:\n\n- Before calculating the hash of a leaf, prepend the corresponding record with the null hexadecimal `0x00`\n\n- Before calculating the hash any interior node, prepend both of its parents' hashes with the unit hexadecimal `0x01`\n\n(See [**here**](https://flawed.net.nz/2018/02/21/attacking-merkle-trees-with-a-second-preimage-attack/) or [**here**](https://news.ycombinator.com/item?id=16572793) for some insight). Read the [`tests/test_defense.py`](https://github.com/FoteinosMerg/pymerkle/blob/master/tests/test_defense.py) file inside the project's repository to see how to perform second-preimage attacks against the current implementation.\n\n\n\n## Running tests\n\n\nIn order to run all integration tests, execute\n\n```shell\n./run_tests.sh\n```\n\nfrom inside the root directory of the project. Alternatively, run the command `pytest tests/`. You can run only a specific test file, e.g., `test_log_encryption.py`, with the command `pytest tests/test_log_encryption.py`.\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": "http://github.com/FoteinosMerg/pymerkle", "keywords": "merkle proof audit consistency log security encryption", "license": "License :: OSI Approved :: MIT License", "maintainer": "", "maintainer_email": "", "name": "pymerkle", "package_url": "https://pypi.org/project/pymerkle/", "platform": "", "project_url": "https://pypi.org/project/pymerkle/", "project_urls": { "Homepage": "http://github.com/FoteinosMerg/pymerkle" }, "release_url": "https://pypi.org/project/pymerkle/1.0.1/", "requires_dist": null, "requires_python": "", "summary": "A Python library for constructing Merkle Trees and validating Log Proofs", "version": "1.0.1" }, "last_serial": 5530475, "releases": { "1.0.1": [ { "comment_text": "", "digests": { "md5": "c2f4970af9f4e51fcf31fe25f3d9dcdf", "sha256": "e9e74c83353f8c477f726b27484b678c71b8399055c743b709e039d8512df2fe" }, "downloads": -1, "filename": "pymerkle-1.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "c2f4970af9f4e51fcf31fe25f3d9dcdf", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 35495, "upload_time": "2019-02-13T16:15:59", "url": "https://files.pythonhosted.org/packages/b1/8f/03df4219e813f7bc125fea38cc950c16e29786347fa1cee38d695dd7c113/pymerkle-1.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a9f9bf5bea859484bfe807b88437bbb5", "sha256": "188c2d7ccda96dbc9e42552cabebac78265515c11f6a4895d67a90d34e017b7a" }, "downloads": -1, "filename": "pymerkle-1.0.1.tar.gz", "has_sig": false, "md5_digest": "a9f9bf5bea859484bfe807b88437bbb5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26895, "upload_time": "2019-02-13T16:16:01", "url": "https://files.pythonhosted.org/packages/2a/01/413c06c73b1b2ba2109d90dae66c0ba1eb6f72d59e521fcc62d3f321f0bc/pymerkle-1.0.1.tar.gz" } ], "2.0.1b0": [ { "comment_text": "", "digests": { "md5": "d5423cd79aa338c15f113c969f9a7bdc", "sha256": "bf0e857ec7f56cc81eb65d22e28af20b183bf4c18d71a8d81d81a66d1a173dc3" }, "downloads": -1, "filename": "pymerkle-2.0.1b0-py3-none-any.whl", "has_sig": false, "md5_digest": "d5423cd79aa338c15f113c969f9a7bdc", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 35606, "upload_time": "2019-02-21T13:20:23", "url": "https://files.pythonhosted.org/packages/c7/a8/d62840408a89ee7d244ad16d01e6ca569dde621ef70b0915e34c2bdf7cb7/pymerkle-2.0.1b0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "4d2d01c3dfcfbe60fe510002b2538697", "sha256": "d50df34aab102f8570a41d3d21a90384d88183a71d80584ad692000866c63c4a" }, "downloads": -1, "filename": "pymerkle-2.0.1b0.tar.gz", "has_sig": false, "md5_digest": "4d2d01c3dfcfbe60fe510002b2538697", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 27028, "upload_time": "2019-02-21T13:20:25", "url": "https://files.pythonhosted.org/packages/bb/f3/bf81438dd2a5faa54aa6ad50d0ea7e2ec622edea531e6de31760a2ca9465/pymerkle-2.0.1b0.tar.gz" } ], "3.0.1b0": [ { "comment_text": "", "digests": { "md5": "c243bd078c986698aad2a0047e14d2ba", "sha256": "eaaf72aa5a0e3e99f02d5bff483a05bf95200ca3c98e4b8389edf4e51d72d454" }, "downloads": -1, "filename": "pymerkle-3.0.1b0-py3-none-any.whl", "has_sig": false, "md5_digest": "c243bd078c986698aad2a0047e14d2ba", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 40167, "upload_time": "2019-04-11T10:54:37", "url": "https://files.pythonhosted.org/packages/f8/87/2730e0f1d6ced0520148bf7b0dc72ae7061fb29ad61c7cec3a2fc9ab9d6b/pymerkle-3.0.1b0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "d566c1d8f9ce215aef9da179b785ce6e", "sha256": "1546961a6e1343f773971445ba148beee377e6d2cbbf2c57a3aca45696586ef4" }, "downloads": -1, "filename": "pymerkle-3.0.1b0.tar.gz", "has_sig": false, "md5_digest": "d566c1d8f9ce215aef9da179b785ce6e", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31488, "upload_time": "2019-04-11T10:54:39", "url": "https://files.pythonhosted.org/packages/ab/fe/712deaa9204129985beff6f2119d5984942d6b6ec2d8e2a5943c5301f7e7/pymerkle-3.0.1b0.tar.gz" } ], "3.0.2b0": [ { "comment_text": "", "digests": { "md5": "912eed957f46aadd79334abcc2516846", "sha256": "c0541b3a762f4ae9ea3dd0325465ac5f940f9a19eae394713562aa5cdbea4080" }, "downloads": -1, "filename": "pymerkle-3.0.2b0-py3-none-any.whl", "has_sig": false, "md5_digest": "912eed957f46aadd79334abcc2516846", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 40004, "upload_time": "2019-04-13T18:40:54", "url": "https://files.pythonhosted.org/packages/58/fc/f28ee8ec54f7ec6a2233fba4372256b4e53b16c962ffff150b4c484cc538/pymerkle-3.0.2b0-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "9ad9d8383e66229a6b60f3a8c64d8d21", "sha256": "9b90e7db7a20bff41a79f3056dfdd002599b07a912279b5e47c78753f22148c0" }, "downloads": -1, "filename": "pymerkle-3.0.2b0.tar.gz", "has_sig": false, "md5_digest": "9ad9d8383e66229a6b60f3a8c64d8d21", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 31353, "upload_time": "2019-04-13T18:40:56", "url": "https://files.pythonhosted.org/packages/df/3e/6789261f425278a99241f6d55a5f61eb25c9f275539ab423bbd7421793f7/pymerkle-3.0.2b0.tar.gz" } ], "4.0.0b1": [ { "comment_text": "", "digests": { "md5": "21eab3f18a8f71ed1ccd989ada3c9cd0", "sha256": "7cb1006f88a18bdaebbbaa0f7968c8807639ca4e6ab37bb16585f61c979881e6" }, "downloads": -1, "filename": "pymerkle-4.0.0b1.tar.gz", "has_sig": false, "md5_digest": "21eab3f18a8f71ed1ccd989ada3c9cd0", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 5093, "upload_time": "2019-07-14T09:00:31", "url": "https://files.pythonhosted.org/packages/73/cb/b81b9589f35ad0745f9c8f825ed2c1c9aa694430d8c93478a05a968e15ce/pymerkle-4.0.0b1.tar.gz" } ], "4.0.0b2": [ { "comment_text": "", "digests": { "md5": "31ec4bf3fbbd15b8e08da0f80a910e90", "sha256": "74fcdcafce4d0a9c605c5d201bd7b2d98d85e0b6458b19b4757274f785522ff3" }, "downloads": -1, "filename": "pymerkle-4.0.0b2-py3-none-any.whl", "has_sig": false, "md5_digest": "31ec4bf3fbbd15b8e08da0f80a910e90", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 5584, "upload_time": "2019-07-14T09:14:04", "url": "https://files.pythonhosted.org/packages/3a/31/72ed6ad44a9993ff395abcd7382258965bc2b63c51b5c684e3fdbb5dce25/pymerkle-4.0.0b2-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "14b52a38d923351e37b5041d5cf3c063", "sha256": "254bbdc5347cb19c8a52d2e34b80a15619fe133dc7eb07f751d708f0cb6e3e01" }, "downloads": -1, "filename": "pymerkle-4.0.0b2.tar.gz", "has_sig": false, "md5_digest": "14b52a38d923351e37b5041d5cf3c063", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 5938, "upload_time": "2019-07-14T09:14:06", "url": "https://files.pythonhosted.org/packages/08/9c/9ebd435b14fbcdfd2cf28e642084b50c7f2d6b333dda983afeaf1afbddf5/pymerkle-4.0.0b2.tar.gz" } ], "4.0.0b3": [ { "comment_text": "", "digests": { "md5": "12ca7e2893f73180f507cbbdc0677540", "sha256": "48a63a74bbabcb797ecf843ec9771aa6ec4cf512742db6e52fd8f8484aa9fa95" }, "downloads": -1, "filename": "pymerkle-4.0.0b3-py3-none-any.whl", "has_sig": false, "md5_digest": "12ca7e2893f73180f507cbbdc0677540", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": ">=3.6", "size": 60946, "upload_time": "2019-07-14T09:18:50", "url": "https://files.pythonhosted.org/packages/a6/ee/9b2aa2dd7cd3970cb1acff48e190fd0d67b081c03ace4ed3762c4d51b874/pymerkle-4.0.0b3-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "5072d370cd80031216f17b6616c1aa78", "sha256": "f24925d4ecaef52a2e3c4b6acafb41afe88983f809d8437a103ca067c35209fe" }, "downloads": -1, "filename": "pymerkle-4.0.0b3.tar.gz", "has_sig": false, "md5_digest": "5072d370cd80031216f17b6616c1aa78", "packagetype": "sdist", "python_version": "source", "requires_python": ">=3.6", "size": 52979, "upload_time": "2019-07-14T09:18:53", "url": "https://files.pythonhosted.org/packages/ef/f9/ddce4ce21b5dda3002e5a058d7c7c28cb9738565581fcd79f265ae6930e6/pymerkle-4.0.0b3.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "c2f4970af9f4e51fcf31fe25f3d9dcdf", "sha256": "e9e74c83353f8c477f726b27484b678c71b8399055c743b709e039d8512df2fe" }, "downloads": -1, "filename": "pymerkle-1.0.1-py3-none-any.whl", "has_sig": false, "md5_digest": "c2f4970af9f4e51fcf31fe25f3d9dcdf", "packagetype": "bdist_wheel", "python_version": "py3", "requires_python": null, "size": 35495, "upload_time": "2019-02-13T16:15:59", "url": "https://files.pythonhosted.org/packages/b1/8f/03df4219e813f7bc125fea38cc950c16e29786347fa1cee38d695dd7c113/pymerkle-1.0.1-py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "a9f9bf5bea859484bfe807b88437bbb5", "sha256": "188c2d7ccda96dbc9e42552cabebac78265515c11f6a4895d67a90d34e017b7a" }, "downloads": -1, "filename": "pymerkle-1.0.1.tar.gz", "has_sig": false, "md5_digest": "a9f9bf5bea859484bfe807b88437bbb5", "packagetype": "sdist", "python_version": "source", "requires_python": null, "size": 26895, "upload_time": "2019-02-13T16:16:01", "url": "https://files.pythonhosted.org/packages/2a/01/413c06c73b1b2ba2109d90dae66c0ba1eb6f72d59e521fcc62d3f321f0bc/pymerkle-1.0.1.tar.gz" } ] }