def __mul__(self, e): e %= self.order() if e == 0: return self._infinity pubkey = create_string_buffer(65) libsecp256k1.secp256k1_ec_pubkey_create(libsecp256k1.ctx, pubkey, c_char_p(to_bytes_32(e))) pubkey_size = c_size_t(65) pubkey_serialized = create_string_buffer(65) libsecp256k1.secp256k1_ec_pubkey_serialize( libsecp256k1.ctx, pubkey_serialized, byref(pubkey_size), pubkey, SECP256K1_EC_UNCOMPRESSED) x = from_bytes_32(pubkey_serialized[1:33]) y = from_bytes_32(pubkey_serialized[33:]) return self.Point(x, y)
def from_text(class_, text, is_compressed=True): """ This function will accept a BIP0032 wallet string, a WIF, or a bitcoin address. The "is_compressed" parameter is ignored unless a public address is passed in. """ data = a2b_hashed_base58(text) netcode, key_type = netcode_and_type_for_data(data) data = data[1:] if key_type in ("pub32", "prv32"): # TODO: fix this... it doesn't belong here from pycoin.key.BIP32Node import BIP32Node return BIP32Node.from_wallet_key(text) if key_type == 'wif': is_compressed = (len(data) > 32) if is_compressed: data = data[:-1] return Key( secret_exponent=from_bytes_32(data), prefer_uncompressed=not is_compressed, netcode=netcode) if key_type == 'address': return Key(hash160=data, is_compressed=is_compressed, netcode=netcode) raise EncodingError("unknown text: %s" % text)
def initial_key_to_master_key(initial_key): """ initial_key: a hex string of length 32 """ b = initial_key.encode("utf8") orig_input = b for i in range(100000): b = hashlib.sha256(b + orig_input).digest() return from_bytes_32(b)
def sign(self, h): """ Return a der-encoded signature for a hash h. Will throw a RuntimeError if this key is not a private key """ if not self.is_private(): raise RuntimeError("Key must be private to be able to sign") val = from_bytes_32(h) r, s = secp256k1_generator.sign(self.secret_exponent(), val) return sigencode_der(r, s)
def __init__(self, colormap, config): """Create a deterministic wallet address manager given a color map <colormap> and a configuration <config>. Note address manager configuration is in the key "hdwam". """ self.config = config self.testnet = config.get('testnet', False) self.colormap = colormap self.addresses = [] # initialize the wallet manager if this is the first time # this will generate a master key. params = config.get('hdwam', None) if params is None: params = self.init_new_wallet() # master key is stored in a separate config entry self.master_key = config['hdw_master_key'] master = hashlib.sha512(self.master_key.decode('hex')).digest() self.pycoin_wallet = BIP32Node( netcode='BTC', chain_code=master[32:], secret_exponent=from_bytes_32(master[:32]) ) self.genesis_color_sets = params['genesis_color_sets'] self.color_set_states = params['color_set_states'] # import the genesis addresses for i, color_desc_list in enumerate(self.genesis_color_sets): addr = self.get_genesis_address(i) addr.color_set = ColorSet(self.colormap, color_desc_list) self.addresses.append(addr) # now import the specific color addresses for color_set_st in self.color_set_states: color_desc_list = color_set_st['color_set'] max_index = color_set_st['max_index'] color_set = ColorSet(self.colormap, color_desc_list) params = { 'testnet': self.testnet, 'pycoin_wallet': self.pycoin_wallet, 'color_set': color_set } for index in xrange(max_index + 1): params['index'] = index self.addresses.append(BIP0032AddressRecord(**params)) # import the one-off addresses from the config for addr_params in config.get('addresses', []): addr_params['testnet'] = self.testnet addr_params['color_set'] = ColorSet(self.colormap, addr_params['color_set']) address = LooseAddressRecord(**addr_params) self.addresses.append(address)
def sign(self, secret_exponent, val, gen_k=None): nonce_function = None if gen_k is not None: k_as_bytes = to_bytes_32(gen_k(self.order(), secret_exponent, val)) def adaptor(nonce32_p, msg32_p, key32_p, algo16_p, data, attempt): nonce32_p.contents[:] = k_as_bytes return 1 p_b32 = POINTER(c_byte*32) nonce_function = CFUNCTYPE(c_int, p_b32, p_b32, p_b32, POINTER(c_byte*16), c_void_p, c_uint)(adaptor) sig = create_string_buffer(64) sig_hash_bytes = to_bytes_32(val) libsecp256k1.secp256k1_ecdsa_sign( libsecp256k1.ctx, sig, sig_hash_bytes, to_bytes_32(secret_exponent), nonce_function, None) compact_signature = create_string_buffer(64) libsecp256k1.secp256k1_ecdsa_signature_serialize_compact(libsecp256k1.ctx, compact_signature, sig) r = from_bytes_32(compact_signature[:32]) s = from_bytes_32(compact_signature[32:]) return (r, s)
def multiply(self, p, e): """Multiply a point by an integer.""" e %= self.order() if p == self._infinity or e == 0: return self._infinity pubkey = create_string_buffer(64) public_pair_bytes = b'\4' + to_bytes_32(p[0]) + to_bytes_32(p[1]) r = libsecp256k1.secp256k1_ec_pubkey_parse( libsecp256k1.ctx, pubkey, public_pair_bytes, len(public_pair_bytes)) if not r: return False r = libsecp256k1.secp256k1_ec_pubkey_tweak_mul(libsecp256k1.ctx, pubkey, to_bytes_32(e)) if not r: return self._infinity pubkey_serialized = create_string_buffer(65) pubkey_size = c_size_t(65) libsecp256k1.secp256k1_ec_pubkey_serialize( libsecp256k1.ctx, pubkey_serialized, byref(pubkey_size), pubkey, SECP256K1_EC_UNCOMPRESSED) x = from_bytes_32(pubkey_serialized[1:33]) y = from_bytes_32(pubkey_serialized[33:]) return self.Point(x, y)
def __init__(self, initial_key=None, master_private_key=None, master_public_key=None, netcode='BTC'): if [initial_key, master_private_key, master_public_key].count(None) != 2: raise ValueError( "exactly one of initial_key, master_private_key, master_public_key must be non-None") self._initial_key = initial_key self._netcode = netcode if initial_key is not None: master_private_key = initial_key_to_master_key(initial_key) pp = None if master_public_key: pp = tuple(from_bytes_32(master_public_key[idx:idx+32]) for idx in (0, 32)) super(ElectrumWallet, self).__init__(secret_exponent=master_private_key, public_pair=pp) self._master_public_key = None
def __init__(self, **kwargs): """Create a LooseAddressRecord for a given wallet <model>, color <color_set> and address <address_data>. Also let the constructor know whether it's on <testnet> (optional). <address_data> is the privKey in base58 format """ super(LooseAddressRecord, self).__init__(**kwargs) bin_privkey = a2b_hashed_base58(kwargs['address_data']) key_type = bin_privkey[0] if key_type != self.prefix: raise InvalidAddressError self.rawPrivKey = from_bytes_32(bin_privkey[1:]) self.publicPoint = BasePoint * self.rawPrivKey self.address = public_pair_to_bitcoin_address( self.publicPoint.pair(), compressed=False, is_test=self.testnet)
def __init__(self, **kwargs): """Create an address for this color <color_set> and index <index> with the master key <master_key>. The address record returned for the same three variables will be the same every time, hence "deterministic". """ super(DeterministicAddressRecord, self).__init__(**kwargs) if len(self.color_set.get_data()) == 0: color_string = "genesis block" else: color_string = self.color_set.get_hash_string() self.index = kwargs.get('index') h = hmac.new(str(kwargs['master_key']), "%s|%s" % (color_string, self.index), hashlib.sha256) string = h.digest() self.rawPrivKey = from_bytes_32(string) self.publicPoint = BasePoint * self.rawPrivKey self.address = public_pair_to_bitcoin_address(self.publicPoint.pair(), compressed=False, is_test=self.testnet)
def verify(self, h, sig): """ Return whether a signature is valid for hash h using this key. """ val = from_bytes_32(h) pubkey = self.public_pair() rs = sigdecode_der(sig) if self.public_pair() is None: # find the pubkey from the signature and see if it matches # our key possible_pubkeys = secp256k1_generator.possible_public_pairs_for_signature(val, rs) hash160 = self.hash160() for candidate in possible_pubkeys: if hash160 == public_pair_to_hash160_sec(candidate, True): pubkey = candidate break if hash160 == public_pair_to_hash160_sec(candidate, False): pubkey = candidate break else: # signature is using a pubkey that's not this key return False return secp256k1_generator.verify(pubkey, val, rs)
def subkey(self, path): """ path: of the form "K" where K is an integer index, or "K/N" where N is usually a 0 (deposit address) or 1 (change address) """ t = path.split("/") if len(t) == 2: n, for_change = t else: n, = t for_change = 0 b = (str(n) + ':' + str(for_change) + ':').encode("utf8") + self.master_public_key() offset = from_bytes_32(double_sha256(b)) if self.master_private_key(): return Key( secret_exponent=((self.master_private_key() + offset) % ORDER), prefer_uncompressed=True ) p1 = offset * ecdsa.generator_secp256k1 x, y = self.public_pair() p2 = ecdsa.Point(ecdsa.generator_secp256k1.curve(), x, y, ORDER) p = p1 + p2 return Key(public_pair=p.pair(), prefer_uncompressed=True)
def public_pair(self): if self._public_pair is None: mpk = self.master_public_key() self._public_pair = tuple( from_bytes_32(mpk[idx:idx + 32]) for idx in (0, 32)) return self._public_pair
def generate_ecc_signature(content, key): key = Key(secret_exponent=from_bytes_32(a2b_hex(key))) return b2a_hex(key.sign(double_hash256(content))).decode()
def signature_for_hash_type_segwit(self, script, tx_in_idx, hash_type): return from_bytes_32(double_sha256(self.segwit_signature_preimage(script, tx_in_idx, hash_type)))
def signature_hash(self, tx_out_script, unsigned_txs_out_idx, hash_type): """ Return the canonical hash for a transaction. We need to remove references to the signature, since it's a signature of the hash before the signature is applied. tx_out_script: the script the coins for unsigned_txs_out_idx are coming from unsigned_txs_out_idx: where to put the tx_out_script hash_type: one of SIGHASH_NONE, SIGHASH_SINGLE, SIGHASH_ALL, optionally bitwise or'ed with SIGHASH_ANYONECANPAY """ # In case concatenating two scripts ends up with two codeseparators, # or an extra one at the end, this prevents all those possible incompatibilities. tx_out_script = tools.delete_subscript(tx_out_script, int_to_bytes(opcodes.OP_HASH160)) # blank out other inputs' signatures txs_in = [self._tx_in_for_idx(i, tx_in, tx_out_script, unsigned_txs_out_idx) for i, tx_in in enumerate(self.txs_in)] txs_out = self.txs_out # Blank out some of the outputs if (hash_type & 0x1f) == self.SIGHASH_NONE: # Wildcard payee txs_out = [] # Let the others update at will for i in range(len(txs_in)): if i != unsigned_txs_out_idx: txs_in[i].sequence = 0 elif (hash_type & 0x1f) == self.SIGHASH_SINGLE: # This preserves the ability to validate existing legacy # transactions which followed a buggy path in Satoshi's # original code; note that higher level functions for signing # new transactions (e.g., is_signature_ok and sign_tx_in) # check to make sure we never get here (or at least they # should) if unsigned_txs_out_idx >= len(txs_out): # This should probably be moved to a constant, but the # likelihood of ever getting here is already really small # and getting smaller return (1 << 248) # Only lock in the TransactionOut payee at same index as TransactionIn; delete # any outputs after this one and set all outputs before this # one to "null" (where "null" means an empty script and a # value of -1) txs_out = [self.TransactionOut(0xffffffffffffffff, b'')] * unsigned_txs_out_idx txs_out.append(self.txs_out[unsigned_txs_out_idx]) # Let the others update at will for i in range(len(self.txs_in)): if i != unsigned_txs_out_idx: txs_in[i].sequence = 0 # Blank out other inputs completely, not recommended for open transactions if hash_type & self.SIGHASH_ANYONECANPAY: txs_in = [txs_in[unsigned_txs_out_idx]] tmp_tx = self.__class__(self.version, txs_in, txs_out, self.lock_time) return from_bytes_32(tmp_tx.hash(hash_type=hash_type))
def test_generate(mode, pdf, dev, cap_menu, pick_menu_item, goto_home, cap_story, need_keypress, microsd_path): # test UX and operation of the 'bitcoin core' wallet export mx = "Don't make PDF" goto_home() pick_menu_item('Advanced') try: pick_menu_item('Paper Wallets') except: raise pytest.skip('Feature absent') time.sleep(0.1) title, story = cap_story() assert 'pick a random' in story assert 'MANY RISKS' in story need_keypress('y') time.sleep(0.1) if mode == 'segwit': pick_menu_item('Classic Address') pick_menu_item('Segwit/Bech32') time.sleep(0.5) if pdf: assert mx in cap_menu() shutil.copy('../docs/paperwallet.pdf', microsd_path('paperwallet.pdf')) pick_menu_item(mx) need_keypress('y') time.sleep(0.1) title, story = cap_story() assert 'Pick PDF' in story pick_menu_item('paperwallet.pdf') pick_menu_item('GENERATE WALLET') time.sleep(0.1) title, story = cap_story() assert 'Created file' in story story = [i for i in story.split('\n') if i] if not pdf: fname = story[-1] else: fname = story[-2] pdf_name = story[-1] assert pdf_name.endswith('.pdf') assert fname.endswith('.txt') path = microsd_path(fname) with open(path, 'rt') as fp: hdr = None for ln in fp: ln = ln.rstrip() if not ln: continue if ln[0] != ' ': hdr = ln continue if '█' in ln: continue val = ln.strip() if 'Deposit address' in hdr: assert val == fname.split('.', 1)[0].split('-', 1)[0] txt_addr = val if mode != 'segwit': addr = Key.from_text(val) else: hrp, data = bech32_decode(val) decoded = convertbits(data[1:], 5, 8, False)[-20:] assert hrp in {'tb', 'bc' } addr = Key(hash160=bytes(decoded), is_compressed=True, netcode='XTN') elif hdr == 'Private key:': # for QR case assert val == wif elif 'Private key' in hdr and 'WIF=Wallet' in hdr: wif = val k1 = Key.from_text(val) elif 'Private key' in hdr and 'Hex, 32 bytes' in hdr: k2 = Key(secret_exponent=from_bytes_32(a2b_hex(val)), is_compressed=True) elif 'Bitcoin Core command': assert wif in val assert 'importmulti' in val or 'importprivkey' in val else: print(f'{hdr} => {val}') raise ValueError(hdr) assert k1.sec() == k2.sec() assert k1.public_pair() == k2.public_pair() assert addr.address() == k1.address() os.unlink(path) if not pdf: return path = microsd_path(pdf_name) with open(path, 'rb') as fp: d = fp.read() assert wif.encode('ascii') in d assert txt_addr.encode('ascii') in d os.unlink(path)
def public_pair(self): if self._public_pair is None: mpk = self.master_public_key() self._public_pair = tuple(from_bytes_32(mpk[idx:idx+32]) for idx in (0, 32)) return self._public_pair
def octetStringtoInteger(octetstring): ## use pycoin.encoding to translate for now return from_bytes_32(octetstring)
def test_raw_to_address(self): privkey = from_bytes_32(a2b_hashed_base58(self.address)[1:]) pubkey = BasePoint * privkey raw = public_pair_to_hash160_sec(pubkey.pair(), False) addr = self.ccc.raw_to_address(raw) self.assertEqual(addr,'1CC3X2gu58d6wXUWMffpuzN9JAfTUWu4Kj')