def to_seed(self, words, password='', validate=True): """ Use Mnemonic words and optionally a password to create a PBKDF2 seed (Password-Based Key Derivation Function 2) First use 'sanitize_mnemonic' to determine language and validate and check words >>> from bitcoinlib.encoding import to_hexstring >>> to_hexstring(Mnemonic().to_seed('chunk gun celery million wood kite tackle twenty story episode raccoon dutch')) '6969ed4666db67fc74fae7869e2acf3c766b5ef95f5e31eb2fcebd93d76069c6de971225f700042b0b513f0ad6c8562277fc4b5ee1344b720f1686dc2dccc220' :param words: Mnemonic passphrase as string with space separated words :type words: str :param password: A password to protect key, leave empty to disable :type password: str :param validate: Validate checksum for given word phrase, default is True :type validate: bool :return bytes: PBKDF2 seed """ words = self.sanitize_mnemonic(words) # Check if passphrase is valid if validate: self.to_entropy(words) mnemonic = to_bytes(words) password = to_bytes(password) return hashlib.pbkdf2_hmac(hash_name='sha512', password=mnemonic, salt=b'mnemonic' + password, iterations=2048)
def to_mnemonic(self, data, add_checksum=True, check_on_curve=True): """ Convert key data entropy to Mnemonic sentence >>> Mnemonic().to_mnemonic('28acfc94465fd2f6774759d6897ec122') 'chunk gun celery million wood kite tackle twenty story episode raccoon dutch' :param data: Key data entropy :type data: bytes, hexstring :param add_checksum: Included a checksum? Default is True :type add_checksum: bool :param check_on_curve: Check if data integer value is on secp256k1 curve. Should be enabled when not testing and working with crypto :type check_on_curve: bool :return str: Mnemonic passphrase consisting of a space seperated list of words """ data = to_bytes(data) data_int = change_base(data, 256, 10) if check_on_curve and not 0 < data_int < secp256k1_n: raise ValueError( "Integer value of data should be in secp256k1 domain between 1 and secp256k1_n-1" ) if add_checksum: binresult = change_base(data_int, 10, 2, len(data) * 8) + self.checksum(data) wi = change_base(binresult, 2, 2048) else: wi = change_base(data_int, 10, 2048, len(data) // 1.375 + len(data) % 1.375 > 0) return normalize_string(' '.join([self._wordlist[i] for i in wi]))
def sendrawtransaction(self, rawtx): """ Dummy method to send transactions on the bitcoinlib testnet. The bitcoinlib testnet does not exists, so it just returns the transaction hash. :param rawtx: A raw transaction hash :type rawtx: bytes, str :return str: Transaction hash """ txid = to_hexstring(hashlib.sha256(hashlib.sha256(to_bytes(rawtx)).digest()).digest()[::-1]) return { 'txid': txid, 'response_dict': {} }
def checksum(data): """ Calculates checksum for given data key :param data: key string :type data: bytes, hexstring :return str: Checksum of key in bits """ data = to_bytes(data) if len(data) % 4 > 0: raise ValueError( 'Data length in bits should be divisible by 32, but it is not (%d bytes = %d bits).' % (len(data), len(data) * 8)) key_hash = hashlib.sha256(data).digest() return change_base(key_hash, 256, 2, 256)[:len(data) * 8 // 32]
def wif_prefix(self, is_private=False, witness_type='legacy', multisig=False): """ Get WIF prefix for this network and specifications in arguments >>> Network('bitcoin').wif_prefix() # xpub b'\\x04\\x88\\xb2\\x1e' >>> Network('bitcoin').wif_prefix(is_private=True, witness_type='segwit', multisig=True) # Zprv b'\\x02\\xaaz\\x99' :param is_private: Private or public key, default is True :type is_private: bool :param witness_type: Legacy, segwit or p2sh-segwit :type witness_type: str :param multisig: Multisignature or single signature wallet. Default is False: no multisig :type multisig: bool :return bytes: """ script_type = script_type_default(witness_type, multisig, locking_script=True) if script_type == 'p2sh' and witness_type in ['p2sh-segwit', 'segwit']: script_type = 'p2sh_p2wsh' if multisig else 'p2sh_p2wpkh' if is_private: ip = 'private' else: ip = 'public' found_prefixes = [ to_bytes(pf[0]) for pf in self.prefixes_wif if pf[2] == ip and script_type == pf[5] ] if found_prefixes: return found_prefixes[0] else: raise NetworkError("WIF Prefix for script type %s not found" % script_type)