11#!/usr/bin/env python3
22
3- # Copyright © 2023-2024 , Meheret Tesfaye Batu <meherett.batu@gmail.com>
3+ # Copyright © 2023-2025 , Meheret Tesfaye Batu <meherett.batu@gmail.com>
44# Distributed under the MIT software license, see the accompanying
55# file COPYING or https://opensource.org/license/mit
66
2727 double_sha256 , get_checksum
2828)
2929from .const import (
30- N ,
30+ NP ,
3131 MAGIC_LOT_AND_SEQUENCE ,
3232 MAGIC_NO_LOT_AND_SEQUENCE ,
3333 NO_EC_MULTIPLIED_WIF_FLAG ,
@@ -93,7 +93,8 @@ def intermediate_code(
9393 passphrase : str ,
9494 lot : Optional [int ] = None ,
9595 sequence : Optional [int ] = None ,
96- owner_salt : Optional [Union [str , bytes ]] = None
96+ owner_salt : Optional [Union [str , bytes ]] = None ,
97+ N : int = 16384 , r : int = 8 , p : int = 8
9798 ) -> str :
9899 """
99100 Generates an intermediate passphrase.
@@ -104,8 +105,14 @@ def intermediate_code(
104105 :type lot: Optional[int]
105106 :param sequence: Optional sequence number (0-4095).
106107 :type sequence: Optional[int]
107- :param owner_salt: Optional owner salt (default: random 8 bytes).
108+ :param owner_salt: Optional owner salt. (default: `` random 8 bytes``)
108109 :type owner_salt: Optional[str, bytes]
110+ :param N: CPU/memory cost parameter (must be a power of two > 1). Higher values increase security but require more resources. (default: ``16384``)
111+ :type N: int
112+ :param r: Block size parameter. Controls memory usage. Must be > 0. (default: ``8``)
113+ :type r: int
114+ :param p: Parallelization parameter. Defines how many threads can run in parallel. Must be > 0. (default: ``8``)
115+ :type p: int
109116
110117 :returns: The intermediate passphrase.
111118 :rtype: str
@@ -134,12 +141,12 @@ def intermediate_code(
134141 if not 0 <= sequence <= 4095 :
135142 raise Error ("Invalid sequence" , expected = "0 <= sequence <= 4095" , got = sequence )
136143
137- pre_factor : bytes = scrypt .hash (unicodedata .normalize ("NFC" , passphrase ), owner_salt [:4 ], 16384 , 8 , 8 , 32 )
144+ pre_factor : bytes = scrypt .hash (unicodedata .normalize ("NFC" , passphrase ), owner_salt [:4 ], N = N , r = r , p = p , buflen = 32 )
138145 owner_entropy : bytes = owner_salt [:4 ] + integer_to_bytes ((lot * 4096 + sequence ), 4 )
139146 pass_factor : bytes = double_sha256 (pre_factor + owner_entropy )
140147 magic : bytes = integer_to_bytes (MAGIC_LOT_AND_SEQUENCE )
141148 else :
142- pass_factor : bytes = scrypt .hash (unicodedata .normalize ("NFC" , passphrase ), owner_salt , 16384 , 8 , 8 , 32 )
149+ pass_factor : bytes = scrypt .hash (unicodedata .normalize ("NFC" , passphrase ), owner_salt , N = N , r = r , p = p , buflen = 32 )
143150 magic : bytes = integer_to_bytes (MAGIC_NO_LOT_AND_SEQUENCE )
144151 owner_entropy : bytes = owner_salt
145152
@@ -150,7 +157,9 @@ def intermediate_code(
150157 magic + owner_entropy + pass_point .raw_compressed ()
151158 ))
152159
153- def encrypt (self , wif : str , passphrase : str , network : Optional [str ] = None ) -> str :
160+ def encrypt (
161+ self , wif : str , passphrase : str , network : Optional [str ] = None , N : int = 16384 , r : int = 8 , p : int = 8
162+ ) -> str :
154163 """
155164 Encrypts a Wallet Import Format (WIF) key using a passphrase with BIP38 encryption.
156165
@@ -160,6 +169,12 @@ def encrypt(self, wif: str, passphrase: str, network: Optional[str] = None) -> s
160169 :type passphrase: str
161170 :param network: Optional network for encryption. Defaults to the class's network if not provided.
162171 :type network: Optional[str]
172+ :param N: CPU/memory cost parameter (must be a power of two > 1). Higher values increase security but require more resources. (default: ``16384``)
173+ :type N: int
174+ :param r: Block size parameter. Controls memory usage. Must be > 0. (default: ``8``)
175+ :type r: int
176+ :param p: Parallelization parameter. Defines how many threads can run in parallel. Must be > 0. (default: ``8``)
177+ :type p: int
163178
164179 :returns: Encrypted WIF key as a string.
165180 :rtype: str
@@ -204,7 +219,7 @@ def encrypt(self, wif: str, passphrase: str, network: Optional[str] = None) -> s
204219 public_key_type = public_key_type
205220 )
206221 address_hash : bytes = get_checksum (get_bytes (address , unhexlify = False ))
207- key : bytes = scrypt .hash (unicodedata .normalize ("NFC" , passphrase ), address_hash , 16384 , 8 , 8 )
222+ key : bytes = scrypt .hash (unicodedata .normalize ("NFC" , passphrase ), address_hash , N = N , r = r , p = p )
208223 derived_half_1 , derived_half_2 = key [0 :32 ], key [32 :64 ]
209224
210225 aes : AESModeOfOperationECB = AESModeOfOperationECB (derived_half_2 )
@@ -236,7 +251,7 @@ def create_new_encrypted_wif(
236251
237252 :param intermediate_passphrase: The intermediate passphrase.
238253 :type intermediate_passphrase: str
239- :param wif_type: The WIF type, either ' wif' or ' wif-compressed' (default is ' wif').
254+ :param wif_type: The WIF type, either `` wif`` or `` wif-compressed``. (default is `` wif``)
240255 :type wif_type: str
241256 :param seed: Optional seed (default: random 24 bytes).
242257 :type seed: Optional[str, bytes]
@@ -298,7 +313,7 @@ def create_new_encrypted_wif(
298313 )
299314
300315 factor_b : bytes = double_sha256 (seed_b )
301- if not 0 < bytes_to_integer (factor_b ) < N :
316+ if not 0 < bytes_to_integer (factor_b ) < NP :
302317 raise Error ("Invalid EC encrypted WIF (Wallet Import Format)" )
303318
304319 public_key : PublicKey = PublicKey .from_point (
@@ -355,7 +370,7 @@ def create_new_encrypted_wif(
355370 )
356371
357372 def confirm_code (
358- self , passphrase : str , confirmation_code : str , network : Optional [str ] = None , detail : bool = False
373+ self , passphrase : str , confirmation_code : str , network : Optional [str ] = None , detail : bool = False , N : int = 16384 , r : int = 8 , p : int = 8
359374 ) -> Union [str , dict ]:
360375 """
361376 Confirms the passphrase using a confirmation code.
@@ -366,8 +381,14 @@ def confirm_code(
366381 :type confirmation_code: str
367382 :param network: Optional network for encryption. Defaults to the class's network if not provided.
368383 :type network: Optional[str]
369- :param detail: Whether to return detailed info (default: False).
384+ :param detail: Whether to return detailed info. (default: `` False``)
370385 :type detail: bool
386+ :param N: CPU/memory cost parameter (must be a power of two > 1). Higher values increase security but require more resources. (default: ``16384``)
387+ :type N: int
388+ :param r: Block size parameter. Controls memory usage. Must be > 0. (default: ``8``)
389+ :type r: int
390+ :param p: Parallelization parameter. Defines how many threads can run in parallel. Must be > 0. (default: ``8``)
391+ :type p: int
371392
372393 :returns: Confirmation result as a string or detailed info as a dictionary.
373394 :rtype: Union[str, dict]
@@ -412,10 +433,10 @@ def confirm_code(
412433 else :
413434 owner_salt : bytes = owner_entropy
414435
415- pass_factor : bytes = scrypt .hash (unicodedata .normalize ("NFC" , passphrase ), owner_salt , 16384 , 8 , 8 , 32 )
436+ pass_factor : bytes = scrypt .hash (unicodedata .normalize ("NFC" , passphrase ), owner_salt , N = N , r = r , p = p , buflen = 32 )
416437 if lot_and_sequence :
417438 pass_factor : bytes = double_sha256 (pass_factor + owner_entropy )
418- if bytes_to_integer (pass_factor ) == 0 or bytes_to_integer (pass_factor ) >= N :
439+ if bytes_to_integer (pass_factor ) == 0 or bytes_to_integer (pass_factor ) >= NP :
419440 raise Error ("Invalid EC encrypted WIF (Wallet Import Format)" )
420441
421442 pass_point : bytes = PrivateKey .from_bytes (pass_factor ).public_key ().raw_compressed ()
@@ -470,7 +491,7 @@ def confirm_code(
470491 raise PassphraseError ("Incorrect passphrase" )
471492
472493 def decrypt (
473- self , encrypted_wif : str , passphrase : str , network : Optional [str ] = None , detail : bool = False
494+ self , encrypted_wif : str , passphrase : str , network : Optional [str ] = None , detail : bool = False , N : int = 16384 , r : int = 8 , p : int = 8
474495 ) -> Union [str , dict ]:
475496 """
476497 Decrypts an encrypted WIF (Wallet Import Format) using a passphrase.
@@ -481,8 +502,14 @@ def decrypt(
481502 :type passphrase: str
482503 :param network: Optional network for encryption. Defaults to the class's network if not provided.
483504 :type network: Optional[str]
484- :param detail: Whether to return detailed info (default: False).
505+ :param detail: Whether to return detailed info. (default: `` False``)
485506 :type detail: bool
507+ :param N: CPU/memory cost parameter (must be a power of two > 1). Higher values increase security but require more resources. (default: ``16384``)
508+ :type N: int
509+ :param r: Block size parameter. Controls memory usage. Must be > 0. (default: ``8``)
510+ :type r: int
511+ :param p: Parallelization parameter. Defines how many threads can run in parallel. Must be > 0. (default: ``8``)
512+ :type p: int
486513
487514 :returns: The decrypted WIF or detailed private key info.
488515 :rtype: Union[str, dict]
@@ -530,7 +557,7 @@ def decrypt(
530557 )
531558
532559 key : bytes = scrypt .hash (
533- unicodedata .normalize ("NFC" , passphrase ), address_hash , 16384 , 8 , 8
560+ unicodedata .normalize ("NFC" , passphrase ), address_hash , N = N , r = r , p = p
534561 )
535562 derived_half_1 , derived_half_2 = key [0 :32 ], key [32 :64 ]
536563 encrypted_half_1 : bytes = encrypted_wif_decode [7 :23 ]
@@ -543,7 +570,7 @@ def decrypt(
543570 private_key : bytes = integer_to_bytes (
544571 bytes_to_integer (decrypted_half_1 + decrypted_half_2 ) ^ bytes_to_integer (derived_half_1 )
545572 )
546- if bytes_to_integer (private_key ) == 0 or bytes_to_integer (private_key ) >= N :
573+ if bytes_to_integer (private_key ) == 0 or bytes_to_integer (private_key ) >= NP :
547574 raise Error ("Invalid Non-EC encrypted WIF (Wallet Import Format)" )
548575
549576 public_key : PublicKey = PrivateKey .from_bytes (private_key ).public_key ()
@@ -584,10 +611,10 @@ def decrypt(
584611 else :
585612 owner_salt : bytes = owner_entropy
586613
587- pass_factor : bytes = scrypt .hash (unicodedata .normalize ("NFC" , passphrase ), owner_salt , 16384 , 8 , 8 , 32 )
614+ pass_factor : bytes = scrypt .hash (unicodedata .normalize ("NFC" , passphrase ), owner_salt , N = N , r = r , p = p , buflen = 32 )
588615 if lot_and_sequence :
589616 pass_factor : bytes = double_sha256 (pass_factor + owner_entropy )
590- if bytes_to_integer (pass_factor ) == 0 or bytes_to_integer (pass_factor ) >= N :
617+ if bytes_to_integer (pass_factor ) == 0 or bytes_to_integer (pass_factor ) >= NP :
591618 raise Error ("Invalid EC encrypted WIF (Wallet Import Format)" )
592619
593620 pre_public_key : PublicKey = PrivateKey .from_bytes (pass_factor ).public_key ()
@@ -609,12 +636,12 @@ def decrypt(
609636 ) + encrypted_half_1_half_2_seed_b_last_3 [8 :]
610637
611638 factor_b : bytes = double_sha256 (seed_b )
612- if bytes_to_integer (factor_b ) == 0 or bytes_to_integer (factor_b ) >= N :
639+ if bytes_to_integer (factor_b ) == 0 or bytes_to_integer (factor_b ) >= NP :
613640 raise Error ("Invalid EC encrypted WIF (Wallet Import Format)" )
614641
615642 # multiply private key
616643 private_key : bytes = integer_to_bytes (
617- (bytes_to_integer (pass_factor ) * bytes_to_integer (factor_b )) % N
644+ (bytes_to_integer (pass_factor ) * bytes_to_integer (factor_b )) % NP
618645 )
619646 public_key : PublicKey = PrivateKey .from_bytes (private_key ).public_key ()
620647 wif_type : Literal ["wif" , "wif-compressed" ] = "wif"
0 commit comments