Skip to content
This repository has been archived by the owner on Aug 7, 2024. It is now read-only.

Commit

Permalink
Add: support Qtum testnet network
Browse files Browse the repository at this point in the history
  • Loading branch information
meherett committed Oct 14, 2023
1 parent 6887162 commit e57f0e3
Showing 1 changed file with 39 additions and 19 deletions.
58 changes: 39 additions & 19 deletions qtum_bip38/bip38.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,12 @@
encode, check_encode, decode, check_decode, ensure_string
)

# Qtum address prefix
ADDRESS_PREFIX: int = 0x3a
# Wallet important format prefix
WIF_PREFIX: int = 0x80
# Qtum Pay to Public Key Hash (P2PKH) address prefixes
ADDRESS_PREFIXES: Dict[Literal["mainnet", "testnet"], int] = {
"mainnet": 0x3a, "testnet": 0x78
}
# BIP38 non-EC-multiplied & EC-multiplied private key prefixes
BIP38_NO_EC_MULTIPLIED_PRIVATE_KEY_PREFIX: int = 0x0142
BIP38_EC_MULTIPLIED_PRIVATE_KEY_PREFIX: int = 0x0143
Expand Down Expand Up @@ -236,7 +238,7 @@ def private_key_to_public_key(private_key: Union[str, bytes], public_key_type: L

if public_key_type == "uncompressed":
public_uncompressed: bytes = (
integer_to_bytes(UNCOMPRESSED_PUBLIC_KEY_PREFIX) + integer_to_bytes(x) + integer_to_bytes(y)
integer_to_bytes(UNCOMPRESSED_PUBLIC_KEY_PREFIX) + integer_to_bytes(x) + integer_to_bytes(y)
)
return public_uncompressed.hex()
elif public_key_type == "compressed":
Expand Down Expand Up @@ -269,11 +271,11 @@ def encode_wif(private_key: Union[str, bytes]) -> Tuple[str, str]:

def private_key_to_wif(private_key: Union[str, bytes], wif_type: Literal["wif", "wif-compressed"] = "wif-compressed") -> str:
"""
Private key to Wallet Important Format (WFI) converter
Private key to Wallet Important Format (WIF) converter
:param private_key: Private key
:type private_key: Union[str, bytes]
:param wif_type: Wallet Important Format (WFI) type, default to ``wif-compressed``
:param wif_type: Wallet Important Format (WIF) type, default to ``wif-compressed``
:type wif_type: Literal["wif", "wif-compressed"]
:returns: str -- Wallet Important Format
Expand Down Expand Up @@ -317,7 +319,7 @@ def decode_wif(wif: str) -> Tuple[bytes, Literal["wif", "wif-compressed"], bytes

def wif_to_private_key(wif: str) -> str:
"""
Wallet Important Format (WFI) to Private key converter
Wallet Important Format (WIF) to Private key converter
:param wif: Wallet Important Format
:type wif: str
Expand All @@ -330,7 +332,7 @@ def wif_to_private_key(wif: str) -> str:

def get_wif_type(wif: str) -> Literal["wif", "wif-compressed"]:
"""
Get Wallet Important Format (WFI) type
Get Wallet Important Format (WIF) type
:param wif: Wallet Important Format
:type wif: str
Expand All @@ -354,20 +356,25 @@ def get_wif_checksum(wif: str) -> str:
return bytes_to_string(decode_wif(wif=wif)[2])


def public_key_to_addresses(public_key: Union[str, bytes]) -> str:
def public_key_to_addresses(public_key: Union[str, bytes], network: Literal["mainnet", "testnet"] = "mainnet") -> str:
"""
Public key to address converter
:param public_key: Public key
:type public_key: Union[str, bytes]
:param network: Network type
:type network: Literal["mainnet", "testnet"], default to ``mainnet``
:returns: str -- Address
"""

if network not in ["mainnet", "testnet"]:
raise ValueError(f"Invalid Qtum network, (expected: 'mainnet' or 'testnet', got: {network})")

# Getting public key hash
public_key_hash: bytes = hash160(get_bytes(public_key))
payload: bytes = (
integer_to_bytes(ADDRESS_PREFIX) + public_key_hash
integer_to_bytes(ADDRESS_PREFIXES[network]) + public_key_hash
)
return ensure_string(encode(payload + get_checksum(payload)))

Expand Down Expand Up @@ -422,14 +429,16 @@ def intermediate_code(
))


def bip38_encrypt(wif: str, passphrase: str) -> str:
def bip38_encrypt(wif: str, passphrase: str, network: Literal["mainnet", "testnet"] = "mainnet") -> str:
"""
BIP38 Encrypt wallet important format using passphrase/password
:param wif: Wallet important format
:type wif: str
:param passphrase: Passphrase or password text
:type passphrase: str
:param network: Network type
:type network: Literal["mainnet", "testnet"], default to ``mainnet``
:returns: str -- Encrypted wallet important format
"""
Expand All @@ -449,7 +458,7 @@ def bip38_encrypt(wif: str, passphrase: str) -> str:
public_key: str = private_key_to_public_key(
private_key=private_key, public_key_type=public_key_type
)
address: str = public_key_to_addresses(public_key=public_key)
address: str = public_key_to_addresses(public_key=public_key, network=network)
address_hash: bytes = get_checksum(get_bytes(address, unhexlify=False))
key: bytes = scrypt.hash(unicodedata.normalize("NFC", passphrase), address_hash, 16384, 8, 8)
derived_half_1, derived_half_2 = key[0:32], key[32:64]
Expand All @@ -473,7 +482,8 @@ def bip38_encrypt(wif: str, passphrase: str) -> str:
def create_new_encrypted_wif(
intermediate_passphrase: str,
public_key_type: Literal["uncompressed", "compressed"] = "uncompressed",
seed: Union[str, bytes] = os.urandom(24)
seed: Union[str, bytes] = os.urandom(24),
network: Literal["mainnet", "testnet"] = "mainnet"
) -> dict:
"""
Create new encrypted wallet important format
Expand All @@ -484,6 +494,8 @@ def create_new_encrypted_wif(
:type public_key_type: Literal["uncompressed", "compressed"]
:param seed: Seed, default to ``os.urandom(24)``
:type seed: Optional[str, bytes]
:param network: Network type
:type network: Literal["mainnet", "testnet"], default to ``mainnet``
:returns: dict -- Encrypted wallet important format
"""
Expand Down Expand Up @@ -522,7 +534,7 @@ def create_new_encrypted_wif(
raise ValueError("Invalid ec encrypted wallet important format")

public_key: bytes = multiply_public_key(pass_point, factor_b, public_key_type)
address: str = public_key_to_addresses(public_key=public_key)
address: str = public_key_to_addresses(public_key=public_key, network=network)
address_hash: bytes = get_checksum(get_bytes(address, unhexlify=False))
salt: bytes = address_hash + owner_entropy
scrypt_hash: bytes = scrypt.hash(pass_point, salt, 1024, 1, 1, 64)
Expand Down Expand Up @@ -566,15 +578,19 @@ def create_new_encrypted_wif(
)


def confirm_code(passphrase: str, confirmation_code: str, detail: bool = False) -> Union[str, dict]:
def confirm_code(
passphrase: str, confirmation_code: str, network: Literal["mainnet", "testnet"] = "mainnet", detail: bool = False
) -> Union[str, dict]:
"""
Confirm passphrase
:param passphrase: Passphrase or password text
:type passphrase: str
:param confirmation_code: Confirmation code
:type confirmation_code: str
:param detail: To show in deatil, default to ``False``
:param network: Network type
:type network: Literal["mainnet", "testnet"], default to ``mainnet``
:param detail: To show in detail, default to ``False``
:type detail: bool
:returns: Union[str, dict] -- Confirmation of address info's
Expand Down Expand Up @@ -636,7 +652,7 @@ def confirm_code(passphrase: str, confirmation_code: str, detail: bool = False)
public_key: bytes = get_bytes(compress_public_key(public_key=public_key))
public_key_type: str = "compressed"

address: str = public_key_to_addresses(public_key=public_key)
address: str = public_key_to_addresses(public_key=public_key, network=network)
if get_checksum(get_bytes(address, unhexlify=False)) == address_hash:
lot: Optional[int] = None
sequence: Optional[int] = None
Expand All @@ -655,14 +671,18 @@ def confirm_code(passphrase: str, confirmation_code: str, detail: bool = False)
raise ValueError("Incorrect passphrase/password")


def bip38_decrypt(encrypted_wif: str, passphrase: str, detail: bool = False) -> Union[str, dict]:
def bip38_decrypt(
encrypted_wif: str, passphrase: str, network: Literal["mainnet", "testnet"] = "mainnet", detail: bool = False
) -> Union[str, dict]:
"""
BIP38 Decrypt encrypted wallet important format using passphrase/password
:param encrypted_wif: Encrypted wallet important format
:type encrypted_wif: str
:param passphrase: Passphrase or password text
:type passphrase: str
:param network: Network type
:type network: Literal["mainnet", "testnet"], default to ``mainnet``
:param detail: To show in detail, default to ``False``
:type detail: bool
Expand Down Expand Up @@ -709,7 +729,7 @@ def bip38_decrypt(encrypted_wif: str, passphrase: str, detail: bool = False) ->
public_key: str = private_key_to_public_key(
private_key=private_key, public_key_type=public_key_type
)
address: str = public_key_to_addresses(public_key=public_key)
address: str = public_key_to_addresses(public_key=public_key, network=network)
if get_checksum(get_bytes(address, unhexlify=False)) != address_hash:
raise ValueError("Incorrect passphrase/password")

Expand Down Expand Up @@ -783,7 +803,7 @@ def bip38_decrypt(encrypted_wif: str, passphrase: str, detail: bool = False) ->
public_key_type = "compressed"
wif_type = "wif-compressed"

address: str = public_key_to_addresses(public_key=public_key)
address: str = public_key_to_addresses(public_key=public_key, network=network)
if get_checksum(get_bytes(address, unhexlify=False)) == address_hash:
wif: str = private_key_to_wif(
private_key=private_key, wif_type=wif_type
Expand Down

0 comments on commit e57f0e3

Please sign in to comment.