diff --git a/Pipfile b/Pipfile index 93f16f9..18703f2 100644 --- a/Pipfile +++ b/Pipfile @@ -5,8 +5,8 @@ name = "pypi" [packages] setuptools = "*" -cryptography = ">=2.3" -pynacl = "*" +cryptography = "~=3.0" +pynacl = "~=1.0" [dev-packages] bumpversion = "*" @@ -22,7 +22,7 @@ codecov = "*" # Testing libraries nbval = "*" # Docs -sphinx = "*" +sphinx = "~=4.0" sphinx-autobuild = "*" sphinx_rtd_theme = "*" # Overrides vulnerable versions allowed by codecov and sphinx: diff --git a/Pipfile.lock b/Pipfile.lock index c20b578..8ed3343 100644 --- a/Pipfile.lock +++ b/Pipfile.lock @@ -1,7 +1,7 @@ { "_meta": { "hash": { - "sha256": "5046c797bf7733818d480d0c9df2934393dbd080d847a85d03221cff74ec7907" + "sha256": "99a991b0f638e7df7d5a351de02f4c808e84cc4d5fd2dc3322648c74403f6613" }, "pipfile-spec": 6, "requires": {}, @@ -328,11 +328,11 @@ }, "ipython": { "hashes": [ - "sha256:a171caa3d3d4c819a1c0742e3abecfd5a2b8ab525ca1c9f114b40b76b0679ab1", - "sha256:f86788eef439891438af3498525094cc2acbdbea4f2aa2f8895782d4ff471341" + "sha256:9bc24a99f5d19721fb8a2d1408908e9c0520a17fff2233ffe82620847f17f1b6", + "sha256:d513e93327cf8657d6467c81f1f894adc125334ffe0e4ddd1abbb1c78d828703" ], "markers": "python_version >= '3.7'", - "version": "==7.24.0" + "version": "==7.24.1" }, "ipython-genutils": { "hashes": [ @@ -436,31 +436,32 @@ }, "mypy": { "hashes": [ - "sha256:0d0a87c0e7e3a9becdfbe936c981d32e5ee0ccda3e0f07e1ef2c3d1a817cf73e", - "sha256:25adde9b862f8f9aac9d2d11971f226bd4c8fbaa89fb76bdadb267ef22d10064", - "sha256:28fb5479c494b1bab244620685e2eb3c3f988d71fd5d64cc753195e8ed53df7c", - "sha256:2f9b3407c58347a452fc0736861593e105139b905cca7d097e413453a1d650b4", - "sha256:33f159443db0829d16f0a8d83d94df3109bb6dd801975fe86bacb9bf71628e97", - "sha256:3f2aca7f68580dc2508289c729bd49ee929a436208d2b2b6aab15745a70a57df", - "sha256:499c798053cdebcaa916eef8cd733e5584b5909f789de856b482cd7d069bdad8", - "sha256:4eec37370483331d13514c3f55f446fc5248d6373e7029a29ecb7b7494851e7a", - "sha256:552a815579aa1e995f39fd05dde6cd378e191b063f031f2acfe73ce9fb7f9e56", - "sha256:5873888fff1c7cf5b71efbe80e0e73153fe9212fafdf8e44adfe4c20ec9f82d7", - "sha256:61a3d5b97955422964be6b3baf05ff2ce7f26f52c85dd88db11d5e03e146a3a6", - "sha256:674e822aa665b9fd75130c6c5f5ed9564a38c6cea6a6432ce47eafb68ee578c5", - "sha256:7ce3175801d0ae5fdfa79b4f0cfed08807af4d075b402b7e294e6aa72af9aa2a", - "sha256:9743c91088d396c1a5a3c9978354b61b0382b4e3c440ce83cf77994a43e8c521", - "sha256:9f94aac67a2045ec719ffe6111df543bac7874cee01f41928f6969756e030564", - "sha256:a26f8ec704e5a7423c8824d425086705e381b4f1dfdef6e3a1edab7ba174ec49", - "sha256:abf7e0c3cf117c44d9285cc6128856106183938c68fd4944763003decdcfeb66", - "sha256:b09669bcda124e83708f34a94606e01b614fa71931d356c1f1a5297ba11f110a", - "sha256:cd07039aa5df222037005b08fbbfd69b3ab0b0bd7a07d7906de75ae52c4e3119", - "sha256:d23e0ea196702d918b60c8288561e722bf437d82cb7ef2edcd98cfa38905d506", - "sha256:d65cc1df038ef55a99e617431f0553cd77763869eebdf9042403e16089fe746c", - "sha256:d7da2e1d5f558c37d6e8c1246f1aec1e7349e4913d8fb3cb289a35de573fe2eb" + "sha256:0190fb77e93ce971954c9e54ea61de2802065174e5e990c9d4c1d0f54fbeeca2", + "sha256:0756529da2dd4d53d26096b7969ce0a47997123261a5432b48cc6848a2cb0bd4", + "sha256:2f9fedc1f186697fda191e634ac1d02f03d4c260212ccb018fabbb6d4b03eee8", + "sha256:353aac2ce41ddeaf7599f1c73fed2b75750bef3b44b6ad12985a991bc002a0da", + "sha256:3f12705eabdd274b98f676e3e5a89f247ea86dc1af48a2d5a2b080abac4e1243", + "sha256:4efc67b9b3e2fddbe395700f91d5b8deb5980bfaaccb77b306310bd0b9e002eb", + "sha256:517e7528d1be7e187a5db7f0a3e479747307c1b897d9706b1c662014faba3116", + "sha256:68a098c104ae2b75e946b107ef69dd8398d54cb52ad57580dfb9fc78f7f997f0", + "sha256:746e0b0101b8efec34902810047f26a8c80e1efbb4fc554956d848c05ef85d76", + "sha256:8be7bbd091886bde9fcafed8dd089a766fa76eb223135fe5c9e9798f78023a20", + "sha256:9236c21194fde5df1b4d8ebc2ef2c1f2a5dc7f18bcbea54274937cae2e20a01c", + "sha256:9ef5355eaaf7a23ab157c21a44c614365238a7bdb3552ec3b80c393697d974e1", + "sha256:9f1d74eeb3f58c7bd3f3f92b8f63cb1678466a55e2c4612bf36909105d0724ab", + "sha256:a26d0e53e90815c765f91966442775cf03b8a7514a4e960de7b5320208b07269", + "sha256:ae94c31bb556ddb2310e4f913b706696ccbd43c62d3331cd3511caef466871d2", + "sha256:b5ba1f0d5f9087e03bf5958c28d421a03a4c1ad260bf81556195dffeccd979c4", + "sha256:b5dfcd22c6bab08dfeded8d5b44bdcb68c6f1ab261861e35c470b89074f78a70", + "sha256:cd01c599cf9f897b6b6c6b5d8b182557fb7d99326bcdf5d449a0fbbb4ccee4b9", + "sha256:e89880168c67cf4fde4506b80ee42f1537ad66ad366c101d388b3fd7d7ce2afd", + "sha256:ebe2bc9cb638475f5d39068d2dbe8ae1d605bb8d8d3ff281c695df1670ab3987", + "sha256:f89bfda7f0f66b789792ab64ce0978e4a991a0e4dd6197349d0767b0f1095b21", + "sha256:fc4d63da57ef0e8cd4ab45131f3fe5c286ce7dd7f032650d0fbc239c6190e167", + "sha256:fd634bc17b1e2d6ce716f0e43446d0d61cdadb1efcad5c56ca211c22b246ebc8" ], "index": "pypi", - "version": "==0.812" + "version": "==0.902" }, "mypy-extensions": { "hashes": [ @@ -836,41 +837,6 @@ "markers": "python_version >= '3.7'", "version": "==5.0.5" }, - "typed-ast": { - "hashes": [ - "sha256:01ae5f73431d21eead5015997ab41afa53aa1fbe252f9da060be5dad2c730ace", - "sha256:067a74454df670dcaa4e59349a2e5c81e567d8d65458d480a5b3dfecec08c5ff", - "sha256:0fb71b8c643187d7492c1f8352f2c15b4c4af3f6338f21681d3681b3dc31a266", - "sha256:1b3ead4a96c9101bef08f9f7d1217c096f31667617b58de957f690c92378b528", - "sha256:2068531575a125b87a41802130fa7e29f26c09a2833fea68d9a40cf33902eba6", - "sha256:209596a4ec71d990d71d5e0d312ac935d86930e6eecff6ccc7007fe54d703808", - "sha256:2c726c276d09fc5c414693a2de063f521052d9ea7c240ce553316f70656c84d4", - "sha256:398e44cd480f4d2b7ee8d98385ca104e35c81525dd98c519acff1b79bdaac363", - "sha256:52b1eb8c83f178ab787f3a4283f68258525f8d70f778a2f6dd54d3b5e5fb4341", - "sha256:5feca99c17af94057417d744607b82dd0a664fd5e4ca98061480fd8b14b18d04", - "sha256:7538e495704e2ccda9b234b82423a4038f324f3a10c43bc088a1636180f11a41", - "sha256:760ad187b1041a154f0e4d0f6aae3e40fdb51d6de16e5c99aedadd9246450e9e", - "sha256:777a26c84bea6cd934422ac2e3b78863a37017618b6e5c08f92ef69853e765d3", - "sha256:95431a26309a21874005845c21118c83991c63ea800dd44843e42a916aec5899", - "sha256:9ad2c92ec681e02baf81fdfa056fe0d818645efa9af1f1cd5fd6f1bd2bdfd805", - "sha256:9c6d1a54552b5330bc657b7ef0eae25d00ba7ffe85d9ea8ae6540d2197a3788c", - "sha256:aee0c1256be6c07bd3e1263ff920c325b59849dc95392a05f258bb9b259cf39c", - "sha256:af3d4a73793725138d6b334d9d247ce7e5f084d96284ed23f22ee626a7b88e39", - "sha256:b36b4f3920103a25e1d5d024d155c504080959582b928e91cb608a65c3a49e1a", - "sha256:b9574c6f03f685070d859e75c7f9eeca02d6933273b5e69572e5ff9d5e3931c3", - "sha256:bff6ad71c81b3bba8fa35f0f1921fb24ff4476235a6e94a26ada2e54370e6da7", - "sha256:c190f0899e9f9f8b6b7863debfb739abcb21a5c054f911ca3596d12b8a4c4c7f", - "sha256:c907f561b1e83e93fad565bac5ba9c22d96a54e7ea0267c708bffe863cbe4075", - "sha256:cae53c389825d3b46fb37538441f75d6aecc4174f615d048321b716df2757fb0", - "sha256:dd4a21253f42b8d2b48410cb31fe501d32f8b9fbeb1f55063ad102fe9c425e40", - "sha256:dde816ca9dac1d9c01dd504ea5967821606f02e510438120091b84e852367428", - "sha256:f2362f3cb0f3172c42938946dbc5b7843c2a28aec307c49100c8b38764eb6927", - "sha256:f328adcfebed9f11301eaedfa48e15bdece9b519fb27e6a8c01aa52a17ec31b3", - "sha256:f8afcf15cc511ada719a88e013cec87c11aff7b91f019295eb4530f96fe5ef2f", - "sha256:fb1bbeac803adea29cedd70781399c99138358c26d05fcbd23c13016b7f5ec65" - ], - "version": "==1.4.3" - }, "typing-extensions": { "hashes": [ "sha256:0ac0f89795dd19de6b97debb0c6af1c70987fd80a2d62d1958f7e56fcc31b497", diff --git a/README.rst b/README.rst index d0a3f41..8d5773e 100644 --- a/README.rst +++ b/README.rst @@ -62,19 +62,19 @@ Additionally, users that delegate access to their data (like Alice, in this exam .. code-block:: python - from umbral import SecretKey, PublicKey, Signer + from umbral import SecretKey, Signer # Generate Umbral keys for Alice. alices_secret_key = SecretKey.random() - alices_public_key = PublicKey.from_secret_key(alices_secret_key) + alices_public_key = alices_secret_key.public_key() alices_signing_key = SecretKey.random() alices_signer = Signer(alices_signing_key) - alices_verifying_key = PublicKey.from_secret_key(alices_signing_key) + alices_verifying_key = alices_signing_key.public_key() # Generate Umbral keys for Bob. bobs_secret_key = SecretKey.random() - bobs_public_key = PublicKey.from_secret_key(bobs_secret_key) + bobs_public_key = bobs_secret_key.public_key() **Encryption** diff --git a/docs/examples/umbral_simple_api.py b/docs/examples/umbral_simple_api.py index 0b9a3b7..076189a 100644 --- a/docs/examples/umbral_simple_api.py +++ b/docs/examples/umbral_simple_api.py @@ -1,6 +1,6 @@ import random from umbral import ( - SecretKey, PublicKey, Signer, CapsuleFrag, + SecretKey, Signer, CapsuleFrag, encrypt, generate_kfrags, reencrypt, decrypt_original, decrypt_reencrypted) # Generate an Umbral key pair @@ -9,10 +9,10 @@ from umbral import ( # A delegating key pair and a Signing key pair. alices_secret_key = SecretKey.random() -alices_public_key = PublicKey.from_secret_key(alices_secret_key) +alices_public_key = alices_secret_key.public_key() alices_signing_key = SecretKey.random() -alices_verifying_key = PublicKey.from_secret_key(alices_signing_key) +alices_verifying_key = alices_signing_key.public_key() alices_signer = Signer(alices_signing_key) # Encrypt some data for Alice @@ -38,7 +38,7 @@ print(cleartext) # ----------- bobs_secret_key = SecretKey.random() -bobs_public_key = PublicKey.from_secret_key(bobs_secret_key) +bobs_public_key = bobs_secret_key.public_key() # Bob receives a capsule through a side channel (s3, ipfs, Google cloud, etc) bob_capsule = capsule diff --git a/docs/notebooks/pyUmbral Simple API.ipynb b/docs/notebooks/pyUmbral Simple API.ipynb index dae16d6..7bc32b5 100644 --- a/docs/notebooks/pyUmbral Simple API.ipynb +++ b/docs/notebooks/pyUmbral Simple API.ipynb @@ -22,15 +22,15 @@ "metadata": {}, "outputs": [], "source": [ - "from umbral import SecretKey, PublicKey, Signer\n", + "from umbral import SecretKey, Signer\n", "\n", "\n", "# Alice's Keys\n", "alices_private_key = SecretKey.random()\n", - "alices_public_key = PublicKey.from_secret_key(alices_private_key)\n", + "alices_public_key = alices_private_key.public_key()\n", "\n", "alices_signing_key = SecretKey.random()\n", - "alices_verifying_key = PublicKey.from_secret_key(alices_signing_key)\n", + "alices_verifying_key = alices_signing_key.public_key()\n", "alices_signer = Signer(alices_signing_key)" ] }, @@ -115,7 +115,7 @@ "outputs": [], "source": [ "bobs_private_key = SecretKey.random()\n", - "bobs_public_key = PublicKey.from_secret_key(bobs_private_key)\n", + "bobs_public_key = bobs_private_key.public_key()\n", "\n", "bob_capsule = capsule" ] diff --git a/docs/source/using_pyumbral.rst b/docs/source/using_pyumbral.rst index bc2aac1..b554929 100644 --- a/docs/source/using_pyumbral.rst +++ b/docs/source/using_pyumbral.rst @@ -43,20 +43,20 @@ A delegating key pair and a signing key pair. .. doctest:: capsule_story - >>> from umbral import SecretKey, PublicKey, Signer + >>> from umbral import SecretKey, Signer >>> alices_secret_key = SecretKey.random() - >>> alices_public_key = PublicKey.from_secret_key(alices_secret_key) + >>> alices_public_key = alices_secret_key.public_key() >>> alices_signing_key = SecretKey.random() - >>> alices_verifying_key = PublicKey.from_secret_key(alices_signing_key) + >>> alices_verifying_key = alices_signing_key.public_key() >>> alices_signer = Signer(alices_signing_key) Encrypt with a public key -------------------------- Now let's encrypt data with Alice's public key. -Invocation of :py:func:`encrypt` returns both a ``capsule`` and a ``ciphertext``. +Invocation of :py:func:`umbral.encrypt` returns both a ``capsule`` and a ``ciphertext``. Note that anyone with Alice's public key can perform this operation. @@ -87,7 +87,7 @@ Bob Exists .. doctest:: capsule_story >>> bobs_secret_key = SecretKey.random() - >>> bobs_public_key = PublicKey.from_secret_key(bobs_secret_key) + >>> bobs_public_key = bobs_secret_key.public_key() Alice grants access to Bob by generating kfrags diff --git a/setup.py b/setup.py index 7b6ed7f..04437a2 100644 --- a/setup.py +++ b/setup.py @@ -58,8 +58,8 @@ class VerifyVersionCommand(install): INSTALL_REQUIRES = [ 'setuptools', - 'cryptography>=2.3', - 'pynacl', + 'cryptography~=3.0', + 'pynacl~=1.0', ] DEV_INSTALL_REQUIRES = [ @@ -75,7 +75,11 @@ DEV_INSTALL_REQUIRES = [ EXTRAS_REQUIRE = { 'testing': DEV_INSTALL_REQUIRES, - 'docs': ['sphinx', 'sphinx-autobuild', 'sphinx_rtd_theme'], + 'docs': [ + 'sphinx~=4.0', + 'sphinx-autobuild', + 'sphinx_rtd_theme', + ], 'benchmarks': ['pytest-benchmark'], } diff --git a/tests/conftest.py b/tests/conftest.py index 9e79727..bf0a688 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,6 @@ import pytest -from umbral import SecretKey, PublicKey, Signer, generate_kfrags, encrypt +from umbral import SecretKey, Signer, generate_kfrags, encrypt @pytest.fixture @@ -13,7 +13,7 @@ def alices_keys(): @pytest.fixture def bobs_keys(): sk = SecretKey.random() - pk = PublicKey.from_secret_key(sk) + pk = sk.public_key() return sk, pk @@ -22,8 +22,8 @@ def verification_keys(alices_keys, bobs_keys): delegating_sk, signing_sk = alices_keys _receiving_sk, receiving_pk = bobs_keys - verifying_pk = PublicKey.from_secret_key(signing_sk) - delegating_pk = PublicKey.from_secret_key(delegating_sk) + verifying_pk = signing_sk.public_key() + delegating_pk = delegating_sk.public_key() return verifying_pk, delegating_pk, receiving_pk @@ -52,7 +52,7 @@ def message(): @pytest.fixture def capsule_and_ciphertext(alices_keys, message): delegating_sk, _signing_sk = alices_keys - capsule, ciphertext = encrypt(PublicKey.from_secret_key(delegating_sk), message) + capsule, ciphertext = encrypt(delegating_sk.public_key(), message) return capsule, ciphertext diff --git a/tests/metrics/reencryption_benchmark.py b/tests/metrics/reencryption_benchmark.py index 7e71eb0..ed0b3e1 100644 --- a/tests/metrics/reencryption_benchmark.py +++ b/tests/metrics/reencryption_benchmark.py @@ -38,13 +38,13 @@ FRAG_VALUES = ((1, 1), # | def __standard_encryption_api(umbral) -> tuple: delegating_sk = umbral.SecretKey.random() - delegating_pk = umbral.PublicKey.from_secret_key(delegating_sk) + delegating_pk = delegating_sk.public_key() signing_sk = umbral.SecretKey.random() signer = umbral.Signer(signing_sk) receiving_sk = umbral.SecretKey.random() - receiving_pk = umbral.PublicKey.from_secret_key(receiving_sk) + receiving_pk = receiving_sk.public_key() plain_data = os.urandom(32) capsule, ciphertext = umbral.encrypt(delegating_pk, plain_data) diff --git a/tests/metrics/reencryption_firehose.py b/tests/metrics/reencryption_firehose.py index 029b760..0b766eb 100644 --- a/tests/metrics/reencryption_firehose.py +++ b/tests/metrics/reencryption_firehose.py @@ -14,13 +14,13 @@ REENCRYPTIONS = 1000 def __produce_kfrags_and_capsule(m: int, n: int) -> Tuple[List[umbral.KeyFrag], umbral.Capsule]: delegating_sk = umbral.SecretKey.random() - delegating_pk = umbral.PublicKey.from_secret_key(delegating_sk) + delegating_pk = delegating_sk.public_key() signing_sk = umbral.SecretKey.random() signer = umbral.Signer(signing_sk) receiving_sk = umbral.SecretKey.random() - receiving_pk = umbral.PublicKey.from_secret_key(receiving_sk) + receiving_pk = receiving_sk.public_key() plain_data = os.urandom(32) capsule, ciphertext = umbral.encrypt(delegating_pk, plain_data) diff --git a/tests/test_capsule.py b/tests/test_capsule.py index 367fb15..5ca25c8 100644 --- a/tests/test_capsule.py +++ b/tests/test_capsule.py @@ -3,7 +3,6 @@ import pytest from umbral import ( Capsule, SecretKey, - PublicKey, Signer, encrypt, decrypt_original, @@ -17,7 +16,7 @@ from umbral.curve_point import CurvePoint def test_capsule_serialization(alices_keys): delegating_sk, _signing_sk = alices_keys - delegating_pk = PublicKey.from_secret_key(delegating_sk) + delegating_pk = delegating_sk.public_key() capsule, _key = Capsule.from_public_key(delegating_pk) new_capsule = Capsule.from_bytes(bytes(capsule)) @@ -35,7 +34,7 @@ def test_capsule_serialization(alices_keys): def test_capsule_is_hashable(alices_keys): delegating_sk, _signing_sk = alices_keys - delegating_pk = PublicKey.from_secret_key(delegating_sk) + delegating_pk = delegating_sk.public_key() capsule1, key1 = Capsule.from_public_key(delegating_pk) capsule2, key2 = Capsule.from_public_key(delegating_pk) @@ -51,7 +50,7 @@ def test_capsule_is_hashable(alices_keys): def test_open_original(alices_keys): delegating_sk, _signing_sk = alices_keys - delegating_pk = PublicKey.from_secret_key(delegating_sk) + delegating_pk = delegating_sk.public_key() capsule, key = Capsule.from_public_key(delegating_pk) key_back = capsule.open_original(delegating_sk) @@ -67,7 +66,7 @@ def test_open_reencrypted(alices_keys, bobs_keys): receiving_sk, receiving_pk = bobs_keys signer = Signer(signing_sk) - delegating_pk = PublicKey.from_secret_key(delegating_sk) + delegating_pk = delegating_sk.public_key() capsule, key = Capsule.from_public_key(delegating_pk) kfrags = generate_kfrags(delegating_sk=delegating_sk, diff --git a/tests/test_capsule_frag.py b/tests/test_capsule_frag.py index 1998a5e..b6669b5 100644 --- a/tests/test_capsule_frag.py +++ b/tests/test_capsule_frag.py @@ -1,6 +1,6 @@ import pytest -from umbral import encrypt, reencrypt, CapsuleFrag, PublicKey, Capsule, VerificationError +from umbral import encrypt, reencrypt, CapsuleFrag, Capsule, VerificationError from umbral.curve_point import CurvePoint diff --git a/tests/test_compatibility.py b/tests/test_compatibility.py index 551d11c..7c7d3e3 100644 --- a/tests/test_compatibility.py +++ b/tests/test_compatibility.py @@ -21,13 +21,13 @@ def pytest_generate_tests(metafunc): def _create_keypair(umbral): sk = umbral.SecretKey.random() - pk = umbral.PublicKey.from_secret_key(sk) + pk = sk.public_key() return bytes(sk), bytes(pk) def _restore_keys(umbral, sk_bytes, pk_bytes): sk = umbral.SecretKey.from_bytes(sk_bytes) - pk_from_sk = umbral.PublicKey.from_secret_key(sk) + pk_from_sk = sk.public_key() pk_from_bytes = umbral.PublicKey.from_bytes(pk_bytes) assert pk_from_sk == pk_from_bytes @@ -155,7 +155,7 @@ def _decrypt_reencrypted(umbral, receiving_sk_bytes, delegating_pk_bytes, verify capsule_bytes, cfrags_bytes, ciphertext): receiving_sk = umbral.SecretKey.from_bytes(receiving_sk_bytes) - receiving_pk = umbral.PublicKey.from_secret_key(receiving_sk) + receiving_pk = receiving_sk.public_key() delegating_pk = umbral.PublicKey.from_bytes(delegating_pk_bytes) verifying_pk = umbral.PublicKey.from_bytes(verifying_pk_bytes) @@ -216,7 +216,7 @@ def test_reencrypt(implementations): def _sign_message(umbral, sk_bytes, message): sk = umbral.SecretKey.from_bytes(sk_bytes) signer = umbral.Signer(sk) - assert signer.verifying_key() == umbral.PublicKey.from_secret_key(sk) + assert signer.verifying_key() == sk.public_key() return bytes(signer.sign(message)) diff --git a/tests/test_key_frag.py b/tests/test_key_frag.py index 4978271..10d1b92 100644 --- a/tests/test_key_frag.py +++ b/tests/test_key_frag.py @@ -1,6 +1,6 @@ import pytest -from umbral import KeyFrag, PublicKey, Signer, VerificationError +from umbral import KeyFrag, Signer, VerificationError from umbral.key_frag import KeyFragID, KeyFragBase, VerifiedKeyFrag from umbral.curve_scalar import CurveScalar @@ -56,8 +56,8 @@ def test_kfrag_signing(alices_keys, bobs_keys, sign_delegating_key, sign_receivi delegating_sk, signing_sk = alices_keys _receiving_sk, receiving_pk = bobs_keys - verifying_pk = PublicKey.from_secret_key(signing_sk) - delegating_pk = PublicKey.from_secret_key(delegating_sk) + verifying_pk = signing_sk.public_key() + delegating_pk = delegating_sk.public_key() base = KeyFragBase(delegating_sk=delegating_sk, receiving_pk=receiving_pk, diff --git a/tests/test_keys.py b/tests/test_keys.py index 966935e..9411f71 100644 --- a/tests/test_keys.py +++ b/tests/test_keys.py @@ -10,10 +10,10 @@ def test_gen_key(): sk = SecretKey.random() assert type(sk) == SecretKey - pk = PublicKey.from_secret_key(sk) + pk = sk.public_key() assert type(pk) == PublicKey - pk2 = PublicKey.from_secret_key(sk) + pk2 = sk.public_key() assert pk == pk2 @@ -30,19 +30,19 @@ def test_derive_key_from_label(): sk1 = factory.secret_key_by_label(label) assert type(sk1) == SecretKey - pk1 = PublicKey.from_secret_key(sk1) + pk1 = sk1.public_key() assert type(pk1) == PublicKey # Check that key derivation is reproducible sk2 = factory.secret_key_by_label(label) - pk2 = PublicKey.from_secret_key(sk2) + pk2 = sk2.public_key() assert sk1 == sk2 assert pk1 == pk2 # Different labels on the same master secret create different keys label = b"my_tax_information" sk3 = factory.secret_key_by_label(label) - pk3 = PublicKey.from_secret_key(sk3) + pk3 = sk3.public_key() assert sk1 != sk3 @@ -81,7 +81,7 @@ def test_secret_key_factory_hash(): def test_public_key_serialization(): sk = SecretKey.random() - pk = PublicKey.from_secret_key(sk) + pk = sk.public_key() encoded_key = bytes(pk) decoded_key = PublicKey.from_bytes(encoded_key) @@ -89,12 +89,12 @@ def test_public_key_serialization(): def test_public_key_point(): - pk = PublicKey.from_secret_key(SecretKey.random()) + pk = SecretKey.random().public_key() assert bytes(pk) == bytes(pk.point()) def test_public_key_str(): - pk = PublicKey.from_secret_key(SecretKey.random()) + pk = SecretKey.random().public_key() s = str(pk) assert 'PublicKey' in s @@ -113,10 +113,10 @@ def test_secret_key_factory_serialization(): def test_public_key_is_hashable(): sk = SecretKey.random() - pk = PublicKey.from_secret_key(sk) + pk = sk.public_key() sk2 = SecretKey.random() - pk2 = PublicKey.from_secret_key(sk2) + pk2 = sk2.public_key() assert hash(pk) != hash(pk2) pk3 = PublicKey.from_bytes(bytes(pk)) diff --git a/tests/test_pre.py b/tests/test_pre.py index ce90f34..9ffb7cc 100644 --- a/tests/test_pre.py +++ b/tests/test_pre.py @@ -2,7 +2,6 @@ import pytest from umbral import ( SecretKey, - PublicKey, Signer, KeyFrag, CapsuleFrag, @@ -16,7 +15,7 @@ from umbral import ( def test_public_key_encryption(alices_keys): delegating_sk, _ = alices_keys - delegating_pk = PublicKey.from_secret_key(delegating_sk) + delegating_pk = delegating_sk.public_key() plaintext = b'peace at dawn' capsule, ciphertext = encrypt(delegating_pk, plaintext) plaintext_decrypted = decrypt_original(delegating_sk, capsule, ciphertext) @@ -51,32 +50,32 @@ def test_simple_api(num_kfrags, threshold): # Key Generation (Alice) delegating_sk = SecretKey.random() - delegating_pk = PublicKey.from_secret_key(delegating_sk) + delegating_pk = delegating_sk.public_key() signing_sk = SecretKey.random() signer = Signer(signing_sk) - verifying_pk = PublicKey.from_secret_key(signing_sk) + verifying_pk = signing_sk.public_key() - # Key Generation (Bob) + # Key Generation (Bob) receiving_sk = SecretKey.random() - receiving_pk = PublicKey.from_secret_key(receiving_sk) + receiving_pk = receiving_sk.public_key() - # Encryption by an unnamed data source + # Encryption by an unnamed data source plaintext = b'peace at dawn' capsule, ciphertext = encrypt(delegating_pk, plaintext) - # Decryption by Alice + # Decryption by Alice plaintext_decrypted = decrypt_original(delegating_sk, capsule, ciphertext) assert plaintext_decrypted == plaintext - # Split Re-Encryption Key Generation (aka Delegation) + # Split Re-Encryption Key Generation (aka Delegation) kfrags = generate_kfrags(delegating_sk=delegating_sk, receiving_pk=receiving_pk, signer=signer, threshold=threshold, num_kfrags=num_kfrags) - # Bob requests re-encryption to some set of M ursulas + # Bob requests re-encryption to some set of M ursulas cfrags = [reencrypt(capsule, kfrag) for kfrag in kfrags] # Decryption by Bob diff --git a/tests/test_signing.py b/tests/test_signing.py index 0fc1244..c98cfff 100644 --- a/tests/test_signing.py +++ b/tests/test_signing.py @@ -8,7 +8,7 @@ from umbral.hashing import Hash @pytest.mark.parametrize('execution_number', range(20)) # Run this test 20 times. def test_sign_and_verify(execution_number): sk = SecretKey.random() - pk = PublicKey.from_secret_key(sk) + pk = sk.public_key() signer = Signer(sk) message = b"peace at dawn" + str(execution_number).encode() @@ -20,7 +20,7 @@ def test_sign_and_verify(execution_number): @pytest.mark.parametrize('execution_number', range(20)) # Run this test 20 times. def test_sign_serialize_and_verify(execution_number): sk = SecretKey.random() - pk = PublicKey.from_secret_key(sk) + pk = sk.public_key() signer = Signer(sk) message = b"peace at dawn" + str(execution_number).encode() @@ -35,7 +35,7 @@ def test_sign_serialize_and_verify(execution_number): def test_verification_fail(): sk = SecretKey.random() - pk = PublicKey.from_secret_key(sk) + pk = sk.public_key() signer = Signer(sk) message = b"peace at dawn" @@ -55,7 +55,7 @@ def test_verification_fail(): def test_signature_str(): sk = SecretKey.random() - pk = PublicKey.from_secret_key(sk) + pk = sk.public_key() signer = Signer(sk) signature = signer.sign(b'peace at dawn') s = str(signature) @@ -64,7 +64,7 @@ def test_signature_str(): def test_signature_is_hashable(): sk = SecretKey.random() - pk = PublicKey.from_secret_key(sk) + pk = sk.public_key() signer = Signer(sk) message = b'peace at dawn' @@ -106,6 +106,6 @@ def test_signer_bytes(): def test_signer_pubkey(): sk = SecretKey.random() - pk = PublicKey.from_secret_key(sk) + pk = sk.public_key() signer = Signer(sk) assert signer.verifying_key() == pk diff --git a/umbral/capsule.py b/umbral/capsule.py index f6275c8..99eaa83 100644 --- a/umbral/capsule.py +++ b/umbral/capsule.py @@ -82,7 +82,7 @@ class Capsule(Serializable, Deserializable): if not all(cfrag.precursor == precursor for cfrag in cfrags[1:]): raise ValueError("CapsuleFrags are not pairwise consistent") - pub_key = PublicKey.from_secret_key(receiving_sk).point() + pub_key = receiving_sk.public_key().point() dh_point = precursor * receiving_sk.secret_scalar() # Combination of CFrags via Shamir's Secret Sharing reconstruction diff --git a/umbral/key_frag.py b/umbral/key_frag.py index da64345..0c0f751 100644 --- a/umbral/key_frag.py +++ b/umbral/key_frag.py @@ -307,7 +307,7 @@ class KeyFragBase: g = CurvePoint.generator() - delegating_pk = PublicKey.from_secret_key(delegating_sk) + delegating_pk = delegating_sk.public_key() receiving_pk_point = receiving_pk.point() diff --git a/umbral/keys.py b/umbral/keys.py index b628c94..17645b3 100644 --- a/umbral/keys.py +++ b/umbral/keys.py @@ -13,15 +13,12 @@ class SecretKey(Serializable, Deserializable): Umbral secret (private) key. """ - __SERIALIZATION_INFO = b"SECRET_KEY" - def __init__(self, scalar_key: CurveScalar): self._scalar_key = scalar_key - # Cached public key. Access it via `PublicKey.from_secret_key()` - - # it may be removed later. - # We are assuming here that there will be on average more calls to - # `PublicKey.from_secret_key()` than secret key instantiations. - self._public_key_point = CurvePoint.generator() * self._scalar_key + # Precached public key. + # We are assuming here that there will be on average more + # derivations of a public key from a secret key than secret key instantiations. + self._public_key = PublicKey(CurvePoint.generator() * self._scalar_key) @classmethod def random(cls) -> 'SecretKey': @@ -30,6 +27,12 @@ class SecretKey(Serializable, Deserializable): """ return cls(CurveScalar.random_nonzero()) + def public_key(self) -> 'PublicKey': + """ + Returns the associated public key. + """ + return self._public_key + def __eq__(self, other): return self._scalar_key == other._scalar_key @@ -39,7 +42,7 @@ class SecretKey(Serializable, Deserializable): def __hash__(self): raise RuntimeError("Hashing secret objects is not secure") - def secret_scalar(self): + def secret_scalar(self) -> CurveScalar: return self._scalar_key @classmethod @@ -57,21 +60,16 @@ class SecretKey(Serializable, Deserializable): class PublicKey(Serializable, Deserializable): """ Umbral public key. + + Created using :py:meth:`SecretKey.public_key`. """ def __init__(self, point_key: CurvePoint): self._point_key = point_key - def point(self): + def point(self) -> CurvePoint: return self._point_key - @classmethod - def from_secret_key(cls, sk: SecretKey) -> 'PublicKey': - """ - Creates the public key corresponding to the given secret key. - """ - return cls(sk._public_key_point) - @classmethod def serialized_size(cls): return CurvePoint.serialized_size() diff --git a/umbral/serializable.py b/umbral/serializable.py index b993f80..f253d4f 100644 --- a/umbral/serializable.py +++ b/umbral/serializable.py @@ -22,10 +22,10 @@ class Deserializable(HasSerializedSize): A mixin for composable deserialization. """ - _T = TypeVar('_T', bound='Deserializable') + Self = TypeVar('Self', bound='Deserializable') @classmethod - def from_bytes(cls: Type[_T], data: bytes) -> _T: + def from_bytes(cls: Type[Self], data: bytes) -> Self: """ Restores the object from serialized bytes. """ @@ -64,7 +64,7 @@ class Deserializable(HasSerializedSize): @classmethod @abstractmethod - def _from_exact_bytes(cls: Type[_T], data: bytes) -> _T: + def _from_exact_bytes(cls: Type[Self], data: bytes) -> Self: """ Deserializes the object from a bytestring of exactly the expected length (defined by ``serialized_size()``). diff --git a/umbral/signing.py b/umbral/signing.py index a119568..18cd34d 100644 --- a/umbral/signing.py +++ b/umbral/signing.py @@ -22,7 +22,7 @@ class Signer: def __init__(self, secret_key: SecretKey): self.__secret_key = secret_key - def sign_digest(self, digest: 'Hash') -> 'Signature': + def sign_digest(self, digest: Hash) -> 'Signature': secret_bn = self.__secret_key.secret_scalar()._backend_bignum r_int, s_int = openssl.ecdsa_sign(curve=CURVE, @@ -54,7 +54,7 @@ class Signer: """ Returns the public verification key corresponding to the secret key used for signing. """ - return PublicKey.from_secret_key(self.__secret_key) + return self.__secret_key.public_key() def __str__(self): return f"{self.__class__.__name__}:..." @@ -75,7 +75,7 @@ class Signature(Serializable, Deserializable): self.r = r self.s = s - def verify_digest(self, verifying_key: 'PublicKey', digest: 'Hash') -> bool: + def verify_digest(self, verifying_key: PublicKey, digest: Hash) -> bool: return openssl.ecdsa_verify(curve=CURVE, sig_r=int(self.r), sig_s=int(self.s), diff --git a/vectors/generate_test_vectors.py b/vectors/generate_test_vectors.py index d53f07e..dd67fd5 100644 --- a/vectors/generate_test_vectors.py +++ b/vectors/generate_test_vectors.py @@ -2,7 +2,7 @@ import json import os from umbral import ( - SecretKey, PublicKey, Signer, KeyFrag, CapsuleFrag, + SecretKey, Signer, KeyFrag, CapsuleFrag, encrypt, generate_kfrags, reencrypt) from umbral.curve_scalar import CurveScalar from umbral.curve_point import CurvePoint @@ -44,9 +44,9 @@ delegating_sk = SecretKey.random() receiving_sk = SecretKey.random() signing_sk = SecretKey.random() -verifying_pk = PublicKey.from_secret_key(signing_sk) -delegating_pk = PublicKey.from_secret_key(delegating_sk) -receiving_pk = PublicKey.from_secret_key(receiving_sk) +verifying_pk = signing_sk.public_key() +delegating_pk = delegating_sk.public_key() +receiving_pk = receiving_sk.public_key() kfrags = generate_kfrags(delegating_sk=delegating_sk, receiving_pk=receiving_pk,