Skip to content

Keys and Addresses

There are two types of address format, "base58check" and "hex str". The base58check variant is more user-friendly.

TronPy accepts both type of address. The Base58check type is preferred.

Key API reference

to_base58check_address

to_base58check_address(raw_addr: str | bytes) -> str

Convert hex address or base58check address to base58check address(and verify it).

Source code in tronpy/keys/__init__.py
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
def to_base58check_address(raw_addr: str | bytes) -> str:
    """Convert hex address or base58check address to base58check address(and verify it)."""
    if isinstance(raw_addr, (str,)):
        if raw_addr[0] == "T" and len(raw_addr) == 34:
            try:
                # assert checked
                base58.b58decode_check(raw_addr)
            except ValueError as e:
                raise BadAddress("bad base58check format") from e
            return raw_addr
        if len(raw_addr) == 42:
            if raw_addr.startswith("0x"):  # eth address format
                return base58.b58encode_check(b"\x41" + bytes.fromhex(raw_addr[2:])).decode()
            return base58.b58encode_check(bytes.fromhex(raw_addr)).decode()
        if raw_addr.startswith("0x") and len(raw_addr) == 44:
            return base58.b58encode_check(bytes.fromhex(raw_addr[2:])).decode()
    elif isinstance(raw_addr, (bytes, bytearray)):
        if len(raw_addr) == 21 and int(raw_addr[0]) == 0x41:
            return base58.b58encode_check(raw_addr).decode()
        if len(raw_addr) == 20:  # eth address format
            return base58.b58encode_check(b"\x41" + raw_addr).decode()
        return to_base58check_address(raw_addr.decode())
    raise BadAddress(repr(raw_addr))

PrivateKey

PrivateKey(private_key_bytes: bytes)

              flowchart TD
              tronpy.keys.PrivateKey[PrivateKey]
              tronpy.keys.BaseKey[BaseKey]

                              tronpy.keys.BaseKey --> tronpy.keys.PrivateKey
                


              click tronpy.keys.PrivateKey href "" "tronpy.keys.PrivateKey"
              click tronpy.keys.BaseKey href "" "tronpy.keys.BaseKey"
            

The private key.

Methods:

Source code in tronpy/keys/__init__.py
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
def __init__(self, private_key_bytes: bytes):
    if not isinstance(private_key_bytes, (bytes,)):
        raise BadKey("private_key_bytes must be bytes")
    if len(private_key_bytes) != 32:
        raise BadKey(f"private_key_bytes must be 32 bytes long, got {len(private_key_bytes)}")
    if not (
        0
        < int.from_bytes(private_key_bytes, "big")
        < 115792089237316195423570985008687907852837564279074904382605163141518161494337
    ):
        raise BadKey("private key is not in the valid range")

    self._raw_key = private_key_bytes

    priv_key = CoincurvePrivateKey(self._raw_key)
    self.public_key = PublicKey(priv_key.public_key.format(compressed=False)[1:])

    super().__init__()

from_passphrase classmethod

from_passphrase(passphrase: bytes) -> PrivateKey

Get a private key from sha256 of a passphrase.

Source code in tronpy/keys/__init__.py
284
285
286
287
@classmethod
def from_passphrase(cls, passphrase: bytes) -> "PrivateKey":
    """Get a private key from sha256 of a passphrase."""
    return cls(sha256(passphrase))

fromhex classmethod

fromhex(hex_str: str) -> BaseKey

Construct a key from a hex str.

Returns:

  • BaseKey –

    The key object.

Source code in tronpy/keys/__init__.py
149
150
151
152
153
154
155
156
@classmethod
def fromhex(cls, hex_str: str) -> "BaseKey":
    """
    Construct a key from a hex str.

    :returns: The key object.
    """
    return cls(bytes.fromhex(hex_str))

hex

hex() -> str

Key as a hex str.

Returns:

  • str –

    A hex str.

Source code in tronpy/keys/__init__.py
141
142
143
144
145
146
147
def hex(self) -> str:
    """
    Key as a hex str.

    :returns: A hex str.
    """
    return self._raw_key.hex()

random classmethod

random() -> PrivateKey

Generate a random private key.

Source code in tronpy/keys/__init__.py
279
280
281
282
@classmethod
def random(cls) -> "PrivateKey":
    """Generate a random private key."""
    return cls(os.urandom(32))

sign_msg

sign_msg(message: bytes) -> Signature

Sign a raw message.

Source code in tronpy/keys/__init__.py
265
266
267
268
def sign_msg(self, message: bytes) -> "Signature":
    """Sign a raw message."""
    message_hash = hash_message(message)
    return self.sign_msg_hash(message_hash)

sign_msg_hash

sign_msg_hash(message_hash: bytes) -> Signature

Sign a message hash.

Source code in tronpy/keys/__init__.py
270
271
272
273
274
275
276
277
def sign_msg_hash(self, message_hash: bytes) -> "Signature":
    """Sign a message hash."""
    private_key_bytes = self.to_bytes()
    signature_bytes = CoincurvePrivateKey(private_key_bytes).sign_recoverable(
        message_hash,
        hasher=None,
    )
    return Signature(signature_bytes)

PublicKey

PublicKey(public_key_bytes: bytes)

              flowchart TD
              tronpy.keys.PublicKey[PublicKey]
              tronpy.keys.BaseKey[BaseKey]

                              tronpy.keys.BaseKey --> tronpy.keys.PublicKey
                


              click tronpy.keys.PublicKey href "" "tronpy.keys.PublicKey"
              click tronpy.keys.BaseKey href "" "tronpy.keys.BaseKey"
            

The public key.

Methods:

Source code in tronpy/keys/__init__.py
198
199
200
201
202
203
204
205
206
def __init__(self, public_key_bytes: bytes):
    if not isinstance(public_key_bytes, (bytes,)):
        raise BadKey("public_key_bytes must be bytes")
    if len(public_key_bytes) != 64:
        raise BadKey(f"public_key_bytes must be 64 bytes long, got {len(public_key_bytes)}")

    self._raw_key = public_key_bytes

    super().__init__()

fromhex classmethod

fromhex(hex_str: str) -> BaseKey

Construct a key from a hex str.

Returns:

  • BaseKey –

    The key object.

Source code in tronpy/keys/__init__.py
149
150
151
152
153
154
155
156
@classmethod
def fromhex(cls, hex_str: str) -> "BaseKey":
    """
    Construct a key from a hex str.

    :returns: The key object.
    """
    return cls(bytes.fromhex(hex_str))

hex

hex() -> str

Key as a hex str.

Returns:

  • str –

    A hex str.

Source code in tronpy/keys/__init__.py
141
142
143
144
145
146
147
def hex(self) -> str:
    """
    Key as a hex str.

    :returns: A hex str.
    """
    return self._raw_key.hex()

recover_from_msg classmethod

recover_from_msg(message: bytes, signature: Signature)

Recover public key(address) from raw message and signature.

Source code in tronpy/keys/__init__.py
208
209
210
211
@classmethod
def recover_from_msg(cls, message: bytes, signature: "Signature"):
    """Recover public key(address) from raw message and signature."""
    return signature.recover_public_key_from_msg(message)

recover_from_msg_hash classmethod

recover_from_msg_hash(message_hash: bytes, signature: Signature)

Recover public key(address) from message hash and signature.

Source code in tronpy/keys/__init__.py
213
214
215
216
@classmethod
def recover_from_msg_hash(cls, message_hash: bytes, signature: "Signature"):
    """Recover public key(address) from message hash and signature."""
    return signature.recover_public_key_from_msg_hash(message_hash)

to_base58check_address

to_base58check_address() -> str

Get the base58check address of the public key.

Source code in tronpy/keys/__init__.py
227
228
229
def to_base58check_address(self) -> str:
    """Get the base58check address of the public key."""
    return public_key_to_base58check_addr(self._raw_key)

verify_msg

verify_msg(message: bytes, signature: Signature) -> bool

Verify message and signature.

Source code in tronpy/keys/__init__.py
218
219
220
def verify_msg(self, message: bytes, signature: "Signature") -> bool:
    """Verify message and signature."""
    return signature.verify_msg(message, self)

verify_msg_hash

verify_msg_hash(message_hash: bytes, signature: Signature) -> bool

Verify message hash and signature.

Source code in tronpy/keys/__init__.py
222
223
224
def verify_msg_hash(self, message_hash: bytes, signature: "Signature") -> bool:
    """Verify message hash and signature."""
    return signature.verify_msg_hash(message_hash, self)

Signature

Signature(signature_bytes: bytes)

              flowchart TD
              tronpy.keys.Signature[Signature]

              

              click tronpy.keys.Signature href "" "tronpy.keys.Signature"
            

The signature object.

Methods:

Source code in tronpy/keys/__init__.py
295
296
297
298
299
300
301
302
303
304
305
306
def __init__(self, signature_bytes: bytes):
    if not isinstance(signature_bytes, (bytes,)):
        raise BadSignature("signature_bytes must be bytes")

    if len(signature_bytes) != 65:
        raise BadSignature(f"signature_bytes must be 65 bytes long, got {len(signature_bytes)}")

    signature_bytes = signature_bytes[:64] + bytes([self.normalize_v(signature_bytes[-1])])

    self._raw_signature = signature_bytes

    super().__init__()

fromhex classmethod

fromhex(hex_str: str) -> Signature

Construct a Signature from hex str.

Source code in tronpy/keys/__init__.py
381
382
383
384
@classmethod
def fromhex(cls, hex_str: str) -> "Signature":
    """Construct a Signature from hex str."""
    return cls(bytes.fromhex(hex_str))

hex

hex() -> str

Return signature as a hex str.

Returns:

  • str –

    A hex str.

Source code in tronpy/keys/__init__.py
366
367
368
369
370
371
372
def hex(self) -> str:
    """
    Return signature as a hex str.

    :returns: A hex str.
    """
    return self._raw_signature.hex()

recover_public_key_from_msg

recover_public_key_from_msg(message: bytes) -> PublicKey

Recover public key(address) from message and signature.

Source code in tronpy/keys/__init__.py
317
318
319
320
def recover_public_key_from_msg(self, message: bytes) -> PublicKey:
    """Recover public key(address) from message and signature."""
    message_hash = hash_message(message)
    return self.recover_public_key_from_msg_hash(message_hash)

recover_public_key_from_msg_hash

recover_public_key_from_msg_hash(message_hash: bytes) -> PublicKey

Recover public key(address) from message hash and signature.

Source code in tronpy/keys/__init__.py
322
323
324
325
326
327
328
329
330
331
332
333
334
335
def recover_public_key_from_msg_hash(self, message_hash: bytes) -> PublicKey:
    """Recover public key(address) from message hash and signature."""
    signature_bytes = self.to_bytes()
    try:
        public_key_bytes = CoincurvePublicKey.from_signature_and_message(
            signature_bytes,
            message_hash,
            hasher=None,
        ).format(compressed=False)[1:]
    except (ValueError, Exception) as err:
        # `coincurve` can raise `ValueError` or `Exception` dependending on
        # how the signature is invalid.
        raise BadSignature(str(err)) from err
    return PublicKey(public_key_bytes)

tronweb_hex

tronweb_hex() -> str

Return signature as a hex str in TronWeb format (v+27).

Source code in tronpy/keys/__init__.py
374
375
376
377
378
379
def tronweb_hex(self) -> str:
    """Return signature as a hex str in TronWeb format (v+27)."""
    r = hex(self.r)[2:].zfill(64)
    s = hex(self.s)[2:].zfill(64)
    v = self.v + 27
    return r + s + f"{v:02x}"

verify_msg

verify_msg(message: bytes, public_key: PublicKey) -> bool

Verify message and signature.

Source code in tronpy/keys/__init__.py
337
338
339
340
def verify_msg(self, message: bytes, public_key: PublicKey) -> bool:
    """Verify message and signature."""
    message_hash = hash_message(message)
    return self.verify_msg_hash(message_hash, public_key)

verify_msg_hash

verify_msg_hash(message_hash: bytes, public_key: PublicKey) -> bool

Verify message hash and signature.

Source code in tronpy/keys/__init__.py
342
343
344
345
346
347
348
349
350
351
352
def verify_msg_hash(self, message_hash: bytes, public_key: PublicKey) -> bool:
    """Verify message hash and signature."""
    # coincurve rejects signatures with a high s, so convert to the equivalent low s form
    low_s = coerce_low_s(self.s)
    der_encoded_signature = bytes(two_int_sequence_encoder(self.r, low_s))
    coincurve_public_key = CoincurvePublicKey(b"\x04" + public_key.to_bytes())
    return coincurve_public_key.verify(
        der_encoded_signature,
        message_hash,
        hasher=None,
    )