Calculate POW target

This commit is contained in:
Kagami Hiiragi 2015-01-08 00:28:13 +03:00
parent 8c2f180037
commit a7eb439706
5 changed files with 90 additions and 3 deletions

View File

@ -5,6 +5,8 @@
"use strict"; "use strict";
var hash = require("hash.js"); var hash = require("hash.js");
var BN = require("bn.js");
var assert = require("./util").assert;
exports.sha512 = function(buf) { exports.sha512 = function(buf) {
return new Buffer(hash.sha512().update(buf).digest()); return new Buffer(hash.sha512().update(buf).digest());
@ -23,3 +25,19 @@ exports.randomBytes = function(size) {
window.crypto.getRandomValues(arr); window.crypto.getRandomValues(arr);
return new Buffer(arr); return new Buffer(arr);
}; };
var B64 = new BN("18446744073709551616");
exports.getTarget = function(opts) {
var length = new BN(opts.payloadLength);
length.iaddn(8);
length.iaddn(opts.payloadLengthExtraBytes);
var denominator = new BN(opts.ttl);
denominator.imul(length);
denominator.idivn(65536);
denominator.iadd(length);
denominator.imul(new BN(opts.nonceTrialsPerByte));
var target = parseInt(B64.div(denominator).toString(16), 16);
assert(target <= 9007199254740991, "Unsafe target");
return target;
};

View File

@ -5,6 +5,9 @@
"use strict"; "use strict";
var crypto = require("crypto"); var crypto = require("crypto");
var bignum = require("bignum");
var assert = require("./util").assert;
var createHash = crypto.createHash; var createHash = crypto.createHash;
exports.sha512 = function(buf) { exports.sha512 = function(buf) {
@ -20,3 +23,25 @@ exports.ripemd160 = function(buf) {
}; };
exports.randomBytes = crypto.randomBytes; exports.randomBytes = crypto.randomBytes;
// 2^64.
var B64 = bignum("18446744073709551616");
// NOTE(Kagami): We can't calculate entire target in JavaScript but the
// result can be represented in native number type without losing
// precision (targets mainly much less than 2^53).
exports.getTarget = function(opts) {
// Calculate it bottom-up, right-to-left.
var length = bignum(opts.payloadLength)
// To account for the nonce which we will append later.
.add(8)
.add(opts.payloadLengthExtraBytes);
var denominator = bignum(opts.ttl)
.mul(length)
.div(65536)
.add(length)
.mul(opts.nonceTrialsPerByte);
var target = B64.div(denominator).toNumber();
assert(target <= 9007199254740991, "Unsafe target");
return target;
};

View File

@ -3,3 +3,34 @@
* @see {@link https://bitmessage.org/wiki/Proof_of_work} * @see {@link https://bitmessage.org/wiki/Proof_of_work}
* @module bitmessage/pow * @module bitmessage/pow
*/ */
"use strict";
var platform = require("./platform");
var DEFAULT_TRIALS_PER_BYTE = 1000;
var DEFAULT_EXTRA_BYTES = 1000;
/**
* Calculate target
* @param {{ttl: number, payloadLength: number}} opts - Target options
* @return {number} Target.
*/
// Just a wrapper around platform-specific implementation.
exports.getTarget = function(opts) {
var nonceTrialsPerByte = opts.nonceTrialsPerByte;
// Automatically raise lower values per spec.
if (!nonceTrialsPerByte || nonceTrialsPerByte < DEFAULT_TRIALS_PER_BYTE) {
nonceTrialsPerByte = DEFAULT_TRIALS_PER_BYTE;
}
var payloadLengthExtraBytes = opts.payloadLengthExtraBytes;
if (!payloadLengthExtraBytes || payloadLengthExtraBytes < DEFAULT_EXTRA_BYTES) {
payloadLengthExtraBytes = DEFAULT_EXTRA_BYTES;
}
return platform.getTarget({
ttl: opts.ttl,
payloadLength: opts.payloadLength,
nonceTrialsPerByte: nonceTrialsPerByte,
payloadLengthExtraBytes: payloadLengthExtraBytes,
});
};

View File

@ -7,7 +7,7 @@
"./lib/platform.js": "./lib/platform.browser.js" "./lib/platform.js": "./lib/platform.browser.js"
}, },
"scripts": { "scripts": {
"test": "ALL_TESTS=1 mocha && xvfb-run -a karma start && jshint .", "test": "ALL_TESTS=1 mocha && ALL_TESTS=1 xvfb-run -a karma start && jshint .",
"m": "mocha", "m": "mocha",
"k": "xvfb-run -a karma start", "k": "xvfb-run -a karma start",
"kc": "xvfb-run -a karma start --browsers Chromium", "kc": "xvfb-run -a karma start --browsers Chromium",
@ -46,10 +46,13 @@
"mocha": "*" "mocha": "*"
}, },
"dependencies": { "dependencies": {
"bignum": "^0.9.0",
"bn.js": "^1.0.0",
"bs58": "^2.0.0", "bs58": "^2.0.0",
"buffer-equal": "~0.0.1", "buffer-equal": "~0.0.1",
"eccrypto": "^0.1.2", "eccrypto": "^0.1.2",
"hash.js": "^1.0.2", "hash.js": "^1.0.2",
"object-assign": "^2.0.0" "object-assign": "^2.0.0",
"sha.js": "^2.3.0"
} }
} }

12
test.js
View File

@ -15,6 +15,7 @@ var messageEncodings = structs.messageEncodings;
var serviceFeatures = structs.serviceFeatures; var serviceFeatures = structs.serviceFeatures;
var pubkeyFeatures = structs.pubkeyFeatures; var pubkeyFeatures = structs.pubkeyFeatures;
var WIF = bitmessage.WIF; var WIF = bitmessage.WIF;
var POW = bitmessage.POW;
var Address = bitmessage.Address; var Address = bitmessage.Address;
describe("Crypto", function() { describe("Crypto", function() {
@ -263,6 +264,13 @@ describe("WIF", function() {
}); });
}); });
describe("POW", function() {
it("should calculate target", function() {
expect(POW.getTarget({ttl: 2418984, payloadLength: 628, nonceTrialsPerByte: 1000, payloadLengthExtraBytes: 1000})).to.equal(297422593171);
expect(POW.getTarget({ttl: 86400, payloadLength: 628})).to.equal(4864647698763);
});
});
describe("High-level classes", function() { describe("High-level classes", function() {
// FIXME(Kagami): Add more fail tests. // FIXME(Kagami): Add more fail tests.
describe("Address", function() { describe("Address", function() {
@ -296,7 +304,9 @@ describe("High-level classes", function() {
expect(addr2.ripe[0]).to.equal(0); expect(addr2.ripe[0]).to.equal(0);
}); });
if (allTests) { // FIXME(Kagami): Don't run it in browser currently because it's
// very slow. This need to be fixed.
if (allTests && typeof window === "undefined") {
it("should allow to generate shorter address", function() { it("should allow to generate shorter address", function() {
this.timeout(60000); this.timeout(60000);
var addr = Address.fromRandom({ripelen: 18}); var addr = Address.fromRandom({ripelen: 18});