crypto: add random.js.

This commit is contained in:
Christopher Jeffrey 2016-09-05 23:33:36 -07:00
parent 28acda024a
commit 1edb5aa4cf
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
9 changed files with 116 additions and 57 deletions

View File

@ -10,11 +10,9 @@
var elliptic = require('elliptic');
var bn = require('bn.js');
var utils = require('../utils/utils');
var random = require('./random');
var assert = utils.assert;
var crypto, secp256k1;
if (!utils.isBrowser)
crypto = require('crypto');
var secp256k1;
try {
if (+process.env.BCOIN_USE_ELLIPTIC !== 1)
@ -67,9 +65,9 @@ ec.curve = ec.elliptic.curve;
ec.generatePrivateKey = function generatePrivateKey() {
var key, priv;
if (secp256k1 && crypto) {
if (secp256k1) {
do {
priv = crypto.randomBytes(32);
priv = random.randomBytes(32);
} while (!secp256k1.privateKeyVerify(priv));
} else {
key = ec.elliptic.genKeyPair();
@ -110,7 +108,7 @@ ec.publicKeyConvert = function publicKeyConvert(key, compressed) {
if (secp256k1)
return secp256k1.publicKeyConvert(key, compressed);
point = ec.elliptic.curve.decodePoint(key);
point = ec.curve.decodePoint(key);
return new Buffer(point.encode('array', compressed !== false));
};
@ -190,51 +188,34 @@ ec.ecdh = function ecdh(pub, priv) {
*/
ec.recover = function recover(msg, sig, j, compressed) {
var keys = [];
var i, point, key;
var point, key;
if (typeof j === 'boolean') {
compressed = j;
j = null;
}
if (!j)
j = 0;
if (secp256k1) {
try {
sig = secp256k1.signatureImport(sig);
} catch (e) {
;
return;
}
}
for (i = 0; i <= 3; i++) {
if (j != null && j !== i)
continue;
if (secp256k1) {
try {
key = secp256k1.recover(msg, sig, i, compressed);
} catch (e) {
continue;
}
keys.push(key);
continue;
}
try {
point = ec.elliptic.recoverPubKey(msg, sig, i);
key = secp256k1.recover(msg, sig, j, compressed);
} catch (e) {
continue;
return;
}
key = ec.elliptic.keyPair({ pub: point });
key = key.getPublic(compressed !== false, 'array');
keys.push(new Buffer(key));
return key;
}
if (j != null)
return keys[0];
try {
point = ec.elliptic.recoverPubKey(msg, sig, j);
} catch (e) {
return;
}
return keys;
key = point.encode('array', compressed !== false);
return new Buffer(key);
};
/**
@ -243,10 +224,8 @@ ec.recover = function recover(msg, sig, j, compressed) {
* @returns {Buffer}
*/
ec.random = function random(size) {
if (crypto)
return crypto.randomBytes(size);
return new Buffer(elliptic.rand(size));
ec.random = function _random(size) {
return random.randomBytes(size);
};
/**
@ -259,8 +238,7 @@ ec.random = function random(size) {
*/
ec.rand = function rand(min, max) {
var num = ec.random(4).readUInt32LE(0, true);
return Math.floor((num / 0x100000000) * (max - min) + min);
return random.randomInt(min, max);
};
/**
@ -362,7 +340,7 @@ ec.privateKeyVerify = function privateKeyVerify(key) {
key = new bn(key);
return key.cmpn(0) !== 0 && key.cmp(ec.elliptic.curve.n) < 0;
return key.cmpn(0) !== 0 && key.cmp(ec.curve.n) < 0;
};
/**
@ -521,7 +499,7 @@ ec.toLowS = function toLowS(sig) {
// If S is greater than half the order,
// it's too high.
if (sig.s.cmp(ec.elliptic.nh) > 0)
sig.s = ec.elliptic.n.sub(sig.s);
sig.s = ec.curve.n.sub(sig.s);
return new Buffer(sig.toDER());
};

69
lib/crypto/random.js Normal file
View File

@ -0,0 +1,69 @@
/*!
* random.js - pseudorandom byte generation for bcoin.
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*
* Parts of this software are based on brorand:
* https://github.com/indutny/brorand
* Copyright (c) 2014, Fedor Indutny (MIT License).
*/
var random, crypto, global;
try {
crypto = require('crypto');
} catch (e) {
;
}
if (crypto) {
random = function random(n) {
return crypto.randomBytes(n);
};
} else {
if (typeof window !== 'undefined')
global = window;
else if (typeof self !== 'undefined')
global = self;
if (!global)
throw new Error('Unknown global.');
crypto = global.crypto || global.msCrypto;
if (crypto && crypto.getRandomValues) {
random = function random(n) {
var data = new Uint8Array(n);
crypto.getRandomValues(data);
return new Buffer(data.buffer);
};
} else {
// Out of luck here. Use bad randomness for now.
// Possibly fall back to randy in the future:
// https://github.com/deestan/randy
random = function random(n) {
var data = new Buffer(n);
var i;
for (i = 0; i < data.length; i++)
data[i] = ((Math.random() * 0x100000000) >>> 0) % 256;
return data;
};
}
}
function randomInt(min, max) {
var num = random(4).readUInt32LE(0, true);
return Math.floor((num / 0x100000000) * (max - min) + min);
}
/*
* Expose
*/
exports = random;
exports.randomBytes = random;
exports.randomInt = randomInt;
module.exports = random;

View File

@ -11,6 +11,7 @@ var elliptic = require('elliptic');
var Signature = require('elliptic/lib/elliptic/ec/signature');
var hmacDRBG = require('elliptic/lib/elliptic/hmac-drbg');
var ec = require('./ec');
var random = require('./random');
var curve = elliptic.ec('secp256k1').curve;
var sha256 = require('./crypto').sha256;
@ -109,7 +110,7 @@ schnorr.sign = function sign(msg, key, hash, pubnonce) {
throw new Error('Bad private key.');
while (!sig) {
k = new bn(ec.random(32));
k = new bn(random.randomBytes(32));
sig = schnorr._sign(msg, prv, k, hash, pubnonce);
}

View File

@ -9,6 +9,7 @@
var bcoin = require('../env');
var utils = require('../utils/utils');
var ec = require('../crypto/ec');
var random = require('../crypto/random');
var assert = utils.assert;
var constants = bcoin.constants;
var BufferWriter = require('../utils/writer');
@ -168,7 +169,7 @@ Mnemonic.prototype.toKey = function toKey(passphrase, network) {
Mnemonic.prototype.getEntropy = function getEntropy() {
if (!this.entropy)
this.entropy = ec.random(this.bits / 8);
this.entropy = random.randomBytes(this.bits / 8);
assert(this.bits / 8 === this.entropy.length);

View File

@ -9,6 +9,7 @@
var bcoin = require('../env');
var utils = require('../utils/utils');
var ec = require('../crypto/ec');
var random = require('../crypto/random');
var assert = utils.assert;
var constants = bcoin.constants;
var networks = bcoin.networks;
@ -577,7 +578,7 @@ HDPrivateKey.fromKey = function fromKey(key, entropy, network) {
HDPrivateKey.generate = function generate(network) {
var key = ec.generatePrivateKey();
var entropy = ec.random(32);
var entropy = random.randomBytes(32);
return HDPrivateKey.fromKey(key, entropy, network);
};

View File

@ -15,6 +15,7 @@ var constants = bcoin.constants;
var http = require('./');
var HTTPBase = http.base;
var utils = require('../utils/utils');
var random = require('../crypto/random');
var assert = utils.assert;
var RPC; /*= require('./rpc'); - load lazily */
@ -57,7 +58,7 @@ function HTTPServer(options) {
this.rpc = null;
if (!this.apiKey)
this.apiKey = utils.toBase58(bcoin.ec.random(20));
this.apiKey = utils.toBase58(random.randomBytes(20));
assert(typeof this.apiKey === 'string', 'API key must be a string.');
assert(this.apiKey.length <= 200, 'API key must be under 200 bytes.');
@ -233,6 +234,9 @@ HTTPServer.prototype._init = function _init() {
if (params.fee)
options.fee = utils.satoshi(params.fee);
if (params.hardFee)
options.hardFee = utils.satoshi(params.hardFee);
if (params.maxFee)
options.maxFee = utils.satoshi(params.maxFee);

View File

@ -19,6 +19,7 @@ var utils = require('../utils/utils');
var assert = utils.assert;
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var random = require('../crypto/random');
var VerifyError = bcoin.errors.VerifyError;
/**
@ -299,7 +300,7 @@ Mempool.prototype.limitOrphans = function limitOrphans() {
var i, hash;
while (this.totalOrphans > constants.mempool.MAX_ORPHAN_TX) {
i = bcoin.ec.rand(0, orphans.length);
i = random.randomInt(0, orphans.length);
hash = orphans[i];
orphans.splice(i, 1);

View File

@ -11,6 +11,7 @@
var EventEmitter = require('events').EventEmitter;
var bcoin = require('../env');
var utils = require('../utils/utils');
var random = require('../crypto/random');
var assert = utils.assert;
var constants = bcoin.constants;
@ -118,7 +119,7 @@ BIP150.prototype.reply = function reply(payload) {
throw new Error('Auth failure.');
if (!this.peerIdentity)
return bcoin.ec.random(32);
return random.randomBytes(32);
sig = bcoin.ec.toDER(data);
msg = this.hash(this.output.sid, type, this.peerIdentity);
@ -126,7 +127,7 @@ BIP150.prototype.reply = function reply(payload) {
result = bcoin.ec.verify(msg, sig, this.peerIdentity);
if (!result)
return bcoin.ec.random(32);
return random.randomBytes(32);
if (this.isAuthed()) {
this.auth = true;

View File

@ -14,6 +14,7 @@ var utils = require('../utils/utils');
var assert = utils.assert;
var BufferReader = require('../utils/reader');
var BufferWriter = require('../utils/writer');
var random = require('../crypto/random');
var TXDB = require('./txdb');
var Path = require('./path');
@ -905,7 +906,8 @@ Wallet.prototype.importKey = function importKey(account, ring, passphrase, callb
* @param {Boolean} options.confirmed - Select only confirmed coins.
* @param {Boolean} options.free - Do not apply a fee if the
* transaction priority is high enough to be considered free.
* @param {Amount?} options.fee - Use a hard fee rather than calculating one.
* @param {Amount?} options.hardFee - Use a hard fee rather than
* calculating one.
* @param {Number|Boolean} options.subtractFee - Whether to subtract the
* fee from existing outputs rather than adding more inputs.
*/
@ -967,11 +969,12 @@ Wallet.prototype.fund = function fund(tx, options, callback, force) {
round: options.round,
confirmed: options.confirmed,
free: options.free,
fee: options.fee,
hardFee: options.hardFee,
subtractFee: options.subtractFee,
changeAddress: account.changeAddress.getAddress(),
height: self.db.height,
rate: rate,
maxFee: options.maxFee,
m: account.m,
n: account.n,
witness: account.witness,
@ -2377,7 +2380,7 @@ MasterKey.prototype.encrypt = function encrypt(passphrase, callback) {
return callback();
data = this.key.toExtended();
iv = bcoin.ec.random(16);
iv = random.randomBytes(16);
this.stop();