From 47033c62dc101080c31c1e8a88118ae8288f6d36 Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Sat, 22 Jun 2024 01:18:37 +0200 Subject: [PATCH 1/3] BIP-352: sending: add step to fail if input privkeys sum a is zero The test vector data was generated with a Python script (see https://github.com/theStack/bitcoin/blob/bc15ea8d0f282908b912dbf62bba816ecd82424d/contrib/silentpayments/submit_input_pubkeys_infinity_tx.py), leading to the following output: --------------------------------------------------------------------------------------------------------- Privkey 1: a6df6a0bb448992a301df4258e06a89fe7cf7146f59ac3bd5ff26083acb22ceb Privkey 2: 592095f44bb766d5cfe20bda71f9575ed2df6b9fb9addc7e5fdffe0923841456 Pubkey 1: 02557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975 Pubkey 2: 03557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975 scriptPubKey 1: 00149d9e24f9fab4e35bf1a6df4b46cb533296ac0792 scriptPubKey 2: 00149860538b5575962776ed0814ae222c7d60c72d7b Address 1: tb1qnk0zf706kn34hudxma95dj6nx2t2cpujz7j5t5 Address 2: tb1qnps98z64wktzwahdpq22ug3v04svwttm7gs8wn -> Funding tx submitted: 3a286147b25e16ae80aff406f2673c6e565418c40f45c071245cdebc8a94174e Taproot output address for spending tx: tb1pqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqkgkkf5 -> Spending tx submitted: fe788cf6578d547819def43d79e6c8f0153d4885f5a343d12bd03f34507aabd6 --------------------------------------------------------------------------------------------------------- --- bip-0352.mediawiki | 1 + bip-0352/reference.py | 3 ++ bip-0352/send_and_receive_test_vectors.json | 47 ++++++++++++++++++++- 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/bip-0352.mediawiki b/bip-0352.mediawiki index f36f3592..def4d0b2 100644 --- a/bip-0352.mediawiki +++ b/bip-0352.mediawiki @@ -302,6 +302,7 @@ After the inputs have been selected, the sender can create one or more outputs f * Collect the private keys for each input from the ''[[#inputs-for-shared-secret-derivation|Inputs For Shared Secret Derivation]]'' list * For each private key ''ai'' corresponding to a [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] taproot output, check that the private key produces a point with an even Y coordinate and negate the private key if not'''Why do taproot private keys need to be checked?''' Recall from [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki BIP340] that each X-only public key has two corresponding private keys, ''d'' and ''n - d''. To maintain parity between sender and receiver, it is necessary to use the private key corresponding to the even Y coordinate when performing the ECDH step since the receiver will assume the even Y coordinate when summing the taproot X-only public keys. * Let ''a = a1 + a2 + ... + an'', where each ''ai'' has been negated if necessary +** If ''a = 0'', fail * Generate the ''input_hash'' with the smallest outpoint lexicographically and ''A = a·G'', using the method described above * Group receiver silent payment addresses by ''Bscan'' (e.g. each group consists of one ''Bscan'' and one or more ''Bm'') * For each group: diff --git a/bip-0352/reference.py b/bip-0352/reference.py index 9b35d040..7882ad1b 100755 --- a/bip-0352/reference.py +++ b/bip-0352/reference.py @@ -127,6 +127,9 @@ def create_outputs(input_priv_keys: List[Tuple[ECKey, bool]], outpoints: List[CO negated_keys.append(k) a_sum = sum(negated_keys) + if not a_sum.valid: + # Input privkeys sum is zero -> fail + return [] input_hash = get_input_hash(outpoints, a_sum * G) silent_payment_groups: Dict[ECPubKey, List[ECPubKey]] = {} for recipient in recipients: diff --git a/bip-0352/send_and_receive_test_vectors.json b/bip-0352/send_and_receive_test_vectors.json index f9b205b8..c0288bc5 100644 --- a/bip-0352/send_and_receive_test_vectors.json +++ b/bip-0352/send_and_receive_test_vectors.json @@ -2669,5 +2669,50 @@ } } ] + }, + { + "comment": "Input keys sum up to zero / point at infinity: sending fails, receiver skips tx", + "sending": [ + { + "given": { + "vin": [ + { + "txid": "3a286147b25e16ae80aff406f2673c6e565418c40f45c071245cdebc8a94174e", + "vout": 0, + "scriptSig": "", + "txinwitness": "024730440220085003179ce1a3a88ce0069aa6ea045e140761ab88c22a26ae2a8cfe983a6e4602204a8a39940f0735c8a4424270ac8da65240c261ab3fda9272f6d6efbf9cfea366012102557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975", + "prevout": { + "scriptPubKey": { + "hex": "00149d9e24f9fab4e35bf1a6df4b46cb533296ac0792" + } + }, + "private_key": "a6df6a0bb448992a301df4258e06a89fe7cf7146f59ac3bd5ff26083acb22ceb" + }, + { + "txid": "3a286147b25e16ae80aff406f2673c6e565418c40f45c071245cdebc8a94174e", + "vout": 1, + "scriptSig": "", + "txinwitness": "0247304402204586a68e1d97dd3c6928e3622799859f8c3b20c3c670cf654cc905c9be29fdb7022043fbcde1689f3f4045e8816caf6163624bd19e62e4565bc99f95c533e599782c012103557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975", + "prevout": { + "scriptPubKey": { + "hex": "00149860538b5575962776ed0814ae222c7d60c72d7b" + } + }, + "private_key": "592095f44bb766d5cfe20bda71f9575ed2df6b9fb9addc7e5fdffe0923841456" + } + ], + "recipients": [ + "sp1qqtrqglu5g8kh6mfsg4qxa9wq0nv9cauwfwxw70984wkqnw2uwz0w2qnehen8a7wuhwk9tgrzjh8gwzc8q2dlekedec5djk0js9d3d7qhnq6lqj3s" + ] + }, + "expected": { + "outputs": [ + [] + ] + } + } + ], + "receiving": [ + ] } -] \ No newline at end of file +] From 59cc43d727000794f18dac0a502cd87c0daec22a Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Fri, 14 Jun 2024 14:33:40 +0200 Subject: [PATCH 2/3] BIP-352: scanning: add step to skip tx if input pubkeys sum A is point at infinity The input data for the test vector is taken from the signet transaction fe788cf6578d547819def43d79e6c8f0153d4885f5a343d12bd03f34507aabd6 which spends two P2WPKH inputs with negated pubkeys (x, y) and (x, -y) from the funding transaction 3a286147b25e16ae80aff406f2673c6e565418c40f45c071245cdebc8a94174e (see also https://github.com/bitcoin-core/secp256k1/pull/1519#issuecomment-2143167510 and the output from the script in the previous commit message). Co-authored-by: josibake --- bip-0352.mediawiki | 1 + bip-0352/reference.py | 4 ++ bip-0352/send_and_receive_test_vectors.json | 42 +++++++++++++++++++++ 3 files changed, 47 insertions(+) diff --git a/bip-0352.mediawiki b/bip-0352.mediawiki index def4d0b2..0cf63a9f 100644 --- a/bip-0352.mediawiki +++ b/bip-0352.mediawiki @@ -335,6 +335,7 @@ A scan and spend key pair using BIP32 derivation are defined (taking inspiration If each of the checks in ''[[#scanning-silent-payment-eligible-transactions|Scanning silent payment eligible transactions]]'' passes, the receiving wallet must: * Let ''A = A1 + A2 + ... + An'', where each ''Ai'' is the public key of an input from the ''[[#inputs-for-shared-secret-derivation|Inputs For Shared Secret Derivation]]'' list +** If ''A'' is the point at infinity, skip the transaction * Generate the ''input_hash'' with the smallest outpoint lexicographically and ''A'', using the method described above * Let ''ecdh_shared_secret = input_hash·bscan·A'' * Check for outputs: diff --git a/bip-0352/reference.py b/bip-0352/reference.py index 7882ad1b..b4eaf945 100755 --- a/bip-0352/reference.py +++ b/bip-0352/reference.py @@ -300,6 +300,10 @@ if __name__ == "__main__": add_to_wallet = [] if (len(input_pub_keys) > 0): A_sum = reduce(lambda x, y: x + y, input_pub_keys) + if A_sum.get_bytes() is None: + # Input pubkeys sum is point at infinity -> skip tx + assert expected["outputs"] == [] + continue input_hash = get_input_hash([vin.outpoint for vin in vins], A_sum) pre_computed_labels = { (generate_label(b_scan, label) * G).get_bytes(False).hex(): generate_label(b_scan, label).hex() diff --git a/bip-0352/send_and_receive_test_vectors.json b/bip-0352/send_and_receive_test_vectors.json index c0288bc5..264f7bec 100644 --- a/bip-0352/send_and_receive_test_vectors.json +++ b/bip-0352/send_and_receive_test_vectors.json @@ -2713,6 +2713,48 @@ } ], "receiving": [ + { + "given": { + "vin": [ + { + "txid": "3a286147b25e16ae80aff406f2673c6e565418c40f45c071245cdebc8a94174e", + "vout": 0, + "scriptSig": "", + "txinwitness": "024730440220085003179ce1a3a88ce0069aa6ea045e140761ab88c22a26ae2a8cfe983a6e4602204a8a39940f0735c8a4424270ac8da65240c261ab3fda9272f6d6efbf9cfea366012102557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975", + "prevout": { + "scriptPubKey": { + "hex": "00149d9e24f9fab4e35bf1a6df4b46cb533296ac0792" + } + } + }, + { + "txid": "3a286147b25e16ae80aff406f2673c6e565418c40f45c071245cdebc8a94174e", + "vout": 1, + "scriptSig": "", + "txinwitness": "0247304402204586a68e1d97dd3c6928e3622799859f8c3b20c3c670cf654cc905c9be29fdb7022043fbcde1689f3f4045e8816caf6163624bd19e62e4565bc99f95c533e599782c012103557ef3e55b0a52489b4454c1169e06bdea43687a69c1f190eb50781644ab6975", + "prevout": { + "scriptPubKey": { + "hex": "00149860538b5575962776ed0814ae222c7d60c72d7b" + } + } + } + ], + "outputs": [ + "0000000000000000000000000000000000000000000000000000000000000000" + ], + "key_material": { + "spend_priv_key": "0000000000000000000000000000000000000000000000000000000000000001", + "scan_priv_key": "0000000000000000000000000000000000000000000000000000000000000002" + }, + "labels": [] + }, + "expected": { + "addresses": [ + "sp1qqtrqglu5g8kh6mfsg4qxa9wq0nv9cauwfwxw70984wkqnw2uwz0w2qnehen8a7wuhwk9tgrzjh8gwzc8q2dlekedec5djk0js9d3d7qhnq6lqj3s" + ], + "outputs": [] + } + } ] } ] From 496e4295e76579b75dbafbd8a6c6e49948cc0d8d Mon Sep 17 00:00:00 2001 From: Sebastian Falbesoner Date: Sat, 22 Jun 2024 01:55:00 +0200 Subject: [PATCH 3/3] BIP-352: add change log (SemVer format) The first paragraph is taken from BIP-327, with the sentence about MAJOR version zero removed, as it's not relevant here (we don't track the pre-merge history). --- bip-0352.mediawiki | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bip-0352.mediawiki b/bip-0352.mediawiki index 0cf63a9f..c9f18547 100644 --- a/bip-0352.mediawiki +++ b/bip-0352.mediawiki @@ -483,6 +483,17 @@ A malicious notification could potentially cause the following issues: Wallet designers can choose which tradeoffs they find appropriate. For example, a wallet could check the block filter to at least probabilistically confirm the likely existence of the UTXO, thus efficiently cutting down on spam. The payment could then be marked as unconfirmed until a scan is performed and the existence of the UTXO in accordance to the silent payment specification is verified. +== Change Log == + +To help implementers understand updates to this document, we attach a version number that resembles ''semantic versioning'' (MAJOR.MINOR.PATCH). +The MAJOR version is incremented if changes to the BIP are introduced that are incompatible with prior versions. +The MINOR version is incremented whenever the inputs or the output of an algorithm changes in a backward-compatible way or new backward-compatible functionality is added. +The PATCH version is incremented for other changes that are noteworthy (bug fixes, test vectors, important clarifications, etc.). + +* '''1.0.1''' (2024-06-22): +** Add steps to fail if private key sum is zero (for sender) or public key sum is point at infinity (for receiver), add corresponding test vectors. +* '''1.0.0''' (2024-05-08): +** Initial version, merged as BIP-352. == Acknowledgements ==