Source code for umbral.keys

import os
from typing import Tuple

from .curve_scalar import CurveScalar
from .curve_point import CurvePoint
from .dem import kdf
from .hashing import Hash
from .serializable import Serializable, SerializableSecret, Deserializable


[docs]class SecretKey(SerializableSecret, Deserializable): """ Umbral secret (private) key. """ def __init__(self, scalar_key: CurveScalar): self._scalar_key = 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)
[docs] @classmethod def random(cls) -> 'SecretKey': """ Generates a random secret key and returns it. """ return cls(CurveScalar.random_nonzero())
[docs] def public_key(self) -> 'PublicKey': """ Returns the associated public key. """ return self._public_key
def __str__(self): return f"{self.__class__.__name__}:..." def __hash__(self): raise RuntimeError("Hashing secret objects is not secure") def secret_scalar(self) -> CurveScalar: return self._scalar_key
[docs] @classmethod def serialized_size(cls): return CurveScalar.serialized_size()
@classmethod def _from_exact_bytes(cls, data: bytes): return cls(CurveScalar._from_exact_bytes(data))
[docs] def to_secret_bytes(self) -> bytes: return bytes(self._scalar_key)
[docs]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) -> CurvePoint: return self._point_key
[docs] @classmethod def serialized_size(cls): return CurvePoint.serialized_size()
@classmethod def _from_exact_bytes(cls, data: bytes): return cls(CurvePoint._from_exact_bytes(data)) def __bytes__(self) -> bytes: return bytes(self._point_key) def __str__(self): return f"{self.__class__.__name__}:{bytes(self).hex()[:16]}"
[docs] def __eq__(self, other): return self._point_key == other._point_key
[docs] def __hash__(self) -> int: return hash((self.__class__, bytes(self)))
[docs]class SecretKeyFactory(SerializableSecret, Deserializable): """ 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. """ _KEY_SEED_SIZE = 32 _DERIVED_KEY_SIZE = 64 def __init__(self, key_seed: bytes): self.__key_seed = key_seed
[docs] @classmethod def random(cls) -> 'SecretKeyFactory': """ Creates a random factory. """ return cls(os.urandom(cls._KEY_SEED_SIZE))
[docs] @classmethod def seed_size(cls): """ Returns the seed size required by :py:meth:`~SecretKeyFactory.from_secure_randomness`. """ return cls._KEY_SEED_SIZE
[docs] @classmethod def from_secure_randomness(cls, seed: bytes) -> 'SecretKeyFactory': """ Creates a secret key factory using the given random bytes (of size :py:meth:`~SecretKeyFactory.seed_size`). .. warning:: Make sure the given seed has been obtained from a cryptographically secure source of randomness! """ if len(seed) != cls.seed_size(): raise ValueError(f"Expected {cls.seed_size()} bytes, got {len(seed)}") return cls(seed)
[docs] def make_key(self, label: bytes) -> SecretKey: """ Creates a :py:class:`SecretKey` deterministically from the given label. """ tag = b"KEY_DERIVATION/" + label key = kdf(self.__key_seed, self._DERIVED_KEY_SIZE, info=tag) digest = Hash(tag) digest.update(key) scalar_key = CurveScalar.from_digest(digest) return SecretKey(scalar_key)
[docs] def make_factory(self, label: bytes) -> 'SecretKeyFactory': """ Creates a :py:class:`SecretKeyFactory` deterministically from the given label. """ tag = b"FACTORY_DERIVATION/" + label key_seed = kdf(self.__key_seed, self._KEY_SEED_SIZE, info=tag) return SecretKeyFactory(key_seed)
[docs] @classmethod def serialized_size(cls): return cls._KEY_SEED_SIZE
@classmethod def _from_exact_bytes(cls, data: bytes): return cls(data)
[docs] def to_secret_bytes(self) -> bytes: return bytes(self.__key_seed)
def __str__(self): return f"{self.__class__.__name__}:..." def __hash__(self): raise RuntimeError("Hashing secret objects is not secure")