summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJon Atack <jon@atack.com>2024-06-22 20:02:56 +0000
committerGitHub <noreply@github.com>2024-06-22 20:02:56 +0000
commite8664b28fb32e9c864243ad4596010a237540f6b (patch)
tree9e02b13d1066e694baa3ddb09f1fef8da38cf60e
parent70a714372f3d7b3f68b61e5dcd68eecdcc6c3b41 (diff)
parent496e4295e76579b75dbafbd8a6c6e49948cc0d8d (diff)
downloadbips-e8664b28fb32e9c864243ad4596010a237540f6b.tar.xz
Merge pull request #1620 from theStack/bip352-mention-input_pubkey_sum-infinity-case
BIP-352: handle invalid privkey / pubkey sums for sending / scanning, add changelog
-rw-r--r--bip-0352.mediawiki13
-rwxr-xr-xbip-0352/reference.py7
-rw-r--r--bip-0352/send_and_receive_test_vectors.json89
3 files changed, 108 insertions, 1 deletions
diff --git a/bip-0352.mediawiki b/bip-0352.mediawiki
index f36f359..c9f1854 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 ''a<sub>i</sub>'' 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<ref name="why_negate_taproot_private_keys">'''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.</ref>
* Let ''a = a<sub>1</sub> + a<sub>2</sub> + ... + a<sub>n</sub>'', where each ''a<sub>i</sub>'' 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 ''B<sub>scan</sub>'' (e.g. each group consists of one ''B<sub>scan</sub>'' and one or more ''B<sub>m</sub>'')
* For each group:
@@ -334,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 = A<sub>1</sub> + A<sub>2</sub> + ... + A<sub>n</sub>'', where each ''A<sub>i</sub>'' 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·b<sub>scan</sub>·A''
* Check for outputs:
@@ -481,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'' (<code>MAJOR.MINOR.PATCH</code>).
+The <code>MAJOR</code> version is incremented if changes to the BIP are introduced that are incompatible with prior versions.
+The <code>MINOR</code> 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 <code>PATCH</code> 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 ==
diff --git a/bip-0352/reference.py b/bip-0352/reference.py
index 9b35d04..b4eaf94 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:
@@ -297,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 f9b205b..264f7be 100644
--- a/bip-0352/send_and_receive_test_vectors.json
+++ b/bip-0352/send_and_receive_test_vectors.json
@@ -2669,5 +2669,92 @@
}
}
]
+ },
+ {
+ "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": [
+ {
+ "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": []
+ }
+ }
+ ]
}
-] \ No newline at end of file
+]