Source code for helium_py.crypto.keypair

"""Keypair class for cryptography."""
from dataclasses import dataclass
from typing import List, Optional

import nacl.bindings

from .address import Address
from .constants import SUPPORTED_NET_TYPES, KeyTypes, NetTypes
from .mnemonic import Mnemonic


[docs]@dataclass class SodiumKeyPair: """Base SodiumKeypair dataclass.""" pk: bytes sk: bytes key_type: Optional[int] = None
[docs]class Keypair: """Keypair class with mnemonic, entropy, and signing capabilities.""" keypair: SodiumKeyPair public_key: bytes private_key: bytes key_type: int net_type: int
[docs] def __init__(self, keypair: SodiumKeyPair, net_type: Optional[int] = None): """Initialize Keypair instance.""" self.keypair = keypair self.public_key = keypair.pk self.private_key = keypair.sk self.key_type = keypair.key_type if keypair.key_type is not None else KeyTypes.ED25519_KEY_TYPE.value self.net_type = net_type if net_type is not None and net_type in SUPPORTED_NET_TYPES else NetTypes.MAINNET.value
@property def address(self) -> Address: """Return Address instance for Keypair.""" return Address(Address.DEFAULT_VERSION, self.net_type, KeyTypes.ED25519_KEY_TYPE.value, self.public_key)
[docs] @staticmethod def make_random(net_type: int = None) -> 'Keypair': """Return randomly generated Keypair.""" keypair = nacl.bindings.crypto_sign_keypair() return Keypair(SodiumKeyPair(pk=keypair[0], sk=keypair[1]), net_type)
[docs] @classmethod def from_words(cls, words: List[str], net_type: Optional[int] = None) -> 'Keypair': """Return Keypair generated from list of words (mnemonic).""" mnemonic = Mnemonic(words) keypair = cls.from_mnemonic(mnemonic, net_type) return keypair
[docs] @classmethod def from_mnemonic(cls, mnemonic: Mnemonic, net_type: Optional[int] = None) -> 'Keypair': """Return Keypair generated from a Mnemonic object.""" entropy = mnemonic.to_entropy() seed = entropy + entropy if len(entropy) == 16 else entropy return cls.from_entropy(seed, net_type)
[docs] @classmethod def from_entropy(cls, entropy: bytes, net_type: Optional[int] = None) -> 'Keypair': """Return Keypair generated from entropy.""" if len(entropy) != 32: raise ValueError(f'Invalid entropy, must be 32 bytes. Found {len(entropy)}') keypair = nacl.bindings.crypto_sign_seed_keypair(entropy) return cls(SodiumKeyPair(pk=keypair[0], sk=keypair[1]), net_type)
[docs] def sign(self, message: bytes) -> bytes: """Return signature for provided message utilizing private_key.""" signature = nacl.bindings.crypto_sign(message, self.private_key) return signature[:signature.index(message)]