diff --git a/lib/crypto-platform.browser.js b/lib/crypto-platform.browser.js index d6bf688..3edc3f0 100644 --- a/lib/crypto-platform.browser.js +++ b/lib/crypto-platform.browser.js @@ -1,6 +1,5 @@ /** * Browser Bitmessage crypto implementation. - * * Documentation: * Browsers support: * Blink implementation details: @@ -34,3 +33,9 @@ exports.ripemd160 = function(buf) { // so use module. return Promise.resolve(ripemd160(buf)); }; + +exports.randomBytes = function(size) { + var arr = new Uint8Array(size); + window.crypto.getRandomValues(arr); + return new Buffer(arr); +}; diff --git a/lib/crypto-platform.js b/lib/crypto-platform.js index 47eaf49..81ae9c0 100644 --- a/lib/crypto-platform.js +++ b/lib/crypto-platform.js @@ -25,3 +25,12 @@ exports.ripemd160 = function(buf) { hash.update(buf); return Promise.resolve(hash.digest()); }; + +/** + * Generate cryptographically strong pseudo-random data. + * @param {number} size - Number of bytes + * @return {Buffer} Buffer with random data. + */ +exports.randomBytes = function(size) { + return crypto.randomBytes(size); +}; diff --git a/lib/crypto.js b/lib/crypto.js index c77f550..cbda353 100644 --- a/lib/crypto.js +++ b/lib/crypto.js @@ -7,6 +7,7 @@ "use strict"; var cryptoPlatform = require("./crypto-platform"); + Object.keys(cryptoPlatform).forEach(function(key) { exports[key] = cryptoPlatform[key]; }); diff --git a/test.js b/test.js index dd25aa2..5ffd7ec 100644 --- a/test.js +++ b/test.js @@ -56,6 +56,29 @@ describe("Crypto", function() { expect(res.toString("hex")).to.equal("5e52fee47e6b070565f74372468cdc699de89107"); }); }); + + it("should implement cryptographically secure PRNG", function() { + var size = 100; + var rnd = bmcrypto.randomBytes(size); + expect(Buffer.isBuffer(rnd)).to.be.true; + expect(rnd.length).to.equal(size); + // Very simple statistical test. + var bytes = {}; + var sum = 0; + var value; + for (var i = 0; i < size; i++) { + value = rnd[i]; + sum += value; + if (!bytes[value]) { + bytes[value] = 0; + } + bytes[value]++; + expect(bytes[value]).to.be.below(5); + } + // Ideal sum = (255 / 2) * size = 12750 + expect(sum).to.be.above(10000); + expect(sum).to.be.below(15000); + }); }); describe("Address", function() {