diff --git a/.gitignore b/.gitignore index 87883f9..71e9605 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ env/ *.eggs *.egg-info .pytest_cache +dist \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..534ee06 --- /dev/null +++ b/Makefile @@ -0,0 +1,34 @@ +CURRENT_VERSION ?= `poetry version -s` +SEMVERS := major minor patch + +install_dependencies: + sudo apt-get install python-dev + sudo apt-get install libssl-dev + sudo apt-get install libffi-dev + +install: install_poetry + +install_poetry: + poetry install + +tests: + poetry run pytest + +clean: + find . -name "*.pyc" -exec rm -rf {} \; + rm -rf dist *.egg-info __pycache__ .eggs + +dist: + poetry build + +tag_version: + git commit -m "build: bump to ${CURRENT_VERSION}" pyproject.toml + git tag ${CURRENT_VERSION} + +$(SEMVERS): + poetry version $@ + $(MAKE) tag_version + +set_version: + poetry version ${CURRENT_VERSION} + $(MAKE) tag_version \ No newline at end of file diff --git a/README.md b/README.md index 9082956..dd578ea 100644 --- a/README.md +++ b/README.md @@ -1,13 +1,15 @@ +> Disclaimer: this is a fork of https://github.com/spring-epfl/SSCred/ where we removed `zksk` dependency and therefore the use of commitment and ACL. Only Abe's blind signature. + # SSCred A python library to facilitate anonymous authentication. SSCred provides the following primitives: -* Anonymous credential light (ACL)[1](#cn1) -* Abe's Blind signature[2](#cn2) -* Blinded Pedersen commitment +- Anonymous credential light (ACL)[1](#cn1) +- Abe's Blind signature[2](#cn2) ## Requirement -SSCred depends on the `petlib` and `zksk` libraries. Before installing the library make sure that `libssl-dev`, `python-dev`, and `libffi-dev` packages are installed on your machine. You can use following commands on Ubuntu/Debian to install them. + +SSCred depends on the `petlib` libraries. Before installing the library make sure that `libssl-dev`, `python-dev`, and `libffi-dev` packages are installed on your machine. You can use following commands on Ubuntu/Debian to install them. ``` sudo apt-get install python-dev @@ -15,9 +17,31 @@ sudo apt-get install libssl-dev sudo apt-get install libffi-dev ``` -Note: Only blinded Pederson commitment and ACL depend on `zksk` and you can use the blind signature without relying on `zksk`. - ## Installing + +### With poetry + +Install system dependencies once and for all:: + +``` +make install_dependencies +``` + +To develop, `install Poetry `\_ then just run:: + +``` +make install +make tests +``` + +To run the server: + +``` + make run +``` + +### With pip + You can use `pip` to install the library. ``` @@ -31,6 +55,7 @@ python -m pytest ``` ### Development + If you are interested in contributing to this library, you can clone the code and install the library in the development mode. @@ -43,47 +68,16 @@ pip install -e . python -m pytest ``` -## Usage -### Anonymous credential light -Provides an one-time-use anonymous credential based on ACL[1](#cn1). The user decides on a list of attributes and a message and engages in an interactive protocol with the issuer. At the end of the protocol, the user computes a credential which is verifiable using the issuer's public key. During this process, the issuer does not learn any information about the attributes or the message. -At a later time, users can show the credential to a verifier to authorize their attributes and the message. This credential is publicly verifiable and anyone who knows the issuer public key can check it. This credential is not linked to the identity of the user. However, using a credential more than once is detectable and the verifier can link interactions with the same credential. In other words, if the user uses the credential more than once, then the credential becomes a pseudo-identity for the user. As a safeguard, the library raises an exception if the user tries to use a credential more than once. - -Attributes can be either `int`, `petlib.Bn`, `str`, or `bytes`. The library hashes attributes for internal use but keeps a copy of raw attribute values as private variables. The user can embed a public key in attributes to be able to sign with the credential after receiving it. - -*Warning*: There is a new attack [2](#cn2) that breaks the ROS security assumption. This means that running concurrent ACL signing sessions is insecure. - - How to use: -```python ->>> # generating keys and wrappers ->>> issuer_priv, issuer_pk = ACLParam().generate_new_key_pair() ->>> issuer = ACLIssuer(issuer_priv, issuer_pk) ->>> user = ACLUser(issuer_pk) ->>> message = "Hello world" - ->>> # Issuance ->>> attributes = [Bn(13), "Hello", "WoRlD", "Hidden"] ->>> attr_proof = user.prove_attr_knowledge(attributes) ->>> com, issuer_state = issuer.commit(attr_proof) ->>> challenge, user_state = user.compute_blind_challenge(com, message) ->>> resp = issuer.respond(challenge, issuer_state) ->>> cred_private = user.compute_credential(resp, user_state) - ->>> # show credential ->>> # Reveal attributes 0, 1, and 2. ->>> cred = cred_private.show_credential([True, True, True, False]) ->>> assert cred.verify_credential(issuer_pk) ->>> print(cred.get_message()) -b'Hello world' ->>> print(cred.get_attributes()) -[13, 'Hello', 'WoRlD', None] -``` +## Usage ### Abe's blind signature + The user decides on a message and engages in an interactive protocol with the signer to compute a signature on the message. This protocol prevents the signer from learning the content of the message. The signature is verifiable by anyone who knows the signer's public key. No one, including the signer, can determine the user's identity when he reveals his signature. This blind signature is similar to an ACL credential with an empty attribute list. This signature is based on Abe's blind signature[3](#cn3). -*Note*: The ROS attack [2](#cn2) does **not** impact the security of Abe's signature. +_Note_: The ROS attack [2](#cn2) does **not** impact the security of Abe's signature. + +How to use: - How to use: ```python >>> # generating keys and wrappers >>> priv, pk = AbeParam().generate_new_key_pair() @@ -103,27 +97,8 @@ The user decides on a message and engages in an interactive protocol with the si b'Hello world' ``` -### Blinded Pedersen Commitment -This scheme allows a party to prove the knowledge of a commitment without revealing any information about underlying values or the commitment itself. This primitive is mainly intended as a building block for more complicated primitives rather than direct use. This commitment only accepts values of type `int`, `petlib.Bn`, `str`, or `bytes`. - - How to use: -```python ->>> values = [Bn(123), Bn(456), 'hello', b"world"] ->>> param = BlindedPedersenParam(hs_size=len(values)) - ->>> # reveal nothing ->>> bcommit, bpriv = param.blind_commit(values) ->>> bproof = bcommit.prove_values(bpriv) ->>> assert bcommit.verify_proof(param, bproof) - ->>> # revealing some values ->>> bproof = bcommit.prove_values(bpriv, reveal_mask=[True, False, True, True]) ->>> assert bcommit.verify_proof(param, bproof) ->>> print(bproof.revealed_values) -[123, None, 'hello', b'world'] -``` - ## Performance + We used the `benchmark.py` to evaluate the performance. This scripts runs operations of ACL and Abe's signature 1000 times and records the cost. `benchmarkStats.py` is a script that compiles statistics based on the measurements of `benchmark.py`. Curve P-224 and P-256 provide 112-bit and 128-bit security respectively. Curve P-256 is heavily optimized for performance. That is why it has better performance despite higher security. @@ -131,27 +106,16 @@ Curve P-224 and P-256 provide 112-bit and 128-bit security respectively. Curve P All measurements are done on a desktop equipped with Intel(R) Core(TM) i7-9700 CPU @ 3.00GHz and 16GiB of RAM running Debian 10. ### Abe's signature + The size of the message and raw values is not included in the credential as it depends on the user input. The communication cost shows the transfer cost of running the protocol, and the signature size shows the size of the resulting signature. -| Curve | Key gen (ms) | Signer (ms) | User (ms) | Verification (ms) | Signature size (B) | Communication (B) | -|-------|:------------:|:-----------:|:----------:|:-----------------:|:------------------:|:-----------------:| -| P-224 | 0.84 | 1.13 | 1.63 | 0.68 | 324 | 367 | -| P-256 | 0.13 | 0.32 | 0.62 | 0.4 | 360 | 413 | - -### ACL -We evaluated ACL credential with 4 attributes; we reveal 3 of these attributes in the showing credential process. - -The communication cost shows the transfer cost of the issuance protocol, and the credential size is the transfer cost of showing the credential. The size of the message and raw values are not included in the credential size as they depend on the user's input. The communication cost of showing the credential is higher than issuance because of large NIZK proofs. - -| Curve | Key gen (ms) | Issuer (ms) | User (ms) | Showing cred(ms)| Verification (ms) | Credential size (B) | Communication (B) | -|-------|:------------:|:-----------:|:----------:|:---------------:|:-----------------:|:-------------------:|:-----------------:| -| P-224 | 4.96 | 0.80 | 2.02 | 1.92 | 2.52 | 1160 | 772 | -| P-256 | 0.36 | 0.48 | 0.95 | 1.32 | 1.65 | 1284 | 864 | - +| Curve | Key gen (ms) | Signer (ms) | User (ms) | Verification (ms) | Signature size (B) | Communication (B) | +| ----- | :----------: | :---------: | :-------: | :---------------: | :----------------: | :---------------: | +| P-224 | 0.84 | 1.13 | 1.63 | 0.68 | 324 | 367 | +| P-256 | 0.13 | 0.32 | 0.62 | 0.4 | 360 | 413 | ## Reference -1: Baldimtsi, F., & Lysyanskaya, A. (2013). Anonymous credentials light, 1087–1098. https://doi.org/10.1145/2508859.2516687 2: Benhamouda F, Lepoint T, Loss J, Orrù M, Raykova M. On the (in) security of ROS. EuroCrypt 2021 diff --git a/docs/examples.py b/docs/examples.py index f19f56d..8a33398 100644 --- a/docs/examples.py +++ b/docs/examples.py @@ -1,42 +1,9 @@ from petlib.bn import Bn -from sscred.commitment import * -from sscred.blind_pedersen import * from sscred.blind_signature import * -from sscred.acl import * from sscred.pack import * -def pederson_commitment_example(): - values = [Bn(2651), Bn(1), Bn(98)] - pparam = PedersenParameters(hs_size=len(values)) - pcommit, prand = pparam.commit(values) - - # reveal the opening - valid = pcommit.verify(pparam, prand, values) - assert valid - - # Prove the knowledge of opening with a nzkp - proof = pcommit.prove_knowledge(pparam, prand, values) - valid = pcommit.verify_proof(pparam, proof) - print(valid) - - -def blinded_pederson_commitment_example(): - values = [Bn(123), Bn(456), "hello", b"world"] - param = BlindedPedersenParam(hs_size=len(values)) - - # reveal nothing - bcommit, bpriv = param.blind_commit(values) - bproof = bcommit.prove_values(bpriv) - assert bcommit.verify_proof(param, bproof) - - # revealing some values - bproof2 = bcommit.prove_values(bpriv, reveal_mask=[True, False, True, True]) - assert bcommit.verify_proof(param, bproof) - print(bproof2.revealed_values) - - def blind_signature_example(): # generating keys and wrappers priv, pk = AbeParam().generate_new_key_pair() @@ -55,28 +22,6 @@ def blind_signature_example(): print(sig.message) -def acl_example(): - # generating keys and wrappers - issuer_priv, issuer_pk = ACLParam().generate_new_key_pair() - issuer = ACLIssuer(issuer_priv, issuer_pk) - user = ACLUser(issuer_pk) - message = "Hello world" - - # Issuance - attributes = [Bn(13), "Hello", "WoRlD", "Hidden"] - attr_proof = user.prove_attr_knowledge(attributes) - com, com_params = issuer.commit(attr_proof) - challenge, challenge_params = user.compute_blind_challenge(com, message) - resp = issuer.respond(challenge, com_params) - cred_private = user.compute_credential(resp, challenge_params) - - # show credential - cred = cred_private.show_credential([True, True, True, False]) - assert cred.verify_credential(issuer_pk) - print(cred.message()) - print(cred.attributes()) - - def pack_example(): priv, pk = AbeParam().generate_new_key_pair() signer = AbeSigner(priv, pk) @@ -108,10 +53,7 @@ def pack_example(): def main(): - pederson_commitment_example() - blinded_pederson_commitment_example() blind_signature_example() - acl_example() pack_example() diff --git a/poetry.lock b/poetry.lock new file mode 100644 index 0000000..aaed038 --- /dev/null +++ b/poetry.lock @@ -0,0 +1,398 @@ +# This file is automatically @generated by Poetry and should not be changed by hand. + +[[package]] +name = "attrs" +version = "22.1.0" +description = "Classes Without Boilerplate" +category = "main" +optional = false +python-versions = ">=3.5" +files = [ + {file = "attrs-22.1.0-py2.py3-none-any.whl", hash = "sha256:86efa402f67bf2df34f51a335487cf46b1ec130d02b8d39fd248abfd30da551c"}, + {file = "attrs-22.1.0.tar.gz", hash = "sha256:29adc2665447e5191d0e7c568fde78b21f9672d344281d0c6e1ab085429b22b6"}, +] + +[package.extras] +dev = ["cloudpickle", "coverage[toml] (>=5.0.2)", "furo", "hypothesis", "mypy (>=0.900,!=0.940)", "pre-commit", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "sphinx", "sphinx-notfound-page", "zope.interface"] +docs = ["furo", "sphinx", "sphinx-notfound-page", "zope.interface"] +tests = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins", "zope.interface"] +tests-no-zope = ["cloudpickle", "coverage[toml] (>=5.0.2)", "hypothesis", "mypy (>=0.900,!=0.940)", "pympler", "pytest (>=4.3.0)", "pytest-mypy-plugins"] + +[[package]] +name = "cffi" +version = "1.15.1" +description = "Foreign Function Interface for Python calling C code." +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "cffi-1.15.1-cp27-cp27m-macosx_10_9_x86_64.whl", hash = "sha256:a66d3508133af6e8548451b25058d5812812ec3798c886bf38ed24a98216fab2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_i686.whl", hash = "sha256:470c103ae716238bbe698d67ad020e1db9d9dba34fa5a899b5e21577e6d52ed2"}, + {file = "cffi-1.15.1-cp27-cp27m-manylinux1_x86_64.whl", hash = "sha256:9ad5db27f9cabae298d151c85cf2bad1d359a1b9c686a275df03385758e2f914"}, + {file = "cffi-1.15.1-cp27-cp27m-win32.whl", hash = "sha256:b3bbeb01c2b273cca1e1e0c5df57f12dce9a4dd331b4fa1635b8bec26350bde3"}, + {file = "cffi-1.15.1-cp27-cp27m-win_amd64.whl", hash = "sha256:e00b098126fd45523dd056d2efba6c5a63b71ffe9f2bbe1a4fe1716e1d0c331e"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_i686.whl", hash = "sha256:d61f4695e6c866a23a21acab0509af1cdfd2c013cf256bbf5b6b5e2695827162"}, + {file = "cffi-1.15.1-cp27-cp27mu-manylinux1_x86_64.whl", hash = "sha256:ed9cb427ba5504c1dc15ede7d516b84757c3e3d7868ccc85121d9310d27eed0b"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:39d39875251ca8f612b6f33e6b1195af86d1b3e60086068be9cc053aa4376e21"}, + {file = "cffi-1.15.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:285d29981935eb726a4399badae8f0ffdff4f5050eaa6d0cfc3f64b857b77185"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:3eb6971dcff08619f8d91607cfc726518b6fa2a9eba42856be181c6d0d9515fd"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:21157295583fe8943475029ed5abdcf71eb3911894724e360acff1d61c1d54bc"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5635bd9cb9731e6d4a1132a498dd34f764034a8ce60cef4f5319c0541159392f"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:2012c72d854c2d03e45d06ae57f40d78e5770d252f195b93f581acf3ba44496e"}, + {file = "cffi-1.15.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:dd86c085fae2efd48ac91dd7ccffcfc0571387fe1193d33b6394db7ef31fe2a4"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:fa6693661a4c91757f4412306191b6dc88c1703f780c8234035eac011922bc01"}, + {file = "cffi-1.15.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:59c0b02d0a6c384d453fece7566d1c7e6b7bae4fc5874ef2ef46d56776d61c9e"}, + {file = "cffi-1.15.1-cp310-cp310-win32.whl", hash = "sha256:cba9d6b9a7d64d4bd46167096fc9d2f835e25d7e4c121fb2ddfc6528fb0413b2"}, + {file = "cffi-1.15.1-cp310-cp310-win_amd64.whl", hash = "sha256:ce4bcc037df4fc5e3d184794f27bdaab018943698f4ca31630bc7f84a7b69c6d"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:3d08afd128ddaa624a48cf2b859afef385b720bb4b43df214f85616922e6a5ac"}, + {file = "cffi-1.15.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:3799aecf2e17cf585d977b780ce79ff0dc9b78d799fc694221ce814c2c19db83"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:a591fe9e525846e4d154205572a029f653ada1a78b93697f3b5a8f1f2bc055b9"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3548db281cd7d2561c9ad9984681c95f7b0e38881201e157833a2342c30d5e8c"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:91fc98adde3d7881af9b59ed0294046f3806221863722ba7d8d120c575314325"}, + {file = "cffi-1.15.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:94411f22c3985acaec6f83c6df553f2dbe17b698cc7f8ae751ff2237d96b9e3c"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:03425bdae262c76aad70202debd780501fabeaca237cdfddc008987c0e0f59ef"}, + {file = "cffi-1.15.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cc4d65aeeaa04136a12677d3dd0b1c0c94dc43abac5860ab33cceb42b801c1e8"}, + {file = "cffi-1.15.1-cp311-cp311-win32.whl", hash = "sha256:a0f100c8912c114ff53e1202d0078b425bee3649ae34d7b070e9697f93c5d52d"}, + {file = "cffi-1.15.1-cp311-cp311-win_amd64.whl", hash = "sha256:04ed324bda3cda42b9b695d51bb7d54b680b9719cfab04227cdd1e04e5de3104"}, + {file = "cffi-1.15.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50a74364d85fd319352182ef59c5c790484a336f6db772c1a9231f1c3ed0cbd7"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:e263d77ee3dd201c3a142934a086a4450861778baaeeb45db4591ef65550b0a6"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:cec7d9412a9102bdc577382c3929b337320c4c4c4849f2c5cdd14d7368c5562d"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:4289fc34b2f5316fbb762d75362931e351941fa95fa18789191b33fc4cf9504a"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.whl", hash = "sha256:173379135477dc8cac4bc58f45db08ab45d228b3363adb7af79436135d028405"}, + {file = "cffi-1.15.1-cp36-cp36m-manylinux_2_5_x86_64.manylinux1_x86_64.whl", hash = "sha256:6975a3fac6bc83c4a65c9f9fcab9e47019a11d3d2cf7f3c0d03431bf145a941e"}, + {file = "cffi-1.15.1-cp36-cp36m-win32.whl", hash = "sha256:2470043b93ff09bf8fb1d46d1cb756ce6132c54826661a32d4e4d132e1977adf"}, + {file = "cffi-1.15.1-cp36-cp36m-win_amd64.whl", hash = "sha256:30d78fbc8ebf9c92c9b7823ee18eb92f2e6ef79b45ac84db507f52fbe3ec4497"}, + {file = "cffi-1.15.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:198caafb44239b60e252492445da556afafc7d1e3ab7a1fb3f0584ef6d742375"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:5ef34d190326c3b1f822a5b7a45f6c4535e2f47ed06fec77d3d799c450b2651e"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8102eaf27e1e448db915d08afa8b41d6c7ca7a04b7d73af6514df10a3e74bd82"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:5df2768244d19ab7f60546d0c7c63ce1581f7af8b5de3eb3004b9b6fc8a9f84b"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:a8c4917bd7ad33e8eb21e9a5bbba979b49d9a97acb3a803092cbc1133e20343c"}, + {file = "cffi-1.15.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0e2642fe3142e4cc4af0799748233ad6da94c62a8bec3a6648bf8ee68b1c7426"}, + {file = "cffi-1.15.1-cp37-cp37m-win32.whl", hash = "sha256:e229a521186c75c8ad9490854fd8bbdd9a0c9aa3a524326b55be83b54d4e0ad9"}, + {file = "cffi-1.15.1-cp37-cp37m-win_amd64.whl", hash = "sha256:a0b71b1b8fbf2b96e41c4d990244165e2c9be83d54962a9a1d118fd8657d2045"}, + {file = "cffi-1.15.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:320dab6e7cb2eacdf0e658569d2575c4dad258c0fcc794f46215e1e39f90f2c3"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:1e74c6b51a9ed6589199c787bf5f9875612ca4a8a0785fb2d4a84429badaf22a"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a5c84c68147988265e60416b57fc83425a78058853509c1b0629c180094904a5"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3b926aa83d1edb5aa5b427b4053dc420ec295a08e40911296b9eb1b6170f6cca"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:87c450779d0914f2861b8526e035c5e6da0a3199d8f1add1a665e1cbc6fc6d02"}, + {file = "cffi-1.15.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4f2c9f67e9821cad2e5f480bc8d83b8742896f1242dba247911072d4fa94c192"}, + {file = "cffi-1.15.1-cp38-cp38-win32.whl", hash = "sha256:8b7ee99e510d7b66cdb6c593f21c043c248537a32e0bedf02e01e9553a172314"}, + {file = "cffi-1.15.1-cp38-cp38-win_amd64.whl", hash = "sha256:00a9ed42e88df81ffae7a8ab6d9356b371399b91dbdf0c3cb1e84c03a13aceb5"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:54a2db7b78338edd780e7ef7f9f6c442500fb0d41a5a4ea24fff1c929d5af585"}, + {file = "cffi-1.15.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:fcd131dd944808b5bdb38e6f5b53013c5aa4f334c5cad0c72742f6eba4b73db0"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_12_i686.manylinux2010_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:7473e861101c9e72452f9bf8acb984947aa1661a7704553a9f6e4baa5ba64415"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c9a799e985904922a4d207a94eae35c78ebae90e128f0c4e521ce339396be9d"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:3bcde07039e586f91b45c88f8583ea7cf7a0770df3a1649627bf598332cb6984"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:33ab79603146aace82c2427da5ca6e58f2b3f2fb5da893ceac0c42218a40be35"}, + {file = "cffi-1.15.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:5d598b938678ebf3c67377cdd45e09d431369c3b1a5b331058c338e201f12b27"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:db0fbb9c62743ce59a9ff687eb5f4afbe77e5e8403d6697f7446e5f609976f76"}, + {file = "cffi-1.15.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:98d85c6a2bef81588d9227dde12db8a7f47f639f4a17c9ae08e773aa9c697bf3"}, + {file = "cffi-1.15.1-cp39-cp39-win32.whl", hash = "sha256:40f4774f5a9d4f5e344f31a32b5096977b5d48560c5592e2f3d2c4374bd543ee"}, + {file = "cffi-1.15.1-cp39-cp39-win_amd64.whl", hash = "sha256:70df4e3b545a17496c9b3f41f5115e69a4f2e77e94e1d2a8e1070bc0c38c8a3c"}, + {file = "cffi-1.15.1.tar.gz", hash = "sha256:d400bfb9a37b1351253cb402671cea7e89bdecc294e8016a707f6d1d8ac934f9"}, +] + +[package.dependencies] +pycparser = "*" + +[[package]] +name = "colorama" +version = "0.4.6" +description = "Cross-platform colored terminal text." +category = "main" +optional = false +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" +files = [ + {file = "colorama-0.4.6-py2.py3-none-any.whl", hash = "sha256:4f1d9991f5acc0ca119f9d443620b77f9d6b33703e51011c16baf57afb285fc6"}, + {file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"}, +] + +[[package]] +name = "coverage" +version = "6.5.0" +description = "Code coverage measurement for Python" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "coverage-6.5.0-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:ef8674b0ee8cc11e2d574e3e2998aea5df5ab242e012286824ea3c6970580e53"}, + {file = "coverage-6.5.0-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:784f53ebc9f3fd0e2a3f6a78b2be1bd1f5575d7863e10c6e12504f240fd06660"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b4a5be1748d538a710f87542f22c2cad22f80545a847ad91ce45e77417293eb4"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83516205e254a0cb77d2d7bb3632ee019d93d9f4005de31dca0a8c3667d5bc04"}, + {file = "coverage-6.5.0-cp310-cp310-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:af4fffaffc4067232253715065e30c5a7ec6faac36f8fc8d6f64263b15f74db0"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:97117225cdd992a9c2a5515db1f66b59db634f59d0679ca1fa3fe8da32749cae"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:a1170fa54185845505fbfa672f1c1ab175446c887cce8212c44149581cf2d466"}, + {file = "coverage-6.5.0-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:11b990d520ea75e7ee8dcab5bc908072aaada194a794db9f6d7d5cfd19661e5a"}, + {file = "coverage-6.5.0-cp310-cp310-win32.whl", hash = "sha256:5dbec3b9095749390c09ab7c89d314727f18800060d8d24e87f01fb9cfb40b32"}, + {file = "coverage-6.5.0-cp310-cp310-win_amd64.whl", hash = "sha256:59f53f1dc5b656cafb1badd0feb428c1e7bc19b867479ff72f7a9dd9b479f10e"}, + {file = "coverage-6.5.0-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:4a5375e28c5191ac38cca59b38edd33ef4cc914732c916f2929029b4bfb50795"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:c4ed2820d919351f4167e52425e096af41bfabacb1857186c1ea32ff9983ed75"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:33a7da4376d5977fbf0a8ed91c4dffaaa8dbf0ddbf4c8eea500a2486d8bc4d7b"}, + {file = "coverage-6.5.0-cp311-cp311-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:a8fb6cf131ac4070c9c5a3e21de0f7dc5a0fbe8bc77c9456ced896c12fcdad91"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:a6b7d95969b8845250586f269e81e5dfdd8ff828ddeb8567a4a2eaa7313460c4"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:1ef221513e6f68b69ee9e159506d583d31aa3567e0ae84eaad9d6ec1107dddaa"}, + {file = "coverage-6.5.0-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:cca4435eebea7962a52bdb216dec27215d0df64cf27fc1dd538415f5d2b9da6b"}, + {file = "coverage-6.5.0-cp311-cp311-win32.whl", hash = "sha256:98e8a10b7a314f454d9eff4216a9a94d143a7ee65018dd12442e898ee2310578"}, + {file = "coverage-6.5.0-cp311-cp311-win_amd64.whl", hash = "sha256:bc8ef5e043a2af066fa8cbfc6e708d58017024dc4345a1f9757b329a249f041b"}, + {file = "coverage-6.5.0-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:4433b90fae13f86fafff0b326453dd42fc9a639a0d9e4eec4d366436d1a41b6d"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:f4f05d88d9a80ad3cac6244d36dd89a3c00abc16371769f1340101d3cb899fc3"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:94e2565443291bd778421856bc975d351738963071e9b8839ca1fc08b42d4bef"}, + {file = "coverage-6.5.0-cp37-cp37m-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:027018943386e7b942fa832372ebc120155fd970837489896099f5cfa2890f79"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:255758a1e3b61db372ec2736c8e2a1fdfaf563977eedbdf131de003ca5779b7d"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:851cf4ff24062c6aec510a454b2584f6e998cada52d4cb58c5e233d07172e50c"}, + {file = "coverage-6.5.0-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:12adf310e4aafddc58afdb04d686795f33f4d7a6fa67a7a9d4ce7d6ae24d949f"}, + {file = "coverage-6.5.0-cp37-cp37m-win32.whl", hash = "sha256:b5604380f3415ba69de87a289a2b56687faa4fe04dbee0754bfcae433489316b"}, + {file = "coverage-6.5.0-cp37-cp37m-win_amd64.whl", hash = "sha256:4a8dbc1f0fbb2ae3de73eb0bdbb914180c7abfbf258e90b311dcd4f585d44bd2"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:d900bb429fdfd7f511f868cedd03a6bbb142f3f9118c09b99ef8dc9bf9643c3c"}, + {file = "coverage-6.5.0-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:2198ea6fc548de52adc826f62cb18554caedfb1d26548c1b7c88d8f7faa8f6ba"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:6c4459b3de97b75e3bd6b7d4b7f0db13f17f504f3d13e2a7c623786289dd670e"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:20c8ac5386253717e5ccc827caad43ed66fea0efe255727b1053a8154d952398"}, + {file = "coverage-6.5.0-cp38-cp38-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6b07130585d54fe8dff3d97b93b0e20290de974dc8177c320aeaf23459219c0b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:dbdb91cd8c048c2b09eb17713b0c12a54fbd587d79adcebad543bc0cd9a3410b"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:de3001a203182842a4630e7b8d1a2c7c07ec1b45d3084a83d5d227a3806f530f"}, + {file = "coverage-6.5.0-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:e07f4a4a9b41583d6eabec04f8b68076ab3cd44c20bd29332c6572dda36f372e"}, + {file = "coverage-6.5.0-cp38-cp38-win32.whl", hash = "sha256:6d4817234349a80dbf03640cec6109cd90cba068330703fa65ddf56b60223a6d"}, + {file = "coverage-6.5.0-cp38-cp38-win_amd64.whl", hash = "sha256:7ccf362abd726b0410bf8911c31fbf97f09f8f1061f8c1cf03dfc4b6372848f6"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:633713d70ad6bfc49b34ead4060531658dc6dfc9b3eb7d8a716d5873377ab745"}, + {file = "coverage-6.5.0-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:95203854f974e07af96358c0b261f1048d8e1083f2de9b1c565e1be4a3a48cfc"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:b9023e237f4c02ff739581ef35969c3739445fb059b060ca51771e69101efffe"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:265de0fa6778d07de30bcf4d9dc471c3dc4314a23a3c6603d356a3c9abc2dfcf"}, + {file = "coverage-6.5.0-cp39-cp39-manylinux_2_5_x86_64.manylinux1_x86_64.manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:8f830ed581b45b82451a40faabb89c84e1a998124ee4212d440e9c6cf70083e5"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:7b6be138d61e458e18d8e6ddcddd36dd96215edfe5f1168de0b1b32635839b62"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:42eafe6778551cf006a7c43153af1211c3aaab658d4d66fa5fcc021613d02518"}, + {file = "coverage-6.5.0-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:723e8130d4ecc8f56e9a611e73b31219595baa3bb252d539206f7bbbab6ffc1f"}, + {file = "coverage-6.5.0-cp39-cp39-win32.whl", hash = "sha256:d9ecf0829c6a62b9b573c7bb6d4dcd6ba8b6f80be9ba4fc7ed50bf4ac9aecd72"}, + {file = "coverage-6.5.0-cp39-cp39-win_amd64.whl", hash = "sha256:fc2af30ed0d5ae0b1abdb4ebdce598eafd5b35397d4d75deb341a614d333d987"}, + {file = "coverage-6.5.0-pp36.pp37.pp38-none-any.whl", hash = "sha256:1431986dac3923c5945271f169f59c45b8802a114c8f548d611f2015133df77a"}, + {file = "coverage-6.5.0.tar.gz", hash = "sha256:f642e90754ee3e06b0e7e51bce3379590e76b7f76b708e1a71ff043f87025c84"}, +] + +[package.dependencies] +tomli = {version = "*", optional = true, markers = "python_full_version <= \"3.11.0a6\" and extra == \"toml\""} + +[package.extras] +toml = ["tomli"] + +[[package]] +name = "exceptiongroup" +version = "1.0.4" +description = "Backport of PEP 654 (exception groups)" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.0.4-py3-none-any.whl", hash = "sha256:542adf9dea4055530d6e1279602fa5cb11dab2395fa650b8674eaec35fc4a828"}, + {file = "exceptiongroup-1.0.4.tar.gz", hash = "sha256:bd14967b79cd9bdb54d97323216f8fdf533e278df937aa2a90089e7d6e06e5ec"}, +] + +[package.extras] +test = ["pytest (>=6)"] + +[[package]] +name = "future" +version = "0.18.2" +description = "Clean single-source support for Python 3 and 2" +category = "main" +optional = false +python-versions = ">=2.6, !=3.0.*, !=3.1.*, !=3.2.*" +files = [ + {file = "future-0.18.2.tar.gz", hash = "sha256:b1bead90b70cf6ec3f0710ae53a525360fa360d306a86583adc6bf83a4db537d"}, +] + +[[package]] +name = "iniconfig" +version = "1.1.1" +description = "iniconfig: brain-dead simple config-ini parsing" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "iniconfig-1.1.1-py2.py3-none-any.whl", hash = "sha256:011e24c64b7f47f6ebd835bb12a743f2fbe9a26d4cecaa7f53bc4f35ee9da8b3"}, + {file = "iniconfig-1.1.1.tar.gz", hash = "sha256:bc3af051d7d14b2ee5ef9969666def0cd1a000e121eaea580d4a313df4b37f32"}, +] + +[[package]] +name = "msgpack" +version = "1.0.4" +description = "MessagePack serializer" +category = "main" +optional = false +python-versions = "*" +files = [ + {file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_universal2.whl", hash = "sha256:4ab251d229d10498e9a2f3b1e68ef64cb393394ec477e3370c457f9430ce9250"}, + {file = "msgpack-1.0.4-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:112b0f93202d7c0fef0b7810d465fde23c746a2d482e1e2de2aafd2ce1492c88"}, + {file = "msgpack-1.0.4-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:002b5c72b6cd9b4bafd790f364b8480e859b4712e91f43014fe01e4f957b8467"}, + {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:35bc0faa494b0f1d851fd29129b2575b2e26d41d177caacd4206d81502d4c6a6"}, + {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:4733359808c56d5d7756628736061c432ded018e7a1dff2d35a02439043321aa"}, + {file = "msgpack-1.0.4-cp310-cp310-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:eb514ad14edf07a1dbe63761fd30f89ae79b42625731e1ccf5e1f1092950eaa6"}, + {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:c23080fdeec4716aede32b4e0ef7e213c7b1093eede9ee010949f2a418ced6ba"}, + {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:49565b0e3d7896d9ea71d9095df15b7f75a035c49be733051c34762ca95bbf7e"}, + {file = "msgpack-1.0.4-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:aca0f1644d6b5a73eb3e74d4d64d5d8c6c3d577e753a04c9e9c87d07692c58db"}, + {file = "msgpack-1.0.4-cp310-cp310-win32.whl", hash = "sha256:0dfe3947db5fb9ce52aaea6ca28112a170db9eae75adf9339a1aec434dc954ef"}, + {file = "msgpack-1.0.4-cp310-cp310-win_amd64.whl", hash = "sha256:4dea20515f660aa6b7e964433b1808d098dcfcabbebeaaad240d11f909298075"}, + {file = "msgpack-1.0.4-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:e83f80a7fec1a62cf4e6c9a660e39c7f878f603737a0cdac8c13131d11d97f52"}, + {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:3c11a48cf5e59026ad7cb0dc29e29a01b5a66a3e333dc11c04f7e991fc5510a9"}, + {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:1276e8f34e139aeff1c77a3cefb295598b504ac5314d32c8c3d54d24fadb94c9"}, + {file = "msgpack-1.0.4-cp36-cp36m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6c9566f2c39ccced0a38d37c26cc3570983b97833c365a6044edef3574a00c08"}, + {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_aarch64.whl", hash = "sha256:fcb8a47f43acc113e24e910399376f7277cf8508b27e5b88499f053de6b115a8"}, + {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_i686.whl", hash = "sha256:76ee788122de3a68a02ed6f3a16bbcd97bc7c2e39bd4d94be2f1821e7c4a64e6"}, + {file = "msgpack-1.0.4-cp36-cp36m-musllinux_1_1_x86_64.whl", hash = "sha256:0a68d3ac0104e2d3510de90a1091720157c319ceeb90d74f7b5295a6bee51bae"}, + {file = "msgpack-1.0.4-cp36-cp36m-win32.whl", hash = "sha256:85f279d88d8e833ec015650fd15ae5eddce0791e1e8a59165318f371158efec6"}, + {file = "msgpack-1.0.4-cp36-cp36m-win_amd64.whl", hash = "sha256:c1683841cd4fa45ac427c18854c3ec3cd9b681694caf5bff04edb9387602d661"}, + {file = "msgpack-1.0.4-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:a75dfb03f8b06f4ab093dafe3ddcc2d633259e6c3f74bb1b01996f5d8aa5868c"}, + {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:9667bdfdf523c40d2511f0e98a6c9d3603be6b371ae9a238b7ef2dc4e7a427b0"}, + {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:11184bc7e56fd74c00ead4f9cc9a3091d62ecb96e97653add7a879a14b003227"}, + {file = "msgpack-1.0.4-cp37-cp37m-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:ac5bd7901487c4a1dd51a8c58f2632b15d838d07ceedaa5e4c080f7190925bff"}, + {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:1e91d641d2bfe91ba4c52039adc5bccf27c335356055825c7f88742c8bb900dd"}, + {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:2a2df1b55a78eb5f5b7d2a4bb221cd8363913830145fad05374a80bf0877cb1e"}, + {file = "msgpack-1.0.4-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:545e3cf0cf74f3e48b470f68ed19551ae6f9722814ea969305794645da091236"}, + {file = "msgpack-1.0.4-cp37-cp37m-win32.whl", hash = "sha256:2cc5ca2712ac0003bcb625c96368fd08a0f86bbc1a5578802512d87bc592fe44"}, + {file = "msgpack-1.0.4-cp37-cp37m-win_amd64.whl", hash = "sha256:eba96145051ccec0ec86611fe9cf693ce55f2a3ce89c06ed307de0e085730ec1"}, + {file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_universal2.whl", hash = "sha256:7760f85956c415578c17edb39eed99f9181a48375b0d4a94076d84148cf67b2d"}, + {file = "msgpack-1.0.4-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:449e57cc1ff18d3b444eb554e44613cffcccb32805d16726a5494038c3b93dab"}, + {file = "msgpack-1.0.4-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:d603de2b8d2ea3f3bcb2efe286849aa7a81531abc52d8454da12f46235092bcb"}, + {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:48f5d88c99f64c456413d74a975bd605a9b0526293218a3b77220a2c15458ba9"}, + {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6916c78f33602ecf0509cc40379271ba0f9ab572b066bd4bdafd7434dee4bc6e"}, + {file = "msgpack-1.0.4-cp38-cp38-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:81fc7ba725464651190b196f3cd848e8553d4d510114a954681fd0b9c479d7e1"}, + {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:d5b5b962221fa2c5d3a7f8133f9abffc114fe218eb4365e40f17732ade576c8e"}, + {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:77ccd2af37f3db0ea59fb280fa2165bf1b096510ba9fe0cc2bf8fa92a22fdb43"}, + {file = "msgpack-1.0.4-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:b17be2478b622939e39b816e0aa8242611cc8d3583d1cd8ec31b249f04623243"}, + {file = "msgpack-1.0.4-cp38-cp38-win32.whl", hash = "sha256:2bb8cdf50dd623392fa75525cce44a65a12a00c98e1e37bf0fb08ddce2ff60d2"}, + {file = "msgpack-1.0.4-cp38-cp38-win_amd64.whl", hash = "sha256:26b8feaca40a90cbe031b03d82b2898bf560027160d3eae1423f4a67654ec5d6"}, + {file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_universal2.whl", hash = "sha256:462497af5fd4e0edbb1559c352ad84f6c577ffbbb708566a0abaaa84acd9f3ae"}, + {file = "msgpack-1.0.4-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:2999623886c5c02deefe156e8f869c3b0aaeba14bfc50aa2486a0415178fce55"}, + {file = "msgpack-1.0.4-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:f0029245c51fd9473dc1aede1160b0a29f4a912e6b1dd353fa6d317085b219da"}, + {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:ed6f7b854a823ea44cf94919ba3f727e230da29feb4a99711433f25800cf747f"}, + {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:0df96d6eaf45ceca04b3f3b4b111b86b33785683d682c655063ef8057d61fd92"}, + {file = "msgpack-1.0.4-cp39-cp39-manylinux_2_5_i686.manylinux1_i686.manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:6a4192b1ab40f8dca3f2877b70e63799d95c62c068c84dc028b40a6cb03ccd0f"}, + {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0e3590f9fb9f7fbc36df366267870e77269c03172d086fa76bb4eba8b2b46624"}, + {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:1576bd97527a93c44fa856770197dec00d223b0b9f36ef03f65bac60197cedf8"}, + {file = "msgpack-1.0.4-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:63e29d6e8c9ca22b21846234913c3466b7e4ee6e422f205a2988083de3b08cae"}, + {file = "msgpack-1.0.4-cp39-cp39-win32.whl", hash = "sha256:fb62ea4b62bfcb0b380d5680f9a4b3f9a2d166d9394e9bbd9666c0ee09a3645c"}, + {file = "msgpack-1.0.4-cp39-cp39-win_amd64.whl", hash = "sha256:4d5834a2a48965a349da1c5a79760d94a1a0172fbb5ab6b5b33cbf8447e109ce"}, + {file = "msgpack-1.0.4.tar.gz", hash = "sha256:f5d869c18f030202eb412f08b28d2afeea553d6613aee89e200d7aca7ef01f5f"}, +] + +[[package]] +name = "packaging" +version = "22.0" +description = "Core utilities for Python packages" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "packaging-22.0-py3-none-any.whl", hash = "sha256:957e2148ba0e1a3b282772e791ef1d8083648bc131c8ab0c1feba110ce1146c3"}, + {file = "packaging-22.0.tar.gz", hash = "sha256:2198ec20bd4c017b8f9717e00f0c8714076fc2fd93816750ab48e2c41de2cfd3"}, +] + +[[package]] +name = "petlib" +version = "0.0.45" +description = "A library implementing a number of Privacy Enhancing Technologies (PETs)" +category = "main" +optional = false +python-versions = "*" +files = [] +develop = false + +[package.dependencies] +cffi = ">=1.0.0" +future = ">=0.14.3" +msgpack = ">=1.0.4" +pycparser = ">=2.10" +pytest = ">=2.5.0" +pytest-cov = ">=1.8.1" + +[package.source] +type = "git" +url = "https://github.com/spring-epfl/petlib.git" +reference = "HEAD" +resolved_reference = "b23c0d29f5f47a20e948b25acc90fe0f7e5bbed4" + +[[package]] +name = "pluggy" +version = "1.0.0" +description = "plugin and hook calling mechanisms for python" +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pluggy-1.0.0-py2.py3-none-any.whl", hash = "sha256:74134bbf457f031a36d68416e1509f34bd5ccc019f0bcc952c7b909d06b37bd3"}, + {file = "pluggy-1.0.0.tar.gz", hash = "sha256:4224373bacce55f955a878bf9cfa763c1e360858e330072059e10bad68531159"}, +] + +[package.extras] +dev = ["pre-commit", "tox"] +testing = ["pytest", "pytest-benchmark"] + +[[package]] +name = "pycparser" +version = "2.21" +description = "C parser in Python" +category = "main" +optional = false +python-versions = ">=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*" +files = [ + {file = "pycparser-2.21-py2.py3-none-any.whl", hash = "sha256:8ee45429555515e1f6b185e78100aea234072576aa43ab53aefcae078162fca9"}, + {file = "pycparser-2.21.tar.gz", hash = "sha256:e644fdec12f7872f86c58ff790da456218b10f863970249516d60a5eaca77206"}, +] + +[[package]] +name = "pytest" +version = "7.2.0" +description = "pytest: simple powerful testing with Python" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "pytest-7.2.0-py3-none-any.whl", hash = "sha256:892f933d339f068883b6fd5a459f03d85bfcb355e4981e146d2c7616c21fef71"}, + {file = "pytest-7.2.0.tar.gz", hash = "sha256:c4014eb40e10f11f355ad4e3c2fb2c6c6d1919c73f3b5a433de4708202cade59"}, +] + +[package.dependencies] +attrs = ">=19.2.0" +colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} +iniconfig = "*" +packaging = "*" +pluggy = ">=0.12,<2.0" +tomli = {version = ">=1.0.0", markers = "python_version < \"3.11\""} + +[package.extras] +testing = ["argcomplete", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "xmlschema"] + +[[package]] +name = "pytest-cov" +version = "4.0.0" +description = "Pytest plugin for measuring coverage." +category = "main" +optional = false +python-versions = ">=3.6" +files = [ + {file = "pytest-cov-4.0.0.tar.gz", hash = "sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"}, + {file = "pytest_cov-4.0.0-py3-none-any.whl", hash = "sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b"}, +] + +[package.dependencies] +coverage = {version = ">=5.2.1", extras = ["toml"]} +pytest = ">=4.6" + +[package.extras] +testing = ["fields", "hunter", "process-tests", "pytest-xdist", "six", "virtualenv"] + +[[package]] +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" +category = "main" +optional = false +python-versions = ">=3.7" +files = [ + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, +] + +[metadata] +lock-version = "2.0" +python-versions = "^3.10" +content-hash = "5242e308bc19397b10b1d7e961a18b7c7fc5952eb20930fc2494e0cd8c80fbff" diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000..7ec935c --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,34 @@ +[tool.poetry] +name = "SSCred without ACL and Commitment" +version = "0.3.0" +description = "SSCred without ACL and Commitment" +authors = ["Kasra EdalatNejad "] +maintainers = [ + "ICIJ " +] +classifiers = [ + "Intended Audience :: Developers", + "Natural Language :: English", + "Programming Language :: Python", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.6", + "Programming Language :: Python :: 3.7", + "Programming Language :: Python :: 3.8", + "Programming Language :: Python :: 3.9", + "Topic :: Software Development :: Libraries :: Python Modules", + "Topic :: Security :: Cryptography", + "License :: OSI Approved :: BSD License" +] +license = "BSD 3-Clause" +readme = "README.md" +packages = [{include = "sscred"}] + + +[tool.poetry.dependencies] +python = "^3.10" +petlib = {git = "https://github.com/spring-epfl/petlib.git"} + + +[build-system] +requires = ["poetry-core"] +build-backend = "poetry.core.masonry.api" diff --git a/sscred/__init__.py b/sscred/__init__.py index 232d85c..a309a2f 100644 --- a/sscred/__init__.py +++ b/sscred/__init__.py @@ -7,9 +7,6 @@ __description__ = "Single Show Credentials: A Python library for anonymous authentication." __copyright__ = "2020, Kasra Edalatnejad (SPRING Lab, EPFL)" -from sscred.commitment import * -from sscred.acl import * from sscred.pack import * -from sscred.blind_pedersen import * from sscred.blind_signature import * diff --git a/sscred/acl.py b/sscred/acl.py deleted file mode 100644 index b0b5904..0000000 --- a/sscred/acl.py +++ /dev/null @@ -1,399 +0,0 @@ -""" -The Baldimtsi-Lysyanskaya Anonymous Credentials Light scheme - -Ref: Baldimtsi, Foteini, and Anna Lysyanskaya. "Anonymous credentials light." -Proceedings of the 2013 ACM SIGSAC conference on Computer & communications -security. ACM, 2013. - -A guide to ACL: -1. Prove attribute knowledge: The user commits to his attributes. She/he proves - the correctness of this commitment to the issuer with a non-interactive zkp. - -2. Preparation: The issuer generates a random generator $Z1$ based on the - commitment and randomness $rnd$ and sends $rnd$ to the user. - -3. CredentialCommitment: the issuer sends an initial commitment $C$ as part of - an interactive sigma protocol to the user. - -4. CredentialChallenge: The user blinds the commitment $C$ with the randomeness - $t$ to get a new commitment $C'$. The user computes the fiat-shamir challenge - $\\epsilon$ based on $C'$, blinds it to $e$, and sends the blinded challenge - to the prover. - -5. CredentialResponse: The prover sends completes the sigma protocol and sends - the response for $(C, e)$ to the user. The user unblinds the response to form - a signature withZ $(C', \\epsilon)$. - -Steps 2 and 3 can be combined together. - -Warning: Running concurrent ACL signing sessions is insecure. - -How to use: - >>> # generating keys and wrappers - >>> issuer_priv, issuer_pk = ACLParam().generate_new_key_pair() - >>> issuer = ACLIssuer(issuer_priv, issuer_pk) - >>> user = ACLUser(issuer_pk) - >>> message = "Hello world" - - >>> # Issuance - >>> attributes = [Bn(13), "Hello", "WoRlD", "Hidden"] - >>> attr_proof = user.prove_attr_knowledge(attributes) - >>> com, com_intern = issuer.commit(attr_proof) - >>> challenge, challenge_intern = user.compute_blind_challenge(com, message) - >>> resp = issuer.respond(challenge, com_intern) - >>> cred_private = user.compute_credential(resp, challenge_internal) - - >>> # show credential - >>> cred = cred_private.show_credential([True, True, True, False]) - >>> assert cred.verify_credential(issuer_pk) - >>> print(cred.get_message()) - b'Hello world' - >>> print(cred.get_attributes()) - [13, 'Hello', 'WoRlD', None] -""" -from __future__ import annotations -from typing import Collection, Tuple, Union - -import attr - -from petlib.bn import Bn -from petlib.ec import EcGroup, EcPt - -from .commitment import PedersenCommitment, PedersenProof -from .blind_pedersen import BlPedersenCommitment, BlPedersenPrivate, BlPedersenProof, BlindedPedersenParam -from .blind_signature import ( - AbeParam, - AbePrivateKey, - AbePublicKey, - AbeSignature, - AbeSigner, - AbeUser, - BlindedChallengeMessage, - SignerCommitMessage, - SignerCommitmentInternalState, - SignerResponseMessage, - UserBlindedChallengeInternalState, -) -from .config import DEFAULT_GROUP_ID - - -Attribute = Union[bytes, str, Bn] - - -class ACLAttributeProofIsInvalid(Exception): - """The attribute proof is invalid.""" - - -class ACLParam(AbeParam): - """Param for ACL credential including both AbeParam and - BlindedPedersenParam. - """ - - def __init__(self, group: EcGroup = EcGroup(DEFAULT_GROUP_ID)): - super().__init__(group) - - - def generate_new_key_pair(self) -> Tuple[ACLIssuerPrivateKey, ACLIssuerPublicKey]: - sk = self.q.random() - private = ACLIssuerPrivateKey(sk) - public = private.public_key(self) - return private, public - - -@attr.s(slots=True) -class ProveAttrKnowledgeMessage: - commit = attr.ib() # type: PedersenCommitment - nizk_proof = attr.ib() # type: PedersenProof - - -class ACLIssuerPrivateKey(AbePrivateKey): - def __init__(self, sk: Bn): - super().__init__(sk=sk) - - - def public_key(self, params: ACLParam) -> ACLIssuerPublicKey: - """Create a public key corresponding to this private key.""" - return ACLIssuerPublicKey(params, self) - - -class ACLIssuerPublicKey(AbePublicKey): - """ Use ACLParam.generate_new_key_pair to generate a fresh key pair. - - Args: - param (ACLParam): parameters - priv (ACLIssuerPrivateKey): issuer's private key - """ - - __slots__ = ("bc_param",) - - def __init__(self, param: ACLParam, private: ACLIssuerPrivateKey): - super().__init__(param, private) - # Improvement: reusing an existing param for common gens can speed up - # the process. - self.bc_param = BlindedPedersenParam( - group=param.group, - hs_size=5, - Z=self.z, - H_2=self.param.g - ) - - - def verify_parameters(self, verify_bases: bool = False): - """Verifies that the public key is generated correctly. - - Args: - verify_bases (bool): if true, verifies public parameter's generators G, H - """ - return all( - ( - self.z == self.bc_param.Z, - self.param.g == self.bc_param.H_2, - super().verify_parameters(verify_bases) - ) - ) - - -class ACLIssuer(AbeSigner): - """A class which handles the issuer role - - Attributes: - private (ACLIssuerPrivateKey): issuer's private key - public (ACLIssuerPublicKey): issuer's public key - """ - - def __init__(self, private: ACLIssuerPrivateKey, public: ACLIssuerPublicKey): - self.private: ACLIssuerPrivateKey - self.public: ACLIssuerPublicKey - super().__init__(private, public) - - - def commit( - self, - prove_attr_msg: ProveAttrKnowledgeMessage - ) -> Tuple[SignerCommitMessage, SignerCommitmentInternalState]: - """Checks the attribute proof and perform AbeSignature's commit phase. - - Errors: - attribute proof is invalid - Args: - prove_attr_msg (ProveAttrKnowledgeMessage): the user's commitment - to his/her values. - Returns: - (SignerCommitMessage) - """ - - valid_commit = prove_attr_msg.commit.verify_proof( - pparam = self.public.bc_param, - proof = prove_attr_msg.nizk_proof - ) - if not valid_commit: - raise ACLAttributeProofIsInvalid("Attribute proof is invalid.") - - commit = prove_attr_msg.commit.commit - g = self.param.g - return super()._commit(lambda rnd, commit=commit, g=g: commit + rnd * g) - - -class ACLUser(AbeUser): - """An ACL user which receives a credential. - This class stores a state and only supports one credential at a time. - - Attributes: - public (ACLIssuerPublicKey): issuer's public key - """ - - __slots__ = ("user_attr_commitment", "attributes", "pcommit", "prand") - - def __init__(self, public: ACLIssuerPublicKey): - self.public: ACLIssuerPublicKey - super().__init__(public) - - - def _compute_z1(self, rnd: Bn) -> EcPt: - if not (isinstance(rnd, Bn) and rnd != 0 and (0 <= rnd < self.param.q)): - raise ValueError("Invalid registration.") - return self.user_attr_commitment.commit + rnd * self.param.g - - def compute_blind_challenge( - self, - commit_message: SignerCommitMessage, - message: Union[bytes, str] - ) -> Tuple[BlindedChallengeMessage, UserBlindedChallengeInternalState]: - """Receive a SignerCommitMessage from the signer and start the procedure - of getting a signature on message m from the signer. - - Args: - commit_message (SignerCommitMessage):response from AbeSigner.commit() - m (bytes): message to sign. - If m is a string, then the procedure encodes it as 'utf8' - """ - return self._compute_blind_challenge( - commit_message, - message, - self._compute_z1 - ) - - - def prove_attr_knowledge(self, attributes: Collection[Attribute]) -> ProveAttrKnowledgeMessage: - """ Prove the knowledge of attributes to initiate an issuance: - - Args: - attributes (List[Union[Bn, str, bytes]]): user's attributes - - Returns: - (ProveAttrKnowledgeMessage) - """ - bc_param = self.public.bc_param - self.attributes = tuple(attributes) - - self.pcommit, self.prand = bc_param.commit(attributes) - proof = self.pcommit.prove_knowledge( - pparam = bc_param, - prand = self.prand, - values = bc_param.process_raw_values(attributes) - ) - self.user_attr_commitment = self.pcommit - return ProveAttrKnowledgeMessage(commit=self.pcommit, nizk_proof=proof) - - - def compute_credential( - self, - response: SignerResponseMessage, - challenge_state: UserBlindedChallengeInternalState - ) -> ACLCredentialPrivate: - """Finish the protocol and form a private credential. - - Args: - response (SignerRespondMessage): output of ACLIssuer.respond - - Returns: - cred_private (ACLCredentialPrivate): A private credential. - cred_private.show_credential() creates a one time use credential - with the private information. - """ - sig = self.compute_signature(response, challenge_state) - bcommit, bpriv = self.public.bc_param.blind_commit( - raw_values=self.attributes, - blindness_rand=challenge_state.blinder, - h_rand=self.prand.rand - ) - cred_private = ACLCredentialPrivate( - signature = sig, - bcommit = bcommit, - bpriv = bpriv - ) - return cred_private - - -class ACLCredentialPrivate: - """An ACL credential's secret. This object can be used to generate a - one-time use credential token - - Args: - signature (AbeSignature): credential's signature - bcommit (BlPedersenCommit): blind commit's public part - bpriv (BlPedersenPrivate): blind commit's randomness - """ - - __slots__ = ("signature", "bcommit", "bpriv", "revealed") - - def __init__(self, signature: AbeSignature, bcommit: BlPedersenCommitment, bpriv: BlPedersenPrivate): - self.signature = signature - self.bcommit = bcommit - self.bpriv = bpriv - self.revealed = False - - - def show_credential(self, revealed_attrs: Collection[bool]) -> ACLCredential: - """Show the credential and reveal $revealed_attrs attributes. - - Error: - One time use only - revealed_attrs should have the same len as attributes. - Args: - revealed_attrs (boolean []): reveals attr[i] iff revealed_attrs[i] - Returns: - ACLCredential: a credential - """ - - if self.revealed: - raise Exception( - "ACL credential is one-time use only. " - "You cannot show it twice." - ) - self.revealed = True - if len(revealed_attrs) != len(self.bpriv.values): - raise Exception( - "Revealed_attrs is a binary mask to decide which attrs " - "should be reveal. It must have the same size as attributes." - ) - - bproof = self.bcommit.prove_values(self.bpriv, revealed_attrs) - cred = ACLCredential( - signature = self.signature, - bcommit = self.bcommit, - bc_proof = bproof - ) - return cred - - -class ACLCredential: - """An ACL credential. - The issuer's public key is intentionally not bundled in this class to force - the verifier to use a known correct issuer's public key. - - Attributes: - signature (AbeSignature): credential's signature - bcommit (BlPedersenCommit): blind commit's public part - bc_proof (BlPedersenProof): blind commit's proof and attributes - """ - - __slots__ = ("signature", "bcommit", "bc_proof") - - def __init__(self, signature: AbeSignature, bcommit: BlPedersenCommitment, bc_proof: BlPedersenProof): - self.signature = signature - self.bcommit = bcommit - self.bc_proof = bc_proof - - - def verify_credential(self, issuer_pk: ACLIssuerPrivateKey) -> bool: - """ verifies the credential. Assumes that issuer_pk and its parameters - are verified. - - Args: - issuer_pk (ACLIssuerPublicKey): issuer's public key. - Returns: - boolean: pass/fail - """ - if not ( - issuer_pk.verify_signature(self.signature) and - self.bcommit.verify_proof(issuer_pk.bc_param, self.bc_proof) - ): - return False - return True - - - def attributes(self) -> Tuple[Attribute]: - """ get attributes. - Returns: - raw_attr []: raw attributes in their original format. None for - non-revealed attributes. - """ - return self.bc_proof.revealed_values - - - def message(self) -> bytes: - """ get message. - Returns: - bytes: message - """ - return self.signature.message - - -def main(): - import doctest - doctest.testmod(verbose=True) - - -if __name__ == "__main__": - main() diff --git a/sscred/blind_pedersen.py b/sscred/blind_pedersen.py deleted file mode 100644 index 17348e2..0000000 --- a/sscred/blind_pedersen.py +++ /dev/null @@ -1,345 +0,0 @@ -""" -An implementation of blinded Pedersen commitment and utility support for using -it. Features: commit, blind_commit, partial open, nizk proof, verify - -Examples: - >>> values = [Bn(123), Bn(456), 'hello', b"world"] - >>> param = BlindedPedersenParam(hs_size=len(values)) - - >>> # reveal nothing - >>> bcommit, bpriv = param.blind_commit(values) - >>> bproof = bcommit.prove_values(bpriv) - >>> assert bcommit.verify_proof(param, bproof) - - >>> # revealing some values - >>> bproof = bcommit.prove_values(bpriv, reveal_mask=[True, False, True, True]) - >>> assert bcommit.verify_proof(param, bproof) - >>> print(bproof.revealed_values) - [123, None, 'hello', b'world'] -""" - -from hashlib import sha256 -from typing import List, Optional, Union - -import attr - -from petlib.bn import Bn -from petlib.ec import EcGroup, EcPt - -from zksk import Secret, DLRep -from zksk.base import NIZK -from zksk.exceptions import StatementMismatch - -from .commitment import PedersenParameters - - -class BlindedPedersenParam(PedersenParameters): - """ Common parameters for blinded Pedersen. - This class provides both vanilla and blinded Pedersen commits. The vanilla - commit is compatible with PedersenCommitment. - """ - - def __init__(self, group: Optional[EcGroup] = None, hs_size=3, Z=None, H_2=None): - """ Return the common parameters for the specified curve. - - Z and H_2 are intended for compatibilities between SSCred submodules. - The ACL submodule uses these two arguments to customize the commitment. - For standalone use of the commitment, leave Z and H_2 empty. - - Args: - group (EcGroup): determines the elliptic curve used in the scheme. - hs_size (int): maximum number of attributes allowed in the commitment. - Z (EcPt): blindness generator(z^y, C^y) (Optional) - H_2 (EcPt): Additional randomizer. Allows ACl compatibility. (Optional) - """ - super().__init__(group, hs_size) - self.Z = Z if Z is not None else self.group.hash_to_point(b"bl_z") - self.H_2 = H_2 if H_2 is not None else self.group.infinite() - - def process_raw_value(self, raw): - """"process raw values. - - Args: - raw_values (int, Bn mod q/string/bytes): committed value. - Raises: - Error: bad value encoding. values can only be Bn, bytes, string, - or None. - Returns: - (Bn mod q): processed value - """ - val = None - if raw is None: - return None - elif isinstance(raw, Bn): - return raw - elif isinstance(raw, bytes): - val = sha256(raw).digest() - elif isinstance(raw, str): - val = sha256(raw.encode('utf8')).digest() - elif isinstance(raw, int): - return Bn(raw) - else: - raise Exception("Bad commitment value encoding." - "values can only be int, Bn, bytes, string, or None.") - return Bn.from_binary(val) % self.q - - - def process_raw_values(self, raw_values): - """process raw values. - - Args: - raw_values (int, Bn mod q/string/bytes[]): committed value. - Raises: - Error: bad value encoding. values can only be Bn, bytes, string, - or None. - - Returns: - (Bn mod q []): processed value - """ - return [self.process_raw_value(raw) for raw in raw_values] - - - def commit(self, raw_values): - """"A non-blinded Pedersen commitment to values. Encodes raw values before - passing them to the PedersenCommitment. - - IMPORTANT: THIS FUNCTION IS NOT BLINDED. - - Args: - raw_values (Bn mod q/string/bytes []): committed values. - Raises: - Error: bad value encoding. values can only be Bn, bytes, or string. - Error: too many values - - Returns: - (PedersenCommitment): commitment - (PedersenRand): commitment's randomness - """ - - values = [self.process_raw_value(raw) for raw in raw_values] - return super(BlindedPedersenParam, self).commit(values) - - - def blind_commit(self, raw_values, blindness_rand=None, h_rand=None): - """"a blind commitment to values. - - Arguments blindness_rand and h_rand enable ACL compatability. - - Args: - raw_values (Bn mod q/string/bytes []): committed values. - blindness_rand (Bn mod q): forces the blinding's randomness. (optional) - h_rand (Bn): fix the randomness for H. (optional) - Raises: - Error: bad value encoding. values can only be Bn, bytes, or string. - Error: blindness generator is unknown - - Returns: - BlPedersenCommitment: commitment - BlPedersenPrivate: commitment's values and randomness - """ - - values = [self.process_raw_value(raw) for raw in raw_values] - - if len(values) > len(self.HS): - self.expand_params_len(len(values)) - - rand = h_rand if h_rand is not None else self.q.random() - - rand_2 = self.q.random() - if blindness_rand is None: - blindness_rand = self.q.random() - - C = (rand * self.H) + (rand_2 * self.H_2) - C += self.group.wsum(values, self.HS[: len(values)]) - - bl_commit = blindness_rand * C - bl_z = blindness_rand * self.Z - - bcommit = BlPedersenCommitment(bl_z=bl_z, bl_commit=bl_commit) - bpriv = BlPedersenPrivate( - param=self, - raw_values=list(raw_values), - values=[Secret(val, name=f"val_{i}") for (i, val) in enumerate(values)], - rand=Secret(rand, name="rand"), - rand_2=Secret(rand_2, name="rand_2"), - blindness_rand=Secret(blindness_rand, name="blindness_rand"), - ) - - return (bcommit, bpriv) - - -@attr.s -class BlPedersenPrivate(): - """A blinded Pedersen commitment's secret values. - - Attributes: - param (BlindedPedersenParam): commitment parameters - raw_values (Union[Bn,string,bytes]): raw committed values. - values (Secret[]): committed values. - rand (Secret): BlPedersen's commit randomness. - rand_2 (Secret): extra commit randomness for ACL. - blindness_rand (Secret): blindness randomness - """ - param = attr.ib() # type: BlindedPedersenParam - raw_values = attr.ib() # type: Union[Bn,str,bytes] - values = attr.ib() # type: List[Secret] - rand = attr.ib() # type: Secret - rand_2 = attr.ib() # type: Secret - blindness_rand = attr.ib() # type: Secret - - -@attr.s -class BlPedersenProof(): - """A NIZK proof of knowing the opening of a BlindedPedersenCommitment. - - Attributes: - bl_h (EcPt): blindness for H - bl_h2 (EcPt): blindness for H_2 - bl_hi (EcPt[]): blindness for HS[i] - revealed_values (Bn []): a list of all values. If a value is not - revealed then rv[i]=None, otherwise rv[i]=open(value[i]) - proof (zksk.NIZK): zksk's nizk proof - - Reminder: - The verifier already has bl_z and bl_commit from the commit phase - """ - bl_h = attr.ib() # type: EcPt - bl_h2 = attr.ib() # type: EcPt - bl_hi = attr.ib() # type: EcPt - revealed_values = attr.ib() # type: List[Bn] - nizk_proof = attr.ib() # type: NIZK - - -class BlPedersenCommitment: - """The public commitment in a blinded Pedersen commitment""" - - def __init__(self, bl_z, bl_commit): - """Create a blinded Pedersen commitment. - - Attributes: - bl_commit (EcPt): randomized commitment = C ^ blindness_rand - bl_z (EcPt): randomized Z base = Z ^ blindness_rand - """ - self.bl_commit = bl_commit - self.bl_z = bl_z - - def prove_values(self, bpriv, reveal_mask=None): - """A nizk proof of opening with the revealed values. - The proof contains the raw value of all revealed values. This protocol - does not reveal any information about non-revealed values. - - Error: - Either reveal_mask should be None or have the same size of private values. - Args: - bpriv (BlPedersenPrivate): values and randomness. - reveal_mask (boolean []): reveals value[i] iff reveal_mask[i] - Optional: mask=None -> reveal nothing - - Returns: (BlPedersenProof): a nizk proof for commitment (self) - """ - param = bpriv.param - if reveal_mask is None: - reveal_mask = len(bpriv.values) * [False] - if len(reveal_mask) != len(bpriv.values): - raise Exception('The size of reveal mask does not match the number of attributes') - - # randomness - expr_bl_z = bpriv.blindness_rand * param.Z - expr_bl_h = bpriv.blindness_rand * param.H - expr_bl_h2 = bpriv.blindness_rand * param.H_2 - bl_h, bl_h2 = expr_bl_h.eval(), expr_bl_h2.eval() - - stmt = ( - DLRep(self.bl_z, expr_bl_z) & - DLRep(bl_h, expr_bl_h) & - DLRep(bl_h2, expr_bl_h2) - ) - - # attributes - bl_hi = list() - for i in range(len(bpriv.values)): - expr = bpriv.blindness_rand * param.HS[i] - bl_hi.append(expr.eval()) - stmt = stmt & DLRep(bl_hi[i], expr) - - # proof - revealed_values = list() - revealed_acc = param.group.infinite() - expr_bl_commit = bpriv.rand * bl_h + bpriv.rand_2 * bl_h2 - for i in range(len(bpriv.values)): - if reveal_mask[i]: - revealed_values.append(bpriv.raw_values[i]) - revealed_acc += bpriv.values[i].value * bl_hi[i] - else: - revealed_values.append(None) - expr_bl_commit += bpriv.values[i] * bl_hi[i] - stmt = stmt & DLRep(self.bl_commit - revealed_acc, expr_bl_commit) - bproof = BlPedersenProof( - bl_h=bl_h, - bl_h2=bl_h2, - bl_hi=bl_hi, - revealed_values=revealed_values, - nizk_proof=stmt.prove() - ) - return bproof - - def verify_proof(self, bc_param, bproof): - """Verify a PedersenProof for this commitment. - Important: besides verifying the proof, you should verify the parameters. - - Args: - bc_param (BlPedersenParam): commitment parameters - bproof (BlPedersenProof): a nizk proof for self - Returns: - boolean: pass/fail - """ - - if bc_param.num_params() < len(bproof.bl_hi): - bc_param.expand_params_len(len(bproof.bl_hi)) - bl_rand_sec = Secret(name="blindness_rand") - - # randomness - expr_bl_z = bl_rand_sec * bc_param.Z - expr_bl_h = bl_rand_sec * bc_param.H - expr_bl_h2 = bl_rand_sec * bc_param.H_2 - stmt = ( - DLRep(self.bl_z, expr_bl_z) & - DLRep(bproof.bl_h, expr_bl_h) & - DLRep(bproof.bl_h2, expr_bl_h2) - ) - - # attributes - for i in range(len(bproof.bl_hi)): - expr = bl_rand_sec *bc_param.HS[i] - stmt = stmt & DLRep(bproof.bl_hi[i], expr) - - # proof - revealed_acc = bc_param.group.infinite() - expr_bl_commit = Secret(name="rand") * bproof.bl_h + Secret(name="rand_2") * bproof.bl_h2 - for i in range(len(bproof.bl_hi)): - if bproof.revealed_values[i] is None: - expr_bl_commit += Secret(name=f"val_{i}") * bproof.bl_hi[i] - else: - val = bc_param.process_raw_value(bproof.revealed_values[i]) - revealed_acc += val * bproof.bl_hi[i] - stmt = stmt & DLRep(self.bl_commit - revealed_acc, expr_bl_commit) - - # Having an invalid revealed secret leads to different - # {commit-revealed_acc} value between prover and verifier. Since this - # value is a zksk.statement constant, the mismatch results in a - # StatementMismatch exception. verify_proof checks for this exception - # and convert it to False - try: - is_valid = stmt.verify(bproof.nizk_proof) - except StatementMismatch: - return False - return is_valid - - -def main(): - import doctest - doctest.testmod(verbose=True) - - -if __name__ == "__main__": - main() diff --git a/sscred/commitment.py b/sscred/commitment.py deleted file mode 100644 index 28af275..0000000 --- a/sscred/commitment.py +++ /dev/null @@ -1,239 +0,0 @@ -""" -An implementation of Pedersen commitment and utility support for using it. -Features: Commitment, opening, nzkp of opening - -Example: - >>> values = [Bn(2651), Bn(1), Bn(98)] - >>> pparam = CommitParam(hs_size=len(values)) - >>> pcommit, prand = pparam.commit(values) - >>> valid = pcommit.verify(pparam, prand, values) - >>> print(valid) - True - >>> proof = pcommit.prove_knowledge(pparam, prand, values) - >>> valid = pcommit.verify_proof(pparam, proof) - >>> print(valid) - True - -""" - -from __future__ import annotations - -from hashlib import sha256 -from typing import ( - Collection, - List, - Optional, - Tuple, -) - -import attr - -from petlib.ec import EcGroup, EcPt -from petlib.bn import Bn - -from . import config - - -class PedersenParameters: - """ Common parameters for Pedersen commitment.""" - - def __init__(self, group: Optional[EcGroup] = None, hs_size: int = 0): - """ Return the common parameters for the specified curve. - - Args: - group: the elliptic curve used in the scheme. - hs_size: generate $hs_size bases for values. expand_params_len - allows expanding parameters. - """ - self.group: EcGroup = EcGroup(config.DEFAULT_GROUP_ID) if group is None else group - self.q: Bn = self.group.order() - - self.H: EcPt = self.group.hash_to_point(b"com_h") - self.HS: List[EcPt] = list() - - self.expand_params_len(hs_size) - - - def num_params(self) -> int: - return len(self.HS) - - - def __repr__(self) -> str: - return f"<{type(self).__name__}:{self.__dict__}" - - - def expand_params_len(self, hs_size: int) -> None: - """Expand the number of available bases.""" - if hs_size <= len(self.HS): - return - - for i in range(len(self.HS), hs_size): - self.HS.append(self.group.hash_to_point(f'com_h{i}'.encode("utf8"))) - - - def verify_parameters(self, valid_parameters: Optional[PedersenParameters] = None): - """Verifies parameters. This function always checks generators' - randomness by reproducing the hash_to_point. valid_parameters is - optional and uses a valid parameter as the base to prevent unnecessary - has_to_points and improve the performance. - - Args: - valid_parameters (CommitParam): a valid Pedersen parameter - Returns: - boolean: pass/fail - """ - - if valid_parameters is None: - valid_parameters = PedersenParameters() - valid_parameters.expand_params_len(self.num_params()) - - if valid_parameters.H != self.H: - return False - - if any(valid_parameters.HS[i] != hs for i, hs in enumerate(self.HS)): - return False - - return True - - - def commit(self, values: Collection[Bn]) -> Tuple[PedersenCommitment, PedersenRandom]: - """"commit to values. - - Args: - values (Bn mod q): committed values. - - Returns: - PedersenCommitment: commitment - PedersenRand: commitment's randomness - """ - - self.expand_params_len(len(values)) - - rand: Bn = self.q.random() - C: EcPt = rand * self.H - C += self.group.wsum(values, self.HS[:len(values)]) - - return PedersenCommitment(C), PedersenRandom(rand) - - -@attr.s -class PedersenRandom: - """Pedersen commitment's random parameter.""" - rand = attr.ib() # type: Bn - - -@attr.s -class PedersenProof: - """A NIZK proof for knowing the values inside a PedersenCommitment - - Attributes: - challenge (Bn mod q): fiat-shamir challenge, - challenge = SHA-256(pcommit, sigma_commit) - response (Bn mod q, Bn mod q[]): sigma protocol's response values - """ - challenge = attr.ib() # type: Bn - response = attr.ib() # type: Bn - - -class PedersenCommitment: - - def __init__(self, commit: EcPt): - """A Pedersen commitment. - - Attributes: - commit (EcPt): commitment's point - """ - self.commit: EcPt = commit - - - def verify( - self, - pparam: PedersenParameters, - prand: PedersenRandom, - values: Collection[Bn] - ) -> bool: - """Verify the commitment. - - Args: - pparam (CommitPram): prameters - prand (PedersenRand): commitment's secret - values (Bn[]): commitment's values - - Returns: - boolean: pass/fail - """ - if len(values) > len(pparam.HS): - raise Exception(f"parameters does not support enough {len(values)} values") - - if not pparam.group.check_point(self.commit): - return False - if not (0 <= prand.rand < pparam.q): - return False - - if any((not (0 <= v < pparam.q) for v in values)): - return False - - rhs: EcPt = prand.rand * pparam.H - rhs += pparam.group.wsum(values, pparam.HS[:len(values)]) - return self.commit == rhs - - - def prove_knowledge( - self, - pparam: PedersenParameters, - prand: PedersenRandom, - values: Collection[Bn] - ) -> PedersenRandom: - """ A non-interactive proof of knowledge of opening an commitment. - - Args: - pparam (CommitPram): prameters - prand (PedersenRand): commitment's secret - values (Bn[]): commitment's values - - Returns: - (PedersenProof) - """ - # sigma protocol's commitment phase - r_h = pparam.q.random() - r_vs = [pparam.q.random() for _ in range(len(values))] - R = r_h * pparam.H - R += pparam.group.wsum(r_vs, pparam.HS[:len(r_vs)]) - - # sigma protocol's challenge: Fiat-Shamir - chash = sha256(self.commit.export() + R.export()).digest() - e = Bn.from_binary(chash) % pparam.q - - # sigma protocol's response phase - s_h = r_h - prand.rand * e - s_vs = [r - x * e for (x, r) in zip(values, r_vs)] - return PedersenProof(e, (s_h, s_vs)) - - - def verify_proof(self, pparam: PedersenParameters, proof: PedersenProof) -> bool: - """Verify a PedersenProof for this commitment. - - Args: - proof (PedersenProof): a nizk proof for self - Returns: - boolean: pass/fail - """ - sigma_commit: EcPt = proof.response[0] * pparam.H - sigma_commit += proof.challenge * self.commit - sigma_commit += pparam.group.wsum( - proof.response[1], - pparam.HS[:len(proof.response[1])] - ) - chash: bytes = sha256(self.commit.export() + sigma_commit.export()).digest() - h: Bn = Bn.from_binary(chash) % pparam.q - - return h == proof.challenge - - -def main(): - import doctest - doctest.testmod(verbose=True) - - -if __name__ == '__main__': - main() diff --git a/sscred/pack.py b/sscred/pack.py index 35bf2a6..67728ee 100644 --- a/sscred/pack.py +++ b/sscred/pack.py @@ -11,12 +11,7 @@ import msgpack import petlib.pack -from zksk import Secret -from zksk.base import NIZK -from . import acl -from . import commitment -from . import blind_pedersen from . import blind_signature COUNTER_BASE = 20 @@ -146,15 +141,6 @@ def eq(a, b): def register_all_classes(): - # commitment - add_msgpack_support(commitment.PedersenParameters, COUNTER_BASE+1) - add_msgpack_support(commitment.PedersenProof, COUNTER_BASE+2) - add_msgpack_support(commitment.PedersenCommitment, COUNTER_BASE+3) - # blind commitment - add_msgpack_support(blind_pedersen.BlPedersenPrivate, COUNTER_BASE+4) - add_msgpack_support(blind_pedersen.BlPedersenProof, COUNTER_BASE+5) - add_msgpack_support(blind_pedersen.BlindedPedersenParam, COUNTER_BASE+6) - add_msgpack_support(blind_pedersen.BlPedersenCommitment, COUNTER_BASE+7) # Abe's signature add_msgpack_support_slots(blind_signature.AbeParam, COUNTER_BASE+8) add_msgpack_support_slots(blind_signature.AbePublicKey, COUNTER_BASE+9) @@ -162,16 +148,6 @@ def register_all_classes(): add_msgpack_support_slots(blind_signature.AbeSignature, COUNTER_BASE+11) add_msgpack_support_slots(blind_signature.SignerCommitMessage, COUNTER_BASE+12) add_msgpack_support_slots(blind_signature.SignerResponseMessage, COUNTER_BASE+13) - # ACL - add_msgpack_support_slots(acl.ACLParam, COUNTER_BASE+14) - add_msgpack_support_slots(acl.ACLIssuerPrivateKey, COUNTER_BASE+15) - add_msgpack_support_slots(acl.ACLIssuerPublicKey, COUNTER_BASE+16) - add_msgpack_support_slots(acl.ProveAttrKnowledgeMessage, COUNTER_BASE+17) - add_msgpack_support_slots(acl.ACLCredential, COUNTER_BASE+18) - add_msgpack_support_slots(acl.ACLCredentialPrivate, COUNTER_BASE+19) - # zksk - add_msgpack_support(Secret, COUNTER_BASE+20, add_cls_methods=False) - add_msgpack_support(NIZK, COUNTER_BASE+21, add_cls_methods=False) # Added later add_msgpack_support_slots(blind_signature.SignerCommitmentInternalState, COUNTER_BASE+22) diff --git a/test/test_sscred.py b/test/test_sscred.py index 9d35213..80e7783 100644 --- a/test/test_sscred.py +++ b/test/test_sscred.py @@ -3,40 +3,11 @@ from petlib.bn import Bn -from sscred.commitment import * from sscred.blind_signature import * -from sscred.blind_pedersen import * -from sscred.acl import * from sscred.config import DEFAULT_GROUP_ID from sscred.pack import packb, unpackb, add_msgpack_support -def test_pedersen_commit_verification(): - values = [Bn(2651), Bn(1), Bn(98)] - pparam = PedersenParameters(hs_size=len(values)) - assert pparam.verify_parameters() - pcommit, prand = pparam.commit(values) - assert pcommit.verify(pparam, prand, values) - - -def test_pedersen_commit_proof(): - values = [Bn(2651), Bn(1), Bn(98)] - pparam = PedersenParameters(hs_size=len(values)) - pcommit, prand = pparam.commit(values) - proof = pcommit.prove_knowledge(pparam, prand, values) - assert pcommit.verify_proof(pparam, proof) - - -def test_pedersen_commit_invalid_proof(): - values = [Bn(2651), Bn(1), Bn(98)] - pparam = PedersenParameters(hs_size=len(values)) - pcommit, prand = pparam.commit(values) - prand = PedersenRandom(pparam.q.random()) - assert not pcommit.verify(pparam, prand, values) - proof = pcommit.prove_knowledge(pparam, prand, values) - assert not pcommit.verify_proof(pparam, proof) - - def auto_sign(signer: AbeSigner, user: AbeUser, message: Union[bytes, str]) -> AbeSignature: m1, p1 = signer.commit() m2, p2 = user.compute_blind_challenge(m1, message) @@ -100,152 +71,6 @@ def test_abe_signature_verification_corrupted(): assert not pk.verify_signature(sig) assert not pk2.verify_signature(sig) - -def test_bl_pedersen_valid(): - values = [Bn(123), Bn(456), 'hello', b"world"] - param = BlindedPedersenParam(hs_size=len(values)) - - # reveal nothing - bcommit, bpriv = param.blind_commit(values) - bproof = bcommit.prove_values(bpriv) - assert bcommit.verify_proof(param, bproof) - - # revealing some values - bproof2 = bcommit.prove_values(bpriv, reveal_mask=[True, False, True, True]) - assert bcommit.verify_proof(param, bproof2) - assert bproof2.revealed_values == [Bn(123), None, 'hello', b"world"] - - -def test_bl_pedersen_with_acl_params_valid(): - group = EcGroup(DEFAULT_GROUP_ID) - g1 = group.hash_to_point(b"test_z") - g2 = group.hash_to_point(b"test_h2") - - values = [Bn(123), Bn(456), 'hello', b"world"] - param = BlindedPedersenParam(hs_size=len(values), Z=g1, H_2=g2 ) - bcommit, bpriv = param.blind_commit(values) - - bproof = bcommit.prove_values(bpriv, reveal_mask=[True, False, True, True]) - assert bcommit.verify_proof(param, bproof) - assert bproof.revealed_values == [Bn(123), None, 'hello', b"world"] - - -def test_bl_pedersen_invalid(): - group = EcGroup(DEFAULT_GROUP_ID) - g1 = group.hash_to_point(b"test_z") - g2 = group.hash_to_point(b"test_h2") - - values = [Bn(123), Bn(456), 'hello', b"world"] - param = BlindedPedersenParam(hs_size=len(values), Z=g1, H_2=g2) - bcommit, bpriv = param.blind_commit(values) - - # corrupt rand - bpriv2 = unpackb(packb(bpriv)) - bpriv2.rand.value = param.q.random() - bproof = bcommit.prove_values(bpriv2, reveal_mask=[True, False, True, True]) - assert not bcommit.verify_proof(param, bproof) - - # corrupt rand2 - bpriv3 = unpackb(packb(bpriv)) - bpriv3.rand_2.value = param.q.random() - bproof = bcommit.prove_values(bpriv3, reveal_mask=[True, False, True, True]) - assert not bcommit.verify_proof(param, bproof) - - # corrupt blindness - bpriv4 = unpackb(packb(bpriv)) - bpriv4.blindness_rand.value = param.q.random() - bproof = bcommit.prove_values(bpriv4, reveal_mask=[True, False, True, True]) - assert not bcommit.verify_proof(param, bproof) - - # corrupt revealed value - # This leads to different zksk.statement constants between prover and - # verifier which result in StatementMismatch exception. verify_proof checks - # for this statement and convert it to False - bpriv5 = unpackb(packb(bpriv)) - bpriv5.values[0].value = param.q.random() - bproof = bcommit.prove_values(bpriv5, reveal_mask=[True, False, True, True]) - assert not bcommit.verify_proof(param, bproof) - - # corrupt hidden value - bpriv6 = unpackb(packb(bpriv)) - bpriv6.values[1].value = param.q.random() - bproof = bcommit.prove_values(bpriv6, reveal_mask=[True, False, True, True]) - assert not bcommit.verify_proof(param, bproof) - - -def auto_cred(user: ACLUser, issuer: ACLIssuer, attrs: List[Attribute]): - # Interactive signing - message = "This isn't a test message." - m0 = user.prove_attr_knowledge(attrs) - m1, p1 = issuer.commit(m0) - m2, p2 = user.compute_blind_challenge(m1, message) - m3 = issuer.respond(m2, p1) - return user.compute_credential(m3, p2) - - -def test_acl_valid(): - # generating keys and wrappers - issuer_priv, issuer_pk = ACLParam().generate_new_key_pair() - issuer = ACLIssuer(issuer_priv, issuer_pk) - user = ACLUser(issuer_pk) - - attrs = [Bn(13), "Hello", "WoRlD", "Hidden"] - cred_private = auto_cred(user, issuer, attrs) - - # show credential - cred = cred_private.show_credential([True, True, True, False]) - assert cred.verify_credential(issuer_pk) - assert cred.message() == b"This isn't a test message." - assert cred.attributes() == [13, 'Hello', 'WoRlD', None] - - with pytest.raises(Exception): - cred_private.show_credential([True, False, True, False]) - - -def test_acl_invalid(): - # generating keys and wrappers - issuer_priv, issuer_pk = ACLParam().generate_new_key_pair() - issuer_priv2, issuer_pk2 = ACLParam().generate_new_key_pair() - attrs = [Bn(13), "Hello", "WoRlD", "Hidden"] - - # verifying against wrong public key - issuer = ACLIssuer(issuer_priv, issuer_pk) - user = ACLUser(issuer_pk) - cred_private = auto_cred(user, issuer, attrs) - cred = cred_private.show_credential([True, True, True, False]) - assert not cred.verify_credential(issuer_pk2) - - # wrong secret key - issuer = ACLIssuer(issuer_priv2, issuer_pk) - user = ACLUser(issuer_pk) - cred_private = auto_cred(user, issuer, attrs) - cred = cred_private.show_credential([True, True, True, False]) - assert not cred.verify_credential(issuer_pk) - - # wrong public key for the issuer - issuer = ACLIssuer(issuer_priv, issuer_pk2) - user = ACLUser(issuer_pk) - cred_private = auto_cred(user, issuer, attrs) - cred = cred_private.show_credential([True, True, True, False]) - assert not cred.verify_credential(issuer_pk) - assert not cred.verify_credential(issuer_pk2) - - # wrong public key for the user - issuer = ACLIssuer(issuer_priv, issuer_pk) - user = ACLUser(issuer_pk2) - cred_private = auto_cred(user, issuer, attrs) - cred = cred_private.show_credential([True, True, True, False]) - assert not cred.verify_credential(issuer_pk) - assert not cred.verify_credential(issuer_pk2) - - # reveal with partial mask - issuer = ACLIssuer(issuer_priv, issuer_pk) - user = ACLUser(issuer_pk) - cred_private = auto_cred(user, issuer, attrs) - with pytest.raises(Exception): - cred = cred_private.show_credential([True, True]) - - def test_pack_cls(): @attr.s class CLS(object): @@ -290,44 +115,6 @@ def test_pack_blind_sig(): assert unpackb(m6) == pk -def test_pack_acl(): - issuer_priv, issuer_pk = ACLParam().generate_new_key_pair() - issuer = ACLIssuer(issuer_priv, issuer_pk) - user = ACLUser(issuer_pk) - attrs = [Bn(13), "Hello", "WoRlD", "Hidden"] - message = "This isn't a test message." - - m0 = user.prove_attr_knowledge(attrs) - m1, p1 = issuer.commit(m0) - m2, p2 = user.compute_blind_challenge(m1, message) - m3 = issuer.respond(m2, p1) - cred_private = user.compute_credential(m3, p2) - cred = cred_private.show_credential([True, True, True, False]) - - m0p = packb(m0) - m1p = packb(m1) - m2p = packb(m2) - m3p = packb(m3) - cred_privatep = packb(cred_private) - credp = packb(cred) - - - # the original message is representing m0.nizk_proof.response as list while - # the unpacked version represent it as a tuple - # assert unpackb(m0p) == m0 - - assert unpackb(m1p) == m1 - assert unpackb(m2p) == m2 - assert unpackb(m3p) == m3 - assert unpackb(cred_privatep) == cred_private - assert unpackb(credp) == cred - - cred = unpackb(credp) - assert cred.verify_credential(issuer_pk) - assert cred.message() == b"This isn't a test message." - assert cred.attributes() == [13, 'Hello', 'WoRlD', None] - - def main(): pass