diff --git a/README.md b/README.md index d772a8e..6feb603 100644 --- a/README.md +++ b/README.md @@ -24,7 +24,7 @@ Constructors: * `generate([icap])` - create an instance based on a new random key (setting `icap` to true will generate an address suitable for the `ICAP Direct mode`) * `fromPrivateKey(input)` - create an instance based on a raw private key * `fromExtendedPrivateKey(input)` - create an instance based on a BIP32 xprv -* `fromPublicKey(input)` - create an instance based on a public key (certain methods will not be available) +* `fromPublicKey(input, [nonStrict])` - create an instance based on a public key (certain methods will not be available) * `fromExtendedPublicKey(input)` - create an instance based on a BIP32 xpub * `fromV1(input, password)` - import a wallet (Version 1 of the Ethereum wallet format) * `fromV3(input, password, [nonStrict])` - import a wallet (Version 3 of the Ethereum wallet format). Set `nonStrict` true to accept files with mixed-caps. @@ -32,6 +32,8 @@ Constructors: For the V1, V3 and EthSale formats the input is a JSON serialized string. All these formats require a password. +Note: `fromPublicKey()` only accepts uncompressed Ethereum-style public keys, unless the `nonStrict` flag is set to true. + Third party imports: * `fromEtherCamp(passphrase)` - import a brain wallet used by Ether.Camp diff --git a/hdkey.js b/hdkey.js index 5089d0d..1dc8fd3 100644 --- a/hdkey.js +++ b/hdkey.js @@ -41,7 +41,7 @@ EthereumHDKey.prototype.getWallet = function () { if (this._hdkey._privateKey) { return Wallet.fromPrivateKey(this._hdkey._privateKey) } else { - return Wallet.fromPublicKey(this._hdkey._publicKey) + return Wallet.fromPublicKey(this._hdkey._publicKey, true) } } diff --git a/index.js b/index.js index b138f88..c759f27 100644 --- a/index.js +++ b/index.js @@ -161,7 +161,12 @@ Wallet.prototype.toV3String = function (password, opts) { return JSON.stringify(this.toV3(password, opts)) } -Wallet.fromPublicKey = function (pub) { +Wallet.fromPublicKey = function (pub, nonStrict) { + // FIXME: duplicate from ethUtil.publicToAddress(), maybe it could be factored out? + if ((pub.length !== 64) && nonStrict) { + pub = secp256k1.publicKeyConvert(pub, false).slice(1) + } + assert(pub.length === 64, 'Invalid public key') return new Wallet(null, pub) } @@ -169,8 +174,7 @@ Wallet.fromExtendedPublicKey = function (pub) { assert(pub.slice(0, 4) === 'xpub', 'Not an extended public key') pub = bs58check.decode(pub).slice(45) // Convert to an Ethereum public key - pub = secp256k1.publicKeyConvert(pub, false).slice(1) - return Wallet.fromPublicKey(pub) + return Wallet.fromPublicKey(pub, true) } Wallet.fromPrivateKey = function (priv) { diff --git a/test/hdkey.js b/test/hdkey.js index 950c273..571f22e 100644 --- a/test/hdkey.js +++ b/test/hdkey.js @@ -69,6 +69,6 @@ describe('.getWallet()', function () { assert.throws(function () { hdnode.getWallet().getPrivateKeyString() }) - assert.equal(hdnode.getWallet().getPublicKeyString(), '0x030639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973d') + assert.equal(hdnode.getWallet().getPublicKeyString(), '0x0639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973defa5cb69df462bcc6d73c31e1c663c225650e80ef14a507b203f2a12aea55bc1') }) }) diff --git a/test/index.js b/test/index.js index 19e3583..310562a 100644 --- a/test/index.js +++ b/test/index.js @@ -58,6 +58,16 @@ describe('public key only wallet', function () { assert.equal(Wallet.fromPublicKey(pubKey).getPublicKey().toString('hex'), '5d4392f450262b276652c1fc037606abac500f3160830ce9df53aa70d95ce7cfb8b06010b2f3691c78c65c21eb4cf3dfdbfc0745d89b664ee10435bb3a0f906c') }) + it('.fromPublicKey() should not accept compressed keys in strict mode', function () { + assert.throws(function () { + Wallet.fromPublicKey(new Buffer('030639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973d', 'hex')) + }) + }) + it('.fromPublicKey() should accept compressed keys in non-strict mode', function () { + var tmp = new Buffer('030639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973d', 'hex') + assert.equal(Wallet.fromPublicKey(tmp, true).getPublicKey().toString('hex'), + '0639797f6cc72aea0f3d309730844a9e67d9f1866e55845c5f7e0ab48402973defa5cb69df462bcc6d73c31e1c663c225650e80ef14a507b203f2a12aea55bc1') + }) it('.getAddress() should work', function () { assert.equal(Wallet.fromPublicKey(pubKey).getAddress().toString('hex'), 'b14ab53e38da1c172f877dbc6d65e4a1b0474c3c') })