def from_base58(cls, encoded): """ Creates a new HDNode from a extended key (xpub/xpriv) :param encoded: a base58check string :return: a new HDNode object """ buffer = base58.b58decode_check(encoded) if len(buffer) != 78: raise ValueError("Invalid argument") version = int.from_bytes(buffer[:4], "big") n = [ x for x in Network.get_supported_networks() if version in [x.version_pub, x.version_priv] ] if not n: raise ValueError("Network not supported") network = n[0] depth = buffer[4] parent_fingerprint = int.from_bytes(buffer[5:9], "big") index = int.from_bytes(buffer[9:13], "big") chain_code = buffer[13:45] key = buffer[45:] if version == network.version_pub: key_pair = ECPair(None, pubkey_buffer=key, network=network) else: #validate key[0] == 0x00 key_pair = ECPair(key[1:], None, network=network) return cls(key_pair, chain_code, depth=depth, index=index, parent_fingerprint=parent_fingerprint)
def derive(self, index): """ Child Extended Key Derivation. Given the parent extended key and an index, computes the corresponding child extended key. :param index: index for derivation :return: HDNode child """ buffer = b"" network = self.keypair.network hardened = index >= HARDENED_BIT if hardened: # hardened derivation if self.is_neutered(): raise RuntimeError( "Neutered node cannot derive hardnened child") buffer += b"\x00" buffer += self.keypair.privkey_buffer buffer += index.to_bytes(4, "big") else: # normal derivation buffer += self.keypair.pubkey_buffer buffer += index.to_bytes(4, "big") i = hashutils.hmac_sha512(self.chain_code, buffer) il = i[:32] # key ir = i[32:] # chaincode parse256_il = int.from_bytes(il, "big") # parse256(IL) # In case parse256(IL) >= n if parse256_il >= ecutils.ORDER: return self.derive(index + 1) if self.is_neutered(): # Public parent key ---> public child key try: pubkey_buf = ecutils.combine_pubkeys( parse256_il, self.keypair.pubkey_buffer) except ValueError: # POINT AT INFINITY return self.derive(index + 1) derived = ECPair(None, pubkey_buf, network=network) else: # private parent key ---> private child key new_key = (parse256_il + self.keypair.privkey) % ecutils.ORDER if new_key == 0: return self.derive(index + 1) derived = ECPair(new_key.to_bytes(32, "big"), None, network=network) return self.__class__(derived, chaincode=ir, depth=self.depth + 1, index=index, parent_fingerprint=int.from_bytes( self.get_fingerprint(), "big"))
def test_msg2(self): m = b"A purely peer-to-peer version of electronic cash would allow " \ b"online payments" r = 53416277923213062165260564277038918077705079659558875401218116132761110201958 s = 86605321333558372720412441800808448223714537838874906966097860970072205178705 ecpair = ECPair(privkey='45d0475126e983f3162c98b73d93585e9c7be66220ba1e95dae87bbbff2fb40e') self.assertVerify(ecpair.pubkey_buffer, r, s, m)
def test_msg3(self): m = b"What is needed is an electronic payment system based on " \ b"cryptographic proof instead of trust" r = 68734943327797312301443474635907363454601483827607971122239706615210184455578 s = 101235560920937280916292394003527251888819329338326063465504738929993008856598 ecpair = ECPair(privkey='eb2bc889499f757cc135bd2da7aea647b3132a2dd330d1ed033d731a4cf2a737') self.assertVerify(ecpair.pubkey_buffer, r, s, m)
def test_msg1(self): # https://kjur.github.io/jsrsasign/sample/sample-ecdsa.html m = b"Bitcoin: A Peer-to-Peer Electronic Cash System" r = 16585169871999922969978897389792393736153195404500074220463475545187239063880 s = 101989596681849864701598391615792467471854786825375833846457837318456308008154 ecpair = ECPair(privkey='73d286994b2ac1a0f160fb45816c1dd6605551eb0ea12d5595a440a3665ef89d') self.assertVerify(ecpair.pubkey_buffer, r, s, m)
def test_to_wif_compressed_testnet(self): ecpair = ECPair( 'ba8c65b5e47143979b3506a742b4bd95c1ddb419195915c3679e38e9bffbeb45', network=BITCOIN_TESTNET) self.assertEqual( ecpair.to_wif(), 'cTqKweNhVkMznPiVgucDxYxer9qWDW3dY7xKq2JPbFgoQK8xhYqi')
def test_to_wif_uncompressed(self): ecpair_uncomp = ECPair( 'ba8c65b5e47143979b3506a742b4bd95c1ddb419195915c3679e38e9bffbeb45', compressed=False) self.assertEqual( ecpair_uncomp.to_wif(), '5KESiB48wksvA4141nwrJGjjC5szu81fd3T2J8SaKqVW2zmxdCr')
def test_to_wif_uncompressed_testnet(self): ecpair_uncomp = ECPair( 'ba8c65b5e47143979b3506a742b4bd95c1ddb419195915c3679e38e9bffbeb45', network=BITCOIN_TESTNET, compressed=False) self.assertEqual( ecpair_uncomp.to_wif(), '9315HusgXyx487WLe8qmAsHgqkEi4HYrxzJyNko5faEYp1dL1wL')
def test_constructor_invalid_fingerprint(self): privkey_hexa = "4ccbf2a1c6ee9a5106cb19c6be343947701a4e4acb2c4311f5"\ "a10836109711a1" number = int(privkey_hexa, 16) ecpair = ECPair(number) with self.assertRaises(ValueError): HDNode(ecpair, chaincode=b'\x1a\xbe\xc1YTQ\xa3\xe7\xb5\xfet' b'\xad5)\x06\x99\x81x,R\xd7L\x1e$\x10' b'\xc4\xf5\x1e\xa2\x08oO', depth=0, index=0, parent_fingerprint=123)
def neutered(self): """ Returns a new node without the private key. (Removes the privkey) :return: a neutered HDNode """ pub_key_buffer = self.keypair.pubkey_buffer # removing private key new_ecpair = ECPair(None, pub_key_buffer, network=self.keypair.network) return self.__class__(new_ecpair, self.chain_code, self.depth, self.index, self.parent_fingerprint)
def from_seed(cls, seed_bytes, network=DEFAULT_NETWORK): """ Creates a new HDNode from a bip39 seed :param seed_bytes: binary bip39 seed :param network: Network object :return: new HDNode object """ h = hashutils.hmac_sha512(BITCOIN_SEED, seed_bytes) privkey = h[:32] # left chaincode = h[32:] # right return cls(ECPair(privkey, network=network), chaincode)
def test_msg4(self): m = b"Maarten Bodewes generated this test vector on 2016-11-08" r = int('241097efbf8b63bf145c8961dbdf10c310efbb3b2676bbc0f8b08505c9e2f795', 16) s = int('021006b7838609339e8b415a7f9acb1b661828131aef1ecbc7955dfb01f3ca0e', 16) ecpair = ECPair(privkey='ebb2c082fd7727890a28ac82f6bdf97bad8de9f5d7c9028692de1a255cad3e0f') self.assertVerify(ecpair.pubkey_buffer, r, s, m)
def test_create_bytes(self): number = int(PRIVKEY_HEXA, 16) b = number.to_bytes(32, "big") self.assertEqual(ECPair(b).privkey_buffer, b)
def test_privkey_compressed_none(self): ecpair = ECPair(PRIVKEY_HEXA, compressed=None) self.assertTrue(ecpair.compressed)
def test_to_wif_compressed(self): ecpair = ECPair( 'ba8c65b5e47143979b3506a742b4bd95c1ddb419195915c3679e38e9bffbeb45') self.assertEqual( ecpair.to_wif(), 'L3ULUjNr4gfjcxFEJVo6bETbDvY6Z3wwU5oribqt692o9a5SHV2R')
def test_unsupported_network(self): with self.assertRaises(ValueError): ECPair(PRIVKEY_HEXA, network=Network('a', 'b', 'c', 'd', 'e'))
def test_arg_invalid_privkey(self): with self.assertRaises(ValueError): ecpair = ECPair([], compressed=True) with self.assertRaises(ValueError): ecpair = ECPair(bytes(random.getrandbits(8) for _ in range(35)), compressed=True)
def test_pubkey_uncompressed(self): ecpair = ECPair(None, pubkey_buffer=UNCOMPRESSED_PUBKEY) self.assertIsNotNone(ecpair) self.assertFalse(ecpair.compressed)
def test_create_pass_both_keys(self): number = int(PRIVKEY_HEXA, 16) b = number.to_bytes(32, "big") with self.assertRaises(ValueError): ECPair(b, COMPRESSED_PUBKEY)
def test_pubkey_invalid_type(self): with self.assertRaises(ValueError): ECPair(None, pubkey_buffer='a')
def test_pubkey_ignore_compressed_passed(self): ecpair2 = ECPair(None, pubkey_buffer=COMPRESSED_PUBKEY, compressed=False) self.assertIsNotNone(ecpair2) self.assertTrue(ecpair2.compressed)
def test_no_keys(self): with self.assertRaises(ValueError): ECPair(None, pubkey_buffer=None)
def test_create_from_int(self): number = int(PRIVKEY_HEXA, 16) ecpair = ECPair(number) self.assertEqual(ecpair.privkey_buffer, number.to_bytes(32, "big"))
def test_arg_compressed_false(self): ecpair = ECPair(True, compressed=False) self.assertIsNotNone(ecpair)
def test_sign_no_privkey(self): wif = 'KzHvGCQJWGr3NT8L83Kpj6KK245QTKeXPy1jGV14LRWd1XA74Ngy' ecpair = ECPair.from_wif(wif) neutered_ecpair = ECPair(None, ecpair.pubkey_buffer) with self.assertRaises(RuntimeError): neutered_ecpair.sign(sha256(b'test'))
def test_arg_compressed_true(self): ecpair = ECPair(PRIVKEY_HEXA, compressed=True) self.assertIsNotNone(ecpair)
def test_to_wif_no_privkey(self): ecpair = ECPair(None, pubkey_buffer=COMPRESSED_PUBKEY) with self.assertRaises(RuntimeError): ecpair.to_wif()
def test_to_str(self): ecpair = ECPair(PRIVKEY_HEXA, compressed=True) a = "{}".format(ecpair)
def test_arg_compressed_invalid(self): with self.assertRaises(ValueError): ecpair = ECPair(PRIVKEY_HEXA, compressed=1)
def test_no_network(self): with self.assertRaises(ValueError): ECPair(PRIVKEY_HEXA, network=None)