Check objects POW

This commit is contained in:
Kagami Hiiragi 2015-01-30 20:13:09 +03:00
parent 25d5b70bae
commit 56679a0f8f
6 changed files with 62 additions and 44 deletions

View File

@ -73,26 +73,28 @@ var getpubkey = exports.getpubkey = {
/**
* Decode `getpubkey` object message.
* @param {Buffer} buf - Message
* @param {?Object} opts - Decoding options
* @return {Promise.<Object>} A promise that contains decoded
* `getpubkey` object structure when fulfilled.
*/
decodeAsync: function(buf) {
decodeAsync: function(buf, opts) {
return new promise(function(resolve) {
var decoded = message.decode(buf);
assert(decoded.command === "object", "Bad command");
resolve(getpubkey.decodePayloadAsync(decoded.payload));
resolve(getpubkey.decodePayloadAsync(decoded.payload, opts));
});
},
/**
* Decode `getpubkey` object message payload.
* @param {Buffer} buf - Message payload
* @param {?Object} opts - Decoding options
* @return {Promise.<Object>} A promise that contains decoded
* `getpubkey` object structure when fulfilled.
*/
decodePayloadAsync: function(buf) {
decodePayloadAsync: function(buf, opts) {
return new promise(function(resolve) {
var decoded = object.decodePayload(buf);
var decoded = object.decodePayload(buf, opts);
assert(decoded.type === object.GETPUBKEY, "Wrong object type");
assert(decoded.version >= 2, "getpubkey version is too low");
assert(decoded.version <= 4, "getpubkey version is too high");
@ -242,7 +244,7 @@ var pubkey = exports.pubkey = {
decodePayloadAsync: function(buf, opts) {
return new promise(function(resolve) {
opts = opts || {};
var decoded = object.decodePayload(buf);
var decoded = object.decodePayload(buf, opts);
assert(decoded.type === object.PUBKEY, "Wrong object type");
var version = decoded.version;
assert(version >= 2, "Address version is too low");
@ -552,7 +554,7 @@ var msg = exports.msg = {
*/
decodePayloadAsync: function(buf, opts) {
return new promise(function(resolve) {
var decoded = object.decodePayload(buf);
var decoded = object.decodePayload(buf, opts);
assert(decoded.type === object.MSG, "Bad object type");
assert(decoded.version === 1, "Bad msg version");
var objectPayload = util.popkey(decoded, "objectPayload");
@ -738,7 +740,7 @@ var DEFAULT_ENCODING = msg.TRIVIAL;
function tryDecryptBroadcastV4(subscriptions, buf) {
function inner(i) {
if (i > last) {
var err = new Error("Failed to decrypt msg with given identities");
var err = new Error("Failed to decrypt broadcast with given identities");
return promise.reject(err);
}
return bmcrypto
@ -801,7 +803,7 @@ var broadcast = exports.broadcast = {
*/
decodePayloadAsync: function(buf, opts) {
return new promise(function(resolve) {
var decoded = object.decodePayload(buf);
var decoded = object.decodePayload(buf, opts);
assert(decoded.type === object.BROADCAST, "Bad object type");
var version = decoded.version;
assert(version === 4 || version === 5, "Bad broadcast version");

View File

@ -45,7 +45,6 @@ exports.randomBytes = function(size) {
var B80 = new BN("1208925819614629174706176");
exports.getTarget = function(opts) {
var length = new BN(opts.payloadLength);
length.iaddn(8);
length.iaddn(opts.payloadLengthExtraBytes);
var denominator = new BN(opts.ttl);
denominator.iaddn(65536);

View File

@ -43,10 +43,7 @@ exports.getTarget = function(opts) {
// Slightly rearrange calculations and compute it bottom-up,
// right-to-left. See also:
// <https://github.com/Bitmessage/PyBitmessage/issues/758>.
var length = bignum(opts.payloadLength)
// To account for the nonce which we will append later.
.add(8)
.add(opts.payloadLengthExtraBytes);
var length = bignum(opts.payloadLength).add(opts.payloadLengthExtraBytes);
var denominator = bignum(opts.ttl)
.add(65536)
.mul(length)

View File

@ -36,9 +36,9 @@ exports.getTarget = function(opts) {
exports.check = function(opts) {
var initialHash;
var nonce;
if (opts.data) {
nonce = opts.data.slice(0, 8);
initialHash = bmcrypto.sha512(opts.data.slice(8));
if (opts.payload) {
nonce = opts.payload.slice(0, 8);
initialHash = bmcrypto.sha512(opts.payload.slice(8));
} else {
if (typeof opts.nonce === "number") {
nonce = new Buffer(8);

View File

@ -11,6 +11,7 @@ var objectAssign = Object.assign || require("object-assign");
var bufferEqual = require("buffer-equal");
var assert = require("./_util").assert;
var bmcrypto = require("./crypto");
var POW = require("./pow");
var util = require("./_util");
function isAscii(str) {
@ -112,42 +113,54 @@ var object = exports.object = {
* Decode `object` message.
* NOTE: `nonce` and `objectPayload` are copied.
* @param {Buffer} buf - Message
* @param {?Object} opts - Decoding options
* @return {Object} Decoded `object` structure.
*/
decode: function(buf) {
decode: function(buf, opts) {
var decoded = message.decode(buf);
assert(decoded.command === "object", "Bad command");
return object.decodePayload(decoded.payload);
return object.decodePayload(decoded.payload, opts);
},
/**
* Decode `object` message payload.
* NOTE: `nonce` and `objectPayload` are copied.
* @param {Buffer} buf - Message payload
* @param {?Object} opts - Decoding options
* @return {Object} Decoded `object` structure.
*/
// FIXME(Kagami): Check a POW.
// TODO(Kagami): Allow lower POW for friends.
// TODO(Kagami): Option to not fail on bad POW (may be useful for
// bitchan).
// TODO(Kagami): Option to not fail on expired objects (would be
// useful for bitchan).
decodePayload: function(buf) {
decodePayload: function(buf, opts) {
opts = opts || {};
// 8 + 8 + 4 + (1+) + (1+)
assert(buf.length >= 22, "object message payload is too small");
assert(buf.length <= 262144, "object message payload is too big");
var nonce = new Buffer(8);
buf.copy(nonce, 0, 0, 8);
// TTL.
var expiresTime = util.readTimestamp64BE(buf.slice(8, 16));
var ttl = expiresTime - util.tnow();
assert(ttl >= -3600, "Object expired more than a hour ago");
assert(ttl <= 2430000, "expiresTime is too far in the future");
if (!opts.allowExpired) {
assert(ttl >= -3600, "Object expired more than a hour ago");
}
// POW.
if (!opts.skipPow) {
// User may specify trials/payload extra options and we will
// account in here.
var targetOpts = objectAssign({}, opts, {ttl: ttl, payload: buf});
var target = POW.getTarget(targetOpts);
assert(POW.check({target: target, payload: buf}), "Insufficient POW");
}
var type = buf.readUInt32BE(16, true);
var decodedVersion = var_int.decode(buf.slice(20));
var decodedStream = var_int.decode(decodedVersion.rest);
var headerLength = 20 + decodedVersion.length + decodedStream.length;
var objectPayload = new Buffer(decodedStream.rest.length);
decodedStream.rest.copy(objectPayload);
return {
nonce: nonce,
ttl: ttl,

43
test.js
View File

@ -33,6 +33,8 @@ var POW = bitmessage.POW;
var Address = bitmessage.Address;
var UserAgent = bitmessage.UserAgent;
var skipPow = {skipPow: true};
describe("Crypto", function() {
it("should implement SHA-1 hash", function() {
expect(bmcrypto.sha1(Buffer("test")).toString("hex")).to.equal("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3");
@ -147,7 +149,7 @@ describe("Common structures", function() {
type: 2,
version: 1,
objectPayload: Buffer("test"),
}));
}), skipPow);
expect(bufferEqual(nonce, res.nonce)).to.be.true;
expect(res.ttl).to.be.at.most(100);
@ -570,7 +572,7 @@ describe("Object types", function() {
to: "BM-2D8Jxw5yiepaQqxrx43iPPNfRqbvWoJLoU",
}).then(function(buf) {
expect(message.decode(buf).command).to.equal("object");
return getpubkey.decodeAsync(buf);
return getpubkey.decodeAsync(buf, skipPow);
}).then(function(res) {
expect(res.ttl).to.be.at.most(100);
expect(res.type).to.equal(object.GETPUBKEY);
@ -587,7 +589,7 @@ describe("Object types", function() {
to: "2cTux3PGRqHTEH6wyUP2sWeT4LrsGgy63z",
}).then(function(buf) {
expect(message.decode(buf).command).to.equal("object");
return getpubkey.decodeAsync(buf);
return getpubkey.decodeAsync(buf, skipPow);
}).then(function(res) {
expect(res.ttl).to.be.at.most(100);
expect(res.type).to.equal(object.GETPUBKEY);
@ -607,7 +609,7 @@ describe("Object types", function() {
to: "BM-onhypnh1UMhbQpmvdiPuG6soLLytYJAfH",
}).then(function(buf) {
expect(message.decode(buf).command).to.equal("object");
return pubkey.decodeAsync(buf);
return pubkey.decodeAsync(buf, skipPow);
}).then(function(res) {
expect(res.ttl).to.be.at.most(123);
expect(res.type).to.equal(object.PUBKEY);
@ -627,7 +629,7 @@ describe("Object types", function() {
to: "BM-2D8Jxw5yiepaQqxrx43iPPNfRqbvWoJLoU",
}).then(function(buf) {
expect(message.decode(buf).command).to.equal("object");
return pubkey.decodeAsync(buf);
return pubkey.decodeAsync(buf, skipPow);
}).then(function(res) {
expect(res.ttl).to.be.at.most(456);
expect(res.type).to.equal(object.PUBKEY);
@ -646,7 +648,7 @@ describe("Object types", function() {
return pubkey.encodeAsync({ttl: 789, from: from, to: from})
.then(function(buf) {
expect(message.decode(buf).command).to.equal("object");
return pubkey.decodeAsync(buf, {needed: from});
return pubkey.decodeAsync(buf, {needed: from, skipPow: true});
}).then(function(res) {
expect(res.ttl).to.be.at.most(789);
expect(res.type).to.equal(object.PUBKEY);
@ -672,7 +674,7 @@ describe("Object types", function() {
message: "test",
}).then(function(buf) {
expect(message.decode(buf).command).to.equal("object");
return msg.decodeAsync(buf, {identities: [from]});
return msg.decodeAsync(buf, {identities: [from], skipPow: true});
}).then(function(res) {
expect(res.ttl).to.be.at.most(111);
expect(res.type).to.equal(object.MSG);
@ -701,7 +703,7 @@ describe("Object types", function() {
message: "test",
}).then(function(buf) {
expect(message.decode(buf).command).to.equal("object");
return msg.decodeAsync(buf, {identities: [fromV2]});
return msg.decodeAsync(buf, {identities: [fromV2], skipPow: true});
}).then(function(res) {
expect(res.ttl).to.be.at.most(111);
expect(res.type).to.equal(object.MSG);
@ -729,8 +731,9 @@ describe("Object types", function() {
to: from,
message: "test",
}).then(function(buf) {
return msg.decodeAsync(buf, {identities: []});
}).catch(function() {
return msg.decodeAsync(buf, {identities: [], skipPow: true});
}).catch(function(err) {
expect(err.message).to.match(/with given identities/i);
done();
});
});
@ -744,7 +747,7 @@ describe("Object types", function() {
subject: "Тема",
message: "Сообщение",
}).then(function(buf) {
return msg.decodeAsync(buf, {identities: [from]});
return msg.decodeAsync(buf, {identities: [from], skipPow: true});
}).then(function(res) {
expect(res.encoding).to.equal(msg.SIMPLE);
expect(res.subject).to.equal("Тема");
@ -773,7 +776,7 @@ describe("Object types", function() {
message: "test",
}).then(function(buf) {
expect(message.decode(buf).command).to.equal("object");
return broadcast.decodeAsync(buf, {subscriptions: fromV3});
return broadcast.decodeAsync(buf, {subscriptions: fromV3, skipPow: true});
}).then(function(res) {
expect(res.ttl).to.be.at.most(987);
expect(res.type).to.equal(object.BROADCAST);
@ -800,7 +803,7 @@ describe("Object types", function() {
message: "test",
}).then(function(buf) {
expect(message.decode(buf).command).to.equal("object");
return broadcast.decodeAsync(buf, {subscriptions: fromV2});
return broadcast.decodeAsync(buf, {subscriptions: fromV2, skipPow: true});
}).then(function(res) {
expect(res.ttl).to.be.at.most(999);
expect(res.type).to.equal(object.BROADCAST);
@ -827,7 +830,7 @@ describe("Object types", function() {
message: "キタ━━━(゜∀゜)━━━!!!!!",
}).then(function(buf) {
expect(message.decode(buf).command).to.equal("object");
return broadcast.decodeAsync(buf, {subscriptions: [from]});
return broadcast.decodeAsync(buf, {subscriptions: [from], skipPow: true});
}).then(function(res) {
expect(res.ttl).to.be.at.most(987);
expect(res.type).to.equal(object.BROADCAST);
@ -853,8 +856,12 @@ describe("Object types", function() {
from: from,
message: "test",
}).then(function(buf) {
return broadcast.decodeAsync(buf, {subscriptions: [fromV3]});
}).catch(function() {
return broadcast.decodeAsync(buf, {
subscriptions: [fromV3],
skipPow: true,
});
}).catch(function(err) {
expect(err.message).to.match(/not interested/i);
done();
});
});
@ -901,8 +908,8 @@ describe("WIF", function() {
describe("POW", function() {
it("should calculate target", function() {
expect(POW.getTarget({ttl: 2418984, payloadLength: 628, nonceTrialsPerByte: 1000, payloadLengthExtraBytes: 1000})).to.equal(297422525267);
expect(POW.getTarget({ttl: 86400, payloadLength: 628})).to.equal(4863575534951);
expect(POW.getTarget({ttl: 2418984, payloadLength: 636, nonceTrialsPerByte: 1000, payloadLengthExtraBytes: 1000})).to.equal(297422525267);
expect(POW.getTarget({ttl: 86400, payloadLength: 636})).to.equal(4863575534951);
});
it("should check a POW", function() {