def test_from_words_num(self): for test in TEST_WORDS_NUM_MAIN: if test["is_valid"]: mnemonic = Bip39MnemonicGenerator.FromWordsNumber(test["words_num"]) self.assertEqual(len(mnemonic.split(" ")), test["words_num"]) else: self.assertRaises(ValueError, Bip39MnemonicGenerator.FromWordsNumber, test["words_num"])
def getMnemonic( password: str = "" ) -> str: while True: res: str = Bip39MnemonicGenerator.FromWordsNumber(Bip39WordsNum.WORDS_NUM_24) seed: bytes = sha256(Bip39SeedGenerator(res).Generate(password)).digest() try: BIP32.derive(seed, [44 + (1 << 31), 5132 + (1 << 31), 0 + (1 << 31), 0]) BIP32.derive(seed, [44 + (1 << 31), 5132 + (1 << 31), 0 + (1 << 31), 1]) except Exception: continue return res
def generate(self): # Generate random mnemonic mnemonic = Bip39MnemonicGenerator.FromWordsNumber(12) # Generate seed from mnemonic seed_bytes = Bip39SeedGenerator(mnemonic).Generate() # Generate BIP44 master keys bip_obj_mst = Bip44.FromSeed(seed_bytes, Bip44Coins.DASH) address = bip_obj_mst.PublicKey().ToAddress() wif = bip_obj_mst.PrivateKey().ToWif() seed = mnemonic return CryptoCoin(address, wif, seed)
def CreateRandom(self, wallet_name, words_num): """ Create wallet randomly. Args: wallet_name (str) : Wallet name words_num (HdWalletWordsNum): Words number, must be a HdWalletWordsNum enum Returns: HdWallet object: HdWallet object Raises: TypeError: If words number is not of HdWalletWordsNum enum """ if not isinstance(words_num, HdWalletWordsNum): raise TypeError("Words number is not an enumerative of HdWalletWordsNum") mnemonic = Bip39MnemonicGenerator.FromWordsNumber(words_num) return self.CreateFromMnemonic(wallet_name, mnemonic)
def generate(self): # Generate random mnemonic mnemonic = Bip39MnemonicGenerator.FromWordsNumber(12) # Generate seed from mnemonic seed_bytes = Bip39SeedGenerator(mnemonic).Generate() # Generate BIP44 master keys bip_obj_mst = Bip44.FromSeed(seed_bytes, Bip44Coins.BITCOIN) wif = WifEncoder.Encode(bip_obj_mst.PrivateKey().Raw().ToBytes(), True, POTE_WIF_NET_VER.Main()) pub_key_bytes = bip_obj_mst.PublicKey().RawCompressed().ToBytes() address = Base58Encoder.CheckEncode(POTE_P2PKH_NET_VER.Main() + CryptoUtils.Hash160(pub_key_bytes)) seed = mnemonic return CryptoCoin(address, wif, seed)
def cli( mnemonic: str, passphrase: str, limit: int, prompt_mnemonic: bool, prompt_passphrase: bool, hide_mnemonic: bool, hide_private: bool, ): if prompt_passphrase: passphrase = click.prompt("passphrase", hide_input=True) if prompt_mnemonic: mnemonic = click.prompt("mnemonic", hide_input=True) if not mnemonic: mnemonic = Bip39MnemonicGenerator.FromWordsNumber( Bip39WordsNum.WORDS_NUM_24) if not Bip39MnemonicValidator(mnemonic).Validate(): return fatal("Invalid mnemonic") seed_bytes = Bip39SeedGenerator(mnemonic).Generate(passphrase) if not hide_mnemonic: click.echo(mnemonic + "\n") bip_obj_mst = Bip44.FromSeed(seed_bytes, Bip44Coins.BITCOIN) bip_obj_acc = bip_obj_mst.Purpose().Coin().Account(0) bip_obj_chain = bip_obj_acc.Change(Bip44Changes.CHAIN_EXT) # m/44'/0'/0'/0/i for i in range(limit): bip_obj_addr = bip_obj_chain.AddressIndex(i) address = bip_obj_addr.PublicKey().ToAddress() private = bip_obj_addr.PrivateKey().ToWif() acc = address if hide_private else f"{address} / {private}" click.echo(acc)
def DerivationTest(rpc: RPC) -> None: #Start by testing BIP 32, 39, and 44 functionality in general. for _ in range(10): rpc.call("personal", "setWallet") verifyMnemonicAndAccount(rpc) #Set specific Mnemonics and ensure they're handled properly. for _ in range(10): mnemonic: str = getMnemonic() rpc.call("personal", "setWallet", {"mnemonic": mnemonic}) verifyMnemonicAndAccount(rpc, mnemonic) #Create Mnemonics with passwords and ensure they're handled properly. for _ in range(10): password: str = os.urandom(32).hex() rpc.call("personal", "setWallet", {"password": password}) verifyMnemonicAndAccount(rpc, password=password) #Set specific Mnemonics with passwords and ensure they're handled properly. for i in range(10): password: str = os.urandom(32).hex() #Non-hex string. if i == 0: password = "******" mnemonic: str = getMnemonic(password) rpc.call("personal", "setWallet", { "mnemonic": mnemonic, "password": password }) verifyMnemonicAndAccount(rpc, mnemonic, password) #setWallet, getMnemonic, getMeritHolderKey, getMeritHolderNick's non-existent case, and getAccount have now been tested. #This leaves getAddress with specific indexes. #Clear the Wallet. rpc.call("personal", "setWallet") #Start by testing specific derivation. password: str = "password since it shouldn't be relevant" for _ in range(10): mnemonic: str = getMnemonic(password) index: int = 100 key: bytes while True: try: key = BIP32.derive( sha256(Bip39SeedGenerator(mnemonic).Generate( password)).digest(), [ 44 + (1 << 31), 5132 + (1 << 31), 0 + (1 << 31), 0, index ]) break except Exception: index += 1 rpc.call("personal", "setWallet", { "mnemonic": mnemonic, "password": password }) addr: str = bech32_encode( "mr", convertbits( bytes([0]) + RistrettoScalar(key[:32]).toPoint().serialize(), 8, 5)) if rpc.call("personal", "getAddress", {"index": index}) != addr: raise TestError("Didn't get the correct address for this index.") #Test if a specific address is requested, it won't come up naturally. #This isn't explicitly required by the RPC spec, which has been worded carefully to leave this open ended. #The only requirement is the address was never funded and the index is sequential (no moving backwards). #The node offers this feature to try to make mixing implicit/explicit addresses safer, along with some internal benefits. #That said, said internal benefits are minimal or questionable, hence why the RPC docs are open ended. #This way we can decide differently in the future. rpc.call("personal", "setWallet") firstAddr: str = rpc.call("personal", "getAddress") #Explicitly get the first address. for i in range(256): try: rpc.call("personal", "getAddress", {"index": i}) break except TestError: if i == 255: raise Exception( "The first 256 address were invalid; this should be practically impossible." ) if firstAddr == rpc.call("personal", "getAddress"): raise TestError("Explicitly grabbed address was naturally returned.") #Test error cases. #Mnemonic with an improper amount of entropy. #Runs multiple times in case the below error pops up for the sole reason the Mnemonic didn't have viable keys. #This should error earlier than that though. for _ in range(16): try: rpc.call( "personal", "setWallet", { "mnemonic": Bip39MnemonicGenerator.FromWordsNumber( Bip39WordsNum.WORDS_NUM_12) }) raise Exception() except Exception as e: if str(e) != "-3 Invalid mnemonic or password.": raise TestError( "Could set a Mnemonic with too little entropy.") #Mnemonic with additional spaces. rpc.call("personal", "setWallet") mnemonic: str = rpc.call("personal", "getMnemonic") rpc.call("personal", "setWallet", {"mnemonic": " " + (" " * 2).join(mnemonic.split(" ")) + " "}) if rpc.call("personal", "getMnemonic") != mnemonic: raise TestError( "Meros didn't handle a mnemonic with extra whitespace.") #Negative index to getAddress. try: rpc.call("personal", "getAddress", {"index": -1}) raise Exception() except Exception as e: if str(e) != "-32602 Invalid params.": raise TestError("Could call getAddress with a negative index.")
def test_from_valid_words_num(self): for test_words_num in TEST_VECT_WORDS_NUM_VALID: mnemonic = Bip39MnemonicGenerator.FromWordsNumber(test_words_num) self.assertEqual(len(mnemonic.split(" ")), test_words_num)