Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[BIP174] Add PSBT_GLOBAL_XPUB_SIGNATURE to BIP #801

Open
wants to merge 4 commits into
base: master
from

Conversation

@junderw
Copy link
Contributor

commented Jul 10, 2019

As discussed on the mailing list:
https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-June/thread.html#start
Search the page for the following subject:
BIP174 extension proposal (Global Type: PSBT_GLOBAL_XPUB_SIGNATURE)

  • POR_COMMITMENT is also a separate BIP, but the encoding spec is listed here, so I am following suit.
  • Maybe there could be a way to offload the encoding descriptions into a "this key will represent the BIP number" etc. but for now no such spec exists. I may create a new BIP to cover the usage of this data for wallets to implement a whitelist for output verification.

Here is the description of the imagined use case:

  1. Securely verify the xpub of the warm / hot wallet.
  2. Using the airgap signing tool, sign the xpub with all cold keys.
  3. Upload the signature/xpub pairs to the online unsigned transaction
    generator.
  4. Include one keyval pair per coldkey/xpub pairing.
  5. When offline signing, if the wallet detects there is a global keyval
    XPUB_SIGNATURE with its pubkey in the key, it must verify that all outputs
    have BIP32_DERIVATION and that it can verify the outputs through the
    derivation, to the xpub, and to the signature.

The 0x01 global xpub entry allows HW wallet to verify change outputs.

This 0x02 global xpub signature will allow HW wallet to "verify" a whitelisted xpub that it has previously signed. Which is useful if HW wallets create some way for users to exchange xpubs securely. Instead of having to do the secure exchange every time, they would only need to do it once, then refer to the whitelist signature.

I was thinking of adding some extra data for a label which would also be signed, that way Trezor could say "Are you sure you want to pay Cindy?" instead of address verification.

Reducing address reuse is a two pronged motion of encouraging change address rotation (0x01) and encouraging people use new addresses every time (0x02 facilitates features that remove some friction)

Any comments are welcome.

Thanks.

junderw added 4 commits Jun 27, 2019
tt
@junderw

This comment has been minimized.

Copy link
Contributor Author

commented Jul 23, 2019

I should make a separate BIP for the signing scheme and how wallets should implement the verification of these signatures.

I will write up a draft and submit to the mailing list for review sometime in the next month or two.

@luke-jr

This comment has been minimized.

Copy link
Member

commented Jul 23, 2019

@dgpv

This comment has been minimized.

Copy link

commented Jul 24, 2019

I was thinking of adding some extra data for a label which would also be signed, that way Trezor could say "Are you sure you want to pay Cindy?" instead of address verification.

I like the idea. All participants will need to agree on the labels, before the signing. The labels can also be used as/include 'serial numbers' or 'epoch words', as a way for xpub revocations - if the signing person sees that the label includes an old serial number or 'epoch word', she will refuse to sign.

@dgpv

This comment has been minimized.

Copy link

commented Jul 24, 2019

m/2042083607'/959190427'/1400854130'/990526201' (Magic number, randomly picked only for low likelyhood of overlapping).

Why not use 174' as the root for this path, using the number of this BIP, in accordance to BIP43 ?
for example: m/174'/2' where 2 is the type of PSBT_GLOBAL_XPUB_SIGNATURE

If all subsequent fields, when there's a need to derive some keys, would use the same scheme m/174'/<field_code>'/... then there should be no overlaps

@achow101

This comment has been minimized.

Copy link
Member

commented Jul 25, 2019

As noted in the discussions about the global xpub field (0x01), the use of only 32 bits as the unique identifier is not necessarily unique enough due to collisions. Since this signature is really just for the offline signer to prove to itself that it has approved these keys for use in outputs, I think it would be better to use the full public key (not the xpub) to avoid collisions and make it easier for the signer to identify which signature is his.

One thing I'm not really a fan of is just specifying the keys and only sticking to single or multisig outputs. I would much rather this be more generic with the use of miniscript and output descriptors, but I suppose that would require miniscript to actually be finalized. That way you could have any arbitrary script for the outputs (or nested within the outputs as p2sh/p2wsh) and be effectively committing to the script directly instead of just the keys.

@dgpv

This comment has been minimized.

Copy link

commented Jul 25, 2019

Since this signature is really just for the offline signer to prove to itself that it has approved these keys for use in outputs, I think it would be better to use the full public key (not the xpub) to avoid collisions and make it easier for the signer to identify which signature is his.

The signer can just ignore the entry if the signature does not match, and if there's no entries with matching signatures, give an error 'no matching signatures found' or something like that.

including a pubkey will make error messages more clear and debugging a little easier, at the price of some extra data included in PSBT.

On the other hand, this is not per-input/per-output field, so the savings will not be big. Including the pubkey makes sense in this case, in my opinion.

@dgpv

This comment has been minimized.

Copy link

commented Jul 25, 2019

I would much rather this be more generic with the use of miniscript and output descriptors

With pre-defined set of scripts in the signer configuration, the signer can process non-standard scripts, and can assign script-specific meaning for each key in the set.

That would require for the xpubs to be ordered by their script-specific meaning, and not alphabetically, or have some sort of tags that the signer can match against a script template. Pubkeys might play the role of these tags.

the signer would have a template like [op1, op2], <pubkey1>, [op3, op4], <pubkey2> [op5 ... opN], <pubkeyX> where ops are the opcodes(1) of the script and <pubkeyN> are the pubkeys of the xpubs. Signer, after it checked that xpub package + script template is signed with trusted key, and that the pubkeys in the script template match pubkeys of the xpubs, can replace the pubkeys in the template with the derived versions, and then check the result against the output scripts.

I am not sure if would be good to put this script template in PSBT itself, and complicate the processing for those who are not concerned with such cases. Most likely each particular usecase would have very few non-standard scripts, and the signers can be made to take those script templates as a configuration. If it is desireable to put the script templates inside PSBT, it can be put after a signature - if the signature field is larger than 64 bytes, then there's a script template there.

(1) actually, for the signer these opcodes would be just bytes, it does not necessary need to interpret them in any way

@achow101

This comment has been minimized.

Copy link
Member

commented Jul 25, 2019

I am not sure if would be good to put this script template in PSBT itself, and complicate the processing for those who are not concerned with such cases. Most likely each particular usecase would have very few non-standard scripts, and the signers can be made to take those script templates as a configuration. If it is desireable to put the script templates inside PSBT, it can be put after a signature - if the signature field is larger than 64 bytes, then there's a script template there.

This proposal is, in effect, already adding script templates. By specifying a m for multisigs or single key, we are already using some form of a template, albeit a very limited one. Since the signature should be committing to the script(s) being used, we should specify the script template that is being signed.

@dgpv

This comment has been minimized.

Copy link

commented Jul 25, 2019

The idea is that to authorize a specific script, you don't need to specify full semantics of the script, you only need the positions of the pubkeys and the values of the bytes around the pubkeys.

You will not be able to specify other parameters of the script beside the pubkeys (1), but just the ability to match/substitute pubkeys would give a lot of flexibility.

(1) otherwise the parsing of the data will get overly complex, IMO - while xpubs have natural 'labels' -- their pubkeys, specifying other things like numbers would require assigning labels to them, etc.

@dgpv

This comment has been minimized.

Copy link

commented Jul 25, 2019

m=0 can mean that there's a script template after the signature.
m=1 can mean that the script is standard single-sig (and no data after the signature)
1 < m <= 15 can mean the script is standard multi-sig (and no data after the signature)
the (less-common) case of single-sig p2sh can be encoded with m=0 and a script template.

@dgpv

This comment has been minimized.

Copy link

commented Jul 25, 2019

Putting the script template after a signature will mean certain duplication (duplicating the pubkeys of xpubs), and also would prevent having different scripts with the same xpub set, within one PSBT (convoluted case, but consievable)

The script template can also be put into the field key itself.

The key would be

{0x02}|{signing_pubkey_fingerprint}|{script_template_including_xpubs}

script_template_inluding_xpubs would consist of a chunks of a script with embedded xpubs.

For example, for standard 2-of-3 multisig, it might consist of

<1>[0x02] 0x00 <xpub1_len>[xpub1] 0x00 <xpub2_len>[xpub2] 0x00 <xpub3_len>[xpub3] <2>[0x03, 0xAC]

where values in angle brackets are varints, values in square brackets are bytes of data (0xAC would be OP_CHECKMULTISIG). 0x00 is a marker indicating that the next chunk is xpub.

The checking code would parse this template into two array of data chunks - the script raw bytes, and xpubs.

data chunks of script raw bytes would be:

[0x02], [], [], [0x03, 0xAC] where [] are empty data chunks

and the xpubs would be
[xpub1], [xpub2], [xpub3]

The checker will derive a pubkey from each xpub, yeliding [pub1],[pub2],[pub3], and then combine the data chunks and the derived pubkeys in-order, placing one pubkey after each script data chunk (includng the empty chunks):

[0x02], [pub1], [], [pub2], [], [pub3] [0x03, 0xAC]

After joining these chunks into a single byte array, the checker will get a data blob that should match the output's redeem/witness script.

This won't work for pubkey hashes - p2pkh and p2wpkh. They would need to be special-cased - for example, when the template consists of a single xpub, that would mean this is a special pubkey-hash case.

@junderw

This comment has been minimized.

Copy link
Contributor Author

commented Jul 26, 2019

  1. miniscript extended to include xpub awareness, a way to denote pubkey sorting, etc. could work.
  2. pubkey instead of fingerprint seems fine

However, one thing I do fear with using miniscript is that miniscript itself would probably need some work and discussion to include it here, and it does increase the scope of this modification significantly.

@sipa

This comment has been minimized.

Copy link
Member

commented Jul 26, 2019

However, one thing I do fear with using miniscript is that miniscript itself would probably need some work and discussion to include it here, and it does increase the scope of this modification significantly.

I agree. I'm not sure it's the right place to integrate it either (checking whether something is change or not doesn't really require understanding the script - perhaps a more level template matching is enough?).

@junderw

This comment has been minimized.

Copy link
Contributor Author

commented Jul 26, 2019

checking whether something is change

Just to clarify... this is not meant just for change. This is meant for a whitelist feature for airgapped / HW wallets to verify addresses so humans don't have to.

(ie. We send from cold to warm / hot all the time, but in order to make address verification easier we had to designate one address of each warm and hot as "the deposit address" even though both warm and hot were HD... since it made human verification of the send-to address easier... the solution we came up with was to have the cold keys sign a message saying "I trust this xpub in this configuration as our hot wallet" and before signing our offline signer will verify the signature and will not send unless it can verify the output script is derived from a whitelisted xpub/config... this way our cold -> warm and cold -> hot transactions don't gather in one address like most exchanges do.)

We also think if this type of whitelist feature is implemented into wallets like Trezor etc. Exchanges could offer a pairing feature which will give the user a "deposit xpub" and their wallet could just save the xpub internally in insecure storage (Dropbox integration in MyTrezor etc) and the HW wallet can verify the xpub each signature.

Overall, I think this sort of integration will be more successful and less wasteful than other types of pairing (ie BIP47) in the long run.

@junderw

This comment has been minimized.

Copy link
Contributor Author

commented Jul 26, 2019

(Although it could be used for change verification for multisig, since verifying from your xpub alone does not tell the airgapped machine whether a hacker replaced the other keys.)

@dgpv

This comment has been minimized.

Copy link

commented Jul 26, 2019

a way to denote pubkey sorting

for a simple byte-level-replace template presented above, bip67-style pubkey sorting is not applicable - in the general case, the script can have sorted pubkeys in one place, and some special pubkeys that are not sorted in another place (timelocked keys). To support sorting, the byte-level-replace template need to allow to express the notion of a 'list of pubkeys'. A bit more complicated, but not by much. If a varint after 0x00 is some small number that cannot be the length of xpub (less than 78, the data length of xpub including version bytes), it can be interpreted as the number of xpubs in a subsequent list. Having xpub lists would mean there's no need for the notion of 'empty data chunks' in the replacement logic that was presented above.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
5 participants
You can’t perform that action at this time.