{ "info": { "author": "Harald Heckmann", "author_email": "harald.heckmann93@web.de", "bugtrack_url": null, "classifiers": [ "Development Status :: 3 - Alpha", "Intended Audience :: Developers", "Intended Audience :: Science/Research", "License :: OSI Approved :: MIT License", "Natural Language :: English", "Operating System :: OS Independent", "Programming Language :: Python", "Programming Language :: Python :: 3.4", "Programming Language :: Python :: 3.5", "Programming Language :: Python :: 3.6", "Programming Language :: Python :: 3.7", "Programming Language :: Python :: 3 :: Only", "Topic :: Security :: Cryptography" ], "description": "|Build Status| |Coverage Status| |Documentation Status| |License: MIT|\n\nWinternitz One-Time-Signature\n==============================\n\nPython implementation of Winternitz one-time-signature schemes\n\nDescription\n-----------\n\nWinternitz one-time-signature is an extension of lamport one-time-signature.\nThis python package can be used to execute WOTS operations, including\nkey generation, signature generation and signature verification.\nCurrently WOTS and WOTS+ are implemented.\n\nIntroduction\n------------\nLamport invented an algorithm in 1979 which allowed one to create one-time-signatures\nusing a cryptographically secure one-way function. It is the basis for the Winternitz\none-time-signature algorithm. Winternitz added the possibility to adjust the tradeoff\nbetween time- and space-complexity.\n\nLamport one-time-signature scheme\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nLamport suggested to create two secret keys for each bit of a message which will\nbe signed. One for each value the bit can take. To derive the verification key,\neach secret key is hashed once. Now you have a secret key and a verification key,\nwhich consists of `m` 2-tuples of values, where `m` is the number\nof bits of the message. The verification key is published.\nThe signature consists of `m` values. For each bit of the message you release a secret key from\nthe corresponding secret keys, depending on which value the bit has. All those secret\nkeys form the signature for the message. The verifier hashes each of your secret keys\nonce and compares it to one verification key for this position, depending on the value\nof the bit. The signature is valid, if and only if all derived verification keys match with\nyour published verification key at the correct position of the 2-tuple, which is determined by the value\nof the bit. This algorithm is quite fast\n(comparing it to existing PQC-algorithms), but the signature sizes are huge.\n\nWinternitz extension\n~~~~~~~~~~~~~~~~~~~~\nWinternitz extended lamports algorithm by offering the possiblity to decide\nhow many bits will be signed together. The amount of numbers those bits can\nrepresent is called the Winternitz parameter (`w = 2^{bits}`). This method offers the huge\nadvantage that the user of this algorithm can choose the time and space tradeoff\n(whether speed or storage capacity is more relevant). A fingerprint of the message which\nwill be signed is split into groups of `ceil(log_2(w))` bits. Each of these groups gets one secret key.\nEach verification key is derived by hashing the secret key for each group `2^{w-1}` times. All verification\nkeys will be published and represent one unified verification key. When signing a message, the\nfingerprint of the message is split into groups of `ceil(log2(w))` bits. To create the signature, the\nprivate key for each bit group is hashed `bitgroup_value` times, where `bitgroup_value` is the value\nof the bitgroup. Additionally a (inverse sum) checksum is appended, which denies man-in-the-middle\nattacks. The checksum is calculated from the signature, split into bit groups of `ceil(log2(w))` bits, and\nsigned. To verify the signature, the fingerprint of the message is first split into bit groups of `ceil(log2(w)`\nbits each. The basic idea is to take the signature of each bit group, calculate the verification key\nfrom it and finally compare it to the published verification key. Since the signature was hashed\n`bitgroup_value` times, all you have to do to calculate the verification key from the signature\nis to hash the signature `2^{w-1} - bitgroup_value - 1` times. Besides verifing the message, the verifier\nmust also calculate the checksum and verify it.\n\nSetup\n-----\nRequires: Python >= 3.4\n\n| Install package: ``pip install winternitz``\n| Install test tools: ``pip install winternitz[TEST]``\n| Install linter (for tox tests): ``pip install winternitz[LINT]``\n| Install documentation tools: ``pip install winternitz[DOCS]``\n| Install everything: ``pip install winternitz[ALL]``\n\nTest\n~~~~\n| Without tox (no linter checks): ``python setup.py test``\n| With tox: ``python -m tox``\n\nGenerate documentation\n~~~~~~~~~~~~~~~~~~~~~~\n``python setup.py docs``\n\n\nUsage\n-----\n\nThe package *winternitz* contains a module called *signatures*.\nWithin this package you can find the classes WOTS and WOTSPLUS.\nThose classes can be used out of the box to sign or verify\nmessages\n\nWOTS\n~~~~\n.. code-block:: python\n\n import winternitz.signatures\n # Create signature and verify it with the same object\n wots = winternitz.signatures.WOTS()\n message = \"My message in bytes format\".encode(\"utf-8\")\n sig = wots.sign(message)\n success = wots.verify(message=message, signature=sig[\"signature\"])\n print(\"Verification success: \" + str(success))\n # Output: Verification success: True\n\nIf you don't specify any values in the constructor of WOTS, it will use\nthe winternitz parameter 16 and the hash function *sha512* as default parameters.\nThe private key will be generated from entropy. After you received the public key,\neither through ``wots.pubkey`` or inside the dict that is returned by the\n``wots.sign(message)`` function call, you publish it. Verify that it was not modified.\nIn the best case a man-in-the-middle attack to modify your public key is impossible\nby the design of the application. The last step is to publish your message and every\ninformation in the dict that is returned by ``wots.sign(message)``, except the public\nkey (since it was already published). Publishing the fingerprint is optional, since it\nis not essential for the signature verification. The signature dict contains the following\nvalues:\n\n.. code-block:: python\n\n {\n \"w\": winternitz parameter (Type: int),\n \"fingerprint\": message hash (Type: bytes),\n \"hashalgo\": hash algorithm (Type: str),\n \"digestsize\": hash byte count (Type: int),\n \"pubkey\": public key (Type: List[bytes]),\n \"signature\": signature (Type: List[bytes])\n }\n\nWith that data, another person can verify the authenticity of your message:\n\n.. code-block:: python\n\n # Another person or machine wants to verify your signature:\n # get required hash function by comparing the name\n # published with local implementaitons\n if sig[\"hashalgo\"] == \"openssl_sha512\":\n hashfunc = winternitz.signatures.openssl_sha512\n elif sig[\"hashalgo\"] == \"openssl_sha256\":\n hashfunc = winternitz.signautres.openssl_sha256\n else:\n raise NotImplementedError(\"Hash function not implemented\")\n\n wots_other = winternitz.signatures.WOTS(w=sig[\"w\"], hashfunction=hashfunc,\n digestsize=sig[\"digestsize\"], pubkey=sig[\"pubkey\"])\n success = wots_other.verify(message=message, signature=sig[\"signature\"])\n print(\"Verification success: \" + str(success))\n # Output: Verification success: True\n\nIn certain situations it might not be wanted to verify the derived public key with the\npublic key inside the executing WOTS object. For example, this can be this case when\nthe verification happens in a wrapping structure, like a XMSS tree. In such cases\nthe public key can be derived from a message and a signature with the function\n``wots.getPubkeyFromSignature(message=message, signature=signature)``\n\nWOTSPLUS\n~~~~~~~~\n.. code-block:: python\n\n import winternitz.signatures\n wotsplus = winternitz.signatures.WOTSPLUS()\n message = \"My message in bytes format\".encode(\"utf-8\")\n sig = wotsplus.sign(message)\n success = wotsplus.verify(message=message, signature=sig[\"signature\"])\n print(\"Verification success: \" + str(success))\n # Output: Verification success: True\n\nIf you don't specify any values in the constructor of WOTSPLUS, it will use the winternitz parameter\n16 and the hash function defaults to *sha256*. It further requires a pseudo random function, which defaults\nto *HMAC-sha256*, as well as a seed which is also generated from entropy. For further\ninformations about functions and their parameters, visit the module reference in\nthis the `documentation `_.\nSince WOTS+ uses a pseudo random function and a seed to derive signatures and public\nkeys, they have to be published as well. In addition to the signature of WOTS, the returned dict contains\nthe following values:\n\n.. code-block:: python\n\n {\n # ...\n \"prf\": pseudo random function (Type: str),\n \"seed\": Seed used in prf (Type: bytes)\n }\n\nThose arguments have to be specified in the constructor of WOTSPLUS in addition to those parameters\nspecified in WOTS.\n\nMisc\n~~~~\nThe WOTS classes come with some features that will be explained in the following sections.\n\nFully configurable\n^^^^^^^^^^^^^^^^^^\nThe WOTS classes are fully parameterizable. You can specify anything that is specified\nin the papers describing the algorithm, including the Winternitz parameter, the hash function,\nthe pseudo random function (WOTSPLUS), the seed (WOTSPLUS), the private key and the public key.\nspecifing both a private key and public key results in the public key beeing discarded.\n\nOn-demand generation of keys\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nIf no private key or no public key is specified, they will be set to None. The same\ngoes for the seed in wots+. Only when they are required, they will be generated or\nderived. This means that as long as you don't execute ``repr(obj)``, ``str(obj)``, ``obj1 == obj2``,\n``obj1 != obj2``, ``obj.pubkey``, ``obj.privkey``, ``obj.sign(...)`` or ``obj.verify(...)``, where obj is a\nWOTS object, the keys will stay None.\n\nCode representation of WOTS objects\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nYou can call ``repr(obj)``, where obj is a WOTS object, to get a line of code which contains\nall information to initialize another object so that it is equal to obj. Executing ``obj2 = eval(repr(obj))``\nexecutes that code which is returned by ``repr(obj)`` and ultimately stores a copy of it in ``obj2``.\n\nHuman readable string representation\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nYou can call ``str(obj)`` to get a string which contains a human readable representation of that object.\n\nComparison of objects\n^^^^^^^^^^^^^^^^^^^^^\nYou can compare two objects from this class ``obj1 == obj2`` and ``obj1 != obj2``\n\nOptimizations\n^^^^^^^^^^^^^\nThe code was carefully written to reduce execution times. It surely is not perfect and can still be optimized,\nfurther time-critical sections could be coded as C extensions, but nevertheless in the current state it should\noffer quite an efficient implementation. It defines ``__slots__`` to reduce execution times and storage requirements\nwithin the class. Implementation of parallelization is planned, but it is only usefull when using huge winternitz\nparameters, since python can only execute code in parallel if you spawn a new process and the overhead of forking\na new python interpreter is not negliable.\n\nNote\n----\n\nThis project has been set up using PyScaffold 3.1. For details and usage\ninformation on PyScaffold see `https://pyscaffold.org/`_.\n\n.. _`https://pyscaffold.org/`: https://pyscaffold.org/\n\n.. |Build Status| image:: https://www.travis-ci.com/sea212/winternitz-one-time-signature.svg?branch=master\n :target: https://www.travis-ci.com/sea212/winternitz-one-time-signature\n.. |Coverage Status| image:: https://coveralls.io/repos/github/sea212/winternitz-one-time-signature/badge.svg?branch=master\n :target: https://coveralls.io/github/sea212/winternitz-one-time-signature?branch=master\n.. |Documentation Status| image:: https://readthedocs.org/projects/winternitz-one-time-signature/badge/?version=latest\n :target: https://winternitz-one-time-signature.readthedocs.io/en/latest/?badge=latest\n :alt: Documentation Status\n.. |License: MIT| image:: https://img.shields.io/badge/License-MIT-yellow.svg\n :target: https://opensource.org/licenses/MIT\n\n\n", "description_content_type": "text/x-rst", "docs_url": null, "download_url": "", "downloads": { "last_day": -1, "last_month": -1, "last_week": -1 }, "home_page": "https://github.com/sea212/winternitz-one-time-signature", "keywords": "", "license": "mit", "maintainer": "", "maintainer_email": "", "name": "winternitz", "package_url": "https://pypi.org/project/winternitz/", "platform": "any", "project_url": "https://pypi.org/project/winternitz/", "project_urls": { "Homepage": "https://github.com/sea212/winternitz-one-time-signature" }, "release_url": "https://pypi.org/project/winternitz/1.0.2/", "requires_dist": [ "recommonmark ; extra == 'all'", "sphinx (>=1.8) ; extra == 'all'", "sphinx-rtd-theme ; extra == 'all'", "isort ; extra == 'all'", "flake8 ; extra == 'all'", "pytest ; extra == 'all'", "pytest-cov ; extra == 'all'", "pytest-runner ; extra == 'all'", "tox ; extra == 'all'", "recommonmark ; extra == 'docs'", "sphinx ; extra == 'docs'", "sphinx-rtd-theme ; extra == 'docs'", "isort ; extra == 'lint'", "flake8 ; extra == 'lint'", "pytest ; extra == 'testing'", "pytest-cov ; extra == 'testing'", "pytest-runner ; extra == 'testing'", "tox ; extra == 'testing'" ], "requires_python": "> 3.4", "summary": "Python Winternitz One-Time-Signature(+) implementation", "version": "1.0.2" }, "last_serial": 4941134, "releases": { "1.0.0": [ { "comment_text": "", "digests": { "md5": "aac1a005e0b1f4e5b3655558f2d99f46", "sha256": "8d9fd29eff3cc85e68c0dc980eccfa744291cf148b5cd24afccc0bf69fb5dcb2" }, "downloads": -1, "filename": "winternitz-1.0.0-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "aac1a005e0b1f4e5b3655558f2d99f46", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": "> 3.4", "size": 11311, "upload_time": "2019-03-10T02:11:02", "url": "https://files.pythonhosted.org/packages/62/d1/13ea46765a5e49089048931f852701588adbb1749127dc66f4465780bd7c/winternitz-1.0.0-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "8870ef9bb9acaa1749384d2d72c0332a", "sha256": "09b9869b5bd070992830c928621ac4a4a3711a57e35a8d3d4d6f628405c6062c" }, "downloads": -1, "filename": "winternitz-1.0.0.tar.gz", "has_sig": false, "md5_digest": "8870ef9bb9acaa1749384d2d72c0332a", "packagetype": "sdist", "python_version": "source", "requires_python": "> 3.4", "size": 29598, "upload_time": "2019-03-10T02:11:05", "url": "https://files.pythonhosted.org/packages/59/ed/58a59bf15ca7c8a33da206247044931f646fa1ce533e2fb92c70f4baf8ad/winternitz-1.0.0.tar.gz" } ], "1.0.1": [ { "comment_text": "", "digests": { "md5": "6d213fa8aa0aa1547fcefdeaf65fe670", "sha256": "317804fc6a0d0a255f99ea344f72e82f5895b3a5043b9bd1d5351fcab479ca03" }, "downloads": -1, "filename": "winternitz-1.0.1-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "6d213fa8aa0aa1547fcefdeaf65fe670", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": "> 3.4", "size": 11898, "upload_time": "2019-03-10T15:18:42", "url": "https://files.pythonhosted.org/packages/51/af/398e561fda36284a2ca2109e817d3b342e63087f886b30fb9197cca2f310/winternitz-1.0.1-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "ba5967eb053a15858572bffccfd578e7", "sha256": "16fcb2bb63515c117b3e1559999e6022d35cf319215f5b69984af1c42c00a4eb" }, "downloads": -1, "filename": "winternitz-1.0.1.tar.gz", "has_sig": false, "md5_digest": "ba5967eb053a15858572bffccfd578e7", "packagetype": "sdist", "python_version": "source", "requires_python": "> 3.4", "size": 31383, "upload_time": "2019-03-10T15:18:43", "url": "https://files.pythonhosted.org/packages/0d/de/34d2b3b590cc45922a99097cdf248b0a95c37f70f7f015971bb50d1ad1a3/winternitz-1.0.1.tar.gz" } ], "1.0.2": [ { "comment_text": "", "digests": { "md5": "051362623d498332b80a35c6d60d571f", "sha256": "2e54d88a96619a828170019ecd1fd226af4162a531f8852282b1b7e32db15893" }, "downloads": -1, "filename": "winternitz-1.0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "051362623d498332b80a35c6d60d571f", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": "> 3.4", "size": 12467, "upload_time": "2019-03-14T18:35:37", "url": "https://files.pythonhosted.org/packages/2f/3d/636adf5d3822d05d60c3a8a8e56dd1a99421270b4ddf2154444b25f785a8/winternitz-1.0.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "dc32d34c89b1379fa3c92891f475a76d", "sha256": "7eba342ac0c44e37fa2684fec1b3f7883a9d5d12675ba1fd6dabdd520c7da563" }, "downloads": -1, "filename": "winternitz-1.0.2.tar.gz", "has_sig": false, "md5_digest": "dc32d34c89b1379fa3c92891f475a76d", "packagetype": "sdist", "python_version": "source", "requires_python": "> 3.4", "size": 32611, "upload_time": "2019-03-14T18:35:39", "url": "https://files.pythonhosted.org/packages/bd/c5/a02b7ae3571974a654ffa4b4aaf683bc44e3a0468d7b5f8436c8fa5a0625/winternitz-1.0.2.tar.gz" } ] }, "urls": [ { "comment_text": "", "digests": { "md5": "051362623d498332b80a35c6d60d571f", "sha256": "2e54d88a96619a828170019ecd1fd226af4162a531f8852282b1b7e32db15893" }, "downloads": -1, "filename": "winternitz-1.0.2-py2.py3-none-any.whl", "has_sig": false, "md5_digest": "051362623d498332b80a35c6d60d571f", "packagetype": "bdist_wheel", "python_version": "py2.py3", "requires_python": "> 3.4", "size": 12467, "upload_time": "2019-03-14T18:35:37", "url": "https://files.pythonhosted.org/packages/2f/3d/636adf5d3822d05d60c3a8a8e56dd1a99421270b4ddf2154444b25f785a8/winternitz-1.0.2-py2.py3-none-any.whl" }, { "comment_text": "", "digests": { "md5": "dc32d34c89b1379fa3c92891f475a76d", "sha256": "7eba342ac0c44e37fa2684fec1b3f7883a9d5d12675ba1fd6dabdd520c7da563" }, "downloads": -1, "filename": "winternitz-1.0.2.tar.gz", "has_sig": false, "md5_digest": "dc32d34c89b1379fa3c92891f475a76d", "packagetype": "sdist", "python_version": "source", "requires_python": "> 3.4", "size": 32611, "upload_time": "2019-03-14T18:35:39", "url": "https://files.pythonhosted.org/packages/bd/c5/a02b7ae3571974a654ffa4b4aaf683bc44e3a0468d7b5f8436c8fa5a0625/winternitz-1.0.2.tar.gz" } ] }