Skip to content

Instantly share code, notes, and snippets.

@evd0kim
Created September 25, 2019 10:37
Show Gist options
  • Save evd0kim/e649b477d426b428d37983347f324f7c to your computer and use it in GitHub Desktop.
Save evd0kim/e649b477d426b428d37983347f324f7c to your computer and use it in GitHub Desktop.
Libwally demo-script with message signing
# see also https://github.com/afilini/wally-examples/blob/master/SignMessage.ipynb
import ctypes
from wallycore import *
import base64
def sign_message(privkey, message=""):
"""
returns signed message for derived address
:return:
"""
msg_bytes = message.encode('utf-8')
wally_BITCOIN_MESSAGE_HASH_FLAG = 1
formatted = format_bitcoin_message(msg_bytes, wally_BITCOIN_MESSAGE_HASH_FLAG)
signature = ec_sig_from_bytes(privkey, formatted, EC_FLAG_ECDSA)
signature = base64.b64encode(signature).decode('ascii')
print("Signature {}".format(signature))
signature = base64.b64decode(signature.encode('ascii'))
return signature
if __name__ == "__main__":
#seed_hex = "fffcf9f6f3f0edeae7e4e1dedbd8d5d2cfccc9c6c3c0bdbab7b4b1aeaba8a5a29f9c999693908d8a8784817e7b7875726f6c696663605d5a5754514e4b484542"
#seed = hex_to_bytes(seed_hex)
mnemonic = "come fury oil antique match off jar ship six feel fall inflict path race impact monitor loan math goose shop autumn area icon barely"
written, seed = bip39_mnemonic_to_seed512(mnemonic, None)
assert written == BIP39_SEED_LEN_512
FLAG_KEY_PRIVATE, FLAG_KEY_PUBLIC, FLAG_SKIP_HASH, = 0x0, 0x1, 0x2
root_key = bip32_key_from_seed(seed, BIP32_VER_TEST_PRIVATE, FLAG_SKIP_HASH)
root_priv = bip32_key_to_base58(root_key, FLAG_KEY_PRIVATE)
root_ser = bip32_key_serialize(root_key, FLAG_KEY_PUBLIC)
print("root key = {} len = {}".format(hex_from_bytes(root_ser), len(root_ser)))
print("root priv = {}".format(root_priv))
print("Electrum BIP44 paths test")
p1 = ctypes.c_uint32(2147483648 + 44).value
p2 = ctypes.c_uint32(2147483648 + 1).value
p3 = ctypes.c_uint32(2147483648).value
xpriv = bip32_key_from_parent_path(root_key, [p1, p2, p3], FLAG_KEY_PRIVATE)
exp_priv = bip32_key_to_base58(xpriv, FLAG_KEY_PRIVATE)
exp_pub = bip32_key_to_base58(xpriv, FLAG_KEY_PUBLIC)
print("Extended priv = {}".format(exp_priv))
print("Extended pub = {}".format(exp_pub))
electum_xpub = 'tpubDDG6bvvvhPutXjQ6iKCYMGmdhzBuC8b6MLD9JTLFG7v1Lh7m1FW86UbYhd4Lfk9vZ33rfUVETw5rUjWf45FaUUmq3fiDmDqZoZ6sqn9jvqY'
electum_xprv = 'tprv8ga4TWtgZ2EDeGNJpfXwws7X8xfy2oQBn2cN1wHwqr7cWCrzNrgXuyygXVCNFcsi7Ra9NQT18aAMoEVgwnMzZsP4nvpGrZJP8E7LcX59U7f'
print("Electrum extended priv = {}".format(electum_xprv))
print("Electrum extended pub = {}".format(electum_xpub))
assert exp_priv == electum_xprv
assert exp_pub == electum_xpub
for i in [0, 1]:
tkpr = bip32_key_from_parent(xpriv, i, FLAG_KEY_PRIVATE)
tkpb = bip32_key_from_parent(xpriv, i, FLAG_KEY_PUBLIC)
t_priv = bip32_key_to_base58(tkpr, FLAG_KEY_PRIVATE)
t_pub = bip32_key_to_base58(tkpb, FLAG_KEY_PUBLIC)
print("extended pubs are equal? {} \n {}".format(t_pub == electum_xpub, t_pub))
address = 'mnQyrFASmAMeSkZSVNtBRATduTmxxr8U2M'
change = 'my5cdeHMfNXs2kkDAT7SiJg3tzKrvgiVE4'
receiving_address = 1
print("Address test, index {}".format(receiving_address))
addr_priv = bip32_key_from_parent_path(xpriv, [0, receiving_address], FLAG_KEY_PRIVATE)
addr_pub = bip32_key_get_pub_key(addr_priv)
exp_addr_priv = bip32_key_to_base58(addr_priv, FLAG_KEY_PRIVATE)
exp_addr_pub = bip32_key_to_base58(addr_priv, FLAG_KEY_PUBLIC)
print("Address priv = {} hex {}".format(exp_addr_priv, hex_from_bytes(addr_pub)))
print("Address pub = {} hex {}".format(exp_addr_pub, hex_from_bytes(addr_pub)))
master_chaincode = bip32_key_get_chain_code(addr_priv)
print(hex_from_bytes(master_chaincode))
version = b'\x6f' #if self.testnet else b'\x00'
pubkey_hash = bytes(hash160(addr_pub))
p2pkh = base58check_from_bytes(version + pubkey_hash)
print(p2pkh)
test_d = {
"mnQyrFASmAMeSkZSVNtBRATduTmxxr8U2M": "p2pkh:cUvEASu4BiphGsuzUxjsTCRrVXuEG5SGr29PCURLpw9PcYPJBF7j",
"miDRc9VRKE3einmNUXHBT2hnCQ8mRzHTMa": "p2pkh:cNZhQQFLzUyT4dmbQ5CSGh6EY8gB14iB9EqEHsVxsVL9ZjkbiMT1",
"n4GgeFq5VS8gfeL1ida9vn1WdncKcPaP5R": "p2pkh:cVJ12Z3qnhFPtuNPmmp1srAQZcseFeUSY47gYL6xFB3xSY6xqSw5",
"mjMJMMJznRKDnRi7ArdEsea7Cu1mJSfNz3": "p2pkh:cTJPXZ9yBNT2r7rEx421WMKZkUe9MMWbXNyewFoNM8aVQ9888TJF",
"mmeRru9pP2WEZ2DtaLDB6HLanrsBFXTG99": "p2pkh:cQKEeapbPBKfUgzKxotHQWb52mpQC71gLEfHpbEqZ1v2h8pzB3Vt",
"mhvatd7P5kXrcAswNHkP9gV86snKzkYyj4": "p2pkh:cPFvbErWUyFs5v7ntuWbZVwsxk4ufhrvsdY1WuRrcqWEQwmu3q34",
"mqCB1ovQBQERcBJ4AdhB3r7BN5Bm5ajNQD": "p2pkh:cQFwfRtEJdA8ApWwEKrzAA6kpAeTvkw1N9dV63ZM4QjsE4ttpycz",
"n3SBgtwewG482LBH837cHnANWAfQN5VwUA": "p2pkh:cRzHtomQSo7GAg5LBqhndGq6cKfk5SE5yNZMAMY6tAyCnEnNEr32",
"muzf848Whf32iEsP28hEV9cm9xwo1uRJwU": "p2pkh:cUhXP6cB8WoTf3v9VEbBxLc6zBogpSXvnWNxHmyHgDjVG1usSWYL",
"mrx4LutvFftHVuhPg1QNRkGTEGngoEPB6B": "p2pkh:cULpRVsmj9CwBXq8zv8kmoN1pM4CZ2ZgwW4guhoobCBJrnmZdhMd",
"miw8xvVzt91QE8ZrnGUQaoRv1ecQUbVTWk": "p2pkh:cRD4ndJvWJes5s6JHwcEkk6xQYsrqjpevqucaHt23PzugQCU6ZuS",
"mpx7W9GK54fNqmtefZDcSvTr2fYhvZgBYP": "p2pkh:cRTXNFBEc9ZzfRFK55Pcb7uWTbAUyv4p6xkJ154HEobaQbmDPiht",
"n3Jjnaa9KkJ24zxu91qN1WjEwpiiGz4wtV": "p2pkh:cPxGYRiCo6Zo7J3C958mdUkvQpad2c4efu8XRFe65bodpSPHVM2B",
"n17mR8d4ixHGiJ6auKjKKywK4bYzmMvZef": "p2pkh:cRcPaHgaMWAwzXRABDRUA3V61QEMjSF6BQeXLoYDjmf3xVKj8UmW",
"mrs9o3gKGqipj2mAM7rtoGWWUisfAWnxR3": "p2pkh:cT7zkr4P96AjkfR5pn6dXFHfbjVs9Hn7DsMsQAffnzAs4hozVvmY",
"msz8jvXfZUTyYwGckTqfn3KcznJi79QdWY": "p2pkh:cRe5U3f69bCA2YXappC8JuAABqQGyBZQuPUDA8JrjKqRGo1KVdLv",
"mu59rfjjKpoWpT84FWxWowYass9a3Wkyb5": "p2pkh:cQQy7GsL7UYq3fXLw2JkXgj7Bf2L7WSvTQ4HsMLAcNNjdT8a5TBG",
"mrJ1FFbMx9PnMaPGZ92snTwNJeQP9GavyU": "p2pkh:cQW5zj6WSztod378xYjGwPojgTcSyiqznf8hYvwvMYuGf1PuffQ6",
"mjb18TT1jxCdATUQbgMFPHN2dzwjUspjWY": "p2pkh:cMcKKmUjTjQ8cJPcNjEdDrczGZmSV2BpdeejmDFZ2pxehc45GCVy",
"mnZx7fwoj6uNVraBaznnMmS3J7VwVGsLV6": "p2pkh:cMdGoqzBa2GfDmmrfjYm5kQK2N1btHcLTpsWmhz98zsmzma6Jmq4",
"my5cdeHMfNXs2kkDAT7SiJg3tzKrvgiVE4": "p2pkh:cPQw7KPG55bK4qEB7eEpVNkpTNzFqXZRXUwVdBW3Rcr25V3wCCaa",
"miSGdqjrmpXKh7WRnBRmwHji8ZakqX7Y9E": "p2pkh:cRw631uFJMrDo8fGdvXfF9B9fgkJCkvrPrTnQGFNhiNkfdXdKXPs",
"mmqd9ooGDnncC4ydNFTeM3okfn3atAHSQd": "p2pkh:cUPSmnm4NCRSeoJSorHgfi7gxMW7qtYtSqnZHfMLsyKy9nnecKe1",
"myrHMphjavXUZ63bmbxbHxcKR9GG11624a": "p2pkh:cNAq8FbTdLnGoYDyayqkfsUjBUMxS5vCEDB8wwMHQCq1C32Y9RZM",
"mnVfSfduKscprPAe56138o9YrqoQWPfPRs": "p2pkh:cVjkf8zMfuncpXyjrNw1zfAaSDa32sYZVJ7aV6A3gZTLWsWjEt8p",
"mnjBAvZ8LZBpJSbvPrKPD31m5TRtDCjjAR": "p2pkh:cTRpqqCR1rcsVf9i4nJ3as2i6ZMSnZ2i4pq5fppbLUDTAVGYKfZh"
}
if p2pkh in test_d:
print("success")
priv_serialized = bip32_key_serialize(addr_priv, FLAG_KEY_PRIVATE)
ec_key = hex_from_bytes(priv_serialized)[91:155]
print("serialized_key = {} len = {}".format(hex_from_bytes(priv_serialized), len(priv_serialized)))
print("ec_from_free_key = {} len = {}".format(ec_key, len(ec_key)))
bec_key = hex_to_bytes(ec_key)
try:
res = ec_private_key_verify(bec_key)
print("Checking EC key: OK")
except ValueError:
print("Checking EC key: ERROR")
ec_pub = ec_public_key_from_private_key(bec_key)
print("pub: {}".format(hex_from_bytes(ec_pub)))
signature = sign_message(privkey=bec_key, message='hello, world')
print("signature: {}".format(hex_from_bytes(signature)))
try:
message = b'hello, world'
formatted = format_bitcoin_message(message, 1)
res = ec_sig_verify(ec_pub, formatted, EC_FLAG_ECDSA, signature)
print("Checking signature: OK")
except ValueError:
print("Checking signature: ERROR")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment