import base64 import hashlib import random from typing import Dict from bip32 import BIP32 from ..settings import settings from .secp import PrivateKey, PublicKey def derive_keys(mnemonic: str, derivation_path: str): """ Deterministic derivation of keys for 2^n values. """ bip32 = BIP32.from_seed(mnemonic.encode()) orders_str = [f"/{i}'" for i in range(settings.max_order)] return { 2**i: PrivateKey( bip32.get_privkey_from_path(derivation_path + orders_str[i]), raw=True, ) for i in range(settings.max_order) } def derive_keys_sha256(seed: str, derivation_path: str = ""): """ Deterministic derivation of keys for 2^n values. TODO: Implement BIP32. """ return { 2**i: PrivateKey( hashlib.sha256((seed + derivation_path + str(i)).encode("utf-8")).digest()[ :32 ], raw=True, ) for i in range(settings.max_order) } def derive_pubkey(seed: str): return PrivateKey( hashlib.sha256((seed).encode("utf-8")).digest()[:32], raw=True, ).pubkey def derive_pubkeys(keys: Dict[int, PrivateKey]): return {amt: keys[amt].pubkey for amt in [2**i for i in range(settings.max_order)]} def derive_keyset_id(keys: Dict[int, PublicKey]): """Deterministic derivation keyset_id from set of public keys.""" # sort public keys by amount sorted_keys = dict(sorted(keys.items())) pubkeys_concat = b"".join([p.serialize() for _, p in sorted_keys.items()]) return "00" + hashlib.sha256(pubkeys_concat).hexdigest()[:14] def derive_keyset_id_deprecated(keys: Dict[int, PublicKey]): """DEPRECATED 0.15.0: Deterministic derivation keyset_id from set of public keys. DEPRECATION: This method produces base64 keyset ids. Use `derive_keyset_id` instead. """ # sort public keys by amount sorted_keys = dict(sorted(keys.items())) pubkeys_concat = "".join([p.serialize().hex() for _, p in sorted_keys.items()]) return base64.b64encode( hashlib.sha256((pubkeys_concat).encode("utf-8")).digest() ).decode()[:12] def random_hash() -> str: """Returns a base64-urlsafe encoded random hash.""" return base64.urlsafe_b64encode( bytes([random.getrandbits(8) for i in range(30)]) ).decode()