Skip to content

Commit 62fe7c5

Browse files
committed
Add serialization functions from BIP32
This better matches conventions used in other BIPS. It's also likely wallet software already has code for doing these operations if they support BIP32.
1 parent a41adb9 commit 62fe7c5

File tree

1 file changed

+8
-6
lines changed

1 file changed

+8
-6
lines changed

bip-0000.mediawiki

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -135,8 +135,10 @@ This gives Bob an alternative to using BIP32 for managing change, while still al
135135
136136
We use the following functions and conventions:
137137
138-
* ''outpoint'' (36 bytes): the <code>COutPoint</code> of an input (32-byte hash + 4-byte little-endian)
139-
* ser<sub>32</sub>(i): serializes a 32-bit unsigned integer ''i'' as a 4-byte little-endian
138+
* ''outpoint'' (36 bytes): the <code>COutPoint</code> of an input (32-byte txid, least significant byte first || 4-byte vout, least significant byte first)<ref name="why_little_endian">'''Why are outpoints little-endian?''' Despite using big endian throughout the rest of the BIP, outpoints are sorted and hashed matching their transaction serialization, which is little-endian. This allows a wallet to parse a serialized transaction for use in silent payments without needing to re-order the bytes when compute the outpoint hash. Note: despite outpoints being stored and serialized as little-endian, the transaction hash (txid) is always displayed as big-endian.</ref>
139+
* ser<sub>32</sub>(i): serializes a 32-bit unsigned integer ''i'' as a 4-byte sequence, most significant byte first.
140+
* ser<sub>256</sub>(p): serializes the integer p as a 32-byte sequence, most significant byte first.
141+
* ser<sub>P</sub>(P): serializes the coordinate pair P = (x,y) as a byte sequence using SEC1's compressed form: (0x02 or 0x03) || ser<sub>256</sub>(x), where the header byte depends on the parity of the omitted y coordinate.
140142
141143
For everything not defined above, we use the notation from [https://github.com/bitcoin/bips/blob/master/bip-0340.mediawiki#specification BIP340].
142144
@@ -230,10 +232,10 @@ After the inputs have been selected, the sender can create one or more outputs f
230232
* Generate the ''outpoints_hash'', using the method described above
231233
* 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>'')
232234
* For each group:
233-
** Let ''ecdh_shared_secret = outpoints_hash·a·B<sub>scan</sub>'', where ''ecdh_shared_secret'' is a compressed public key
235+
** Let ''ecdh_shared_secret = outpoints_hash·a·B<sub>scan</sub>''
234236
** Let ''n = 0''
235237
** For each ''B<sub>m</sub>'' in the group:
236-
*** Let ''t<sub>n</sub> = sha256(ecdh_shared_secret || ser<sub>32</sub>(n))''
238+
*** Let ''t<sub>n</sub> = sha256(ser<sub>P</sub>(ecdh_shared_secret) || ser<sub>32</sub>(n))''
237239
*** Let ''P<sub>mn</sub> = B<sub>m</sub> + t<sub>n</sub>·G''
238240
*** Encode ''P<sub>mn</sub>'' as a [https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki BIP341] taproot output
239241
*** Optionally, repeat with n++ to create additional outputs for the current ''B<sub>m</sub>''
@@ -259,11 +261,11 @@ For each transaction the receiving wallet suspects might be a silent payment to
259261
260262
* Generate the ''outpoints_hash'', using the method described above
261263
* Let ''A = A<sub>0</sub> + A<sub>1</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
262-
* Let ''ecdh_shared_secret = outpoints_hash·b<sub>scan</sub>·A'', where ''ecdh_shared_secret'' is a compressed public key
264+
* Let ''ecdh_shared_secret = outpoints_hash·b<sub>scan</sub>·A''
263265
* Check for outputs:
264266
** Let ''outputs_to_check = the taproot output key from each unspent taproot output in the transaction''
265267
** Starting with ''n = 0'':
266-
*** Let ''t<sub>n</sub> = sha256(ecdh_shared_secret || ser<sub>32</sub>(n))''
268+
*** Let ''t<sub>n</sub> = sha256(ser<sub>P</sub>(ecdh_shared_secret) || ser<sub>32</sub>(n))''
267269
*** Compute ''P<sub>n</sub> = B<sub>spend</sub> + t<sub>n</sub>·G''
268270
**** If ''P<sub>n</sub>'' is in ''outputs_to_check'', add it to the wallet and continue with ''n++''
269271
**** If ''P<sub>n</sub>'' is not found and the wallet has precomputed labels<ref name="precompute_labels">''' Why precompute labels?''' Naively, a wallet could store some max integer ''M'' which indicates the total number of labels it has used. When checking a transaction, the wallet would need to add all possible labels to each output. This ends up being ''n·m'' additions, where ''n'' is the number of outputs in the transaction and ''m'' is the number of labels in the wallet. By precomputing the labels, the wallet only needs to compute ''m·G'' once per label and can determine if a label was used via a lookup, rather than adding each label to each output.</ref>:

0 commit comments

Comments
 (0)