101 lines
3.6 KiB
Python
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:]
|