Skip to content

Commit

Permalink
Merge pull request #47 from fjarri/interfacing-2
Browse files Browse the repository at this point in the history
Interfacing with Python, part 2
  • Loading branch information
fjarri authored May 19, 2021
2 parents d70d6ae + 81bc70f commit 3cba902
Show file tree
Hide file tree
Showing 23 changed files with 1,123 additions and 566 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/umbral-pre.yml
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ jobs:
strategy:
matrix:
rust:
- 1.46.0 # MSRV
- 1.51.0 # MSRV
- stable
target:
# TODO (#13): there are some build problems with `getrandom` package.
Expand All @@ -47,15 +47,15 @@ jobs:
include:
# 32-bit Linux
- target: i686-unknown-linux-gnu
rust: 1.46.0 # MSRV
rust: 1.51.0 # MSRV
deps: sudo apt install gcc-multilib
- target: i686-unknown-linux-gnu
rust: stable
deps: sudo apt install gcc-multilib

# 64-bit Linux
- target: x86_64-unknown-linux-gnu
rust: 1.46.0 # MSRV
rust: 1.51.0 # MSRV
- target: x86_64-unknown-linux-gnu
rust: stable

Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/workspace.yml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ jobs:
- uses: actions/checkout@v1
- uses: actions-rs/toolchain@v1
with:
toolchain: 1.46.0 # MSRV
toolchain: 1.51.0 # MSRV
components: clippy
override: true
profile: minimal
Expand Down
2 changes: 1 addition & 1 deletion umbral-pre-python/build-wheels.sh
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ export PATH="$HOME/.cargo/bin:$PATH"

cd /io/umbral-pre-python

for PYBIN in /opt/python/cp{35,36,37,38,39}*/bin; do
for PYBIN in /opt/python/cp{36,37,38,39}*/bin; do
"${PYBIN}/pip" install -U setuptools wheel setuptools-rust
"${PYBIN}/python" setup.py bdist_wheel
done
Expand Down
40 changes: 35 additions & 5 deletions umbral-pre-python/docs/index.rst
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,28 @@ API reference
Returns a hash of self.

.. py:class:: Signer(secret_key: SecretKey)
An object possessing the capability to create signatures.
For safety reasons serialization is prohibited.

.. py:method:: sign(message: bytes) -> Signature
Hashes and signs the message.

.. py:method:: verifying_key() -> PublicKey
Returns the public verification key corresponding to the secret key used for signing.

.. py:class:: Signature
Wrapper for ECDSA signatures.

.. py:method:: verify(verifying_key: PublicKey, message: bytes) -> bool
Returns ``True`` if the ``message`` was signed by someone possessing the secret counterpart
to ``verifying_key``.

.. py:class:: Capsule
An encapsulated symmetric key.
Expand All @@ -90,26 +112,26 @@ API reference
Decrypts ``ciphertext`` with the key used to encrypt it.

.. py:function:: generate_kfrags(delegating_sk: SecretKey, receiving_pk: PublicKey, signing_sk: SecretKey, threshold: int, num_kfrags: int, sign_delegating_key: bool, sign_receiving_key: bool) -> List[KeyFrag]
.. py:function:: generate_kfrags(delegating_sk: SecretKey, receiving_pk: PublicKey, signer: Signer, threshold: int, num_kfrags: int, sign_delegating_key: bool, sign_receiving_key: bool) -> List[VerifiedKeyFrag]
Generates ``num_kfrags`` key fragments that can be used to reencrypt the capsule for the holder of the secret key corresponding to ``receiving_pk``. ``threshold`` fragments will be enough for decryption.

If ``sign_delegating_key`` or ``sign_receiving_key`` are ``True``, include these keys in the signature allowing proxies to verify the fragments were created with a given key or for a given key, respectively.

.. py:function:: reencrypt(capsule: Capsule, kfrag: KeyFrag, metadata: Optional[bytes]) -> CapsuleFrag
.. py:function:: reencrypt(capsule: Capsule, kfrag: VerifiedKeyFrag, metadata: Optional[bytes]) -> VerifiedCapsuleFrag
Reencrypts a capsule using a key fragment.
May include optional ``metadata`` to sign.

.. py:function:: decrypt_reencrypted(decrypting_sk: SecretKey, delegating_pk: PublicKey, capsule: Capsule, cfrags: Sequence[CapsuleFrag], ciphertext: bytes) -> Optional[bytes]
.. py:function:: decrypt_reencrypted(decrypting_sk: SecretKey, delegating_pk: PublicKey, capsule: Capsule, cfrags: Sequence[VerifiedCapsuleFrag], ciphertext: bytes) -> Optional[bytes]
Attempts to decrypt the plaintext using the original capsule and reencrypted capsule fragments (at least ``threshold`` of them, see :py:func:`generate_kfrags`).

.. py:class:: KeyFrag
A fragment of a public key used by proxies during reencryption.

.. py:method:: verify(signing_pk: PublicKey, delegating_pk: Optional[PublicKey], receiving_pk: Optional[PublicKey]) -> bool:
.. py:method:: verify(verifying_pk: PublicKey, delegating_pk: Optional[PublicKey], receiving_pk: Optional[PublicKey]) -> VerifiedKeyFrag:
Verifies the integrity of the fragment using the signing key and, optionally, the delegating and the receiving keys (if they were included in the signature in :py:func:`generate_kfrags`).

Expand All @@ -125,11 +147,15 @@ API reference
Returns a hash of self.

.. py:class:: VerifiedKeyFrag
A verified key fragment, good for reencryption.

.. py:class:: CapsuleFrag
A reencrypted fragment of an encapsulated symmetric key.

.. py:method:: verify(capsule: Capsule, delegating_pk: PublicKey, receiving_pk: PublicKey, signing_pk: PublicKey, metadata: Optional[bytes]) -> bool
.. py:method:: verify(capsule: Capsule, verifying_pk: PublicKey, delegating_pk: PublicKey, receiving_pk: PublicKey, metadata: Optional[bytes]) -> VerifiedCapsuleFrag
Verifies the integrity of the fragment.

Expand All @@ -145,6 +171,10 @@ API reference
Returns a hash of self.

.. py:class:: VerifiedCapsuleFrag
A verified capsule fragment, good for decryption.


Indices and tables
==================
Expand Down
33 changes: 21 additions & 12 deletions umbral-pre-python/example/example.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
alice_sk = umbral_pre.SecretKey.random()
alice_pk = umbral_pre.PublicKey.from_secret_key(alice_sk)
signing_sk = umbral_pre.SecretKey.random()
signing_pk = umbral_pre.PublicKey.from_secret_key(signing_sk)
signer = umbral_pre.Signer(signing_sk)
verifying_pk = umbral_pre.PublicKey.from_secret_key(signing_sk)

# Key Generation (on Bob's side)
bob_sk = umbral_pre.SecretKey.random()
Expand Down Expand Up @@ -40,8 +41,8 @@
m = 2 # how many should be enough to decrypt

# Split Re-Encryption Key Generation (aka Delegation)
kfrags = umbral_pre.generate_kfrags(
alice_sk, bob_pk, signing_sk, m, n,
verified_kfrags = umbral_pre.generate_kfrags(
alice_sk, bob_pk, signer, m, n,
True, # add the delegating key (alice_pk) to the signature
True, # add the receiving key (bob_pk) to the signature
)
Expand All @@ -56,29 +57,37 @@
# Bob must gather at least `m` cfrags
# in order to open the capsule.

# Ursulas can optionally check that the received kfrags
# Simulate network transfer
kfrag0 = KeyFrag.from_bytes(bytes(verified_kfrags[0]))
kfrag1 = KeyFrag.from_bytes(bytes(verified_kfrags[1]))

# Ursulas must check that the received kfrags
# are valid and perform the reencryption.

# Ursula 0
metadata0 = b"metadata0"
assert kfrags[0].verify(signing_pk, alice_pk, bob_pk)
cfrag0 = umbral_pre.reencrypt(capsule, kfrags[0], metadata0)
verified_kfrag0 = kfrag0.verify(verifying_pk, alice_pk, bob_pk)
verified_cfrag0 = umbral_pre.reencrypt(capsule, kfrags[0], metadata0)

# Ursula 1
metadata1 = b"metadata1"
assert kfrags[1].verify(signing_pk, alice_pk, bob_pk)
cfrag1 = umbral_pre.reencrypt(capsule, kfrags[1], metadata1)
verified_kfrag1 = kfrag1.verify(verifying_pk, alice_pk, bob_pk)
verified_cfrag1 = umbral_pre.reencrypt(capsule, kfrags[1], metadata1)

# ...

# Simulate network transfer
cfrag0 = CapsuleFrag.from_bytes(bytes(verified_cfrag0))
cfrag1 = CapsuleFrag.from_bytes(bytes(verified_cfrag1))

# Finally, Bob opens the capsule by using at least `m` cfrags,
# and then decrypts the re-encrypted ciphertext.

# Bob can optionally check that cfrags are valid
assert cfrag0.verify(capsule, alice_pk, bob_pk, signing_pk, metadata0)
assert cfrag1.verify(capsule, alice_pk, bob_pk, signing_pk, metadata1)
# Bob must check that cfrags are valid
verified_cfrag0 = cfrag0.verify(capsule, verifying_pk, alice_pk, bob_pk, metadata0)
verified_cfrag1 = cfrag1.verify(capsule, verifying_pk, alice_pk, bob_pk, metadata1)

# Decryption by Bob
plaintext_bob = umbral_pre.decrypt_reencrypted(
bob_sk, alice_pk, capsule, [cfrag0, cfrag1], ciphertext)
bob_sk, alice_pk, capsule, [verified_cfrag0, verified_cfrag1], ciphertext)
assert plaintext_bob == plaintext
Loading

0 comments on commit 3cba902

Please sign in to comment.