diff --git a/tests/test_simple_api.py b/tests/test_simple_api.py index 0af43c12..f817e19a 100644 --- a/tests/test_simple_api.py +++ b/tests/test_simple_api.py @@ -2,10 +2,12 @@ from cryptography.exceptions import InvalidTag from cryptography.hazmat.primitives.asymmetric import ec -from umbral import pre, keys +from umbral import pre +from umbral.fragments import KFrag, CapsuleFrag from umbral.config import default_curve from umbral.params import UmbralParameters from umbral.signing import Signer +from umbral.keys import UmbralPrivateKey, UmbralPublicKey from .conftest import parameters secp_curves = [ @@ -20,14 +22,14 @@ def test_simple_api(N, M, curve=default_curve()): params = UmbralParameters(curve=curve) - delegating_privkey = keys.UmbralPrivateKey.gen_key(params=params) + delegating_privkey = UmbralPrivateKey.gen_key(params=params) delegating_pubkey = delegating_privkey.get_pubkey() - signing_privkey = keys.UmbralPrivateKey.gen_key(params=params) + signing_privkey = UmbralPrivateKey.gen_key(params=params) signing_pubkey = signing_privkey.get_pubkey() signer = Signer(signing_privkey) - receiving_privkey = keys.UmbralPrivateKey.gen_key(params=params) + receiving_privkey = UmbralPrivateKey.gen_key(params=params) receiving_pubkey = receiving_privkey.get_pubkey() plain_data = b'peace at dawn' @@ -57,6 +59,122 @@ def test_simple_api_on_multiple_curves(N, M, curve): test_simple_api(N, M, curve) +@pytest.mark.parametrize("N, M", parameters) +def test_lifecycle_with_serialization(N, M, curve=default_curve()): + """ + This test is a variant of test_simple_api, but with intermediate + serialization/deserialization steps, modeling how pyUmbral artifacts + (such as keys, ciphertexts, etc) will actually be used. + These intermediate steps are in between the different 'usage domains' + in NuCypher, namely, key generation, delegation, encryption, decryption by + Alice, re-encryption by Ursula, and decryption by Bob. + + Manually injects UmbralParameters for multi-curve testing. + """ + + # Convenience method to avoid replicating key generation code + def new_keypair_bytes(): + privkey = UmbralPrivateKey.gen_key(params=params) + return bytes(privkey), bytes(privkey.get_pubkey()) + + ## SETUP + params = UmbralParameters(curve=curve) + + delegating_privkey_bytes, delegating_pubkey_bytes = new_keypair_bytes() + signing_privkey_bytes, signing_pubkey_bytes = new_keypair_bytes() + receiving_privkey_bytes, receiving_pubkey_bytes = new_keypair_bytes() + + ## DELEGATION DOMAIN: + ## Alice delegates decryption rights to some Bob by generating a set of + ## KFrags, using her delegating private key and Bob's receiving public key + + delegating_privkey = UmbralPrivateKey.from_bytes(delegating_privkey_bytes, params) + signing_privkey = UmbralPrivateKey.from_bytes(signing_privkey_bytes, params) + receiving_pubkey = UmbralPublicKey.from_bytes(receiving_pubkey_bytes, params) + + signer = Signer(signing_privkey) + kfrags = pre.split_rekey(delegating_privkey, signer, receiving_pubkey, M, N) + kfrags_bytes = tuple(map(bytes, kfrags)) + + del kfrags + del signer + del delegating_privkey + del signing_privkey + del receiving_pubkey + del params + + ## ENCRYPTION DOMAIN ## + + params = UmbralParameters(curve=curve) + + delegating_pubkey = UmbralPublicKey.from_bytes(delegating_pubkey_bytes, params) + + plain_data = b'peace at dawn' + ciphertext, capsule = pre.encrypt(delegating_pubkey, plain_data) + capsule_bytes = bytes(capsule) + + del capsule + del delegating_pubkey + del params + + ## DECRYPTION BY ALICE ## + + params = UmbralParameters(curve=curve) + + delegating_privkey = UmbralPrivateKey.from_bytes(delegating_privkey_bytes, params) + capsule = pre.Capsule.from_bytes(capsule_bytes, params) + cleartext = pre.decrypt(ciphertext, capsule, delegating_privkey) + assert cleartext == plain_data + + del delegating_privkey + del capsule + del params + + ## RE-ENCRYPTION DOMAIN (i.e., Ursula's side) + + cfrags_bytes = list() + for kfrag_bytes in kfrags_bytes: + params = UmbralParameters(curve=curve) + capsule = pre.Capsule.from_bytes(capsule_bytes, params) + # TODO: use params instead of curve? + kfrag = KFrag.from_bytes(kfrag_bytes, params.curve) + + cfrag_bytes = bytes(pre.reencrypt(kfrag, capsule)) + cfrags_bytes.append(cfrag_bytes) + + del capsule + del kfrag + del params + + ## DECRYPTION DOMAIN (i.e., Bob's side) + params = UmbralParameters(curve=curve) + + capsule = pre.Capsule.from_bytes(capsule_bytes, params) + delegating_pubkey = UmbralPublicKey.from_bytes(delegating_pubkey_bytes, params) + signing_pubkey = UmbralPublicKey.from_bytes(signing_pubkey_bytes, params) + receiving_privkey = UmbralPrivateKey.from_bytes(receiving_privkey_bytes, params) + receiving_pubkey = receiving_privkey.get_pubkey() + + capsule.set_correctness_keys(delegating=delegating_pubkey, + receiving=receiving_pubkey, + verifying=signing_pubkey) + + for cfrag_bytes in cfrags_bytes: + # TODO: use params instead of curve? + cfrag = CapsuleFrag.from_bytes(cfrag_bytes, params.curve) + capsule.attach_cfrag(cfrag) + + reenc_cleartext = pre.decrypt(ciphertext, capsule, receiving_privkey, + delegating_pubkey, signing_pubkey) + assert reenc_cleartext == plain_data + +@pytest.mark.skip(reason="several bugs with multi-curve support") +@pytest.mark.parametrize("curve", secp_curves) +@pytest.mark.parametrize("N, M", parameters) +def test_lifecycle_with_serialization_on_multiple_curves(N, M, curve): + test_lifecycle_with_serialization(N, M, curve) + + def test_public_key_encryption(alices_keys): delegating_privkey, _ = alices_keys plain_data = b'peace at dawn'