Address.fromPassphrase

This commit is contained in:
Kagami Hiiragi 2015-01-18 15:34:02 +03:00
parent 09f7be7062
commit bc3fef1aea
3 changed files with 69 additions and 17 deletions

View File

@ -51,12 +51,8 @@ API documentation is available [here](https://bitchan.github.io/bitmessage/docs/
- [ ] broadcast - [ ] broadcast
- [x] WIF - [x] WIF
- [x] POW - [x] POW
- [ ] High-level classes - [x] High-level classes
- [ ] Address - [x] Address
- [x] encode
- [x] decode
- [x] fromRandom
- [ ] fromPassphrase
- [x] UserAgent - [x] UserAgent
- [ ] Parse PyBitmessage configs - [ ] Parse PyBitmessage configs
- [ ] keys.dat - [ ] keys.dat

View File

@ -216,27 +216,21 @@ Address.fromRandom = function(opts) {
var version = opts.version = opts.version || 4; var version = opts.version = opts.version || 4;
var ripelen = popkey(opts, "ripelen") || 19; var ripelen = popkey(opts, "ripelen") || 19;
assertripelen(ripelen, version); assertripelen(ripelen, version);
// Should the generated ripe length be strictly equal to the specified
// (less or equal by default).
var strictripelen = !!popkey(opts, "strictripelen");
// TODO(Kagami): Speed it up using web workers in Browser. // TODO(Kagami): Speed it up using web workers in Browser.
// TODO(Kagami): Bind to C++ version of this code in Node. // TODO(Kagami): Bind to C++ version of this code in Node.
var encPrivateKey, encPublicKey, ripe; var encPrivateKey, encPublicKey, ripe, len;
var signPrivateKey = bmcrypto.getPrivate(); var signPrivateKey = bmcrypto.getPrivate();
var signPublicKey = bmcrypto.getPublic(signPrivateKey); var signPublicKey = bmcrypto.getPublic(signPrivateKey);
var keysbuf = Buffer(130); var keysbuf = new Buffer(130);
signPublicKey.copy(keysbuf); signPublicKey.copy(keysbuf);
while (true) { while (true) {
encPrivateKey = bmcrypto.getPrivate(); encPrivateKey = bmcrypto.getPrivate();
encPublicKey = bmcrypto.getPublic(encPrivateKey); encPublicKey = bmcrypto.getPublic(encPrivateKey);
encPublicKey.copy(keysbuf, 65); encPublicKey.copy(keysbuf, 65);
ripe = bmcrypto.ripemd160(bmcrypto.sha512(keysbuf)); ripe = bmcrypto.ripemd160(bmcrypto.sha512(keysbuf));
var len = getripelen(ripe); len = getripelen(ripe);
if ( if (len <= ripelen && checkripelen(len, version)) {
(strictripelen && len === ripelen) ||
(!strictripelen && len <= ripelen && checkripelen(ripelen, version))
) {
// TODO(Kagami): Do we need to put all these properties or compute // TODO(Kagami): Do we need to put all these properties or compute
// them manually via ECMA5 getters/setters instead? // them manually via ECMA5 getters/setters instead?
opts.signPrivateKey = signPrivateKey; opts.signPrivateKey = signPrivateKey;
@ -249,4 +243,55 @@ Address.fromRandom = function(opts) {
} }
}; };
/**
* Create new Bitmessage address from passphrase.
* @param {?Object} opts - Address options
* @return {Address} Generated address object.
*/
Address.fromPassphrase = function(opts) {
opts = objectAssign({}, opts);
var version = opts.version = opts.version || 4;
var ripelen = popkey(opts, "ripelen") || 19;
assertripelen(ripelen, version);
var passphrase = popkey(opts, "passphrase");
// TODO(Kagami): Speed it up using web workers in Browser.
// TODO(Kagami): Bind to C++ version of this code in Node.
var signPrivateKey, signPublicKey, encPrivateKey, encPublicKey;
var ripe, len, tmp;
var signnonce = 0;
var encnonce = 1;
var keysbuf = new Buffer(130);
// XXX(Kagami): Spec doesn't mention encoding, using UTF-8.
var phrasebuf = new Buffer(passphrase, "utf8");
while (true) {
// TODO(Kagami): We may slightly optimize it and pre-create tmp
// buffers based on the encoded nonce size (1, 3, 5 and 9 bytes).
tmp = Buffer.concat([phrasebuf, var_int.encode(signnonce)]);
signPrivateKey = bmcrypto.sha512(tmp).slice(0, 32);
signPublicKey = bmcrypto.getPublic(signPrivateKey);
signPublicKey.copy(keysbuf);
tmp = Buffer.concat([phrasebuf, var_int.encode(encnonce)]);
encPrivateKey = bmcrypto.sha512(tmp).slice(0, 32);
encPublicKey = bmcrypto.getPublic(encPrivateKey);
encPublicKey.copy(keysbuf, 65);
ripe = bmcrypto.ripemd160(bmcrypto.sha512(keysbuf));
len = getripelen(ripe);
if (len <= ripelen && checkripelen(len, version)) {
// TODO(Kagami): Do we need to put all these properties or compute
// them manually via ECMA5 getters/setters instead?
opts.signPrivateKey = signPrivateKey;
opts.signPublicKey = signPublicKey;
opts.encPrivateKey = encPrivateKey;
opts.encPublicKey = encPublicKey;
opts.ripe = ripe;
return new Address(opts);
}
signnonce += 2;
encnonce += 2;
};
};
module.exports = Address; module.exports = Address;

13
test.js
View File

@ -525,7 +525,7 @@ describe("High-level classes", function() {
expect(addr.ripe.toString("hex")).to.equal("003ab6655de4bd8c603eba9b00dd5970725fdd56"); expect(addr.ripe.toString("hex")).to.equal("003ab6655de4bd8c603eba9b00dd5970725fdd56");
}); });
it("should allow to generate new Bitmessage address", function() { it("should allow to create random Bitmessage address", function() {
this.timeout(60000); this.timeout(60000);
var addr = Address.fromRandom(); var addr = Address.fromRandom();
expect(addr.version).to.equal(4); expect(addr.version).to.equal(4);
@ -541,6 +541,17 @@ describe("High-level classes", function() {
expect(addr2.ripe[0]).to.equal(0); expect(addr2.ripe[0]).to.equal(0);
}); });
it("should allow to create Bitmessage address from passphrase", function() {
this.timeout(60000);
var addr = Address.fromPassphrase({passphrase: "test"});
expect(addr.version).to.equal(4);
expect(addr.stream).to.equal(1);
expect(bufferEqual(addr.signPrivateKey, WIF.decode("5JY1CFeeyN4eyfL35guWAuUqu5VLmd7LojtkNP6wmt5msZxxZ57"))).to.be.true;
expect(bufferEqual(addr.encPrivateKey, WIF.decode("5J1oDgZDicNhUgbfzBDQqi2m5jUPnDrfZinnTqEEEaLv63jVFTM"))).to.be.true;
expect(addr.getRipe().toString("hex")).to.equal("00ac14944b00decea5628eb40d0ff4b0f9ee9eca");
expect(addr.encode()).to.equal("BM-2cWFkyuXXFw6d393RGnin2RpSXj8wxtt6F");
});
it("should calculate tag", function() { it("should calculate tag", function() {
var addr = Address.decode("2cTux3PGRqHTEH6wyUP2sWeT4LrsGgy63z"); var addr = Address.decode("2cTux3PGRqHTEH6wyUP2sWeT4LrsGgy63z");
expect(addr.getTag().toString("hex")).to.equal("facf1e3e6c74916203b7f714ca100d4d60604f0917696d0f09330f82f52bed1a"); expect(addr.getTag().toString("hex")).to.equal("facf1e3e6c74916203b7f714ca100d4d60604f0917696d0f09330f82f52bed1a");