mirror of https://github.com/nucypher/pyUmbral.git
Add some API docs
parent
bcb0071f9e
commit
0f82580c7e
|
@ -0,0 +1,57 @@
|
|||
Public API
|
||||
==========
|
||||
|
||||
.. automodule:: umbral
|
||||
|
||||
Keys
|
||||
----
|
||||
|
||||
.. autoclass:: SecretKey()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: PublicKey()
|
||||
:members:
|
||||
:special-members: __eq__, __hash__
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: SecretKeyFactory()
|
||||
:members:
|
||||
:show-inheritance:
|
||||
|
||||
Intermediate objects
|
||||
--------------------
|
||||
|
||||
.. autoclass:: Capsule()
|
||||
:special-members: __eq__, __hash__
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: KeyFrag()
|
||||
:members: verify
|
||||
:special-members: __eq__, __hash__
|
||||
:show-inheritance:
|
||||
|
||||
.. autoclass:: CapsuleFrag()
|
||||
:members: verify
|
||||
:special-members: __eq__, __hash__
|
||||
:show-inheritance:
|
||||
|
||||
Encryption, re-encryption and decryption
|
||||
----------------------------------------
|
||||
|
||||
.. autofunction:: encrypt
|
||||
|
||||
.. autofunction:: decrypt_original
|
||||
|
||||
.. autofunction:: generate_kfrags
|
||||
|
||||
.. autofunction:: reencrypt
|
||||
|
||||
.. autofunction:: decrypt_reencrypted
|
||||
|
||||
Utilities
|
||||
---------
|
||||
|
||||
.. autoclass:: umbral.serializable.Serializable
|
||||
:members: from_bytes
|
||||
:special-members: __bytes__
|
|
@ -59,6 +59,7 @@ a proxy re-encryption network to empower privacy in decentralized systems.
|
|||
|
||||
installation
|
||||
using_pyumbral
|
||||
api
|
||||
|
||||
|
||||
Academic Whitepaper
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
|
||||
Installing pyUmbral
|
||||
====================
|
||||
v0.1.3-alpha.2
|
||||
|
||||
|
||||
Using pip
|
||||
-------------------------
|
||||
|
|
|
@ -20,6 +20,9 @@ def lambda_coeff(xs: Sequence[CurveScalar], i: int) -> CurveScalar:
|
|||
|
||||
|
||||
class Capsule(Serializable):
|
||||
"""
|
||||
Encapsulated symmetric key.
|
||||
"""
|
||||
|
||||
class NotValid(ValueError):
|
||||
"""
|
||||
|
|
|
@ -95,6 +95,9 @@ class CapsuleFragProof(Serializable):
|
|||
|
||||
|
||||
class CapsuleFrag(Serializable):
|
||||
"""
|
||||
Re-encrypted fragment of :py:class:`Capsule`.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
point_e1: CurvePoint,
|
||||
|
@ -160,6 +163,11 @@ class CapsuleFrag(Serializable):
|
|||
signing_pk: PublicKey,
|
||||
metadata: Optional[bytes] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
Verifies the validity of this fragment.
|
||||
|
||||
``metadata`` should coincide with the one given to :py:func:`reencrypt`.
|
||||
"""
|
||||
|
||||
params = PARAMETERS
|
||||
|
||||
|
|
|
@ -126,6 +126,9 @@ def poly_eval(coeffs: List[CurveScalar], x: CurveScalar) -> CurveScalar:
|
|||
|
||||
|
||||
class KeyFrag(Serializable):
|
||||
"""
|
||||
A signed fragment of the delegating key.
|
||||
"""
|
||||
|
||||
def __init__(self,
|
||||
id_: KeyFragID,
|
||||
|
@ -195,6 +198,12 @@ class KeyFrag(Serializable):
|
|||
delegating_pk: Optional[PublicKey] = None,
|
||||
receiving_pk: Optional[PublicKey] = None,
|
||||
) -> bool:
|
||||
"""
|
||||
Verifies the validity of this fragment.
|
||||
|
||||
If the delegating and/or receiving key were not signed in :py:func:`generate_kfrags`,
|
||||
but are given to this function, they are ignored.
|
||||
"""
|
||||
|
||||
u = PARAMETERS.u
|
||||
|
||||
|
@ -280,6 +289,12 @@ def generate_kfrags(delegating_sk: SecretKey,
|
|||
sign_delegating_key: bool = True,
|
||||
sign_receiving_key: bool = True,
|
||||
) -> List[KeyFrag]:
|
||||
"""
|
||||
Generates ``num_kfrags`` key fragments to pass to proxies for re-encryption.
|
||||
At least ``threshold`` of them will be needed for decryption.
|
||||
If ``sign_delegating_key`` or ``sign_receiving_key`` are ``True``,
|
||||
the corresponding keys will have to be provided to :py:meth:`KeyFrag.verify`.
|
||||
"""
|
||||
|
||||
base = KeyFragBase(delegating_sk, receiving_pk, signing_sk, threshold)
|
||||
|
||||
|
|
|
@ -17,6 +17,9 @@ if TYPE_CHECKING: # pragma: no cover
|
|||
|
||||
|
||||
class SecretKey(Serializable):
|
||||
"""
|
||||
Umbral secret (private) key.
|
||||
"""
|
||||
|
||||
__SERIALIZATION_INFO = b"SECRET_KEY"
|
||||
|
||||
|
@ -26,7 +29,7 @@ class SecretKey(Serializable):
|
|||
@classmethod
|
||||
def random(cls) -> 'SecretKey':
|
||||
"""
|
||||
Generates a secret key and returns it.
|
||||
Generates a random secret key and returns it.
|
||||
"""
|
||||
return cls(CurveScalar.random_nonzero())
|
||||
|
||||
|
@ -74,8 +77,6 @@ class SecretKey(Serializable):
|
|||
class Signature(Serializable):
|
||||
"""
|
||||
Wrapper for ECDSA signatures.
|
||||
We store signatures as r and s; this class allows interoperation
|
||||
between (r, s) and DER formatting.
|
||||
"""
|
||||
|
||||
def __init__(self, r: CurveScalar, s: CurveScalar):
|
||||
|
@ -114,6 +115,9 @@ class Signature(Serializable):
|
|||
|
||||
|
||||
class PublicKey(Serializable):
|
||||
"""
|
||||
Umbral public key.
|
||||
"""
|
||||
|
||||
def __init__(self, point_key: CurvePoint):
|
||||
self._point_key = point_key
|
||||
|
@ -123,6 +127,9 @@ class PublicKey(Serializable):
|
|||
|
||||
@classmethod
|
||||
def from_secret_key(cls, sk: SecretKey) -> 'PublicKey':
|
||||
"""
|
||||
Creates the public key corresponding to the given secret key.
|
||||
"""
|
||||
return cls(CurvePoint.generator() * sk.secret_scalar())
|
||||
|
||||
@classmethod
|
||||
|
@ -145,8 +152,9 @@ class PublicKey(Serializable):
|
|||
|
||||
class SecretKeyFactory(Serializable):
|
||||
"""
|
||||
This class handles keying material for Umbral, by allowing deterministic
|
||||
derivation of SecretKeys based on labels.
|
||||
This class handles keyring material for Umbral, by allowing deterministic
|
||||
derivation of :py:class:`SecretKey` objects based on labels.
|
||||
|
||||
Don't use this key material directly as a key.
|
||||
"""
|
||||
|
||||
|
@ -158,9 +166,15 @@ class SecretKeyFactory(Serializable):
|
|||
|
||||
@classmethod
|
||||
def random(cls) -> 'SecretKeyFactory':
|
||||
"""
|
||||
Creates a random factory.
|
||||
"""
|
||||
return cls(os.urandom(cls._KEY_SEED_SIZE))
|
||||
|
||||
def secret_key_by_label(self, label: bytes) -> SecretKey:
|
||||
"""
|
||||
Creates a :py:class:`SecretKey` from the given label.
|
||||
"""
|
||||
tag = b"KEY_DERIVATION/" + label
|
||||
key = kdf(self.__key_seed, self._DERIVED_KEY_SIZE, info=tag)
|
||||
|
||||
|
|
|
@ -9,8 +9,7 @@ from .key_frag import KeyFrag
|
|||
|
||||
def encrypt(pk: PublicKey, plaintext: bytes) -> Tuple[Capsule, bytes]:
|
||||
"""
|
||||
Performs an encryption using the UmbralDEM object and encapsulates a key
|
||||
for the sender using the public key provided.
|
||||
Generates and encapsulates a symmetric key and uses it to encrypt the given plaintext.
|
||||
|
||||
Returns the KEM Capsule and the ciphertext.
|
||||
"""
|
||||
|
@ -32,6 +31,13 @@ def decrypt_original(sk: SecretKey, capsule: Capsule, ciphertext: bytes) -> byte
|
|||
|
||||
|
||||
def reencrypt(capsule: Capsule, kfrag: KeyFrag, metadata: Optional[bytes] = None) -> CapsuleFrag:
|
||||
"""
|
||||
Creates a capsule fragment using the given key fragment.
|
||||
Capsule fragments can later be used to decrypt the ciphertext.
|
||||
|
||||
If `metadata` is provided, it will have to be used for verification in
|
||||
:py:meth:`CapsuleFrag.verify`.
|
||||
"""
|
||||
return CapsuleFrag.reencrypted(capsule, kfrag, metadata)
|
||||
|
||||
|
||||
|
@ -41,6 +47,9 @@ def decrypt_reencrypted(decrypting_sk: SecretKey,
|
|||
cfrags: Sequence[CapsuleFrag],
|
||||
ciphertext: bytes,
|
||||
) -> bytes:
|
||||
"""
|
||||
Decrypts the ciphertext using the original capsule and the reencrypted capsule fragments.
|
||||
"""
|
||||
|
||||
key_seed = capsule.open_reencrypted(decrypting_sk, delegating_pk, cfrags)
|
||||
# TODO: add salt and info here?
|
||||
|
|
|
@ -3,11 +3,17 @@ from typing import Tuple, Type, List, Any, TypeVar
|
|||
|
||||
|
||||
class Serializable(ABC):
|
||||
"""
|
||||
A mixin for composable serialization.
|
||||
"""
|
||||
|
||||
_T = TypeVar('_T', bound='Serializable')
|
||||
|
||||
@classmethod
|
||||
def from_bytes(cls: Type[_T], data: bytes) -> _T:
|
||||
"""
|
||||
Restores the object from serialized bytes.
|
||||
"""
|
||||
obj, remainder = cls.__take__(data)
|
||||
if len(remainder) != 0:
|
||||
raise ValueError(f"{len(remainder)} bytes remaining after deserializing {cls}")
|
||||
|
@ -15,12 +21,19 @@ class Serializable(ABC):
|
|||
|
||||
@classmethod
|
||||
def __take_bytes__(cls, data: bytes, size: int) -> Tuple[bytes, bytes]:
|
||||
"""
|
||||
Takes ``size`` bytes from the bytestring and returns them along with the remainder.
|
||||
"""
|
||||
if len(data) < size:
|
||||
raise ValueError(f"{cls} cannot take {size} bytes from a bytestring of size {len(data)}")
|
||||
return data[:size], data[size:]
|
||||
|
||||
@classmethod
|
||||
def __take_types__(cls, data: bytes, *types: Type) -> Tuple[List[Any], bytes]:
|
||||
"""
|
||||
Given a list of ``Serializable`` types, attempts to deserialize them from the bytestring
|
||||
one by one and returns the list of the resulting objects and the remaining bytestring.
|
||||
"""
|
||||
objs = []
|
||||
for tp in types:
|
||||
obj, data = tp.__take__(data)
|
||||
|
@ -30,10 +43,19 @@ class Serializable(ABC):
|
|||
@classmethod
|
||||
@abstractmethod
|
||||
def __take__(cls: Type[_T], data: bytes) -> Tuple[_T, bytes]:
|
||||
"""
|
||||
Take however much is necessary from ``data`` and instantiate the object,
|
||||
returning it and the remaining bytestring.
|
||||
|
||||
Must be implemented by the derived class.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
@abstractmethod
|
||||
def __bytes__(self):
|
||||
"""
|
||||
Serializes the object into bytes.
|
||||
"""
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue