|
| 1 | +from __future__ import annotations |
| 2 | + |
| 3 | +import secp256k1 |
| 4 | + |
| 5 | +from pactus.crypto.hrp import HRP |
| 6 | +from pactus.utils import utils |
| 7 | + |
| 8 | +from .public_key import PublicKey |
| 9 | +from .signature import SIGNATURE_TYPE_SECP256K1, Signature |
| 10 | + |
| 11 | +PRIVATE_KEY_SIZE = 32 |
| 12 | + |
| 13 | + |
| 14 | +class PrivateKey: |
| 15 | + def __init__(self, scalar: secp256k1.PrivateKey) -> None: |
| 16 | + self.scalar = scalar |
| 17 | + |
| 18 | + @classmethod |
| 19 | + def from_bytes(cls, buffer: bytes) -> PrivateKey: |
| 20 | + sk = secp256k1.PrivateKey() |
| 21 | + sk.set_raw_privkey(buffer) |
| 22 | + return cls(sk) |
| 23 | + |
| 24 | + @classmethod |
| 25 | + def random(cls) -> PrivateKey: |
| 26 | + sk = secp256k1.PrivateKey() |
| 27 | + return cls(sk) |
| 28 | + |
| 29 | + @classmethod |
| 30 | + def from_string(cls, text: str) -> PrivateKey: |
| 31 | + hrp, typ, data = utils.decode_to_base256_with_type(text) |
| 32 | + |
| 33 | + if hrp != HRP.PRIVATE_KEY_HRP: |
| 34 | + msg = f"Invalid hrp: {hrp}" |
| 35 | + raise ValueError(msg) |
| 36 | + |
| 37 | + if typ != SIGNATURE_TYPE_SECP256K1: |
| 38 | + msg = f"Invalid Private key type: {typ}" |
| 39 | + raise ValueError(msg) |
| 40 | + |
| 41 | + if len(data) != PRIVATE_KEY_SIZE: |
| 42 | + msg = "Private key data must be 32 bytes long" |
| 43 | + raise ValueError(msg) |
| 44 | + |
| 45 | + sk = secp256k1.PrivateKey() |
| 46 | + sk.set_raw_privkey(bytes(data)) |
| 47 | + return cls(sk) |
| 48 | + |
| 49 | + def raw_bytes(self) -> bytes: |
| 50 | + # serialize() returns a hex string, convert to bytes |
| 51 | + hex_str = self.scalar.serialize() |
| 52 | + return bytes.fromhex(hex_str) |
| 53 | + |
| 54 | + def string(self) -> str: |
| 55 | + return utils.encode_from_base256_with_type( |
| 56 | + HRP.PRIVATE_KEY_HRP, |
| 57 | + SIGNATURE_TYPE_SECP256K1, |
| 58 | + self.raw_bytes(), |
| 59 | + ) |
| 60 | + |
| 61 | + def public_key(self) -> PublicKey: |
| 62 | + return PublicKey(self.scalar.pubkey) |
| 63 | + |
| 64 | + def sign(self, msg: bytes) -> Signature: |
| 65 | + sig = self.scalar.ecdsa_sign(msg) |
| 66 | + sig_compact = self.scalar.ecdsa_serialize_compact(sig) |
| 67 | + return Signature(sig_compact) |
0 commit comments