def pk_scriptdecompress(pk): # https://github.com/bitcoin/bitcoin/blob/5961b23898ee7c0af2626c46d5d70e80136578d3/src/compressor.cpp#L118 xpk = bytes(bytearray([pk[0] - 2]) + pk[1:]) pk = CPubKey(xpk) cec = CECKey() cec.set_compressed(True) res = cec.set_pubkey(pk) if res is None: raise Exception(ssl_get_error()) cec.set_compressed(False) pubkey = cec.get_pubkey() return CPubKey(pubkey, _cec_key=cec)
def get_public_key(self, f="b64", public_key=None): if public_key == None: public_key = self.public_key #O4 = uncompressed. public_key_hex = "04" + binascii.hexlify(public_key).decode("utf-8") if self.use_compression: public_key = binascii.unhexlify(public_key_hex) public_key = self.compress_public_key(public_key) public_key_hex = binascii.hexlify(public_key).decode("utf-8") else: public_key = binascii.unhexlify(public_key_hex) cpub = CPubKey(x(public_key_hex)) if f == "bin": return public_key elif f == "hex": return public_key_hex elif f == "cpub": return cpub elif f == "hash": return Hash160(cpub) else: return base64.b64encode(public_key).decode("utf-8")
def analyze_key_pair(key_pair): """ Converts a key pair to different formats which is useful for working with Bitcoin Script. """ if "priv" not in key_pair: key_pair["priv"] = None pub = CPubKey(x(key_pair["pub"])) addr = None if "addr" in key_pair: addr = key_pair["addr"] """ The Hash160 function in Python-bitcoin lib actually wraps around sha256 hash so every call to Hash160 also sha256 hashes the input before ripemd160 hashing, meaning it the output is valid for address hashes. """ return { "addr": { "base58": addr }, "pub": { "hash": Hash160(pub), "hex": key_pair["pub"], "bin": pub }, "priv": { "wif": key_pair["priv"], "hex": None, "bin": None } }
def test_from_valid_pubkey(self): """Create P2PKHBitcoinAddress's from valid pubkeys""" def T(pubkey, expected_str_addr): addr = P2PKHBitcoinAddress.from_pubkey(pubkey) self.assertEqual(str(addr), expected_str_addr) T(x('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71'), '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') T(x('0478d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71a1518063243acd4dfe96b66e3f2ec8013c8e072cd09b3834a19f81f659cc3455'), '1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T') T(CPubKey(x('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71')), '1C7zdTfnkzmr13HfA2vNm5SJYRK6nEKyq8') T(CPubKey(x('0478d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c71a1518063243acd4dfe96b66e3f2ec8013c8e072cd09b3834a19f81f659cc3455')), '1JwSSubhmg6iPtRjtyqhUYYH7bZg3Lfy1T')
def test_from_invalid_pubkeys(self): """Create P2PKHBitcoinAddress's from invalid pubkeys""" # first test with accept_invalid=True def T(invalid_pubkey, expected_str_addr): addr = P2PKHBitcoinAddress.from_pubkey(invalid_pubkey, accept_invalid=True) self.assertEqual(str(addr), expected_str_addr) T(x(''), '1HT7xU2Ngenf7D4yocz2SAcnNLW7rK8d4E') T( x('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c72' ), '1L9V4NXbNtZsLjrD3nkU7gtEYLWRBWXLiZ') # With accept_invalid=False we should get CBitcoinAddressError's with self.assertRaises(CBitcoinAddressError): P2PKHBitcoinAddress.from_pubkey(x('')) with self.assertRaises(CBitcoinAddressError): P2PKHBitcoinAddress.from_pubkey( x('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c72' )) with self.assertRaises(CBitcoinAddressError): P2PKHBitcoinAddress.from_pubkey( CPubKey( x('0378d430274f8c5ec1321338151e9f27f4c676a008bdf8638d07c0b6be9ab35c72' )))
def VerifyMessage(address, message, sig): sig = base64.b64decode(sig) hash = message.GetHash() pubkey = CPubKey.recover_compact(hash, sig) return str(P2PKHBitcoinAddress.from_pubkey(pubkey)) == str(address)
def __init__(self, data): if isinstance(data, str): data = bytearray.fromhex(data) if isinstance(data, bytearray): data = bytes(data) if not isinstance(data, bytes): raise ValueError( 'PubKey can be constructed only from either hex string, bytearray or byte data' ) object.__setattr__(self, 'cpubkey', CPubKey(data))
def make_fully_valid(pubkey): assert len(pubkey) == 31 # One sign byte and one nonce byte required (for 33 bytes). cpubkey = CPubKey(b'') random_bytes = hashlib.sha256(pubkey).digest() # Deterministically generated, for unit tests. sign = (random_bytes[0] & 0b1) + 2 # 0x02 or 0x03 nonce = initial_nonce = random_bytes[1] while not cpubkey.is_fullyvalid: # Increment nonce. nonce += 1 assert nonce != initial_nonce # Construct a possibly fully valid public key. possibly_fully_valid_pubkey = bytes([sign]) + pubkey + bytes([nonce % 256]) cpubkey = CPubKey(possibly_fully_valid_pubkey) fully_valid_pubkey = possibly_fully_valid_pubkey assert len(fully_valid_pubkey) == 33 return fully_valid_pubkey
def format_variable_value(value, var_type): """Returns a 2-tuple of (is_valid, formatted_value).""" if var_type == 'address': try: h160 = CBase58Data(value).to_bytes() except Exception: # Check if value is a hash160. if is_hex(value) and len( format_hex_string(value, with_prefix=False)) == 40: h160 = format_hex_string(value, with_prefix=False).decode('hex') else: return False, 'Error: Could not decode address.' return True, '0x' + h160.encode('hex') elif var_type == 'pubkey': if not is_hex(value): return False, 'Error: Pubkey must be hex.' key_hex = format_hex_string(value, with_prefix=False) pub = CPubKey(key_hex.decode('hex')) if not pub.is_fullyvalid: return False, 'Error: Pubkey is invalid.' return True, '0x' + key_hex elif var_type == 'text': try: return True, '0x' + value.encode('hex') except Exception as e: return False, 'Error: ' + str(e) elif var_type == 'signature': if not is_hex(value): return False, 'Error: Signature must be hex.' # We remain algorithm-agnostic by not checking the length. return True, format_hex_string(value, with_prefix=True) elif var_type == 'script': if not is_hex(value): try: scr = Script.from_human(value) return True, format_hex_string(scr.get_hex(), with_prefix=True) except Exception: return False, 'Error: Cannot parse human-readable script.' try: scr = Script( format_hex_string(value, with_prefix=False).decode('hex')) return True, format_hex_string(value, with_prefix=True) except Exception: return False, 'Error: Cannot parse script.' return True, value
def is_valid(self): mb = BitcoinMessage(self.message) sig = base64.b64decode(self.sig) message_hash = mb.GetHash() #print("hash: %s" % message_hash.hex()) pubkey = CPubKey.recover_compact(message_hash, sig) if not pubkey: return False #print("pubkey: %s" % pubkey.hex()) if pubkey.hex() == self.address: return True for txin_type in ['p2pkh', 'p2wpkh', 'p2wpkh-p2sh']: addr = pubkey_to_address(txin_type, pubkey.hex()) if addr == str(self.address): return True return False
def createTransaction(txid, vout, value, output_address, escrow_index, state): """ Create an transaction from an escrow address, defined by a previous txid, to the output address """ # This will be the return value, a little indirection to not return a Share. tx_deferred = Deferred() def _fire_response(tx): tx_deferred.callback(tx) return def _signatureCallback(signature, shares, hash, transaction): return signature def _computeSignatureShare(hash): def _get_R(R_deferred): R = R_deferred.x() return R def _compute_summand2(R, k_inv_d_share): summand2 = ConstantMultiplicationSmpcValue(state) summand2_deferred = summand2.initialize(R, k_inv_d_share) return summand2_deferred def _final_sum(deferreds): global transaction_ctr summand1 = WrapperSmpcValue(state) summand2 = WrapperSmpcValue(state) summand1.initialize(deferreds[0][1]) summand2.initialize(deferreds[1][1]) s = AdditionSmpcValue( state) # add secret values of summand1, summand2 (see below) s_deferred = s.initialize(summand1, summand2) return s_deferred # Set parameters for creating the share of the signature e = int(hexlify(hash), 16) kG_deferred = state.smpc.getValue('k', escrow_index).getPublicValue() R = state.smpc.getValue('k', escrow_index).getPublicValue() k_inv_share = state.smpc.getValue('ki', escrow_index) k_inv_d_share = state.smpc.getValue('kid', escrow_index) """ Calculation to be performed: S_share = e * k_inv_share + R * k_inv_d_share """ try: summand1 = ConstantMultiplicationSmpcValue(state) summand1_deferred = summand1.initialize(e, k_inv_share) kG_deferred.addCallback(_get_R) kG_deferred.addCallback(_compute_summand2, k_inv_d_share=k_inv_d_share) R.addCallback(_get_R) S_share = DeferredList([summand1_deferred, kG_deferred]) S_share.addCallback(_final_sum) return (S_share, R) except BaseException as ex: log.critical('Error in signature generation! Error: ' + str(ex)) raise RuntimeError('signing_share_failed') def _signatureToDER(S, R): S_der = der.encode_integer(int(S)) R_der = der.encode_integer(int(R)) signature_der = der.encode_sequence(R_der, S_der) + chr(0x01) return signature_der def _reconstruct_signature(S_share): try: global transaction_ctr final_sum = WrapperSmpcValue(state) final_sum.initialize(S_share) S = state.smpc.newValue('rec', state, 'S', transaction_ctr) return S.initialize(final_sum) except BaseException as e: log.critical('S reconstruction failed! ' + str(e)) raise RuntimeError('signing_reconstruct_failed') def _computeSignature(S_share_R): S_share = S_share_R[0][1] R = S_share_R[1][1] def _extract_signature(_): global transaction_ctr signature = state.smpc.getValue('S', transaction_ctr).getPublicValue() transaction_ctr += 1 return signature signature = _reconstruct_signature(S_share) signature.addCallback(_extract_signature) signature.addCallback(_signatureToDER, R=R) return signature def _computeTransaction(signature, tx, script_pubkey, pubkey): txin = tx.vin[0] txin.scriptSig = bc.core.script.CScript([signature, pubkey]) try: VerifyScript(txin.scriptSig, script_pubkey, tx, 0, (bc.core.scripteval.SCRIPT_VERIFY_P2SH, )) except BaseException as e: log.error(str(e)) raise RuntimeError('signing_failed') transaction_serialized = bc.core.b2x(tx.serialize()) return transaction_serialized cpub = CPubKey(state.input.getInputPeer('id', escrow_index)['pubkey']) txid = bc.core.lx(txid) # TXIN information txin = bc.core.CMutableTxIn(bc.core.COutPoint(txid, vout)) txin_scriptPubKey = bc.core.script.CScript([ bc.core.script.OP_DUP, bc.core.script.OP_HASH160, bc.core.Hash160(cpub), bc.core.script.OP_EQUALVERIFY, bc.core.script.OP_CHECKSIG ]) # TXOUT information txout = bc.core.CMutableTxOut( int(value * bc.core.COIN), CBitcoinAddress(output_address).to_scriptPubKey()) # Create unsigned transaction tx = bc.core.CMutableTransaction([txin], [txout]) # Create signature hash sighash = bc.core.script.SignatureHash(txin_scriptPubKey, tx, 0, bc.core.script.SIGHASH_ALL) (S_share, R) = _computeSignatureShare(sighash) deferreds = DeferredList([S_share, R]) deferreds.addCallback(_computeSignature) deferreds.addCallback(_computeTransaction, tx=tx, script_pubkey=txin_scriptPubKey, pubkey=cpub) deferreds.addCallback(_fire_response) return tx_deferred
def is_fully_valid(pubkey_bin): """Check if the public key is valid.""" cpubkey = CPubKey(pubkey_bin) return cpubkey.is_fullyvalid
data = json.load(data_file) pprint(data) pprint(data['va']) parts = data['va'].split('|') pprint(parts) msg = parts[0] sig = parts[2] pprint(sig) sig = sig + "===" pprint(sig) sig = base64.b64decode(sig, '-_') msg = BitcoinMessage(msg) hash = msg.GetHash() pubkey = CPubKey.recover_compact(hash, sig) pprint(pubkey) hex_bytes = binascii.hexlify(pubkey) pprint(hex_bytes) print('\n\n') print('Address:') print(data['ad']) print('Pubkey:') hex_str = hex_bytes.decode("ascii") print(hex_str)
def initialize(private_key=None): """ Setup and initialize a new vault in the current working directory. This is the primary entrypoint for the prototype. """ check_vaultfile_existence() check_private_key_is_conformant(private_key) #amount = random.randrange(0, 100 * COIN) #amount = 7084449357 amount = 2 * COIN # TODO: A more sophisticated private key system is required, for any real # production use. some_private_keys = [CBitcoinSecret(private_key)] * 6 parameter_names = [ "user_key", "ephemeral_key_1", "ephemeral_key_2", "cold_key1", "cold_key2", "hot_wallet_key", ] parameters = { "num_shards": 5, "enable_burn_transactions": True, "enable_graphviz": True, "enable_graphviz_popup": False, "amount": amount, "unspendable_key_1": CPubKey( x("0279be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798" )), } for some_name in parameter_names: private_key = some_private_keys.pop() public_key = private_key.pub parameters[some_name] = { "private_key": private_key, "public_key": public_key } parameters["user_key_hash160"] = b2x( Hash160(parameters["user_key"]["public_key"])) # consistency check against required parameters required_parameters = ScriptTemplate.get_required_parameters() missing_parameters = False for required_parameter in required_parameters: if required_parameter not in parameters.keys(): logger.error(f"Missing parameter: {required_parameter}") missing_parameters = True if missing_parameters: logger.error("Missing parameters!") sys.exit(1) # connect to bitcoind (ideally, regtest) connection = get_bitcoin_rpc_connection() # setup the user private key (for P2WPKH) connection._call("importprivkey", str(parameters["user_key"]["private_key"]), "user") # Mine some coins into the "user_key" P2WPKH address #user_address = "bcrt1qrnwea7zc93l5wh77y832wzg3cllmcquqeal7f5" # parsed_address = P2WPKHBitcoinAddress(user_address) user_address = P2WPKHBitcoinAddress.from_scriptPubKey( CScript([OP_0, Hash160(parameters["user_key"]["public_key"])])) blocks = 110 if connection._call("getblockchaininfo")["blocks"] < blocks: try: connection._call("sendtoaddress", user_address, 50) except Exception: pass connection._call("generatetoaddress", blocks, str(user_address)) # Now find an unspent UTXO. unspent = connection._call("listunspent", 6, 9999, [str(user_address)], True, {"minimumAmount": amount / COIN}) if len(unspent) == 0: raise VaultException( "can't find a good UTXO for amount {}".format(amount)) # pick the first UTXO utxo_details = unspent[0] txid = utxo_details["txid"] # have to consume the whole UTXO amount = int(utxo_details["amount"] * COIN) initial_tx_txid = lx(utxo_details["txid"]) initial_tx = InitialTransaction(txid=initial_tx_txid) segwit_utxo = PlannedUTXO( name="segwit input coin", transaction=initial_tx, script_template=UserScriptTemplate, amount=amount, ) segwit_utxo._vout_override = utxo_details["vout"] initial_tx.output_utxos = [segwit_utxo] # for establishing vout # =============== # Here's where the magic happens. vault_initial_utxo = setup_vault(segwit_utxo, parameters) # =============== # Check that the tree is conforming to applicable rules. safety_check(segwit_utxo.transaction) # To test that the sharded UTXOs have the right amounts, do the following: # assert (second_utxo_amount * 99) + first_utxo_amount == amount # Display all UTXOs and transactions-- render the tree of possible # transactions. Mostly helpful for debugging purposes. render_planned_tree_to_text_file(segwit_utxo, filename=TEXT_RENDERING_FILENAME) # stats logger.info("*** Stats and numbers") logger.info( f"{PlannedUTXO.__counter__} UTXOs, {PlannedTransaction.__counter__} transactions" ) sign_transaction_tree(segwit_utxo, parameters) save(segwit_utxo) # TODO: Delete the ephemeral keys. # (graph generation can wait until after key deletion) if parameters["enable_graphviz"] == True: generate_graphviz(segwit_utxo, parameters, output_filename="output.gv") # Create another planned transaction tree this time using # OP_CHECKTEMPLATEVERIFY from bip119. This can be performed after key # deletion because OP_CTV standard template hashes are not based on keys # and signatures. make_planned_transaction_tree_using_bip119_OP_CHECKTEMPLATEVERIFY( initial_tx, parameters=parameters) save(segwit_utxo, filename="transaction-store.ctv.json") # A vault has been established. Write the vaultfile. make_vaultfile()
def is_fully_valid(pubkey_bin): cpubkey = CPubKey(pubkey_bin) return cpubkey.is_fullyvalid
{'buyerurlhash': "906618b107da70ed301d701ce8dbff533f35812d"}) phrase = "sample core fitness wrong unusual inch hurry chaos myself credit welcome margin" seed = mnemonic.Mnemonic.to_seed(phrase) wallet = BIP32Node.from_master_secret(seed, 'XTN') toddkeys = [] keys = [] for k in escrow['keys']: print k['subkey'] hdkey = wallet.subkey_for_path(k['subkey']) print b2x(CKey(hdkey.sec()).pub) print hdkey.sec_as_hex() print k['publickey'] print "" toddkeys.append(CKey(hdkey.sec())) keys.append(CPubKey(hdkey.address())) """ keys = [] for pubkey in escrow['keys']: print "PUBLIC KEY", pubkey['publickey'] keys.append(CPubKey(pubkey['publickey'])) """ # Create a redeemScript. Similar to a scriptPubKey the redeemScript must be # satisfied for the funds to be spent. redeemScript = CScript(keys) print(b2x(redeemScript)) # Create the magic P2SH scriptPubKey format from that redeemScript. You should # look at the CScript.to_p2sh_scriptPubKey() function in bitcoin.core.script to # understand what's happening, as well as read BIP16:
def hodl_redeemScript(pubkey, nLockTime): publicKey = CPubKey(x(pubkey)) return CScript([nLockTime, OP_NOP2, OP_DROP, publicKey, OP_CHECKSIG])
addr_uncompressed, allowable_prefixes=my_pubaddr_prefix)) print() ## Uncompressed public key pubkey_bytes = encoding.public_pair_to_sec(pubkey_pair, False) # uncompressed pubkey_b58 = encoding.b2a_base58(pubkey_bytes) assert (pubkey_bytes == encoding.a2b_base58(pubkey_b58)) btc_addr = CBitcoinAddress.from_bytes( pubkey_bytes, bitcoin.params.BASE58_PREFIXES['PUBKEY_ADDR']) assert (b2h(cec_key.get_pubkey()) == b2h(btc_addr.to_bytes())) assert (hexlify(cec_key.get_pubkey()) == hexlify(pubkey_bytes)) #print("Uncompressed public key") c_pubkey = CPubKey(pubkey_bytes) #print("Is public key valid? ", c_pubkey.is_valid, ", compressed? ", c_pubkey.is_compressed) assert (c_pubkey.is_compressed == False) assert (c_pubkey.is_valid == True) #print("Public Key base58:", pubkey_b58) #print(" hashed:", encoding.b2a_hashed_base58(pubkey_bytes)) ## Compressed public key pubkey_bytes = encoding.public_pair_to_sec(pubkey_pair, True) # compressed pubkey_b58 = encoding.b2a_base58(pubkey_bytes) assert (pubkey_bytes == encoding.a2b_base58(pubkey_b58)) btc_addr = CBitcoinAddress.from_bytes( pubkey_bytes, bitcoin.params.BASE58_PREFIXES['PUBKEY_ADDR'])