ZeroNet/src/lib/pybitcointools/stealth.py

101 lines
3.6 KiB
Python

from . import main as main
from . import transaction as tx
# Shared secrets and uncovering pay keys
def shared_secret_sender(scan_pubkey, ephem_privkey):
shared_point = main.multiply(scan_pubkey, ephem_privkey)
shared_secret = main.sha256(main.encode_pubkey(shared_point, 'bin_compressed'))
return shared_secret
def shared_secret_receiver(ephem_pubkey, scan_privkey):
shared_point = main.multiply(ephem_pubkey, scan_privkey)
shared_secret = main.sha256(main.encode_pubkey(shared_point, 'bin_compressed'))
return shared_secret
def uncover_pay_pubkey_sender(scan_pubkey, spend_pubkey, ephem_privkey):
shared_secret = shared_secret_sender(scan_pubkey, ephem_privkey)
return main.add_pubkeys(spend_pubkey, main.privtopub(shared_secret))
def uncover_pay_pubkey_receiver(scan_privkey, spend_pubkey, ephem_pubkey):
shared_secret = shared_secret_receiver(ephem_pubkey, scan_privkey)
return main.add_pubkeys(spend_pubkey, main.privtopub(shared_secret))
def uncover_pay_privkey(scan_privkey, spend_privkey, ephem_pubkey):
shared_secret = shared_secret_receiver(ephem_pubkey, scan_privkey)
return main.add_privkeys(spend_privkey, shared_secret)
# Address encoding
# Functions for basic stealth addresses,
# i.e. one scan key, one spend key, no prefix
def pubkeys_to_basic_stealth_address(scan_pubkey, spend_pubkey, magic_byte=42):
# magic_byte = 42 for mainnet, 43 for testnet.
hex_scankey = main.encode_pubkey(scan_pubkey, 'hex_compressed')
hex_spendkey = main.encode_pubkey(spend_pubkey, 'hex_compressed')
hex_data = '00{0:066x}01{1:066x}0100'.format(int(hex_scankey, 16), int(hex_spendkey, 16))
addr = main.hex_to_b58check(hex_data, magic_byte)
return addr
def basic_stealth_address_to_pubkeys(stealth_address):
hex_data = main.b58check_to_hex(stealth_address)
if len(hex_data) != 140:
raise Exception('Stealth address is not of basic type (one scan key, one spend key, no prefix)')
scan_pubkey = hex_data[2:68]
spend_pubkey = hex_data[70:136]
return scan_pubkey, spend_pubkey
# Sending stealth payments
def mk_stealth_metadata_script(ephem_pubkey, nonce):
op_return = '6a'
msg_size = '26'
version = '06'
return op_return + msg_size + version + '{0:08x}'.format(nonce) + main.encode_pubkey(ephem_pubkey, 'hex_compressed')
def mk_stealth_tx_outputs(stealth_addr, value, ephem_privkey, nonce, network='btc'):
scan_pubkey, spend_pubkey = basic_stealth_address_to_pubkeys(stealth_addr)
if network == 'btc':
btc_magic_byte = 42
if stealth_addr != pubkeys_to_basic_stealth_address(scan_pubkey, spend_pubkey, btc_magic_byte):
raise Exception('Invalid btc mainnet stealth address: ' + stealth_addr)
magic_byte_addr = 0
elif network == 'testnet':
testnet_magic_byte = 43
if stealth_addr != pubkeys_to_basic_stealth_address(scan_pubkey, spend_pubkey, testnet_magic_byte):
raise Exception('Invalid testnet stealth address: ' + stealth_addr)
magic_byte_addr = 111
ephem_pubkey = main.privkey_to_pubkey(ephem_privkey)
output0 = {'script': mk_stealth_metadata_script(ephem_pubkey, nonce),
'value': 0}
pay_pubkey = uncover_pay_pubkey_sender(scan_pubkey, spend_pubkey, ephem_privkey)
pay_addr = main.pubkey_to_address(pay_pubkey, magic_byte_addr)
output1 = {'address': pay_addr,
'value': value}
return [output0, output1]
# Receiving stealth payments
def ephem_pubkey_from_tx_script(stealth_tx_script):
if len(stealth_tx_script) != 80:
raise Exception('Wrong format for stealth tx output')
return stealth_tx_script[14:]