diff --git a/generate-test-vector.py b/generate-test-vector.py index 6dbcfe1..4e210f3 100755 --- a/generate-test-vector.py +++ b/generate-test-vector.py @@ -6,14 +6,22 @@ from bitcoin_utils import deser_txid, hash160, COutPoint import bip32 from copy import deepcopy -from importlib import reload -reload(reference) - -G = ECKey().set(1).get_pubkey() -sending_test_vectors = [] +from typing import Tuple, List +from itertools import permutations HRP="sp" -#TODO: use clearly mock signatures, e.g. 010203040506... + +def derive_silent_payment_key_pair(seed: bytes) -> Tuple[ECKey, ECKey, ECPubKey, ECPubKey]: + SCAN_KEY = "m/352h/0h/0h/1h/0" + SPEND_KEY = "m/352h/0h/0h/0h/0" + + master = bip32.BIP32.from_seed(seed) + scan = ECKey().set(master.get_privkey_from_path(SCAN_KEY)) + spend = ECKey().set(master.get_privkey_from_path(SPEND_KEY)) + Scan = scan.get_pubkey() + Spend = spend.get_pubkey() + + return scan, spend, Scan, Spend def get_key_pair(index, seed=b'deadbeef', derivation='m/0h'): @@ -23,12 +31,6 @@ def get_key_pair(index, seed=b'deadbeef', derivation='m/0h'): return d, P -def add_private_keys(inputs, input_priv_keys): - for x, i in enumerate(inputs): - i['private_key'] = input_priv_keys[x][0].get_bytes().hex() - - return inputs - def get_p2pkh_scriptsig(pub_key, priv_key): msg = hashlib.sha256(b'message').digest() sig = priv_key.sign_ecdsa(msg, low_s=False, rfc6979=True).hex() @@ -60,7 +62,108 @@ def serialize_witness_stack(stack_items): result += f'{size:02x}' + item return result -def new_test_case(): +def unique_permutations(lst): + # Generate all permutations of the list + perms = permutations(lst, len(lst)) + unique_perms = set(perms) + unique_perms_list = list(unique_perms) + return unique_perms_list + +def create_output_permutations(input_priv_keys: List[Tuple[ECKey, bool]], input_hash: bytes, recipients: List[str], hrp="tsp") -> List[List[str]]: + G = ECKey().set(1).get_pubkey() + negated_keys = [] + for key, is_xonly in input_priv_keys: + k = ECKey().set(key.get_bytes()) + if is_xonly and k.get_pubkey().get_y() % 2 != 0: + k.negate() + negated_keys.append(k) + + a_sum = sum(negated_keys) + all_outputs = [] + for permutation in unique_permutations(recipients): + silent_payment_groups: Dict[ECPubKey, List[ECPubKey]] = {} + for recipient in permutation: + B_scan, B_m = reference.decode_silent_payment_address(recipient, hrp=hrp) + if B_scan in silent_payment_groups: + silent_payment_groups[B_scan].append(B_m) + else: + silent_payment_groups[B_scan] = [B_m] + outputs = [] + for B_scan, B_m_values in silent_payment_groups.items(): + ecdh_shared_secret = input_hash * a_sum * B_scan + k = 0 + for B_m in B_m_values: + t_k = TaggedHash("BIP0352/SharedSecret", ecdh_shared_secret.get_bytes(False) + reference.ser_uint32(k)) + P_km = B_m + t_k * G + outputs.append(P_km.get_bytes().hex()) + k += 1 + all_outputs.append(outputs) + set_of_sets = set() + for s in all_outputs: + set_of_sets.add(frozenset(s)) + return [sorted(list(fz)) for fz in set_of_sets] + +def custom_sort(sublist): + return tuple(sorted(sublist)) + +def sort_list_of_lists(list_of_lists): + return sorted(list_of_lists, key=custom_sort) + +def generated_test_case(inputs, scan_key, spend_key, addrs, labels, comment): + test_case = { + "comment": "", + "sending": [], + "receiving": [], + } + test_case['sending'].append(generated_sender(inputs, addrs)) + # For the sender, there may be more than one valid output set, so we pick + # the first one to test for the recipient (although any would be valid) + test_case['receiving'].append(generated_recipient(inputs, test_case['sending'][0]['expected']['outputs'][0], scan_key, spend_key, labels)) + test_case['comment'] = deepcopy(comment) + return deepcopy(test_case) + +def generated_sender(inputs, addrs,): + sender = { + "given": { + "vin": [], + "recipients": [] + }, + "expected": { + "outputs": [], + } + } + sender['given']['vin'] = deepcopy(inputs) + sender['given']['recipients'] = deepcopy(addrs) + vins = [ + reference.VinInfo( + outpoint=COutPoint(hash=deser_txid(input["txid"]), n=input["vout"]), + scriptSig=bytes.fromhex(input["scriptSig"]), + txinwitness=reference.CTxInWitness().deserialize(reference.from_hex(input["txinwitness"])), + prevout=bytes.fromhex(input["prevout"]["scriptPubKey"]["hex"]), + private_key=ECKey().set(bytes.fromhex(input["private_key"])), + ) + for input in inputs + ] + + input_pubkeys = [] + input_priv_keys = [] + for input in vins: + input_pubkey = reference.get_pubkey_from_input(input) + if input_pubkey.valid: + input_pubkeys.append(input_pubkey) + input_priv_keys.append((input.private_key, reference.is_p2tr(input.prevout))) + if len(input_pubkeys) == 0: + sender['expected']['outputs'] = [[]] + else: + A_sum = sum(input_pubkeys) + input_hash = reference.get_input_hash([o.outpoint for o in vins], A_sum) + outputs = create_output_permutations(input_priv_keys, input_hash, addrs, hrp=HRP) + sender['expected']['outputs'] = sort_list_of_lists(outputs) + return deepcopy(sender) + +def generated_recipient(inputs, output_set: List[str], scan_key: ECKey, spend_key: ECKey, labels: List[int]): + msg = hashlib.sha256(b'message').digest() + aux = hashlib.sha256(b'random auxiliary data').digest() recipient = { "given": { "vin": [], @@ -76,30 +179,75 @@ def new_test_case(): "outputs": [], } } - sender = { - "given": { - "vin": [], - "recipients": [] - }, - "expected": { - "outputs": [] - } - } - test_case = { - "comment": "", - "sending": [], - "receiving": [], - } - return sender, recipient, test_case + vins = [ + reference.VinInfo( + outpoint=COutPoint(hash=deser_txid(input["txid"]), n=input["vout"]), + scriptSig=bytes.fromhex(input["scriptSig"]), + txinwitness=reference.CTxInWitness().deserialize(reference.from_hex(input["txinwitness"])), + prevout=bytes.fromhex(input["prevout"]["scriptPubKey"]["hex"]), + private_key=ECKey(), + ) + for input in inputs + ] + recipient['given']['outputs'] = deepcopy(sorted(output_set)) + recipient['given']['key_material']['scan_priv_key'] = scan_key.get_bytes().hex() + recipient['given']['key_material']['spend_priv_key'] = spend_key.get_bytes().hex() + recipient['given']['labels'] = deepcopy(labels) + addr = reference.encode_silent_payment_address( + scan_key.get_pubkey(), + spend_key.get_pubkey(), + hrp="sp", + ) + recipient['expected']['addresses'].append(addr) + label_cache = dict() + for label in labels: + label_tweak = reference.generate_label(scan_key, label) + label_pubkey = ECKey().set(label_tweak).get_pubkey() + label_cache[label_pubkey.get_bytes(False).hex()] = label_tweak.hex() + l_addr = reference.create_labeled_silent_payment_address(scan_key, spend_key.get_pubkey(), label, hrp="sp") + recipient['expected']['addresses'].append(l_addr) + input_pubkeys = [] + for input in vins: + input_pubkey = reference.get_pubkey_from_input(input) + if input_pubkey.valid: + input_pubkeys.append(input_pubkey) + if len(input_pubkeys) == 0: + recipient['expected']['outputs'] = [] + else: + A_sum = sum(input_pubkeys) + input_hash = reference.get_input_hash([o.outpoint for o in vins], A_sum) + found_outputs = reference.scanning( + scan_key, + spend_key.get_pubkey(), + A_sum, + input_hash, + [ECPubKey().set(bytes.fromhex(p)) for p in output_set], + label_cache, + ) + for found in found_outputs: + pubkey = ECPubKey().set(bytes.fromhex(found['pub_key'])) + full_private_key = spend_key.add( + bytes.fromhex(found['priv_key_tweak']) + ) + if full_private_key.get_pubkey().get_y()%2 != 0: + full_private_key.negate() + + sig = full_private_key.sign_schnorr(msg, aux) + assert pubkey.verify_schnorr(sig, msg) + found['signature'] = sig.hex() + recipient['expected']['outputs'] = sorted([dict(sorted(f.items())) for f in found_outputs], key=lambda d: d['pub_key']) + + inputs_receiver = deepcopy(inputs) + for input in inputs_receiver: + del input['private_key'] -# In[10]: + recipient['given']['vin'] = deepcopy(inputs_receiver) + return deepcopy(recipient) +# Test cases def generate_labeled_output_tests(): - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() - G = ECKey().set(1).get_pubkey() test_cases = [] outpoints = [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), @@ -110,82 +258,31 @@ def generate_labeled_output_tests(): i2, I2 = get_key_pair(1, seed=bytes.fromhex(sender_bip32_seed)) input_priv_keys = [(i1, False), (i2, False)] input_pub_keys = [I1, I2] + inputs = [] + for i, outpoint in enumerate(outpoints): + inputs += [{ + 'txid': outpoint[0], + 'vout': outpoint[1], + 'scriptSig': get_p2pkh_scriptsig(input_pub_keys[i], input_priv_keys[i][0]), + 'txinwitness': '', + 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(input_pub_keys[i])}}, + 'private_key': input_priv_keys[i][0].get_bytes().hex(), + }] recipient_bip32_seed = 'f00dbabe' - b_scan, b_spend, B_scan, B_spend = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) + b_scan, b_spend, B_scan, B_spend = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) label_ints = [2, 3, 1001337] address = reference.encode_silent_payment_address(B_scan, B_spend, hrp=HRP) - labeled_addresses = [ - reference.create_labeled_silent_payment_address(b_scan, B_spend, case, hrp=HRP) for case in label_ints - ] - recipient_addresses = [address] + labeled_addresses comments = ["Receiving with labels: label with even parity", "Receiving with labels: label with odd parity", "Receiving with labels: large label integer"] for i, case in enumerate(label_ints): - sender, recipient, test_case = new_test_case() address = reference.create_labeled_silent_payment_address(b_scan, B_spend, case, hrp=HRP) - addresses = [(address, 1.0)] - - inputs = [] - for i, outpoint in enumerate(outpoints): - inputs += [{ - 'txid': outpoint[0], - 'vout': outpoint[1], - 'scriptSig': get_p2pkh_scriptsig(input_pub_keys[i], input_priv_keys[i][0]), - 'txinwitness': '', - 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(input_pub_keys[i])}}, - }] - - sender['given']['vin'] = add_private_keys(deepcopy(inputs), input_priv_keys) - sender['given']['recipients'] = addresses - recipient['given']['vin'] = inputs - recipient['given']['key_material']['scan_priv_key'] = b_scan.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = b_spend.get_bytes().hex() - recipient['expected']['addresses'] = recipient_addresses - recipient['given']['labels'] = label_ints - - A_sum = sum(input_pub_keys) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - outputs = reference.create_outputs(input_priv_keys, deterministic_nonce, addresses, hrp=HRP) - sender['expected']['outputs'] = outputs - output_pub_keys = [r[0] for r in outputs] - recipient['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - b_scan, - B_spend, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - labels={(reference.generate_label(b_scan, l)*G).get_bytes(False).hex():reference.generate_label(b_scan, l).hex() for l in label_ints}, - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = b_spend.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient['expected']['outputs'] = add_to_wallet - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient]) - test_case["comment"] = comments[i] - test_cases.append(test_case) - + addresses = [address] + test_cases.append(generated_test_case(inputs, b_scan, b_spend, addresses, labels=label_ints, comment=comments[i])) return test_cases - def generate_single_output_outpoint_tests(): - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() - G = ECKey().set(1).get_pubkey() outpoint_test_cases = [ [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), @@ -203,6 +300,10 @@ def generate_single_output_outpoint_tests(): ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 7), ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 3) ], + [ + ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 1), + ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 256) + ], ] sender_bip32_seed = 'deadbeef' @@ -217,74 +318,27 @@ def generate_single_output_outpoint_tests(): "Simple send: two inputs", "Simple send: two inputs, order reversed", "Simple send: two inputs from the same transaction", - "Simple send: two inputs from the same transaction, order reversed" + "Simple send: two inputs from the same transaction, order reversed", + "Outpoint ordering byte-lexicographically vs. vout-integer", ] + b_scan, b_spend, B_scan, B_spend = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) + address = reference.encode_silent_payment_address(B_scan, B_spend, hrp="sp") for i, outpoints in enumerate(outpoint_test_cases): - sender, recipient, test_case = new_test_case() - test_case["comment"] = comments[i] - inputs = [] - for i, outpoint in enumerate(outpoints): + for j, outpoint in enumerate(outpoints): inputs += [{ 'txid': outpoint[0], 'vout': outpoint[1], - 'scriptSig': get_p2pkh_scriptsig(input_pub_keys[i], input_priv_keys[i][0]), + 'scriptSig': get_p2pkh_scriptsig(input_pub_keys[j], input_priv_keys[j][0]), 'txinwitness': '', - 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(input_pub_keys[i])}}, + 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(input_pub_keys[j])}}, + 'private_key': input_priv_keys[j][0].get_bytes().hex(), }] - sender['given']['vin'] = add_private_keys(deepcopy(inputs), input_priv_keys) - - recipient['given']['vin'] = inputs - - b_scan, b_spend, B_scan, B_spend = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) - recipient['given']['key_material']['scan_priv_key'] = b_scan.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = b_spend.get_bytes().hex() - address = reference.encode_silent_payment_address(B_scan, B_spend, hrp=HRP) - - sender['given']['recipients'].extend([(address, 1.0)]) - recipient['expected']['addresses'].extend([address]) - - A_sum = sum(input_pub_keys) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - outputs = reference.create_outputs(input_priv_keys, deterministic_nonce, [(address, 1.0)], hrp=HRP) - sender['expected']['outputs'] = outputs - output_pub_keys = [recipient[0] for recipient in outputs] - recipient['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - b_scan, - B_spend, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = b_spend.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient['expected']['outputs'] = add_to_wallet - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient]) - test_cases.append(test_case) - + test_cases.append(generated_test_case(inputs, b_scan, b_spend, [address], labels=[], comment=comments[i])) return test_cases - def generate_multiple_output_tests(): - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() - G = ECKey().set(1).get_pubkey() - recipient_test_cases = [] outpoints = [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 0), @@ -295,24 +349,6 @@ def generate_multiple_output_tests(): input_priv_keys = [(i1, False), (i2, False)] input_pub_keys = [I1, I2] - recipient_one_bip32_seed = 'f00dbabe' - recipient_two_bip32_seed = 'decafbad' - - scan1, spend1, Scan1, Spend1 = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_one_bip32_seed)) - address1 = reference.encode_silent_payment_address(Scan1, Spend1, hrp=HRP) - addresses1 = [(address1, amount) for amount in [2.0, 3.0]] - - scan2, spend2, Scan2, Spend2 = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_two_bip32_seed)) - address2 = reference.encode_silent_payment_address(Scan2, Spend2, hrp=HRP) - addresses2 = [(address2, amount) for amount in [4.0, 5.0]] - - test_cases = [] - - sender, recipient1, test_case = new_test_case() - sender1 = deepcopy(sender) - recipient2 = deepcopy(recipient1) - test_case2 = deepcopy(test_case) - inputs = [] for i, outpoint in enumerate(outpoints): inputs += [{ @@ -321,162 +357,28 @@ def generate_multiple_output_tests(): 'scriptSig': get_p2pkh_scriptsig(input_pub_keys[i], input_priv_keys[i][0]), 'txinwitness': '', 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(input_pub_keys[i])}}, + 'private_key': input_priv_keys[i][0].get_bytes().hex(), }] - sender1['given']['vin'] = sender['given']['vin'] = add_private_keys(deepcopy(inputs), input_priv_keys) - sender['given']['recipients'] = addresses1 - recipient1['given']['vin'] = inputs - recipient2['given']['vin'] = inputs - recipient1['given']['key_material']['scan_priv_key'] = scan1.get_bytes().hex() - recipient1['given']['key_material']['spend_priv_key'] = spend1.get_bytes().hex() - recipient1['expected']['addresses'] = [address1] - recipient2['given']['key_material']['scan_priv_key'] = scan2.get_bytes().hex() - recipient2['given']['key_material']['spend_priv_key'] = spend2.get_bytes().hex() - recipient2['expected']['addresses'] = [address2] - - A_sum = sum(input_pub_keys) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - outputs = reference.create_outputs(input_priv_keys, deterministic_nonce, addresses1, hrp=HRP) - sender['expected']['outputs'] = outputs - output_pub_keys = [recipient[0] for recipient in outputs] - recipient1['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - scan1, - Spend1, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = spend1.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient1['expected']['outputs'] = add_to_wallet - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient1]) - test_case["comment"] = "Multiple outputs: multiple outputs, same recipient" - test_cases.append(test_case) - - sender1['given']['recipients'] = addresses1 + addresses2 - outputs = reference.create_outputs(input_priv_keys, deterministic_nonce, addresses1 + addresses2, hrp=HRP) - sender1['expected']['outputs'] = outputs - output_pub_keys = [recipient[0] for recipient in outputs] - recipient1['given']['outputs'] = output_pub_keys - recipient2['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - scan2, - Spend2, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = spend2.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient2['expected']['outputs'] = add_to_wallet - test_case2['sending'].extend([sender1]) - test_case2['receiving'].extend([recipient1, recipient2]) - test_case2["comment"] = "Multiple outputs: multiple outputs, multiple recipients" - test_cases.append(test_case2) - - return test_cases - - -# In[13]: + recipient_one_bip32_seed = 'f00dbabe' + recipient_two_bip32_seed = 'decafbad' + scan1, spend1, Scan1, Spend1 = derive_silent_payment_key_pair(bytes.fromhex(recipient_one_bip32_seed)) + address1 = reference.encode_silent_payment_address(Scan1, Spend1, hrp=HRP) + addresses1 = [address1, address1] -def generate_paying_to_self_test(): + scan2, spend2, Scan2, Spend2 = derive_silent_payment_key_pair(bytes.fromhex(recipient_two_bip32_seed)) + address2 = reference.encode_silent_payment_address(Scan2, Spend2, hrp=HRP) + addresses2 = [address1, address2, address2] - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() - outpoints = [ - ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), - ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 0) + test_cases = [ + generated_test_case(inputs, scan1, spend1, addresses1, labels=[], comment="Multiple outputs: multiple outputs, same recipient"), + generated_test_case(inputs, scan2, spend2, addresses2, labels=[], comment="Multiple outputs: multiple outputs, multiple recipients"), ] - - sender_bip32_seed = 'deadbeef' - recipient_bip32_seed = 'deadbeef' - i1, I1 = get_key_pair(0, seed=bytes.fromhex(sender_bip32_seed)) - i2, I2 = get_key_pair(1) - input_priv_keys = [(i1, False), (i2, False)] - input_pub_keys = [I1, I2] - - sender, recipient, test_case = new_test_case() - sender['given']['outpoints'] = outpoints - recipient['given']['outpoints'] = outpoints - sender['given']['input_priv_keys'].extend([i1.get_bytes().hex(), i2.get_bytes().hex()]) - recipient['given']['input_pub_keys'].extend([I1.get_bytes(False).hex(), I2.get_bytes(False).hex()]) - - b_scan, b_spend, B_scan, B_spend = create_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) - recipient['given']['bip32_seed'] = recipient_bip32_seed - recipient['given']['scan_priv_key'] = b_scan.get_bytes().hex() - recipient['given']['spend_priv_key'] = b_spend.get_bytes().hex() - address = reference.encode_silent_payment_address(B_scan, B_spend, hrp=HRP) - - sender['given']['recipients'].extend([(address, 1.0)]) - recipient['expected']['addresses'].extend([address]) - - A_sum = sum(input_pub_keys) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - outputs = reference.create_outputs(input_priv_keys, deterministic_nonce, [(address, 1.0)], hrp=HRP) - sender['expected']['outputs'] = outputs - output_pub_keys = [recipient[0] for recipient in outputs] - recipient['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - b_scan, - B_spend, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = b_spend.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient['expected']['outputs'] = add_to_wallet - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient]) - - return test_case - + return test_cases def generate_multiple_outputs_with_labels_tests(): - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() - G = ECKey().set(1).get_pubkey() - recipient_test_cases = [] outpoints = [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 0), @@ -488,7 +390,7 @@ def generate_multiple_outputs_with_labels_tests(): input_pub_keys = [I1, I2] recipient_bip32_seed = 'f00dbabe' - scan1, spend1, Scan1, Spend1 = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) + scan1, spend1, Scan1, Spend1 = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) address = reference.encode_silent_payment_address(Scan1, Spend1, hrp=HRP) l1 = 1 l2 = 1337 @@ -496,81 +398,35 @@ def generate_multiple_outputs_with_labels_tests(): labels_three = [l1, l2] label_address_one = reference.create_labeled_silent_payment_address(scan1, Spend1, m=l1, hrp=HRP) label_address_two = reference.create_labeled_silent_payment_address(scan1, Spend1, m=l2, hrp=HRP) - addresses1 = [(address, 1.0), (label_address_one, 2.0)] - addresses2 = [(label_address_one, 3.0), (label_address_one, 4.0)] - addresses3 = [(address, 5.0), (label_address_one, 6.0), (label_address_two, 7.0), (label_address_two, 8.0)] + addresses1 = [label_address_one, address] + addresses2 = [label_address_one, label_address_one] + addresses3 = [address, label_address_one, label_address_two, label_address_two] test_cases = [] - labels = [labels_one, labels_one, labels_three] - sp_addresses = [[address, label_address_one], [address, label_address_one], [address, label_address_one, label_address_two]] - comments = [ - "Multiple outputs with labels: un-labeled and labeled address; same recipient", - "Multiple outputs with labels: multiple outputs for labeled address; same recipient", - "Multiple outputs with labels: un-labeled, labeled, and multiple outputs for labeled address; multiple recipients", - ] - for i, addrs in enumerate([addresses1, addresses2, addresses3]): - sender, recipient, test_case = new_test_case() - - inputs = [] - for i, outpoint in enumerate(outpoints): - inputs += [{ - 'txid': outpoint[0], - 'vout': outpoint[1], - 'scriptSig': get_p2pkh_scriptsig(input_pub_keys[i], input_priv_keys[i][0]), - 'txinwitness': '', - 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(input_pub_keys[i])}}, - }] - - sender['given']['vin'] = add_private_keys(deepcopy(inputs), input_priv_keys) - recipient['given']['vin'] = inputs - - recipient['given']['key_material']['scan_priv_key'] = scan1.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = spend1.get_bytes().hex() - sender['given']['recipients'] = addrs - recipient['expected']['addresses'] = sp_addresses[i] - recipient['given']['labels'] = labels[i] - A_sum = sum(input_pub_keys) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - outputs = reference.create_outputs(input_priv_keys, deterministic_nonce, addrs, hrp=HRP) - sender['expected']['outputs'] = outputs - output_pub_keys = [recipient[0] for recipient in outputs] - recipient['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - scan1, - Spend1, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - labels={(reference.generate_label(scan1, l)*G).get_bytes(False).hex():reference.generate_label(scan1, l).hex() for l in labels[i]}, - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = spend1.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient['expected']['outputs'] = add_to_wallet - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient]) - test_case["comment"] = comments[i] - test_cases.append(test_case) + inputs = [] + for i, outpoint in enumerate(outpoints): + inputs += [{ + 'txid': outpoint[0], + 'vout': outpoint[1], + 'scriptSig': get_p2pkh_scriptsig(input_pub_keys[i], input_priv_keys[i][0]), + 'txinwitness': '', + 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(input_pub_keys[i])}}, + 'private_key': input_priv_keys[i][0].get_bytes().hex(), + }] + test_cases.append( + generated_test_case(inputs, scan1, spend1, addresses1, labels_one, "Multiple outputs with labels: un-labeled and labeled address; same recipient") + ) + test_cases.append( + generated_test_case(inputs, scan1, spend1, addresses2, labels_one, "Multiple outputs with labels: multiple outputs for labeled address; same recipient") + ) + test_cases.append( + generated_test_case(inputs, scan1, spend1, addresses3, labels_three, "Multiple outputs with labels: un-labeled, labeled, and multiple outputs for labeled address; same recipients") + ) return test_cases - def generate_single_output_input_tests(): - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() - G = ECKey().set(1).get_pubkey() outpoints = [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 0) @@ -630,8 +486,6 @@ def generate_single_output_input_tests(): "Single recipient: taproot input with odd y-value and non-taproot input" ] for i, inputs in enumerate([address_reuse, taproot_only, taproot_only_with_odd_y, mixed, mixed_with_odd_y]): - sender, recipient, test_case = new_test_case() - inp = [] for x, (key, is_taproot) in enumerate(inputs[0]): pub_key = inputs[1][x] @@ -642,6 +496,7 @@ def generate_single_output_input_tests(): "scriptSig": "", "txinwitness": get_p2tr_witness(key), "prevout": {"scriptPubKey": {"hex": get_p2tr_scriptPubKey(pub_key)}}, + "private_key": key.get_bytes().hex(), }] else: inp += [{ @@ -650,69 +505,17 @@ def generate_single_output_input_tests(): "scriptSig": get_p2pkh_scriptsig(pub_key, key), "txinwitness": "", "prevout": {"scriptPubKey": {"hex": get_p2pkh_scriptPubKey(pub_key)}}, + "private_key": key.get_bytes().hex(), }] - priv_keys = [] - for (priv_key, is_taproot) in inputs[0]: - priv_keys += [priv_key.get_bytes().hex()] - - - sender['given']['vin'] = add_private_keys(deepcopy(inp), inputs[0]) - recipient['given']['vin'] = inp - - b_scan, b_spend, B_scan, B_spend = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) - recipient['given']['key_material']['scan_priv_key'] = b_scan.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = b_spend.get_bytes().hex() + b_scan, b_spend, B_scan, B_spend = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) address = reference.encode_silent_payment_address(B_scan, B_spend, hrp=HRP) - - sender['given']['recipients'].extend([(address, 1.0)]) - recipient['expected']['addresses'].extend([address]) - - A_sum = sum([p if not inputs[0][i][1] or p.get_y()%2==0 else p * -1 for i, p in enumerate(inputs[1])]) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - - outputs = reference.create_outputs(inputs[0], deterministic_nonce, [(address, 1.0)], hrp=HRP) - sender['expected']['outputs'] = outputs - output_pub_keys = [recipient[0] for recipient in outputs] - recipient['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - b_scan, - B_spend, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = b_spend.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient['expected']['outputs'] = add_to_wallet - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient]) - test_case["comment"] = comments[i] - test_cases.append(test_case) + test_cases.append(generated_test_case(inp, b_scan, b_spend, [address], labels=[], comment=comments[i])) return test_cases - def generate_change_tests(): - sender, recipient, test_case = new_test_case() - - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() - G = ECKey().set(1).get_pubkey() - recipient_test_cases = [] outpoints = [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 0), @@ -723,31 +526,6 @@ def generate_change_tests(): input_priv_keys = [(i1, False), (i2, False)] input_pub_keys = [I1, I2] - scan0, spend0, Scan0, Spend0 = reference.derive_silent_payment_key_pair(bytes.fromhex(sender_bip32_seed)) - sender_address = reference.encode_silent_payment_address(Scan0, Spend0, hrp=HRP) - change_label = 0 - change_labels = [change_label] - change_address = reference.create_labeled_silent_payment_address(scan0, Spend0, m=change_label, hrp=HRP) - - recipient_bip32_seed = 'f00dbabe' - seeds = [sender_bip32_seed, recipient_bip32_seed] - scan1, spend1, Scan1, Spend1 = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) - address = reference.encode_silent_payment_address(Scan1, Spend1, hrp=HRP) - addresses = [(address, 1.0), (change_address, 2.0)] - - test_cases = [] - sp_recipients = [[address, change_address]] - - rec1, rec2 = deepcopy(recipient), deepcopy(recipient) - rec1['given']['key_material']['scan_priv_key'] = scan0.get_bytes().hex() - rec1['given']['key_material']['spend_priv_key'] = spend0.get_bytes().hex() - rec2['given']['key_material']['scan_priv_key'] = scan1.get_bytes().hex() - rec2['given']['key_material']['spend_priv_key'] = spend1.get_bytes().hex() - rec1['expected']['addresses'] = [sender_address, change_address] - rec1['given']['labels'] = change_labels - rec2['expected']['addresses'] = [address] - - inputs = [] for i, outpoint in enumerate(outpoints): inputs += [{ @@ -756,121 +534,23 @@ def generate_change_tests(): 'scriptSig': get_p2pkh_scriptsig(input_pub_keys[i], input_priv_keys[i][0]), 'txinwitness': '', 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(input_pub_keys[i])}}, + 'private_key': input_priv_keys[i][0].get_bytes().hex(), }] - sender['given']['vin'] = add_private_keys(deepcopy(inputs), input_priv_keys) - sender['given']['recipients'] = addresses - A_sum = sum(input_pub_keys) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - outputs = reference.create_outputs(input_priv_keys, deterministic_nonce, addresses, hrp=HRP) - sender['expected']['outputs'] = outputs - - output_pub_keys = [recipient[0] for recipient in outputs] - - test_case['sending'].extend([sender]) - labels = [change_labels, []] - for i, rec in enumerate([rec1, rec2]): - rec['given']['vin'] = inputs - rec['given']['outputs'] = output_pub_keys - - scan, spend, Scan, Spend = reference.derive_silent_payment_key_pair(bytes.fromhex(seeds[i])) - add_to_wallet = reference.scanning( - scan, - Spend, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - labels={(reference.generate_label(scan, l)*G).get_bytes(False).hex():reference.generate_label(scan, l).hex() for l in labels[i]}, - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = spend.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - rec['expected']['outputs'] = add_to_wallet - test_case['receiving'].extend([rec]) - test_case["comment"] = "Single recipient: use silent payments for sender change" - test_cases.append(test_case) - return test_cases - - -# In[17]: + scan0, spend0, Scan0, Spend0 = derive_silent_payment_key_pair(bytes.fromhex(sender_bip32_seed)) + change_address = reference.create_labeled_silent_payment_address(scan0, Spend0, m=0, hrp=HRP) - -def generate_unknown_segwit_ver_test(): - sender, recipient, test_case = new_test_case() - - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() - outpoints = [ - ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), - ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 0), - ] - sender_bip32_seed = 'deadbeef' recipient_bip32_seed = 'f00dbabe' - scan, spend, Scan, Spend = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) - address = reference.encode_silent_payment_address(Scan, Spend, hrp=HRP) - addresses = [(address, 1.0)] - - recipient['given']['key_material']['scan_priv_key'] = scan.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = spend.get_bytes().hex() - - inputs = [] - input_priv_keys = [] - input_pub_keys = [] - - ## included - # p2pkh - i = len(inputs) - priv, pub = get_key_pair(i, seed=bytes.fromhex(sender_bip32_seed)) - inputs += [{ - 'prevout': list(outpoints[i]) + [get_p2pkh_scriptsig(pub, priv), ""], - 'scriptPubKey': get_p2pkh_scriptPubKey(pub), - }] - input_priv_keys += [(priv, False)] - input_pub_keys += [pub] - - # unknown segwit version - i = len(inputs) - priv, pub = get_key_pair(i, seed=bytes.fromhex(sender_bip32_seed)) - sig = priv.sign_ecdsa(msg, low_s=False, rfc6979=True).hex() - inputs += [{ - 'prevout': list(outpoints[i]) + ["", serialize_witness_stack([sig, pub.get_bytes(False).hex()])], - 'scriptPubKey': "5214" + hash160(pub.get_bytes(False)), - }] - input_priv_keys += [(priv, False)] - input_pub_keys += [pub] + scan1, spend1, Scan1, Spend1 = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) + address = reference.encode_silent_payment_address(Scan1, Spend1, hrp=HRP) + addresses = [address, change_address] - sender['given']['recipients'] = addresses - sender['given']['inputs'] = add_private_keys(deepcopy(inputs), input_priv_keys) - # TODO: encode failure of sending explicitly - test_case['sending'].extend([sender]) - - recipient['given']['inputs'] = inputs - # create plausible outputs - # a) using all detected keys - outputs_a = reference.create_outputs(input_priv_keys, reference.hash_outpoints(outpoints), addresses, hrp=HRP) - # b) using only p2pkh input - outputs_b = reference.create_outputs(input_priv_keys[:1], reference.hash_outpoints(outpoints), addresses, hrp=HRP) - recipient['given']['outputs'] = [outputs_a[0][0], outputs_b[0][0]] - test_case['receiving'].extend([recipient]) - - test_case["comment"] = "Skipped tx: unknown segwit version input" + test_case = generated_test_case(inputs, scan0, spend0, addresses, labels=[0], comment="Single recipient: use silent payments for sender change") + test_case['receiving'].append(generated_recipient(inputs, test_case['sending'][0]['expected']['outputs'][0], scan1, spend1, labels=[])) return [test_case] def generate_taproot_with_nums_point_test(): - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() - G = ECKey().set(1).get_pubkey() outpoints = [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 0), @@ -890,7 +570,7 @@ def generate_taproot_with_nums_point_test(): if I2.get_y()%2 != 0: i2.negate() I2.negate() - + if I3.get_y()%2 == 0: i3.negate() I3.negate() @@ -902,13 +582,11 @@ def generate_taproot_with_nums_point_test(): test_cases = [] comments = [ - "Single receipient: taproot input with NUMS point" + "Single recipient: taproot input with NUMS point" ] included_keys = [] included_pubkeys = [] for i, inputs in enumerate([nums_point]): - sender, recipient, test_case = new_test_case() - inp = [] for x, (key, internal_key, add_annex) in enumerate(inputs[0]): pub_key = inputs[1][x] @@ -920,6 +598,7 @@ def generate_taproot_with_nums_point_test(): "scriptSig": "", "txinwitness": get_p2tr_witness(key), "prevout": {"scriptPubKey": {"hex": get_p2tr_scriptPubKey(pub_key)}}, + "private_key": key.get_bytes().hex(), }] included_keys += [(key, True)] included_pubkeys += [pub_key] @@ -932,6 +611,7 @@ def generate_taproot_with_nums_point_test(): tap_tweak = TaggedHash("TapTweak", internal_key_bytes + leaf_hash) tweaked_key = ECPubKey().set(internal_key_bytes).tweak_add(tap_tweak) control_block = "c1" + internal_key_bytes.hex() + msg = hashlib.sha256(b'message').digest() sig = key.sign_schnorr(msg).hex() stack = [sig, script, control_block] if (add_annex): @@ -942,61 +622,18 @@ def generate_taproot_with_nums_point_test(): "scriptSig": "", "txinwitness": serialize_witness_stack(stack), "prevout": {"scriptPubKey": {"hex": get_p2tr_scriptPubKey(tweaked_key)}}, + "private_key": key.get_bytes().hex(), }] # Notice that the keys are not added to included list because they should be skipped since they use NUMS_POINT - sender['given']['vin'] = add_private_keys(deepcopy(inp), inputs[0]) - recipient['given']['vin'] = inp - - b_scan, b_spend, B_scan, B_spend = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) - recipient['given']['key_material']['scan_priv_key'] = b_scan.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = b_spend.get_bytes().hex() + b_scan, b_spend, B_scan, B_spend = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) address = reference.encode_silent_payment_address(B_scan, B_spend, hrp=HRP) - sender['given']['recipients'].extend([(address, 1.0)]) - recipient['expected']['addresses'].extend([address]) - - A_sum = sum([p if p.get_y()%2==0 else p * -1 for p in included_pubkeys]) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - - outputs = reference.create_outputs([(inp[0], True) for inp in included_keys], deterministic_nonce, [(address, 1.0)], hrp=HRP) - sender['expected']['outputs'] = outputs - output_pub_keys = [recipient[0] for recipient in outputs] - recipient['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - b_scan, - B_spend, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = b_spend.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient['expected']['outputs'] = add_to_wallet - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient]) - test_case["comment"] = comments[i] - test_cases.append(test_case) + test_cases.append(generated_test_case(inp, b_scan, b_spend, [address], labels=[], comment=comments[i])) return test_cases def generate_malleated_p2pkh_test(): - sender, recipient, test_case = new_test_case() - - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() outpoints = [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), @@ -1005,14 +642,9 @@ def generate_malleated_p2pkh_test(): ] sender_bip32_seed = 'deadbeef' recipient_bip32_seed = 'f00dbabe' - scan, spend, Scan, Spend = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) + scan, spend, Scan, Spend = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) address = reference.encode_silent_payment_address(Scan, Spend, hrp=HRP) - addresses = [(address, 1.0)] - - sender['given']['recipients'] = addresses - recipient['given']['key_material']['scan_priv_key'] = scan.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = spend.get_bytes().hex() - recipient['expected']['addresses'] = [address] + addresses = [address] inputs = [] input_priv_keys = [] @@ -1027,12 +659,13 @@ def add_input(inputs, input_priv_keys, input_pub_keys, get_script_sig): 'scriptSig': get_script_sig(pub, priv), 'txinwitness': '', 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(pub)}}, + 'private_key': priv.get_bytes().hex(), }] input_priv_keys += [(priv, False)] input_pub_keys += [pub] ## All inputs should be included - + # p2pkh add_input(inputs, input_priv_keys, input_pub_keys, get_p2pkh_scriptsig) @@ -1046,57 +679,17 @@ def add_input(inputs, input_priv_keys, input_pub_keys, get_script_sig): fake_script = get_p2pkh_scriptsig(fake_pub, fake_priv) add_input(inputs, input_priv_keys, input_pub_keys, lambda pub, priv: "5163" + get_p2pkh_scriptsig(pub, priv) + "67" + fake_script + "68") - sender['given']['recipients'] = addresses - A_sum = sum([p if not input_priv_keys[i][1] or p.get_y()%2==0 else p * -1 for i, p in enumerate(input_pub_keys)]) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - outputs = reference.create_outputs(input_priv_keys, deterministic_nonce, addresses, hrp=HRP) - sender['expected']['outputs'] = outputs - sender['given']['vin'] = add_private_keys(deepcopy(inputs), input_priv_keys) - - output_pub_keys = [recipient[0] for recipient in outputs] - - recipient['given']['vin'] = inputs - recipient['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - scan, - Spend, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - labels={}, - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = spend.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient['expected']['outputs'] = add_to_wallet - - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient]) - test_case["comment"] = "Pubkey extraction from malleated p2pkh" - test_cases = [] - test_cases.append(test_case) + test_cases = [ + generated_test_case(inputs, scan, spend, addresses, labels=[], comment="Pubkey extraction from malleated p2pkh") + ] return test_cases def generate_uncompressed_keys_tests(): - sender, recipient, test_case = new_test_case() msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() - outpoints = [ - ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 0), + ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 1), ("a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", 2), ] @@ -1107,13 +700,9 @@ def generate_uncompressed_keys_tests(): input_pub_keys = [] recipient_bip32_seed = 'f00dbabe' - scan, spend, Scan, Spend = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) + scan, spend, Scan, Spend = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) address = reference.encode_silent_payment_address(Scan, Spend, hrp=HRP) - - recipient['given']['key_material']['scan_priv_key'] = scan.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = spend.get_bytes().hex() - recipient['expected']['addresses'] = [address] - addresses = [(address, 1.0)] + addresses = [address] # p2pkh compressed Key i = len(inputs) @@ -1124,6 +713,7 @@ def generate_uncompressed_keys_tests(): 'scriptSig': get_p2pkh_scriptsig(pub, priv), 'txinwitness': '', 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(pub)}}, + 'private_key': priv.get_bytes().hex(), }] input_priv_keys += [(priv, False)] input_pub_keys += [pub] @@ -1138,6 +728,7 @@ def generate_uncompressed_keys_tests(): 'scriptSig': get_p2pkh_scriptsig(pub, priv), 'txinwitness': '', 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(pub)}}, + 'private_key': priv.get_bytes().hex(), }] input_priv_keys += [(priv, False)] @@ -1152,54 +743,18 @@ def generate_uncompressed_keys_tests(): 'scriptSig': '', 'txinwitness': serialize_witness_stack([sig, pub.get_bytes(False).hex()]), 'prevout': {'scriptPubKey': {'hex': "0014" + reference.hash160(pub.get_bytes(False)).hex()}}, + 'private_key': priv.get_bytes().hex(), }] input_priv_keys += [(priv, False)] - A_sum = sum([p for p in input_pub_keys]) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - outputs = reference.create_outputs(input_priv_keys[:1], deterministic_nonce, addresses, hrp=HRP) - sender['expected']['outputs'] = outputs - sender['given']['vin'] = add_private_keys(deepcopy(inputs), input_priv_keys) - sender['given']['recipients'] = addresses - - output_pub_keys = [recipient[0] for recipient in outputs] - - test_case['sending'].extend([sender]) - recipient['given']['vin'] = inputs - recipient['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - scan, - Spend, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - labels={}, - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = spend.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient['expected']['outputs'] = add_to_wallet - - test_case['receiving'].extend([recipient]) - test_case["comment"] = "P2PKH and P2WPKH Uncompressed Keys are skipped" - return [test_case] + test_cases = [ + generated_test_case(inputs, scan, spend, addresses, labels=[], comment="P2PKH and P2WPKH Uncompressed Keys are skipped") + ] + return test_cases def generate_p2sh_tests(): - sender, recipient, test_case = new_test_case() - msg = hashlib.sha256(b'message').digest() - aux = hashlib.sha256(b'random auxiliary data').digest() + msg = hashlib.sha256(b'message').digest() outpoints = [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 1), @@ -1207,19 +762,14 @@ def generate_p2sh_tests(): ] sender_bip32_seed = 'deadbeef' recipient_bip32_seed = 'f00dbabe' - scan, spend, Scan, Spend = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) + scan, spend, Scan, Spend = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) address = reference.encode_silent_payment_address(Scan, Spend, hrp=HRP) - addresses = [(address, 1.0)] - - sender['given']['recipients'] = addresses - recipient['given']['key_material']['scan_priv_key'] = scan.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = spend.get_bytes().hex() - recipient['expected']['addresses'] = [address] + addresses = [address] inputs = [] input_priv_keys = [] input_pub_keys = [] - + # p2sh(p2wpkh) compressed i = len(inputs) priv, pub = get_key_pair(i, seed=bytes.fromhex(sender_bip32_seed)) @@ -1231,7 +781,8 @@ def generate_p2sh_tests(): 'vout': outpoints[i][1], 'scriptSig': f'{(len(p2wpkh)//2):0x}'+p2wpkh, 'txinwitness': serialize_witness_stack([sig, pub.get_bytes(False).hex()]), - 'prevout': { 'scriptPubKey': { 'hex': p2sh } } + 'prevout': { 'scriptPubKey': { 'hex': p2sh } }, + 'private_key': priv.get_bytes().hex(), }] input_priv_keys += [(priv, False)] input_pub_keys += [pub] @@ -1248,7 +799,8 @@ def generate_p2sh_tests(): 'vout': outpoints[i][1], 'scriptSig': f'{(len(p2wpkh)//2):0x}'+p2wpkh, 'txinwitness': serialize_witness_stack([sig, pub.get_bytes(False).hex()]), - 'prevout': { 'scriptPubKey': { 'hex': p2sh } } + 'prevout': { 'scriptPubKey': { 'hex': p2sh } }, + 'private_key': priv.get_bytes().hex(), }] input_priv_keys += [(priv, False)] @@ -1271,53 +823,17 @@ def generate_p2sh_tests(): 'vout': outpoints[i][1], 'scriptSig': f"00{''.join(sigs)}4c{(len(multisig_script)//2):0x}{multisig_script}", 'txinwitness': '', - 'prevout': { 'scriptPubKey': { 'hex': p2sh } } + 'prevout': { 'scriptPubKey': { 'hex': p2sh } }, + 'private_key': keys[0][0].get_bytes().hex(), }] input_priv_keys += [(keys[0][0], False)] - A_sum = sum([p for p in input_pub_keys]) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - outputs = reference.create_outputs(input_priv_keys[:1], deterministic_nonce, addresses, hrp=HRP) - sender['expected']['outputs'] = outputs - sender['given']['vin'] = add_private_keys(deepcopy(inputs), input_priv_keys) - sender['given']['recipients'] = addresses - - output_pub_keys = [recipient[0] for recipient in outputs] - - test_case['sending'].extend([sender]) - recipient['given']['vin'] = inputs - recipient['given']['outputs'] = output_pub_keys - - add_to_wallet = reference.scanning( - scan, - Spend, - A_sum, - deterministic_nonce, - [ECPubKey().set(bytes.fromhex(pub)) for pub in output_pub_keys], - labels={}, - ) - for o in add_to_wallet: - - pubkey = ECPubKey().set(bytes.fromhex(o['pub_key'])) - full_private_key = spend.add( - bytes.fromhex(o['priv_key_tweak']) - ) - if full_private_key.get_pubkey().get_y()%2 != 0: - full_private_key.negate() - - sig = full_private_key.sign_schnorr(msg, aux) - assert pubkey.verify_schnorr(sig, msg) - o['signature'] = sig.hex() - - recipient['expected']['outputs'] = add_to_wallet - - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient]) - test_case["comment"] = "Skip invalid P2SH inputs" - return [test_case] + test_cases = [ + generated_test_case(inputs, scan, spend, addresses, labels=[], comment="Skip invalid P2SH inputs") + ] + return test_cases def generate_no_outputs_tests(): - sender, recipient, test_case = new_test_case() outpoints = [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), @@ -1337,14 +853,7 @@ def generate_no_outputs_tests(): i2.negate() I2.negate() - scan, spend, Scan, Spend = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) - address = reference.encode_silent_payment_address(Scan, Spend, hrp=HRP) - addresses = [(address, 1.0)] - - sender['given']['recipients'] = addresses - recipient['given']['key_material']['scan_priv_key'] = scan.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = spend.get_bytes().hex() - recipient['expected']['addresses'] = [address] + scan, spend, _, _ = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) inputs = [] input_priv_keys = [] @@ -1357,7 +866,8 @@ def generate_no_outputs_tests(): 'vout': outpoints[i][1], 'scriptSig': "", 'txinwitness': get_p2tr_witness(i1), - 'prevout': { "scriptPubKey": { "hex": get_p2tr_scriptPubKey(I1) } } + 'prevout': { "scriptPubKey": { "hex": get_p2tr_scriptPubKey(I1) } }, + 'private_key': i1.get_bytes().hex(), }] input_priv_keys += [(i1, True)] tr_input_pub_keys += [I1] @@ -1370,37 +880,26 @@ def generate_no_outputs_tests(): 'scriptSig': get_p2pkh_scriptsig(pub, priv), 'txinwitness': '', 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(pub)}}, + 'private_key': priv.get_bytes().hex(), }] input_priv_keys += [(priv, False)] pkpkh_input_pub_keys += [pub] - sender['given']['vin'] = add_private_keys(deepcopy(inputs), input_priv_keys) - sender['given']['recipients'] = addresses - recipient['given']['vin'] = inputs - - A_sum = sum([p if p.get_y()%2==0 else p * -1 for p in tr_input_pub_keys] + pkpkh_input_pub_keys) - deterministic_nonce = reference.get_input_hash([COutPoint(deser_txid(o[0]), o[1]) for o in outpoints], A_sum) - # Regular taproot scriptpubkey regular_p2tr = I2.get_bytes(True).hex() # Decoy scriptpubkey - scan_decoy, spend_decoy, Scan_decoy, Spend_decoy = reference.derive_silent_payment_key_pair(bytes.fromhex("decafbad")) + _, _, Scan_decoy, Spend_decoy = derive_silent_payment_key_pair(bytes.fromhex("decafbad")) decoy_address = reference.encode_silent_payment_address(Scan_decoy, Spend_decoy, hrp=HRP) - decoy_outputs = reference.create_outputs(input_priv_keys, deterministic_nonce, [(decoy_address, 1.0)], hrp=HRP) - outputs = reference.create_outputs(input_priv_keys, deterministic_nonce, [(address, 1.0)], hrp=HRP) - sender['expected']['outputs'] = outputs - recipient['given']['outputs'] = [regular_p2tr] + [d[0] for d in decoy_outputs] - recipient['expected']['outputs'] = [] - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient]) - test_case["comment"] = "Recipient ignores unrelated outputs" - return [test_case] + test_cases = [ + generated_test_case(inputs, scan, spend, [decoy_address], labels=[], comment="Recipient ignores unrelated outputs") + ] + test_cases[0]['receiving'][0]['given']['outputs'].append(regular_p2tr) + return test_cases def generate_no_valid_inputs_tests(): - sender, recipient, test_case = new_test_case() outpoints = [ ("f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", 0), @@ -1409,14 +908,9 @@ def generate_no_valid_inputs_tests(): sender_bip32_seed = 'deadbeef' recipient_bip32_seed = 'f00dbabe' - scan, spend, Scan, Spend = reference.derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) + scan, spend, Scan, Spend = derive_silent_payment_key_pair(bytes.fromhex(recipient_bip32_seed)) address = reference.encode_silent_payment_address(Scan, Spend, hrp=HRP) - addresses = [(address, 1.0)] - - sender['given']['recipients'] = addresses - recipient['given']['key_material']['scan_priv_key'] = scan.get_bytes().hex() - recipient['given']['key_material']['spend_priv_key'] = spend.get_bytes().hex() - recipient['expected']['addresses'] = [address] + addresses = [address] inputs = [] input_priv_keys = [] @@ -1429,7 +923,8 @@ def generate_no_valid_inputs_tests(): 'vout': outpoints[i][1], 'scriptSig': get_p2pkh_scriptsig(pub, priv), 'txinwitness': '', - 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(pub)}} + 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(pub)}}, + 'private_key': priv.get_bytes().hex(), }] input_priv_keys += [(priv, False)] @@ -1441,26 +936,20 @@ def generate_no_valid_inputs_tests(): 'vout': outpoints[i][1], 'scriptSig': get_p2pkh_scriptsig(pub, priv), 'txinwitness': '', - 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(pub)}} + 'prevout': {'scriptPubKey': {'hex': get_p2pkh_scriptPubKey(pub)}}, + 'private_key': priv.get_bytes().hex(), }] input_priv_keys += [(priv, False)] - sender['given']['vin'] = add_private_keys(deepcopy(inputs), input_priv_keys) - sender['given']['recipients'] = addresses - recipient['given']['vin'] = inputs - # Regular taproot pubkeys regular_p2tr1 = get_key_pair(i, seed=bytes.fromhex(sender_bip32_seed))[1].get_bytes(True).hex() regular_p2tr2 = get_key_pair(i+1, seed=bytes.fromhex(sender_bip32_seed))[1].get_bytes(True).hex() - sender['expected']['outputs'] = [] - recipient['given']['outputs'] = [regular_p2tr1, regular_p2tr2] - recipient['expected']['outputs'] = [] - - test_case['sending'].extend([sender]) - test_case['receiving'].extend([recipient]) - test_case["comment"] = "No valid inputs, sender generates no outputs" - return [test_case] + test_cases = [ + generated_test_case(inputs, scan, spend, addresses, labels=[], comment="No valid inputs, sender generates no outputs"), + ] + test_cases[0]['receiving'][0]['given']['outputs'] = [regular_p2tr1, regular_p2tr2] + return test_cases with open("send_and_receive_test_vectors.json", "w") as f: json.dump( diff --git a/reference.py b/reference.py old mode 100644 new mode 100755 index e16d69d..c98dac8 --- a/reference.py +++ b/reference.py @@ -1,13 +1,13 @@ #!/usr/bin/env python3 +# For running the test vectors, run this script: +# ./reference.py send_and_receive_test_vectors.json -import bip32 # type: ignore import hashlib import json -import struct -from io import BytesIO -from typing import List, Tuple, Dict, Union, cast -from sys import argv +from typing import List, Tuple, Dict, cast +from sys import argv, exit from functools import reduce +from itertools import permutations # local files from bech32m import convertbits, bech32_encode, decode, Encoding @@ -74,36 +74,24 @@ def get_pubkey_from_input(vin: VinInfo) -> ECPubKey: if (internal_key == NUMS_H.to_bytes(32, 'big')): # Skip if NUMS_H return ECPubKey() - + pubkey = ECPubKey().set(vin.prevout[2:]) if (pubkey.valid) & (pubkey.compressed): - return pubkey - - + return pubkey + + return ECPubKey() def get_input_hash(outpoints: List[COutPoint], sum_input_pubkeys: ECPubKey) -> bytes: - lowest_outpoint = sorted(outpoints, key=lambda outpoint: (outpoint.hash, outpoint.n))[0] + lowest_outpoint = sorted(outpoints, key=lambda outpoint: outpoint.serialize())[0] return TaggedHash("BIP0352/Inputs", lowest_outpoint.serialize() + cast(bytes, sum_input_pubkeys.get_bytes(False))) -def derive_silent_payment_key_pair(seed: bytes) -> Tuple[ECKey, ECKey, ECPubKey, ECPubKey]: - SCAN_KEY = "m/352h/0h/0h/1h/0" - SPEND_KEY = "m/352h/0h/0h/0h/0" - - master = bip32.BIP32.from_seed(seed) - scan = ECKey().set(master.get_privkey_from_path(SCAN_KEY)) - spend = ECKey().set(master.get_privkey_from_path(SPEND_KEY)) - Scan = scan.get_pubkey() - Spend = spend.get_pubkey() - - return scan, spend, Scan, Spend - def encode_silent_payment_address(B_scan: ECPubKey, B_m: ECPubKey, hrp: str = "tsp", version: int = 0) -> str: - data = convertbits(B_scan.get_bytes(False) + B_m.get_bytes(False), 8, 5) - return bech32_encode(hrp, [version] + data, Encoding.BECH32M) + data = convertbits(cast(bytes, B_scan.get_bytes(False)) + cast(bytes, B_m.get_bytes(False)), 8, 5) + return bech32_encode(hrp, [version] + cast(List[int], data), Encoding.BECH32M) def generate_label(b_scan: ECKey, m: int) -> bytes: @@ -120,14 +108,16 @@ def create_labeled_silent_payment_address(b_scan: ECKey, B_spend: ECPubKey, m: i def decode_silent_payment_address(address: str, hrp: str = "tsp") -> Tuple[ECPubKey, ECPubKey]: - version, data = decode(hrp, address) + _, data = decode(hrp, address) + if data is None: + return ECPubKey(), ECPubKey() B_scan = ECPubKey().set(data[:33]) B_spend = ECPubKey().set(data[33:]) return B_scan, B_spend -def create_outputs(input_priv_keys: List[Tuple[ECKey, bool]], input_hash: bytes, recipients: List[Tuple[str, float]], hrp="tsp") -> List[Tuple[str, float]]: +def create_outputs(input_priv_keys: List[Tuple[ECKey, bool]], input_hash: bytes, recipients: List[str], hrp="tsp") -> List[str]: G = ECKey().set(1).get_pubkey() negated_keys = [] for key, is_xonly in input_priv_keys: @@ -137,30 +127,25 @@ def create_outputs(input_priv_keys: List[Tuple[ECKey, bool]], input_hash: bytes, negated_keys.append(k) a_sum = sum(negated_keys) - silent_payment_groups: Dict[ECPubKey, List[Tuple[ECPubKey, float]]] = {} + silent_payment_groups: Dict[ECPubKey, List[ECPubKey]] = {} for recipient in recipients: - addr, amount = recipient - B_scan, B_m = decode_silent_payment_address(addr, hrp=hrp) + B_scan, B_m = decode_silent_payment_address(recipient, hrp=hrp) if B_scan in silent_payment_groups: - silent_payment_groups[B_scan].append((B_m, amount)) + silent_payment_groups[B_scan].append(B_m) else: - silent_payment_groups[B_scan] = [(B_m, amount)] + silent_payment_groups[B_scan] = [B_m] outputs = [] for B_scan, B_m_values in silent_payment_groups.items(): - k = 0 ecdh_shared_secret = input_hash * a_sum * B_scan - - # Sort B_m_values by amount to ensure determinism in the tests - # Note: the receiver can find the outputs regardless of the ordering, this - # sorting step is only for testing - B_m_values.sort(key=lambda x: x[1]) - for B_m, amount in B_m_values: + k = 0 + for B_m in B_m_values: t_k = TaggedHash("BIP0352/SharedSecret", ecdh_shared_secret.get_bytes(False) + ser_uint32(k)) P_km = B_m + t_k * G - outputs.append((P_km.get_bytes().hex(), amount)) + outputs.append(P_km.get_bytes().hex()) k += 1 - return outputs + + return list(set(outputs)) def scanning(b_scan: ECKey, B_spend: ECPubKey, A_sum: ECPubKey, input_hash: bytes, outputs_to_check: List[ECPubKey], labels: Dict[str, str] = {}) -> List[Dict[str, str]]: @@ -189,6 +174,7 @@ def scanning(b_scan: ECKey, B_spend: ECPubKey, A_sum: ECPubKey, input_hash: byte }) outputs_to_check.remove(output) k += 1 + break else: output.negate() m_G_sub = output - P_k @@ -209,6 +195,10 @@ def scanning(b_scan: ECKey, B_spend: ECPubKey, A_sum: ECPubKey, input_hash: byte if __name__ == "__main__": + if len(argv) != 2 or argv[1] in ('-h', '--help'): + print("Usage: ./reference.py send_and_receive_test_vectors.json") + exit(0) + with open(argv[1], "r") as f: test_data = json.loads(f.read()) @@ -243,18 +233,20 @@ def scanning(b_scan: ECKey, B_spend: ECPubKey, A_sum: ECPubKey, input_hash: byte is_p2tr(vin.prevout), )) input_pub_keys.append(pubkey) - + sending_outputs = [] if (len(input_pub_keys) > 0): A_sum = reduce(lambda x, y: x + y, input_pub_keys) input_hash = get_input_hash([vin.outpoint for vin in vins], A_sum) - sending_outputs = [ - list(t) - for t in create_outputs(input_priv_keys, input_hash, given["recipients"], hrp="sp") - ] - # Check that for a given set of inputs, we were able to generate the expected outputs for the receiver - sending_outputs.sort(key=lambda x: cast(float, x[1])) - assert sending_outputs == expected["outputs"], "Sending test failed" + sending_outputs = create_outputs(input_priv_keys, input_hash, given["recipients"], hrp="sp") + + # Note: order doesn't matter for creating/finding the outputs. However, different orderings of the recipient addresses + # will produce different generated outputs if sending to multiple silent payment addresses belonging to the + # same sender but with different labels. Because of this, expected["outputs"] contains all possible valid output sets, + # based on all possible permutations of recipient address orderings. Must match exactly one of the possible output sets. + assert(any(set(sending_outputs) == set(lst) for lst in expected["outputs"])), "Sending test failed" + else: + assert(sending_outputs == expected["outputs"][0] == []), "Sending test failed" # Test receiving msg = hashlib.sha256(b"message").digest() @@ -330,7 +322,14 @@ def scanning(b_scan: ECKey, B_spend: ECPubKey, A_sum: ECPubKey, input_hash: byte assert pub_key.verify_schnorr(sig, msg), f"Invalid signature for {pub_key}" output["signature"] = sig.hex() - # Check if the found output public keys match the expected output public keys - assert add_to_wallet == expected["outputs"], "Receiving test failed" + # Note: order doesn't matter for creating/finding the outputs. However, different orderings of the recipient addresses + # will produce different generated outputs if sending to multiple silent payment addresses belonging to the + # same sender but with different labels. Because of this, expected["outputs"] contains all possible valid output sets, + # based on all possible permutations of recipient address orderings. Must match exactly one of the possible found output + # sets in expected["outputs"] + generated_set = {frozenset(d.items()) for d in add_to_wallet} + expected_set = {frozenset(d.items()) for d in expected["outputs"]} + assert generated_set == expected_set, "Receive test failed" + print("All tests passed") diff --git a/secp256k1.py b/secp256k1.py index 10083c6..32ac2cb 100644 --- a/secp256k1.py +++ b/secp256k1.py @@ -254,6 +254,10 @@ def __eq__(self, other): assert isinstance(other, ECPubKey) return self.get_bytes() == other.get_bytes() + def __lt__(self, other): + assert isinstance(other, ECPubKey) + return self.get_bytes(False) < other.get_bytes(False) + def __hash__(self): return hash(self.get_bytes()) diff --git a/send_and_receive_test_vectors.json b/send_and_receive_test_vectors.json index 8d6dcf2..f9b205b 100644 --- a/send_and_receive_test_vectors.json +++ b/send_and_receive_test_vectors.json @@ -31,17 +31,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", - 1.0 + "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1" ] ] } @@ -89,8 +85,8 @@ ], "outputs": [ { - "pub_key": "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", "priv_key_tweak": "f438b40179a3c4262de12986c0e6cce0634007cdc79c1dcd3e20b9ebc2e7eef6", + "pub_key": "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", "signature": "74f85b856337fbe837643b86f462118159f93ac4acc2671522f27e8f67b079959195ccc7a5dbee396d2909f5d680d6e30cda7359aa2755822509b70d6b0687a1" } ] @@ -130,17 +126,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", - 1.0 + "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1" ] ] } @@ -188,8 +180,8 @@ ], "outputs": [ { - "pub_key": "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", "priv_key_tweak": "f438b40179a3c4262de12986c0e6cce0634007cdc79c1dcd3e20b9ebc2e7eef6", + "pub_key": "3e9fce73d4e77a4809908e3c3a2e54ee147b9312dc5044a193d1fc85de46e3c1", "signature": "74f85b856337fbe837643b86f462118159f93ac4acc2671522f27e8f67b079959195ccc7a5dbee396d2909f5d680d6e30cda7359aa2755822509b70d6b0687a1" } ] @@ -229,17 +221,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "79e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6", - 1.0 + "79e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6" ] ] } @@ -287,8 +275,8 @@ ], "outputs": [ { - "pub_key": "79e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6", "priv_key_tweak": "4851455bfbe1ab4f80156570aa45063201aa5c9e1b1dcd29f0f8c33d10bf77ae", + "pub_key": "79e71baa2ba3fc66396de3a04f168c7bf24d6870ec88ca877754790c1db357b6", "signature": "10332eea808b6a13f70059a8a73195808db782012907f5ba32b6eae66a2f66b4f65147e2b968a1678c5f73d57d5d195dbaf667b606ff80c8490eac1f3b710657" } ] @@ -328,17 +316,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38", - 1.0 + "f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38" ] ] } @@ -386,8 +370,8 @@ ], "outputs": [ { - "pub_key": "f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38", "priv_key_tweak": "ab0c9b87181bf527879f48db9f14a02233619b986f8e8f2d5d408ce68a709f51", + "pub_key": "f4c2da807f89cb1501f1a77322a895acfb93c28e08ed2724d2beb8e44539ba38", "signature": "398a9790865791a9db41a8015afad3a47d60fec5086c50557806a49a1bc038808632b8fe679a7bb65fc6b455be994502eed849f1da3729cd948fc7be73d67295" } ] @@ -395,6 +379,101 @@ } ] }, + { + "comment": "Outpoint ordering byte-lexicographically vs. vout-integer", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 1, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + }, + "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 256, + "scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac" + } + }, + "private_key": "93f5ed907ad5b2bdbbdcb5d9116ebc0a4e1f92f910d5260237fa45a9408aad16" + } + ], + "recipients": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ] + }, + "expected": { + "outputs": [ + [ + "a85ef8701394b517a4b35217c4bd37ac01ebeed4b008f8d0879f9e09ba95319c" + ] + ] + } + } + ], + "receiving": [ + { + "given": { + "vin": [ + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 1, + "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" + } + } + }, + { + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "vout": 256, + "scriptSig": "48304602210086783ded73e961037e77d49d9deee4edc2b23136e9728d56e4491c80015c3a63022100fda4c0f21ea18de29edbce57f7134d613e044ee150a89e2e64700de2d4e83d4e2103bd85685d03d111699b15d046319febe77f8de5286e9e512703cdee1bf3be3792", + "txinwitness": "", + "prevout": { + "scriptPubKey": { + "hex": "76a914d9317c66f54ff0a152ec50b1d19c25be50c8e15988ac" + } + } + } + ], + "outputs": [ + "a85ef8701394b517a4b35217c4bd37ac01ebeed4b008f8d0879f9e09ba95319c" + ], + "key_material": { + "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", + "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" + ], + "outputs": [ + { + "priv_key_tweak": "c8ac0292997b5bca98b3ebd99a57e253071137550f270452cd3df8a3e2266d36", + "pub_key": "a85ef8701394b517a4b35217c4bd37ac01ebeed4b008f8d0879f9e09ba95319c", + "signature": "c036ee38bfe46aba03234339ae7219b31b824b52ef9d5ce05810a0d6f62330dedc2b55652578aa5bdabf930fae941acd839d5a66f8fce7caa9710ccb446bddd1" + } + ] + } + } + ] + }, { "comment": "Single recipient: multiple UTXOs from the same public key", "sending": [ @@ -427,17 +506,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566", - 1.0 + "548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566" ] ] } @@ -485,8 +560,8 @@ ], "outputs": [ { - "pub_key": "548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566", "priv_key_tweak": "f032695e2636619efa523fffaa9ef93c8802299181fd0461913c1b8daf9784cd", + "pub_key": "548ae55c8eec1e736e8d3e520f011f1f42a56d166116ad210b3937599f87f566", "signature": "f238386c5d5e5444f8d2c75aabbcb28c346f208c76f60823f5de3b67b79e0ec72ea5de2d7caec314e0971d3454f122dda342b3eede01b3857e83654e36b25f76" } ] @@ -526,17 +601,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb", - 1.0 + "de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb" ] ] } @@ -584,8 +655,8 @@ ], "outputs": [ { - "pub_key": "de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb", "priv_key_tweak": "3fb9ce5ce1746ced103c8ed254e81f6690764637ddbc876ec1f9b3ddab776b03", + "pub_key": "de88bea8e7ffc9ce1af30d1132f910323c505185aec8eae361670421e749a1fb", "signature": "c5acd25a8f021a4192f93bc34403fd8b76484613466336fb259c72d04c169824f2690ca34e96cee86b69f376c8377003268fda56feeb1b873e5783d7e19bcca5" } ] @@ -625,17 +696,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "77cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1", - 1.0 + "77cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1" ] ] } @@ -683,8 +750,8 @@ ], "outputs": [ { - "pub_key": "77cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1", "priv_key_tweak": "f5382508609771068ed079b24e1f72e4a17ee6d1c979066bf1d4e2a5676f09d4", + "pub_key": "77cab7dd12b10259ee82c6ea4b509774e33e7078e7138f568092241bf26b99f1", "signature": "ff65833b8fd1ed3ef9d0443b4f702b45a3f2dd457ba247687e8207745c3be9d2bdad0ab3f07118f8b2efc6a04b95f7b3e218daf8a64137ec91bd2fc67fc137a5" } ] @@ -724,17 +791,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "30523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0", - 1.0 + "30523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0" ] ] } @@ -782,8 +845,8 @@ ], "outputs": [ { - "pub_key": "30523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0", "priv_key_tweak": "b40017865c79b1fcbed68896791be93186d08f47e416b289b8c063777e14e8df", + "pub_key": "30523cca96b2a9ae3c98beb5e60f7d190ec5bc79b2d11a0b2d4d09a608c448f0", "signature": "d1edeea28cf1033bcb3d89376cabaaaa2886cbd8fda112b5c61cc90a4e7f1878bdd62180b07d1dfc8ffee1863c525a0c7b5bcd413183282cfda756cb65787266" } ] @@ -823,17 +886,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a", - 1.0 + "359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a" ] ] } @@ -881,8 +940,8 @@ ], "outputs": [ { - "pub_key": "359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a", "priv_key_tweak": "a2f9dd05d1d398347c885d9c61a64d18a264de6d49cea4326bafc2791d627fa7", + "pub_key": "359358f59ee9e9eec3f00bdf4882570fd5c182e451aa2650b788544aff012a3a", "signature": "96038ad233d8befe342573a6e54828d863471fb2afbad575cc65271a2a649480ea14912b6abbd3fbf92efc1928c036f6e3eef927105af4ec1dd57cb909f360b8" } ] @@ -922,25 +981,15 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 2.0 - ], - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 3.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ - [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - 2.0 - ], [ "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", - 3.0 + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac" ] ] } @@ -974,10 +1023,8 @@ } ], "outputs": [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", - "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", - "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a" + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac" ], "key_material": { "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", @@ -991,14 +1038,14 @@ ], "outputs": [ { - "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", - "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" - }, - { - "pub_key": "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", "priv_key_tweak": "d97e442d110c0bdd31161a7bb6e7862e038d02a09b1484dfbb463f2e0f7c9230", + "pub_key": "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", "signature": "29bd25d0f808d7fcd2aa6d5ed206053899198397506c301b218a9e47a3d7070af03e903ff718978d50d1b6b9af8cc0e313d84eda5d5b1e8e85e5516d630bbeb9" + }, + { + "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", + "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" } ] } @@ -1037,41 +1084,17 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 2.0 - ], - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 3.0 - ], - [ - "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn", - 4.0 - ], - [ - "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn", - 5.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn", + "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn" ] }, "expected": { "outputs": [ - [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - 2.0 - ], - [ - "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", - 3.0 - ], - [ - "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", - 4.0 - ], [ "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a", - 5.0 + "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac" ] ] } @@ -1105,66 +1128,9 @@ } ], "outputs": [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", - "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", - "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a" - ], - "key_material": { - "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", - "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" - }, - "labels": [] - }, - "expected": { - "addresses": [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" - ], - "outputs": [ - { - "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", - "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" - }, - { - "pub_key": "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", - "priv_key_tweak": "d97e442d110c0bdd31161a7bb6e7862e038d02a09b1484dfbb463f2e0f7c9230", - "signature": "29bd25d0f808d7fcd2aa6d5ed206053899198397506c301b218a9e47a3d7070af03e903ff718978d50d1b6b9af8cc0e313d84eda5d5b1e8e85e5516d630bbeb9" - } - ] - } - }, - { - "given": { - "vin": [ - { - "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", - "vout": 0, - "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", - "txinwitness": "", - "prevout": { - "scriptPubKey": { - "hex": "76a91419c2f3ae0ca3b642bd3e49598b8da89f50c1416188ac" - } - } - }, - { - "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", - "vout": 0, - "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b972103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", - "txinwitness": "", - "prevout": { - "scriptPubKey": { - "hex": "76a9147cdd63cc408564188e8e472640e921c7c90e651d88ac" - } - } - } - ], - "outputs": [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", + "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a", "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", - "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a" + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac" ], "key_material": { "spend_priv_key": "9902c3c56e84002a7cd410113a9ab21d142be7f53cf5200720bb01314c5eb920", @@ -1178,14 +1144,14 @@ ], "outputs": [ { - "pub_key": "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", - "priv_key_tweak": "2f17ea873a0047fc01ba8010fef0969e76d0e4283f600d48f735098b1fee6eb9", - "signature": "c26f4e3cf371b90b840f48ea0e761b5ec31883ed55719f9ef06a90e282d85f565790ab780a3f491bc2668cc64e944dca849d1022a878cdadb8d168b8da4a6da3" - }, - { - "pub_key": "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a", "priv_key_tweak": "72cd082cccb633bf85240a83494b32dc943a4d05647a6686d23ad4ca59c0ebe4", + "pub_key": "2e847bb01d1b491da512ddd760b8509617ee38057003d6115d00ba562451323a", "signature": "38745f3d9f5eef0b1cfb17ca314efa8c521efab28a23aa20ec5e3abb561d42804d539906dce60c4ee7977966184e6f2cab1faa0e5377ceb7148ec5218b4e7878" + }, + { + "priv_key_tweak": "2f17ea873a0047fc01ba8010fef0969e76d0e4283f600d48f735098b1fee6eb9", + "pub_key": "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", + "signature": "c26f4e3cf371b90b840f48ea0e761b5ec31883ed55719f9ef06a90e282d85f565790ab780a3f491bc2668cc64e944dca849d1022a878cdadb8d168b8da4a6da3" } ] } @@ -1193,7 +1159,7 @@ ] }, { - "comment": "Receiving with labels: label with odd parity", + "comment": "Receiving with labels: label with even parity", "sending": [ { "given": { @@ -1224,17 +1190,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjex54dmqmmv6rw353tsuqhs99ydvadxzrsy9nuvk74epvee55drs734pqq", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjex54dmqmmv6rw353tsuqhs99ydvadxzrsy9nuvk74epvee55drs734pqq" ] }, "expected": { "outputs": [ [ - "d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a", - 1.0 + "d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a" ] ] } @@ -1289,8 +1251,8 @@ ], "outputs": [ { - "pub_key": "d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a", "priv_key_tweak": "51d4e9d0d482b5700109b4b2e16ff508269b03d800192a043d61dca4a0a72a52", + "pub_key": "d014d4860f67d607d60b1af70e0ee236b99658b61bb769832acbbe87c374439a", "signature": "c30fa63bad6f0a317f39a773a5cbf0b0f8193c71dfebba05ee6ae4ed28e3775e6e04c3ea70a83703bb888122855dc894cab61692e7fd10c9b3494d479a60785e" } ] @@ -1330,17 +1292,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqsg59z2rppn4qlkx0yz9sdltmjv3j8zgcqadjn4ug98m3t6plujsq9qvu5n", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqsg59z2rppn4qlkx0yz9sdltmjv3j8zgcqadjn4ug98m3t6plujsq9qvu5n" ] }, "expected": { "outputs": [ [ - "67626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c", - 1.0 + "67626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c" ] ] } @@ -1395,8 +1353,8 @@ ], "outputs": [ { - "pub_key": "67626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c", "priv_key_tweak": "6024ae214876356b8d917716e7707d267ae16a0fdb07de2a786b74a7bbcddead", + "pub_key": "67626aebb3c4307cf0f6c39ca23247598fabf675ab783292eb2f81ae75ad1f8c", "signature": "a86d554d0d6b7aa0907155f7e0b47f0182752472fffaeddd68da90e99b9402f166fd9b33039c302c7115098d971c1399e67c19e9e4de180b10ea0b9d6f0db832" } ] @@ -1405,7 +1363,7 @@ ] }, { - "comment": "Receiving with labels: label with odd parity", + "comment": "Receiving with labels: large label integer", "sending": [ { "given": { @@ -1436,17 +1394,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq7c2zfthc6x3a5yecwc52nxa0kfd20xuz08zyrjpfw4l2j257yq6qgnkdh5", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgq7c2zfthc6x3a5yecwc52nxa0kfd20xuz08zyrjpfw4l2j257yq6qgnkdh5" ] }, "expected": { "outputs": [ [ - "7efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951", - 1.0 + "7efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951" ] ] } @@ -1501,8 +1455,8 @@ ], "outputs": [ { - "pub_key": "7efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951", "priv_key_tweak": "e336b92330c33030285ce42e4115ad92d5197913c88e06b9072b4a9b47c664a2", + "pub_key": "7efa60ce78ac343df8a013a2027c6c5ef29f9502edcbd769d2c21717fecc5951", "signature": "c9e80dd3bdd25ca2d352ce77510f1aed37ba3509dc8cc0677f2d7c2dd04090707950ce9dd6c83d2a428063063aff5c04f1744e334f661f2fc01b4ef80b50f739" } ] @@ -1511,7 +1465,7 @@ ] }, { - "comment": "Multiple outputs with labels: multiple outputs for labeled address; same recipient", + "comment": "Multiple outputs with labels: un-labeled and labeled address; same recipient", "sending": [ { "given": { @@ -1542,25 +1496,19 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ], - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", - 2.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - 1.0 + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac" ], [ - "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", - 2.0 + "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", + "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca" ] ] } @@ -1594,8 +1542,8 @@ } ], "outputs": [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c" + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac" ], "key_material": { "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", @@ -1612,14 +1560,14 @@ ], "outputs": [ { - "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", - "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" - }, - { - "pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", "priv_key_tweak": "43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914", + "pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", "signature": "15c92509b67a6c211ebb4a51b7528d0666e6720de2343b2e92cfb97942ca14693c1f1fdc8451acfdb2644039f8f5c76114807fdc3d3a002d8a46afab6756bd75" + }, + { + "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", + "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" } ] } @@ -1658,25 +1606,15 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", - 3.0 - ], - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", - 4.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj" ] }, "expected": { "outputs": [ - [ - "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", - 3.0 - ], [ "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", - 4.0 + "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c" ] ] } @@ -1710,8 +1648,8 @@ } ], "outputs": [ - "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", - "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c" + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c" ], "key_material": { "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", @@ -1728,14 +1666,14 @@ ], "outputs": [ { - "pub_key": "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", - "priv_key_tweak": "9d5fd3b91cac9ddfea6fc2e6f9386f680e6cee623cda02f53706306c081de87f", - "signature": "db0dfacc98b6a6fcc67cc4631f080b1ca38c60d8c397f2f19843f8f95ec91594b24e47c5bd39480a861c1209f7e3145c440371f9191fb96e324690101eac8e8e" - }, - { - "pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", "priv_key_tweak": "43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914", + "pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", "signature": "15c92509b67a6c211ebb4a51b7528d0666e6720de2343b2e92cfb97942ca14693c1f1fdc8451acfdb2644039f8f5c76114807fdc3d3a002d8a46afab6756bd75" + }, + { + "priv_key_tweak": "9d5fd3b91cac9ddfea6fc2e6f9386f680e6cee623cda02f53706306c081de87f", + "pub_key": "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", + "signature": "db0dfacc98b6a6fcc67cc4631f080b1ca38c60d8c397f2f19843f8f95ec91594b24e47c5bd39480a861c1209f7e3145c440371f9191fb96e324690101eac8e8e" } ] } @@ -1743,7 +1681,7 @@ ] }, { - "comment": "Multiple outputs with labels: multiple outputs for labeled address; same recipient", + "comment": "Multiple outputs with labels: un-labeled, labeled, and multiple outputs for labeled address; same recipients", "sending": [ { "given": { @@ -1774,41 +1712,85 @@ } ], "recipients": [ + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjyh2ju7hd5gj57jg5r9lev3pckk4n2shtzaq34467erzzdfajfggty6aa5", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjyh2ju7hd5gj57jg5r9lev3pckk4n2shtzaq34467erzzdfajfggty6aa5" + ] + }, + "expected": { + "outputs": [ [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 5.0 + "006a02c308ccdbf3ac49f0638f6de128f875db5a213095cf112b3b77722472ae", + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701", + "ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa" ], [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", - 6.0 + "006a02c308ccdbf3ac49f0638f6de128f875db5a213095cf112b3b77722472ae", + "3edf1ff6657c6e69568811bd726a7a7f480493aa42161acfe8dd4f44521f99ed", + "7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3", + "ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa" ], [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjyh2ju7hd5gj57jg5r9lev3pckk4n2shtzaq34467erzzdfajfggty6aa5", - 7.0 + "006a02c308ccdbf3ac49f0638f6de128f875db5a213095cf112b3b77722472ae", + "7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3", + "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", + "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701" ], [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjyh2ju7hd5gj57jg5r9lev3pckk4n2shtzaq34467erzzdfajfggty6aa5", - 8.0 - ] - ] - }, - "expected": { - "outputs": [ + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + "3c54444944d176437644378c23efb999ab6ab1cacdfe1dc1537b607e3df330e2", + "ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa", + "f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b" + ], [ + "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", + "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701", "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - 5.0 + "f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b" ], [ - "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", - 6.0 + "3c54444944d176437644378c23efb999ab6ab1cacdfe1dc1537b607e3df330e2", + "602e10e6944107c9b48bd885b493676578c935723287e0ab2f8b7f136862568e", + "7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3", + "ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa" + ], + [ + "3c54444944d176437644378c23efb999ab6ab1cacdfe1dc1537b607e3df330e2", + "7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3", + "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", + "f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b" + ], + [ + "3edf1ff6657c6e69568811bd726a7a7f480493aa42161acfe8dd4f44521f99ed", + "7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3", + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b" + ], + [ + "3edf1ff6657c6e69568811bd726a7a7f480493aa42161acfe8dd4f44521f99ed", + "ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa", + "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", + "f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b" + ], + [ + "602e10e6944107c9b48bd885b493676578c935723287e0ab2f8b7f136862568e", + "7ee1543ed5d123ffa66fbebc128c020173eb490d5fa2ba306e0c9573a77db8f3", + "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701", + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac" ], [ + "602e10e6944107c9b48bd885b493676578c935723287e0ab2f8b7f136862568e", "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701", - 7.0 + "ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa", + "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca" ], [ - "f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b", - 8.0 + "83dc944e61603137294829aed56c74c9b087d80f2c021b98a7fae5799000696c", + "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701", + "e976a58fbd38aeb4e6093d4df02e9c1de0c4513ae0c588cef68cda5b2f8834ca", + "f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b" ] ] } @@ -1842,34 +1824,46 @@ } ], "outputs": [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", + "006a02c308ccdbf3ac49f0638f6de128f875db5a213095cf112b3b77722472ae", "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701", - "f4569fc5f69c10f0082cfbb8e072e6266ec55f69fba8cffca4cbb4c144b7e59b" + "ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa" ], "key_material": { "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", "scan_priv_key": "0f694e068028a717f8af6b9411f9a133dd3565258714cc226594b34db90c1f2c" }, "labels": [ - 1 + 1, + 1337 ] }, "expected": { "addresses": [ "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj" + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqaxww2fnhrx05cghth75n0qcj59e3e2anscr0q9wyknjxtxycg07y3pevyj", + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjyh2ju7hd5gj57jg5r9lev3pckk4n2shtzaq34467erzzdfajfggty6aa5" ], "outputs": [ { - "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", - "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" + "priv_key_tweak": "4e3352fbe0505c25e718d96007c259ef08db34f8c844e4ff742d9855ff03805a", + "pub_key": "006a02c308ccdbf3ac49f0638f6de128f875db5a213095cf112b3b77722472ae", + "signature": "6eeae1ea9eb826e3d0e812f65937100e0836ea188c04f36fabc4981eda29de8d3d3529390a0a8b3d830f7bca4f5eae5994b9788ddaf05ad259ffe26d86144b4b" }, { - "pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", "priv_key_tweak": "43100f89f1a6bf10081c92b473ffc57ceac7dbed600b6aba9bb3976f17dbb914", + "pub_key": "39f42624d5c32a77fda80ff0acee269afec601d3791803e80252ae04e4ffcf4c", "signature": "15c92509b67a6c211ebb4a51b7528d0666e6720de2343b2e92cfb97942ca14693c1f1fdc8451acfdb2644039f8f5c76114807fdc3d3a002d8a46afab6756bd75" + }, + { + "priv_key_tweak": "bf709f98d4418f8a67e738154ae48818dad44689cd37fbc070891a396dd1c633", + "pub_key": "ae1a780c04237bd577283c3ddb2e499767c3214160d5a6b0767e6b8c278bd701", + "signature": "42a19fd8a63dde1824966a95d65a28203e631e49bf96ca5dae1b390e7a0ace2cc8709c9b0c5715047032f57f536a3c80273cbecf4c05be0b5456c183fa122c06" + }, + { + "priv_key_tweak": "736f05e4e3072c3b8656bedef2e9bf54cbcaa2b6fe5320d3e86f5b96874dda71", + "pub_key": "ca64abe1e0f737823fb9a94f597eed418fb2df77b1317e26b881a14bb594faaa", + "signature": "2e61bb3d79418ecf55f68847cf121bfc12d397b39d1da8643246b2f0a9b96c3daa4bfe9651beb5c9ce20e1f29282c4566400a4b45ee6657ec3b18fdc554da0b4" } ] } @@ -1908,25 +1902,15 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ], - [ - "sp1qqw6vczcfpdh5nf5y2ky99kmqae0tr30hgdfg88parz50cp80wd2wqqlv6saelkk5snl4wfutyxrchpzzwm8rjp3z6q7apna59z9huq4x754e5atr", - 2.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", + "sp1qqw6vczcfpdh5nf5y2ky99kmqae0tr30hgdfg88parz50cp80wd2wqqlv6saelkk5snl4wfutyxrchpzzwm8rjp3z6q7apna59z9huq4x754e5atr" ] }, "expected": { "outputs": [ - [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - 1.0 - ], [ "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff", - 2.0 + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac" ] ] } @@ -1960,8 +1944,8 @@ } ], "outputs": [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff" + "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff", + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac" ], "key_material": { "spend_priv_key": "b8f87388cbb41934c50daca018901b00070a5ff6cc25a7e9e716a9d5b9e4d664", @@ -1978,8 +1962,8 @@ ], "outputs": [ { - "pub_key": "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff", "priv_key_tweak": "80cd767ed20bd0bb7d8ea5e803f8c381293a62e8a073cf46fb0081da46e64e1f", + "pub_key": "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff", "signature": "7fbd5074cf1377273155eefafc7c330cb61b31da252f22206ac27530d2b2567040d9af7808342ed4a09598c26d8307446e4ed77079e6a2e61fea736e44da5f5a" } ] @@ -2012,8 +1996,8 @@ } ], "outputs": [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff" + "be368e28979d950245d742891ae6064020ba548c1e2e65a639a8bb0675d95cff", + "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac" ], "key_material": { "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", @@ -2027,8 +2011,8 @@ ], "outputs": [ { - "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", "priv_key_tweak": "33ce085c3c11eaad13694aae3c20301a6c83382ec89a7cde96c6799e2f88805a", + "pub_key": "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", "signature": "335667ca6cae7a26438f5cfdd73b3d48fa832fa9768521d7d5445f22c203ab0d74ed85088f27d29959ba627a4509996676f47df8ff284d292567b1beef0e3912" } ] @@ -2037,7 +2021,7 @@ ] }, { - "comment": "Single receipient: taproot input with NUMS point", + "comment": "Single recipient: taproot input with NUMS point", "sending": [ { "given": { @@ -2080,17 +2064,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "79e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d", - 1.0 + "79e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d" ] ] } @@ -2149,8 +2129,8 @@ ], "outputs": [ { - "pub_key": "79e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d", "priv_key_tweak": "3ddec3232609d348d6b8b53123b4f40f6d4f5398ca586f087b0416ec3b851496", + "pub_key": "79e79897c52935bfd97fc6e076a6431a0c7543ca8c31e0fc3cf719bb572c842d", "signature": "d7d06e3afb68363031e4eb18035c46ceae41bdbebe7888a4754bc9848c596436869aeaecff0527649a1f458b71c9ceecec10b535c09d01d720229aa228547706" } ] @@ -2202,17 +2182,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "4612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f", - 1.0 + "4612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f" ] ] } @@ -2271,8 +2247,8 @@ ], "outputs": [ { - "pub_key": "4612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f", "priv_key_tweak": "10bde9781def20d7701e7603ef1b1e5e71c67bae7154818814e3c81ef5b1a3d3", + "pub_key": "4612cdbf845c66c7511d70aab4d9aed11e49e48cdb8d799d787101cdd0d53e4f", "signature": "6137969f810e9e8ef6c9755010e808f5dd1aed705882e44d7f0ae64eb0c509ec8b62a0671bee0d5914ac27d2c463443e28e999d82dc3d3a4919f093872d947bb" } ] @@ -2287,7 +2263,7 @@ "given": { "vin": [ { - "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", "vout": 0, "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", "txinwitness": "", @@ -2299,7 +2275,7 @@ "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" }, { - "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", "vout": 0, "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab", "txinwitness": "", @@ -2324,17 +2300,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", - 1.0 + "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6" ] ] } @@ -2345,7 +2317,7 @@ "given": { "vin": [ { - "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", + "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", "vout": 0, "scriptSig": "483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", "txinwitness": "", @@ -2356,7 +2328,7 @@ } }, { - "txid": "a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48d", + "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", "vout": 0, "scriptSig": "473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab", "txinwitness": "", @@ -2393,8 +2365,8 @@ ], "outputs": [ { - "pub_key": "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", "priv_key_tweak": "688fa3aeb97d2a46ae87b03591921c2eaf4b505eb0ddca2733c94701e01060cf", + "pub_key": "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", "signature": "72e7ad573ac23255d4651d5b0326a200496588acb7a4894b22092236d5eda6a0a9a4d8429b022c2219081fefce5b33795cae488d10f5ea9438849ed8353624f2" } ] @@ -2446,73 +2418,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] - ] - }, - "expected": { - "outputs": [ - [ - "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", - 1.0 - ] - ] - } - }, - { - "given": { - "vin": [ - { - "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", - "vout": 0, - "scriptSig": "16001419c2f3ae0ca3b642bd3e49598b8da89f50c14161", - "txinwitness": "02483046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d621025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be5", - "prevout": { - "scriptPubKey": { - "hex": "a9148629db5007d5fcfbdbb466637af09daf9125969387" - } - }, - "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" - }, - { - "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", - "vout": 1, - "scriptSig": "1600144b92ac4ac6fe6212393894addda332f2e47a3156", - "txinwitness": "02473045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b974104782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233387c5343bf58e23269e903335b958a12182f9849297321e8d710e49a8727129cab", - "prevout": { - "scriptPubKey": { - "hex": "a9146c9bf136fbb7305fd99d771a95127fcf87dedd0d87" - } - }, - "private_key": "0378e95685b74565fa56751b84a32dfd18545d10d691641b8372e32164fad66a" - }, - { - "txid": "f4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e16", - "vout": 2, - "scriptSig": "00493046022100ad79e6801dd9a8727f342f31c71c4912866f59dc6e7981878e92c5844a0ce929022100fb0d2393e813968648b9753b7e9871d90ab3d815ebf91820d704b19f4ed224d601483045022100a8c61b2d470e393279d1ba54f254b7c237de299580b7fa01ffcc940442ecec4502201afba952f4e4661c40acde7acc0341589031ba103a307b886eb867b23b850b97014c695221025a1e61f898173040e20616d43e9f496fba90338a39faa1ed98fcbaeee4dd9be52103782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c3799373233382102e0ec4f64b3fa2e463ccfcf4e856e37d5e1e20275bc89ec1def9eb098eff1f85d53ae", - "txinwitness": "", - "prevout": { - "scriptPubKey": { - "hex": "a9141044ddc6cea09e4ac40fbec2ba34ad62de6db25b87" - } - }, - "private_key": "eadc78165ff1f8ea94ad7cfdc54990738a4c53f6e0507b42154201b8e5dff3b1" - } - ], - "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { "outputs": [ [ - "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", - 1.0 + "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6" ] ] } @@ -2571,8 +2483,8 @@ ], "outputs": [ { - "pub_key": "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", "priv_key_tweak": "688fa3aeb97d2a46ae87b03591921c2eaf4b505eb0ddca2733c94701e01060cf", + "pub_key": "67fee277da9e8542b5d2e6f32d660a9bbd3f0e107c2d53638ab1d869088882d6", "signature": "72e7ad573ac23255d4651d5b0326a200496588acb7a4894b22092236d5eda6a0a9a4d8429b022c2219081fefce5b33795cae488d10f5ea9438849ed8353624f2" } ] @@ -2581,7 +2493,7 @@ ] }, { - "comment": "Ignore unrelated outputs", + "comment": "Recipient ignores unrelated outputs", "sending": [ { "given": { @@ -2612,17 +2524,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgrz6j0lcqnc04vxccydl0kpsj4frfje0ktmgcl2t346hkw30226xqupawdf48k8882j0strrvcmgg2kdawz53a54dd376ngdhak364hzcmynqtn" ] }, "expected": { "outputs": [ [ - "f207162b1a7abc51c42017bef055e9ec1efc3d3567cb720357e2b84325db33ac", - 1.0 + "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8" ] ] } @@ -2656,8 +2564,8 @@ } ], "outputs": [ - "782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338", - "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8" + "841792c33c9dc6193e76744134125d40add8f2f4a96475f28ba150be032d64e8", + "782eeb913431ca6e9b8c2fd80a5f72ed2024ef72a3c6fb10263c379937323338" ], "key_material": { "spend_priv_key": "9d6ad855ce3417ef84e836892e5a56392bfba05fa5d97ccea30e266f540e08b3", @@ -2706,14 +2614,13 @@ } ], "recipients": [ - [ - "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv", - 1.0 - ] + "sp1qqgste7k9hx0qftg6qmwlkqtwuy6cycyavzmzj85c6qdfhjdpdjtdgqjuexzk6murw56suy3e0rd2cgqvycxttddwsvgxe2usfpxumr70xc9pkqwv" ] }, "expected": { - "outputs": [] + "outputs": [ + [] + ] } } ],