-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
Support for BIP49 YPUB/UPUB #927
Conversation
From reading that BIP, I don't see the network constants you've specified... Instead, the only difference I saw was that the
|
My address generation happens outside of bitcoinjs-lib, and I'm not sure if there are more implications to fully supporting an implementation of BIP49 as a result. The use case was for an electrum wallet. See: The usage of these constants (which translate to ypub and upub) allow for auto-detection of a bip49-style wallet. When using a bip32-style xpub, it's impossible to determine whether the wallet is bip32 or bip49. While the constants do not appear in a BIP, they are the constants currently in use by wallet providers like electrum. |
Is this related to #934 ? |
@@ -64,7 +64,9 @@ HDNode.fromBase58 = function (string, networks) { | |||
if (Array.isArray(networks)) { | |||
network = networks.filter(function (x) { | |||
return version === x.bip32.private || | |||
version === x.bip32.public | |||
version === x.bip32.public || | |||
version === x.bip49.private || |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think these semantics should be opt-in. Imagine someone supported Bitcoin Cash, and imported keys. There's not currently a bitcoin-cash network in the library, so they're using the bitcoin network for that. Imagine they didn't read the release notes, and allowed users to import a P2SH(P2WPKH) address, and funded that on Bitcoin Cash.. They're unspendable without talking to a miner.
I think this feature should be opt in, so a new function bip44TypefromBase58
or something that forces developers to think about what they are doing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@afk11 I don't understand, what about these new BIP49 constants would trap users into creating unspendable addresses?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Isn't the risk that any P2SH(P2WPKH) scripts are unspendable by BCash nodes?
Nothing to do with the BIP49 constants?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Applications might accept stuff they shouldn't when forks like bitcoin cash happen, and developers start using bitcoin.networks.bitcoin
as a bitcoin cash network. It's mostly that the feature should only be used via specialized encoding/decoding/factory functions. That way, developers have to consider the difference between xpub only, and the format that uses different scripts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
https://github.com/plasticlobster/bitcoinjs-lib/blob/8f39b516946805c6b4640d1df0fdd33a0ebedba7/src/hdnode.js#L129
This should be updated to use script type
Should also be opt in, and not usable by people who expect fromBase58 to only parse normal BIP32 keys.
In general I think the proposal has its merits, it's nice to support what some of the major wallets are doing. I have some comments on the PR and proposal in general. Generally, concept ACK once it's opt in. Worth mentioning that the situation with these new prefixes isn't perfect, since some prefixes can have two script types. The specification just seems to be the ML post and electrum website, so it's not clear what the official spec actually is outside of specific prefixes. I think we can introduce this as limited support for such versioned BIP32 wallets, and see what other prefixes people request. Maybe the config parameters could go into bip32ScriptVersions, as a new property on the network? Minor nit though |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, waiting on @afk11
Shouldn't |
@dabura667 @junderw where does |
@dcousens Honestly... I think maybe this is a little bit early. I would really like to see a BIP from @ecdsa before we merge this. Also, I think this is insufficient. Electrum also has extra version bytes for WIF private keys. We should probably include those if we include this. zpub/prv are for native P2WPKH. Currently, ECPair and HDNode have a network attribute which refers to a network in networks. I think they should also have an attribute for "scriptType" which will tell us what to use when using toWIF or toBase58Check respectively. So we can look at the scriptType, and use that to guide us as to what to fetch from the network object. I also dislike calling this bip49... perhaps keep all the legacy network structure and add a new key: ie. bitcoin: {
messagePrefix: '\x18Bitcoin Signed Message:\n',
bech32: 'bc',
bip32: {
public: 0x0488b21e,
private: 0x0488ade4
},
pubKeyHash: 0x00,
scriptHash: 0x05,
wif: 0x80,
versionBytes: {
ECPair: {
'P2PKH': {
wif: 0x80
},
'P2SH(P2WPKH)': {
wif: 0x82
},
'P2WPKH': {
wif: 0x81
}
},
HDNode: {
'P2PKH': {
public: 0x0488b21e,
private: 0x0488ade4
},
'P2SH(P2WPKH)': {
public: 0x049d7cb2,
private: 0x049d7878
},
'P2WPKH': {
public: 0x04b24746,
private: 0x04b2430c
}
}
}
}, (WIF values weren't in wiki, but they are in the bitcoin.py. |
What a mess. |
Yup. It is. Big old mess. But I have been thinking for a while that now we have different ways to use private keys, we need a state similar to compressed that can store the script type. The way this is represented when exported or imported can be added later when BIPs are written. What do you think? @dcousens |
@junderw it feels like the version bytes are becoming useless as network information, and instead, acting as flags for other meta information. Maybe we should support non-strict |
Can we simply tell these muppets to please stop abusing the BIP32 standard and instead write a BIP that stores this information somewhere else? |
IMO we have bech32, why not use it? lol. |
hrp could be p2shp2wpkh or something |
xpubp2shp2wpkh1sdfouofgsdfijo9df8ehosf8feojosihfhe8fh etc etc |
@junderw I have an idea, lets write a BIP that captures the path information AND the address type(s). (semi serious, it might take less time than writing sane APIs for this mess) |
While that comic is true. Character encoding has a clear winner. If you don't use UTF-8 you are wrong. |
@junderw would Why is this necessary anyway? Who is actually passing around these base58 strings rather than a mnemonic? |
@dabura667 we will submit a BIP |
@ecdsa are you open to engaging in a discussion about a more generic standard e.g like the above? |
Mainly for xpubs. A lot of people pass around xpubs for watch-only and merchant services. |
Everyone read the Security and Implications part of BIP32, right? We even have an example of how to take advantage of this weakness in our integration tests. |
can you be more specific? |
Have you ever used Electrum? Electrum made it a thing since before BIP32 was even a thing. The rationale is that you can't export individual private keys from Electrum, so it's not a problem. (iirc) |
To create watch-only wallets for internal (but secure) use; just like I am trying to do right now.
Wallet >> Private Keys >> Export |
Watch-only wallets are easy to hack: Just replace the xpub with a hacker's xpub. Now everyone will send money to the hacker and not you. |
That is pointless; exactly the same can be done regardless if you are using xpub or not. So no "xpub hack" here. |
This PR is not complete, that’s why it’s not working. |
We also have the SLIP-32 proposal out there, which encodes the derivation path within the serialized |
@mautematico You're right. getAddress would need modification to get the proper address, but you can do it as follows:
Obviously a change like this would have to be implemented in getAddress to make this easier, but I don't even want to pretend I understand the coding requirements of this project enough to propose that change. |
For context on const bitcoin = require('bitcoinjs-lib')
const pubKey = bitcoin.HDNode.fromBase58('ypub6XMTwf6NSvfzYYgVgdNWRNfMTiQt4rSjZbEk8qoCnBGhUD2rsgZ2A8pexgzaGLKgySZxqxrctDpAVU8QtfxqfX8QUAhtFmGFUFx9B51TVg8')
.derive(0)
.derive(27)
.getPublicKeyBuffer()
const { address } = bitcoin.payments.p2sh({
redeem: bitcoin.payments.p2wpk({
pubkey: pubKey
})
}) |
ping @afk11 |
I think the PR needs to address generating the scriptPubKey/address for it to be complete, first of all. It'd really be nice for it to work with the other BIP's that do this custom HD prefix to indicate an address. There's BIP49, and BIP84, each has custom HD prefixes implementing the same logic, which is constructing a HD key capable of producing a P2SH|P2WPKH address, or P2WPKH respectively. Electrum takes this a step further, and defines 5 prefix/scriptTypes for which they do this. I've been thinking about the missing address generation part of this PR: could we add an optional parameter to the hdkey constructor, a closure accepting a public or private key, and returns a {scriptPubKey:, rs:, ws:, address: } when called? We can add the optional parameter to the generation methods as well. Derivations could pass on the closure to children as well. hdkey.getAddress could then check if the closure was set, and call it if so. If it wasn't set, just return P2PKH. A default closure of P2PKH could be how we make this work, actually. Maybe we want to add another function to hdkey, that returns {scriptPubKey:, rs:, ws:, address: }, since getAddress exclusively returns the address. This information would be really handy for signing time! That way, we can inject different kinds of closures to work with all the types that electrum supports (http://docs.electrum.org/en/latest/seedphrase.html):
It'd be nice to support the 5 (or more) serialization formats as well. One issue I have with the PR is that the deserialization will succeed even for people who don't want the feature. It'd be nice if people could control which prefix/scriptTypes are active during a deserialization? Could we find a way to pass in the extra prefixes/scriptTypes/closures for consideration in a call Maybe the prefixes/scriptTypes could be defined in the network, then a selection of these can be passed into deserialize/serialize methods? Whew.. this one's been on my mind anyway, overall the feature is nice to have if it's future proof against script-types, and developers need to opt into the behavior somehow! |
We're putting these registered HD prefix types in SLIP-0132, to pull the
reference out of any one implementation's docs.
https://github.com/satoshilabs/slips/blob/master/slip-0132.md
…-Clark
On Sat, Mar 3, 2018 at 5:46 PM, Thomas Kerin ***@***.***> wrote:
I think the PR needs to address generating the scriptPubKey/address for it
to be complete, first of all.
It'd really be nice for it to work with the other BIP's that do this
custom HD prefix to indicate an address. There's BIP49, and BIP84, each has
custom HD prefixes implementing the same logic, which is constructing a HD
key capable of producing a P2SH|P2WPKH address, or P2WPKH respectively.
Electrum takes this a step further, and defines 5 prefix/scriptTypes for
which they do this.
I've been thinking about the missing address generation part of this PR:
could we add an optional parameter to the hdkey constructor, a closure
accepting a public or private key, and returns a {scriptPubKey:, rs:, ws:,
address: } when called? We can add the optional parameter to the generation
methods as well. Derivations could pass on the closure to children as well.
hdkey.getAddress could then check if the closure was set, and call it if
so. If it wasn't set, just return P2PKH. A default closure of P2PKH could
be how we make this work, actually. Maybe we want to add another function
to hdkey, that returns {scriptPubKey:, rs:, ws:, address: }, since
getAddress exclusively returns the address. This information would be
really handy for signing time!
That way, we can inject different kinds of closures to work with all the
types that electrum supports (http://docs.electrum.org/en/
latest/seedphrase.html):
- P2PKH (xprv)
- P2SH|P2PKH (xprv)
- P2SH|P2WPKH (yprv)
- P2WSH|P2PKH (Yprv)
- P2WPKH (zprv)
- P2WSH ???? (this doesn't say which type, just p2wsh)
It'd be nice to support the 5 (or more) serialization formats as well. One
issue I have with the PR is that the deserialization will succeed even for
people who don't want the feature. It'd be nice if people could control
which prefix/scriptTypes are active during a deserialization? Could we find
a way to pass in the extra prefixes/scriptTypes/closures for consideration
in a call
Maybe the prefixes/scriptTypes could be defined in the network, then a
selection of these can be passed into deserialize/serialize methods?
—
You are receiving this because you commented.
Reply to this email directly, view it on GitHub
<#927 (comment)>,
or mute the thread
<https://github.com/notifications/unsubscribe-auth/ABfXMZ_xDzySJB0QEK-Sd5huwKc06vjGks5taytugaJpZM4QixnQ>
.
|
I took a quick look at getting getAddress to work, but a mocked getAddress test fails, since keyPair.getAddress was overwritten and now the results aren't identical. Makes me wonder if keyPair should have getAddress, but anyways. I'll comment the test for now since the addresses will vary going forward! #1014 - allows 'extra' prefixes to be provided by developers, or allows regular behavior of using the networks |
Related to bitcoin/bips#673 ? |
@mautematico may I have one question? for this code:
I'd like to know what's the meaning of Thank you very much. |
@jackylimel sure, have you read about bip32 derivation paths? They let you generate multiple public-private key pairs from a single initial master public-private pair (ypub & ypriv). twice https://bitcoin.stackexchange.com/questions/56561/bip32-derivation-path |
for anyone waiting for ypub support in bitcoinjs, heres a quick workaround I borrowed from #966
|
@Overtorment, thanks for that. This should be the zpub equivalent workaround:
EDIT: SLIP-0132 is a better source than the email linked above until it's in an actual BIP |
What do I do here? Thoughts? |
@dcousens i believe that "YPUB/UPUB" is now a part of BIP49. See Extended Key Version |
The only thing missing from bitcoinjs-lib to support BIP49 is the network type designator. This simple change allows the HD wallet to support BIP49 YPUB's (or testnet UPUB's). This allows for the import of pure segwit HD wallets.
See also: https://github.com/bitcoin/bips/blob/master/bip-0049.mediawiki
Understanding that BIP49 is draft, you may reject this change, but I've made this change for a project and figured submitting a PR would be an appropriate offer to allow you to implement this simple functionality.