modules: remove all conditional requires. see #105.

This commit is contained in:
Christopher Jeffrey 2016-11-18 23:04:37 -08:00
parent 9f522c5ca4
commit 67a00bfe50
No known key found for this signature in database
GPG Key ID: 8962AB9DE6666BBD
55 changed files with 1615 additions and 1306 deletions

View File

@ -1,3 +1,2 @@
// Empty module for browserify.
module.exports = null;
throw new Error('Module not available.');
exports.empty = true;

View File

@ -10,6 +10,5 @@ exports.PaymentRequest = require('./paymentrequest');
exports.PaymentDetails = require('./paymentdetails');
exports.Payment = require('./payment');
exports.PaymentACK = require('./paymentack');
exports.asn1 = require('./asn1');
exports.x509 = require('./x509');
exports.pk = require('./pk');

View File

@ -10,7 +10,7 @@ var assert = require('assert');
var Output = require('../primitives/output');
var TX = require('../primitives/tx');
var Script = require('../script/script');
var protobuf = require('./protobuf');
var protobuf = require('../utils/protobuf');
var PaymentDetails = require('./paymentdetails');
var ProtoReader = protobuf.ProtoReader;
var ProtoWriter = protobuf.ProtoWriter;

View File

@ -7,7 +7,7 @@
'use strict';
var assert = require('assert');
var protobuf = require('./protobuf');
var protobuf = require('../utils/protobuf');
var Payment = require('./payment');
var ProtoReader = protobuf.ProtoReader;
var ProtoWriter = protobuf.ProtoWriter;

View File

@ -9,7 +9,7 @@
var assert = require('assert');
var utils = require('../utils/utils');
var Output = require('../primitives/output');
var protobuf = require('./protobuf');
var protobuf = require('../utils/protobuf');
var ProtoReader = protobuf.ProtoReader;
var ProtoWriter = protobuf.ProtoWriter;

View File

@ -10,8 +10,8 @@ var assert = require('assert');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var x509 = require('./x509');
var asn1 = require('./asn1');
var protobuf = require('./protobuf');
var PEM = require('../utils/pem');
var protobuf = require('../utils/protobuf');
var PaymentDetails = require('./paymentdetails');
var ProtoReader = protobuf.ProtoReader;
var ProtoWriter = protobuf.ProtoWriter;
@ -154,7 +154,7 @@ PaymentRequest.prototype.setChain = function setChain(chain) {
for (i = 0; i < chain.length; i++) {
cert = chain[i];
if (typeof cert === 'string') {
pem = asn1.fromPEM(cert);
pem = PEM.decode(cert);
assert(pem.type === 'certificate', 'Bad certificate PEM.');
cert = pem.data;
}

View File

@ -6,248 +6,38 @@
'use strict';
var BN = require('bn.js');
var asn1 = require('./asn1');
var elliptic = require('elliptic');
var crypto = require('../crypto/crypto');
var pk = require('../crypto/pk');
var nativeCrypto;
try {
nativeCrypto = require('crypto');
} catch (e) {
;
}
var pk = exports;
var rsa = {};
var ecdsa = {};
var native = {};
rsa.prefixes = {
md5: new Buffer('3020300c06082a864886f70d020505000410', 'hex'),
sha1: new Buffer('3021300906052b0e03021a05000414', 'hex'),
sha224: new Buffer('302d300d06096086480165030402040500041c', 'hex'),
sha256: new Buffer('3031300d060960864801650304020105000420', 'hex'),
sha384: new Buffer('3041300d060960864801650304020205000430', 'hex'),
sha512: new Buffer('3051300d060960864801650304020305000440', 'hex'),
md5sha1: new Buffer(0),
ripemd160: new Buffer('30203008060628cf060300310414', 'hex')
};
// Ported from:
// https://github.com/golang/go/blob/master/src/crypto/rsa/pkcs1v15.go
rsa.verify = function verify(hashAlg, msg, sig, key) {
var hash = crypto.hash(hashAlg, msg);
var prefix = rsa.prefixes[hashAlg];
var len = prefix.length + hash.length;
var pub = asn1.parseRSAPublic(key);
var N = new BN(pub.modulus);
var e = new BN(pub.publicExponent);
var k = Math.ceil(N.bitLength() / 8);
var m, em, ok, i;
if (k < len + 11)
throw new Error('Message too long.');
m = rsa.encrypt(N, e, sig);
em = leftpad(m, k);
ok = crypto.ceq(em[0], 0x00);
ok &= crypto.ceq(em[1], 0x01);
ok &= crypto.ccmp(em.slice(k - hash.length, k), hash);
ok &= crypto.ccmp(em.slice(k - len, k - hash.length), prefix);
ok &= crypto.ceq(em[k - len - 1], 0x00);
for (i = 2; i < k - len - 1; i++)
ok &= crypto.ceq(em[i], 0xff);
return ok === 1;
};
rsa.sign = function sign(hashAlg, msg, key) {
var hash = crypto.hash(hashAlg, msg);
var prefix = rsa.prefixes[hashAlg];
var len = prefix.length + hash.length;
var priv = asn1.parseRSAPrivate(key);
var N = new BN(priv.modulus);
var D = new BN(priv.privateExponent);
var k = Math.ceil(N.bitLength() / 8);
var i, em;
if (k < len + 11)
throw new Error('Message too long.');
em = new Buffer(k);
em.fill(0);
em[1] = 0x01;
for (i = 2; i < k - len - 1; i++)
em[i] = 0xff;
prefix.copy(em, k - len);
hash.copy(em, k - hash.length);
return rsa.decrypt(N, D, em);
};
rsa.decrypt = function decrypt(N, D, m) {
var c = new BN(m);
if (c.cmp(N) > 0)
throw new Error('Cannot decrypt.');
return c
.toRed(BN.red(N))
.redPow(D)
.fromRed()
.toArrayLike(Buffer, 'be');
};
rsa.encrypt = function encrypt(N, e, m) {
return new BN(m)
.toRed(BN.red(N))
.redPow(e)
.fromRed()
.toArrayLike(Buffer, 'be');
};
ecdsa.verify = function verify(curve, msg, hashAlg, key, sig) {
var hash = crypto.hash(hashAlg, msg);
var ec = elliptic.ec(curve);
return ec.verify(hash, sig, key);
};
ecdsa.sign = function sign(curve, msg, hashAlg, key) {
var hash = crypto.hash(hashAlg, msg);
var ec = elliptic.ec(curve);
return new Buffer(ec.sign(hash, key));
};
native.verify = function verify(alg, hash, msg, sig, key) {
var algo, verify;
if (!nativeCrypto)
return false;
algo = normalizeAlg(alg, hash);
verify = nativeCrypto.createVerify(algo);
verify.update(msg);
return verify.verify(key, sig);
};
native.sign = function _sign(alg, hash, msg, key) {
var algo, sig;
if (!nativeCrypto)
return false;
algo = normalizeAlg(alg, hash);
sig = nativeCrypto.createSign(algo);
sig.update(msg);
return sig.sign(key);
};
pk.pemTag = {
dsa: 'DSA',
rsa: 'RSA',
ecdsa: 'EC'
};
pk.toPEM = function toPEM(key, type) {
var tag = pk.pemTag[key.alg];
var pem = asn1.toPEM(key.data, tag, type);
// Key parameters, usually present
// if selecting an EC curve.
if (key.params)
pem += asn1.toPEM(key.params, tag, 'parameters');
return pem;
};
pk._verify = function verify(hash, msg, sig, key) {
var pem;
exports._verify = function verify(hash, msg, sig, key) {
switch (key.alg) {
case 'dsa':
pem = pk.toPEM(key, 'public key');
return native.verify(key.alg, hash, msg, sig, pem);
return pk.dsa.verify(hash, msg, sig, key.data, key.params);
case 'rsa':
if (nativeCrypto) {
pem = pk.toPEM(key, 'public key');
return native.verify(key.alg, hash, msg, sig, pem);
}
return rsa.verify(hash, msg, sig, key.data);
return pk.rsa.verify(hash, msg, sig, key.data);
case 'ecdsa':
if (!key.curve)
throw new Error('No curve present.');
return ecdsa.verify(key.curve, hash, msg, sig, key.data);
return pk.ecdsa.verify(key.curve, hash, msg, sig, key.data);
default:
throw new Error('Unsupported algorithm.');
}
};
pk.verify = function verify(hash, msg, sig, key) {
exports.verify = function verify(hash, msg, sig, key) {
try {
return pk._verify(hash, msg, sig, key);
return exports._verify(hash, msg, sig, key);
} catch (e) {
return false;
}
};
pk.sign = function sign(hash, msg, key) {
var pem;
exports.sign = function sign(hash, msg, key) {
switch (key.alg) {
case 'dsa':
pem = pk.toPEM(key, 'private key');
return native.sign(key.alg, hash, msg, pem);
return pk.dsa.sign(hash, msg, key.data, key.params);
case 'rsa':
if (nativeCrypto) {
pem = pk.toPEM(key, 'private key');
return native.sign(key.alg, hash, msg, pem);
}
return rsa.sign(hash, msg, key.data);
return pk.rsa.sign(hash, msg, key.data);
case 'ecdsa':
if (!key.curve)
throw new Error('No curve present.');
return ecdsa.sign(key.curve, hash, msg, key.data);
return pk.ecdsa.sign(key.curve, hash, msg, key.data);
default:
throw new Error('Unsupported algorithm.');
}
};
function leftpad(input, size) {
var n = input.length;
var out;
if (n > size)
n = size;
out = new Buffer(size);
out.fill(0);
input.copy(out, out.length - n);
return out;
}
function normalizeAlg(alg, hash) {
var name = alg.toUpperCase() + '-' + hash.toUpperCase();
switch (name) {
case 'ECDSA-SHA1':
name = 'ecdsa-with-SHA1';
break;
case 'ECDSA-SHA256':
name = 'ecdsa-with-SHA256';
break;
}
return name;
}
pk.rsa = rsa;
pk.ecdsa = ecdsa;
pk.native = native;

View File

@ -7,7 +7,8 @@
'use strict';
var assert = require('assert');
var asn1 = require('./asn1');
var ASN1 = require('../utils/asn1');
var PEM = require('../utils/pem');
var utils = require('../utils/utils');
var crypto = require('../crypto/crypto');
var pk = require('./pk');
@ -69,7 +70,7 @@ x509.setTrust = function setTrust(certs) {
}
if (typeof cert === 'string') {
pem = asn1.fromPEM(cert);
pem = PEM.decode(cert);
assert(pem.type === 'certificate', 'Must add certificates to trust.');
cert = pem.data;
}
@ -137,7 +138,7 @@ x509.getCurve = function getCurve(params) {
return;
try {
oid = asn1.parseOID(params);
oid = ASN1.parseOID(params);
} catch (e) {
return;
}
@ -147,7 +148,7 @@ x509.getCurve = function getCurve(params) {
x509.parse = function parse(der) {
try {
return asn1.parseCert(der);
return ASN1.parseCert(der);
} catch (e) {
;
}
@ -189,7 +190,7 @@ x509.signSubject = function signSubject(hash, msg, key, chain) {
assert(cert, 'Could not parse certificate.');
if (typeof key === 'string') {
key = asn1.fromPEM(key);
key = PEM.decode(key);
if (key.alg === 'ecdsa')
curve = x509.getCurve(key.params);
key = {
@ -291,8 +292,6 @@ x509.verifyChain = function verifyChain(chain) {
return false;
};
x509.asn1 = asn1;
function isHash(data) {
if (typeof data === 'string')
return utils.isHex(data) && data.length === 64;

View File

@ -0,0 +1,73 @@
/*!
* backend-browser.js - browser crypto backend for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
/* jshint worker: true */
'use strict';
var assert = require('assert');
var hashjs = require('hash.js');
var aes = require('./aes');
var backend = exports;
var crypto, global;
if (typeof window !== 'undefined')
global = window;
else if (typeof self !== 'undefined')
global = self;
if (global)
crypto = global.crypto || global.msCrypto;
backend.hash = function hash(alg, data) {
return new Buffer(hashjs[alg]().update(data).digest());
};
backend.hmac = function hmac(alg, data, salt) {
var hash = hashjs[alg];
var hmac;
assert(hash != null, 'Unknown algorithm.');
hmac = hashjs.hmac(hash, salt);
return new Buffer(hmac.update(data).digest());
};
backend.pbkdf2 = null;
backend.pbkdf2Async = null;
backend.encipher = function encipher(data, key, iv) {
return aes.cbc.encrypt(data, key, iv);
};
backend.decipher = function decipher(data, key, iv) {
try {
return aes.cbc.decrypt(data, key, iv);
} catch (e) {
throw new Error('Bad key for decryption.');
}
};
backend.randomBytes = function randomBytes(n) {
var data = new Uint8Array(n);
crypto.getRandomValues(data);
return new Buffer(data.buffer);
};
if (!crypto || !crypto.getRandomValues) {
// Out of luck here. Use bad randomness for now.
backend.randomBytes = function randomBytes(n) {
var data = new Buffer(n);
var i;
for (i = 0; i < data.length; i++)
data[i] = Math.floor(Math.random() * 256);
return data;
};
}

50
lib/crypto/backend.js Normal file
View File

@ -0,0 +1,50 @@
/*!
* backend.js - crypto backend for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var utils = require('../utils/utils');
var crypto = require('crypto');
var backend = exports;
backend.hash = function hash(alg, data) {
return crypto.createHash(alg).update(data).digest();
};
backend.hmac = function hmac(alg, data, salt) {
var hmac = crypto.createHmac(alg, salt);
return hmac.update(data).digest();
};
backend.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
return crypto.pbkdf2Sync(key, salt, iter, len, alg);
};
if (!crypto.pbkdf2Sync)
backend.pbkdf2 = null;
backend.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg, callback) {
return crypto.pbkdf2(key, salt, iter, len, alg, callback);
};
if (!crypto.pbkdf2)
backend.pbkdf2Async = null;
backend.encipher = function encipher(data, key, iv) {
var cipher = crypto.createCipheriv('aes-256-cbc', key, iv);
return utils.concat(cipher.update(data), cipher.final());
};
backend.decipher = function decipher(data, key, iv) {
var decipher = crypto.createDecipheriv('aes-256-cbc', key, iv);
try {
return utils.concat(decipher.update(data), decipher.final());
} catch (e) {
throw new Error('Bad key for decryption.');
}
};
backend.randomBytes = crypto.randomBytes;

View File

@ -7,7 +7,7 @@
'use strict';
var assert = require('assert');
var native = require('../utils/native');
var native = require('../utils/native').binding;
var BIG_ENDIAN = new Int8Array(new Int16Array([1]).buffer)[0] === 0;

View File

@ -8,25 +8,13 @@
'use strict';
var assert = require('assert');
var random = require('./random');
var scrypt = require('./scrypt');
var scryptAsync = require('./scrypt-async');
var utils = require('../utils/utils');
var co = require('../utils/co');
var native = require('../utils/native');
var native = require('../utils/native').binding;
var backend = require('./backend');
var lazy = require('../utils/lazy')(require, exports);
var nodeCrypto, hash, aes;
var isBrowser =
(typeof process !== 'undefined' && process.browser)
|| typeof window !== 'undefined';
if (!isBrowser) {
nodeCrypto = require('crypto');
} else {
hash = require('hash.js');
aes = require('./aes');
}
/**
* @exports crypto
@ -42,10 +30,7 @@ var crypto = exports;
*/
crypto.hash = function _hash(alg, data) {
if (!nodeCrypto)
return new Buffer(hash[alg]().update(data).digest());
return nodeCrypto.createHash(alg).update(data).digest();
return backend.hash(alg, data);
};
if (native)
@ -129,15 +114,7 @@ crypto.checksum = function checksum(data) {
*/
crypto.hmac = function hmac(alg, data, salt) {
var hmac;
if (!nodeCrypto) {
hmac = hash.hmac(hash[alg], salt);
return new Buffer(hmac.update(data).digest());
}
hmac = nodeCrypto.createHmac(alg, salt);
return hmac.update(data).digest();
return backend.hmac(alg, data, salt);
};
if (native)
@ -160,8 +137,8 @@ crypto.pbkdf2 = function pbkdf2(key, salt, iter, len, alg) {
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (nodeCrypto && nodeCrypto.pbkdf2Sync)
return nodeCrypto.pbkdf2Sync(key, salt, iter, len, alg);
if (backend.pbkdf2)
return backend.pbkdf2(key, salt, iter, len, alg);
return crypto._pbkdf2(key, salt, iter, len, alg);
};
@ -185,9 +162,9 @@ crypto.pbkdf2Async = function pbkdf2Async(key, salt, iter, len, alg) {
if (typeof salt === 'string')
salt = new Buffer(salt, 'utf8');
if (nodeCrypto && nodeCrypto.pbkdf2) {
if (backend.pbkdf2Async) {
return new Promise(function(resolve, reject) {
nodeCrypto.pbkdf2(key, salt, iter, len, alg, co.wrap(resolve, reject));
backend.pbkdf2Async(key, salt, iter, len, alg, co.wrap(resolve, reject));
});
}
@ -292,20 +269,13 @@ crypto.encrypt = co(function* encrypt(data, passphrase, iv) {
*/
crypto.encipher = function encipher(data, key, iv) {
var cipher;
assert(Buffer.isBuffer(data));
assert(Buffer.isBuffer(key));
assert(Buffer.isBuffer(iv));
assert(key.length === 32);
assert(iv.length === 16);
if (!nodeCrypto)
return aes.cbc.encrypt(data, key, iv);
cipher = nodeCrypto.createCipheriv('aes-256-cbc', key, iv);
return utils.concat(cipher.update(data), cipher.final());
return backend.encipher(data, key, iv);
};
/**
@ -351,31 +321,7 @@ crypto.decipher = function decipher(data, key, iv) {
assert(Buffer.isBuffer(iv));
assert(key.length === 32);
assert(iv.length === 16);
try {
return crypto._decipher(data, key, iv);
} catch (e) {
throw new Error('Bad key for decryption.');
}
};
/**
* Decrypt with aes-256-cbc.
* @private
* @param {Buffer} data
* @param {Buffer} key
* @param {Buffer} iv
* @returns {Buffer}
*/
crypto._decipher = function decipher(data, key, iv) {
var decipher;
if (!nodeCrypto)
return aes.cbc.decrypt(data, key, iv);
decipher = nodeCrypto.createDecipheriv('aes-256-cbc', key, iv);
return utils.concat(decipher.update(data), decipher.final());
return backend.decipher(data, key, iv);
};
/**
@ -661,7 +607,19 @@ if (native)
* @returns {Buffer}
*/
crypto.randomBytes = random.randomBytes;
crypto.randomBytes = backend.randomBytes;
/**
* Generate a random uint32.
* Probably more cryptographically sound than
* `Math.random()`.
* @function
* @returns {Number}
*/
crypto.randomInt = function randomInt() {
return crypto.randomBytes(4).readUInt32LE(0, true);
};
/**
* Generate a random number within a range.
@ -673,17 +631,10 @@ crypto.randomBytes = random.randomBytes;
* @returns {Number}
*/
crypto.randomRange = random.randomRange;
/**
* Generate a random uint32.
* Probably more cryptographically sound than
* `Math.random()`.
* @function
* @returns {Number}
*/
crypto.randomInt = random.randomInt;
crypto.randomRange = function randomRange(min, max) {
var num = crypto.randomInt();
return Math.floor((num / 0x100000000) * (max - min) + min);
};
/*
* Expose other objects.
@ -694,3 +645,4 @@ lazy('chachapoly', './chachapoly');
lazy('ec', './ec');
lazy('schnorr', './schnorr');
lazy('siphash', './siphash');
lazy('pk', './pk');

347
lib/crypto/ec-elliptic.js Normal file
View File

@ -0,0 +1,347 @@
/*!
* ec.js - ecdsa wrapper for elliptic
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var elliptic = require('elliptic');
var secp256k1 = elliptic.ec('secp256k1');
var Signature = require('elliptic/lib/elliptic/ec/signature');
var curve = elliptic.curve;
var BN = require('bn.js');
/**
* @exports ec
*/
var ec = exports;
/**
* Generate a private key.
* @returns {Buffer} Private key.
*/
ec.generatePrivateKey = function generatePrivateKey() {
var key = secp256k1.genKeyPair();
var priv = key.getPrivate().toArrayLike(Buffer, 'be', 32);
return priv;
};
/**
* Create a public key from a private key.
* @param {Buffer} priv
* @param {Boolean?} compressed
* @returns {Buffer}
*/
ec.publicKeyCreate = function publicKeyCreate(priv, compressed) {
var key;
assert(Buffer.isBuffer(priv));
key = secp256k1.keyPair({ priv: priv });
key = key.getPublic(compressed !== false, 'array');
return new Buffer(key);
};
/**
* Compress or decompress public key.
* @param {Buffer} pub
* @returns {Buffer}
*/
ec.publicKeyConvert = function publicKeyConvert(key, compressed) {
var point = curve.decodePoint(key);
return new Buffer(point.encode('array', compressed !== false));
};
/**
* ((tweak + key) % n)
* @param {Buffer} privateKey
* @param {Buffer} tweak
* @returns {Buffer} privateKey
*/
ec.privateKeyTweakAdd = function privateKeyTweakAdd(privateKey, tweak) {
var key = new BN(tweak)
.add(new BN(privateKey))
.mod(curve.n)
.toArrayLike(Buffer, 'be', 32);
// Only a 1 in 2^127 chance of happening.
if (!ec.privateKeyVerify(key))
throw new Error('Private key is invalid.');
return key;
};
/**
* ((g * tweak) + key)
* @param {Buffer} publicKey
* @param {Buffer} tweak
* @returns {Buffer} publicKey
*/
ec.publicKeyTweakAdd = function publicKeyTweakAdd(publicKey, tweak, compressed) {
var key = curve.decodePoint(publicKey);
var point = curve.g.mul(new BN(tweak)).add(key);
var pub = new Buffer(point.encode('array', compressed !== false));
if (!ec.publicKeyVerify(pub))
throw new Error('Public key is invalid.');
return pub;
};
/**
* Create an ecdh.
* @param {Buffer} pub
* @param {Buffer} priv
* @returns {Buffer}
*/
ec.ecdh = function ecdh(pub, priv) {
priv = secp256k1.keyPair({ priv: priv });
pub = secp256k1.keyPair({ pub: pub });
return priv.derive(pub.getPublic()).toArrayLike(Buffer, 'be', 32);
};
/**
* Recover a public key.
* @param {Buffer} msg
* @param {Buffer} sig
* @param {Number?} j
* @param {Boolean?} compressed
* @returns {Buffer[]|Buffer|null}
*/
ec.recover = function recover(msg, sig, j, compressed) {
var point, key;
if (!j)
j = 0;
try {
point = secp256k1.recoverPubKey(msg, sig, j);
} catch (e) {
return;
}
key = point.encode('array', compressed !== false);
return new Buffer(key);
};
/**
* Verify a signature.
* @param {Buffer} msg
* @param {Buffer} sig - DER formatted.
* @param {Buffer} key
* @param {Boolean?} - Whether this should be treated as a
* "historical" signature. This allows signatures to be of
* odd lengths.
* @param {Boolean?} high - Allow high S value.
* @returns {Boolean}
*/
ec.verify = function verify(msg, sig, key, historical, high) {
assert(Buffer.isBuffer(msg));
assert(Buffer.isBuffer(sig));
assert(Buffer.isBuffer(key));
if (sig.length === 0)
return false;
if (key.length === 0)
return false;
// Attempt to normalize the signature
// length before passing to elliptic.
// Note: We only do this for historical data!
// https://github.com/indutny/elliptic/issues/78
if (historical)
sig = normalizeLength(sig);
// Make elliptic mimic secp256k1's
// failure with high S values.
if (!high && !ec.isLowS(sig))
return false;
try {
return secp256k1.verify(msg, sig, key);
} catch (e) {
return false;
}
};
/**
* Validate a public key.
* @param {Buffer} key
* @returns {Boolean} True if buffer is a valid public key.
*/
ec.publicKeyVerify = function publicKeyVerify(key) {
try {
return secp256k1.keyPair({ pub: key }).validate();
} catch (e) {
return false;
}
};
/**
* Validate a private key.
* @param {Buffer} key
* @returns {Boolean} True if buffer is a valid private key.
*/
ec.privateKeyVerify = function privateKeyVerify(key) {
if (key.length !== 32)
return false;
key = new BN(key);
return key.cmpn(0) !== 0 && key.cmp(curve.n) < 0;
};
/**
* Sign a message.
* @param {Buffer} msg
* @param {Buffer} key - Private key.
* @returns {Buffer} DER-formatted signature.
*/
ec.sign = function sign(msg, key) {
var sig;
assert(Buffer.isBuffer(msg));
assert(Buffer.isBuffer(key));
// Sign message and ensure low S value
sig = secp256k1.sign(msg, key, { canonical: true });
// Convert to DER array
sig = new Buffer(sig.toDER());
return sig;
};
/**
* Convert DER signature to R/S.
* @param {Buffer} sig
* @returns {Buffer} R/S-formatted signature.
*/
ec.fromDER = function fromDER(sig) {
var out;
assert(Buffer.isBuffer(sig));
sig = new Signature(sig);
out = new Buffer(64);
sig.r.toArrayLike(Buffer, 'be', 32).copy(out, 0);
sig.s.toArrayLike(Buffer, 'be', 32).copy(out, 32);
return out;
};
/**
* Convert R/S signature to DER.
* @param {Buffer} sig
* @returns {Buffer} DER-formatted signature.
*/
ec.toDER = function toDER(sig) {
var out;
assert(Buffer.isBuffer(sig));
out = new Signature({
r: new BN(sig.slice(0, 32), 'be'),
s: new BN(sig.slice(32, 64), 'be')
});
return new Buffer(out.toDER());
};
/**
* Test whether a signature has a low S value.
* @param {Buffer} sig
* @returns {Boolean}
*/
ec.isLowS = function isLowS(sig) {
try {
sig = new Signature(sig);
} catch (e) {
return false;
}
if (sig.s.cmpn(0) === 0)
return false;
// If S is greater than half the order,
// it's too high.
if (sig.s.cmp(secp256k1.nh) > 0)
return false;
return true;
};
/*
* Helpers
*/
function normalizeLength(sig) {
var data = sig;
var p = { place: 0 };
var len, rlen, slen;
if (data[p.place++] !== 0x30)
return sig;
len = getLength(data, p);
if (data.length > len + p.place)
data = data.slice(0, len + p.place);
if (data[p.place++] !== 0x02)
return sig;
rlen = getLength(data, p);
p.place += rlen;
if (data[p.place++] !== 0x02)
return sig;
slen = getLength(data, p);
if (data.length > slen + p.place)
data = data.slice(0, slen + p.place);
return data;
}
function getLength(buf, p) {
var initial = buf[p.place++];
var octetLen, val, i, off;
if (!(initial & 0x80))
return initial;
octetLen = initial & 0xf;
val = 0;
for (i = 0, off = p.place; i < octetLen; i++, off++) {
val <<= 8;
val |= buf[off];
}
p.place = off;
return val;
}

263
lib/crypto/ec-secp256k1.js Normal file
View File

@ -0,0 +1,263 @@
/*!
* ec-secp256k1.js - ecdsa wrapper for secp256k1
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var utils = require('../utils/utils');
var crypto = require('./crypto');
var secp256k1 = require('secp256k1');
/*
* Constants
*/
var ZERO_S = new Buffer(
'0000000000000000000000000000000000000000000000000000000000000000',
'hex'
);
var HALF_ORDER = new Buffer(
'7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0',
'hex');
/**
* @exports ec
*/
var ec = exports;
/**
* Generate a private key.
* @returns {Buffer} Private key.
*/
ec.generatePrivateKey = function generatePrivateKey() {
var priv;
do {
priv = crypto.randomBytes(32);
} while (!secp256k1.privateKeyVerify(priv));
return priv;
};
/**
* Create a public key from a private key.
* @param {Buffer} priv
* @param {Boolean?} compressed
* @returns {Buffer}
*/
ec.publicKeyCreate = function publicKeyCreate(priv, compressed) {
assert(Buffer.isBuffer(priv));
return secp256k1.publicKeyCreate(priv, compressed);
};
/**
* Compress or decompress public key.
* @param {Buffer} pub
* @returns {Buffer}
*/
ec.publicKeyConvert = function publicKeyConvert(key, compressed) {
return secp256k1.publicKeyConvert(key, compressed);
};
/**
* ((tweak + key) % n)
* @param {Buffer} privateKey
* @param {Buffer} tweak
* @returns {Buffer} privateKey
*/
ec.privateKeyTweakAdd = function privateKeyTweakAdd(privateKey, tweak) {
return secp256k1.privateKeyTweakAdd(privateKey, tweak);
};
/**
* ((g * tweak) + key)
* @param {Buffer} publicKey
* @param {Buffer} tweak
* @returns {Buffer} publicKey
*/
ec.publicKeyTweakAdd = function publicKeyTweakAdd(publicKey, tweak, compressed) {
return secp256k1.publicKeyTweakAdd(publicKey, tweak, compressed);
};
/**
* Create an ecdh.
* @param {Buffer} pub
* @param {Buffer} priv
* @returns {Buffer}
*/
ec.ecdh = function ecdh(pub, priv) {
var point = secp256k1.ecdhUnsafe(pub, priv, true);
return point.slice(1, 33);
};
/**
* Recover a public key.
* @param {Buffer} msg
* @param {Buffer} sig
* @param {Number?} j
* @param {Boolean?} compressed
* @returns {Buffer[]|Buffer|null}
*/
ec.recover = function recover(msg, sig, j, compressed) {
var key;
if (!j)
j = 0;
try {
sig = secp256k1.signatureImport(sig);
} catch (e) {
return;
}
try {
key = secp256k1.recover(msg, sig, j, compressed);
} catch (e) {
return;
}
return key;
};
/**
* Verify a signature.
* @param {Buffer} msg
* @param {Buffer} sig - DER formatted.
* @param {Buffer} key
* @param {Boolean?} - Whether this should be treated as a
* "historical" signature. This allows signatures to be of
* odd lengths.
* @param {Boolean?} high - Allow high S value.
* @returns {Boolean}
*/
ec.verify = function verify(msg, sig, key, historical, high) {
assert(Buffer.isBuffer(msg));
assert(Buffer.isBuffer(sig));
assert(Buffer.isBuffer(key));
if (sig.length === 0)
return false;
if (key.length === 0)
return false;
try {
if (historical)
sig = secp256k1.signatureImportLax(sig);
else
sig = secp256k1.signatureImport(sig);
if (high)
sig = secp256k1.signatureNormalize(sig);
return secp256k1.verify(msg, sig, key);
} catch (e) {
return false;
}
};
/**
* Validate a public key.
* @param {Buffer} key
* @returns {Boolean} True if buffer is a valid public key.
*/
ec.publicKeyVerify = function publicKeyVerify(key) {
return secp256k1.publicKeyVerify(key);
};
/**
* Validate a private key.
* @param {Buffer} key
* @returns {Boolean} True if buffer is a valid private key.
*/
ec.privateKeyVerify = function privateKeyVerify(key) {
return secp256k1.privateKeyVerify(key);
};
/**
* Sign a message.
* @param {Buffer} msg
* @param {Buffer} key - Private key.
* @returns {Buffer} DER-formatted signature.
*/
ec.sign = function sign(msg, key) {
var sig;
assert(Buffer.isBuffer(msg));
assert(Buffer.isBuffer(key));
// Sign message
sig = secp256k1.sign(msg, key);
// Ensure low S value
sig = secp256k1.signatureNormalize(sig.signature);
// Convert to DER array
return secp256k1.signatureExport(sig);
};
/**
* Convert DER signature to R/S.
* @param {Buffer} sig
* @returns {Buffer} R/S-formatted signature.
*/
ec.fromDER = function fromDER(sig) {
assert(Buffer.isBuffer(sig));
return secp256k1.signatureImport(sig);
};
/**
* Convert R/S signature to DER.
* @param {Buffer} sig
* @returns {Buffer} DER-formatted signature.
*/
ec.toDER = function toDER(sig) {
assert(Buffer.isBuffer(sig));
return secp256k1.signatureExport(sig);
};
/**
* Test whether a signature has a low S value.
* @param {Buffer} sig
* @returns {Boolean}
*/
ec.isLowS = function isLowS(sig) {
var rs, s;
try {
rs = secp256k1.signatureImport(sig);
s = rs.slice(32, 64);
} catch (e) {
return false;
}
if (utils.equal(s, ZERO_S))
return false;
// If S is greater than half the order,
// it's too high.
if (utils.cmp(s, HALF_ORDER) > 0)
return false;
return true;
};

View File

@ -1,524 +1,21 @@
/*!
* ec.js - ecdsa wrapper for secp256k1 and elliptic
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var elliptic = require('elliptic');
var BN = require('bn.js');
var utils = require('../utils/utils');
var crypto = require('./crypto');
var assert = require('assert');
var secp256k1;
try {
if (+process.env.BCOIN_USE_ELLIPTIC !== 1)
if (+process.env.BCOIN_USE_ELLIPTIC !== 1) {
try {
secp256k1 = require('secp256k1');
} catch (e) {
;
} catch (e) {
;
}
}
/*
* Constants
*/
var ZERO_S = new Buffer(
'0000000000000000000000000000000000000000000000000000000000000000',
'hex'
);
var HALF_ORDER = new Buffer(
'7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0',
'hex');
/**
* @exports ec
*/
var ec = exports;
/**
* elliptic.js secp256k1 curve.
* @type {Object}
*/
ec.elliptic = elliptic.ec('secp256k1');
/**
* elliptic.js signature constructor.
* @static
* @type {Function}
*/
ec.signature = require('elliptic/lib/elliptic/ec/signature');
/**
* elliptic.js keypair constructor.
* @static
* @type {Function}
*/
ec.keypair = require('elliptic/lib/elliptic/ec/key');
/**
* A reference to the secp256k1 curve.
* @const {Object}
*/
ec.curve = ec.elliptic.curve;
/**
* Generate a private key.
* @returns {Buffer} Private key.
*/
ec.generatePrivateKey = function generatePrivateKey() {
var key, priv;
if (secp256k1) {
do {
priv = crypto.randomBytes(32);
} while (!secp256k1.privateKeyVerify(priv));
} else {
key = ec.elliptic.genKeyPair();
priv = key.getPrivate().toArrayLike(Buffer, 'be', 32);
}
return priv;
};
/**
* Create a public key from a private key.
* @param {Buffer} priv
* @param {Boolean?} compressed
* @returns {Buffer}
*/
ec.publicKeyCreate = function publicKeyCreate(priv, compressed) {
assert(Buffer.isBuffer(priv));
if (secp256k1)
return secp256k1.publicKeyCreate(priv, compressed);
priv = ec.elliptic.keyPair({ priv: priv });
priv = priv.getPublic(compressed !== false, 'array');
return new Buffer(priv);
};
/**
* Compress or decompress public key.
* @param {Buffer} pub
* @returns {Buffer}
*/
ec.publicKeyConvert = function publicKeyConvert(key, compressed) {
var point;
if (secp256k1)
return secp256k1.publicKeyConvert(key, compressed);
point = ec.curve.decodePoint(key);
return new Buffer(point.encode('array', compressed !== false));
};
/**
* ((tweak + key) % n)
* @param {Buffer} privateKey
* @param {Buffer} tweak
* @returns {Buffer} privateKey
*/
ec.privateKeyTweakAdd = function privateKeyTweakAdd(privateKey, tweak) {
var key;
if (secp256k1)
return secp256k1.privateKeyTweakAdd(privateKey, tweak);
key = new BN(tweak)
.add(new BN(privateKey))
.mod(ec.curve.n)
.toArrayLike(Buffer, 'be', 32);
// Only a 1 in 2^127 chance of happening.
if (!ec.privateKeyVerify(key))
throw new Error('Private key is invalid.');
return key;
};
/**
* ((g * tweak) + key)
* @param {Buffer} publicKey
* @param {Buffer} tweak
* @returns {Buffer} publicKey
*/
ec.publicKeyTweakAdd = function publicKeyTweakAdd(publicKey, tweak, compressed) {
var point, key;
if (secp256k1)
return secp256k1.publicKeyTweakAdd(publicKey, tweak, compressed);
point = ec.curve.decodePoint(publicKey);
point = ec.curve.g.mul(new BN(tweak)).add(point);
key = new Buffer(point.encode('array', compressed !== false));
if (!ec.publicKeyVerify(key))
throw new Error('Public key is invalid.');
return key;
};
/**
* Create an ecdh.
* @param {Buffer} pub
* @param {Buffer} priv
* @returns {Buffer}
*/
ec.ecdh = function ecdh(pub, priv) {
var point;
if (secp256k1) {
point = secp256k1.ecdhUnsafe(pub, priv, true);
return point.slice(1, 33);
}
priv = ec.elliptic.keyPair({ priv: priv });
pub = ec.elliptic.keyPair({ pub: pub });
return priv.derive(pub.getPublic()).toArrayLike(Buffer, 'be', 32);
};
/**
* Recover a public key.
* @param {Buffer} msg
* @param {Buffer} sig
* @param {Number?} j
* @param {Boolean?} compressed
* @returns {Buffer[]|Buffer|null}
*/
ec.recover = function recover(msg, sig, j, compressed) {
var point, key;
if (!j)
j = 0;
if (secp256k1) {
try {
sig = secp256k1.signatureImport(sig);
} catch (e) {
return;
}
try {
key = secp256k1.recover(msg, sig, j, compressed);
} catch (e) {
return;
}
return key;
}
try {
point = ec.elliptic.recoverPubKey(msg, sig, j);
} catch (e) {
return;
}
key = point.encode('array', compressed !== false);
return new Buffer(key);
};
/**
* Verify a signature.
* @param {Buffer} msg
* @param {Buffer} sig - DER formatted.
* @param {Buffer} key
* @param {Boolean?} - Whether this should be treated as a
* "historical" signature. This allows signatures to be of
* odd lengths.
* @param {Boolean?} high - Allow high S value.
* @returns {Boolean}
*/
ec.verify = function verify(msg, sig, key, historical, high) {
var result;
assert(Buffer.isBuffer(msg));
assert(Buffer.isBuffer(sig));
assert(Buffer.isBuffer(key));
if (sig.length === 0)
return false;
if (key.length === 0)
return false;
if (secp256k1) {
try {
if (historical)
sig = secp256k1.signatureImportLax(sig);
else
sig = secp256k1.signatureImport(sig);
if (high)
sig = secp256k1.signatureNormalize(sig);
result = secp256k1.verify(msg, sig, key);
} catch (e) {
result = false;
}
return result;
}
// Attempt to normalize the signature
// length before passing to elliptic.
// Note: We only do this for historical data!
// https://github.com/indutny/elliptic/issues/78
if (historical)
sig = ec.normalizeLength(sig);
// Make elliptic mimic secp256k1's
// failure with high S values.
if (!high && !ec.isLowS(sig))
return false;
try {
result = ec.elliptic.verify(msg, sig, key);
} catch (e) {
result = false;
}
return result;
};
/**
* Validate a public key.
* @param {Buffer} key
* @returns {Boolean} True if buffer is a valid public key.
*/
ec.publicKeyVerify = function publicKeyVerify(key) {
var result;
if (secp256k1)
return secp256k1.publicKeyVerify(key);
try {
result = ec.elliptic.keyPair({ pub: key }).validate();
} catch (e) {
result = false;
}
return result;
};
/**
* Validate a private key.
* @param {Buffer} key
* @returns {Boolean} True if buffer is a valid private key.
*/
ec.privateKeyVerify = function privateKeyVerify(key) {
if (secp256k1)
return secp256k1.privateKeyVerify(key);
if (key.length !== 32)
return false;
key = new BN(key);
return key.cmpn(0) !== 0 && key.cmp(ec.curve.n) < 0;
};
/**
* Sign a message.
* @param {Buffer} msg
* @param {Buffer} key - Private key.
* @returns {Buffer} DER-formatted signature.
*/
ec.sign = function sign(msg, key) {
var sig;
assert(Buffer.isBuffer(msg));
assert(Buffer.isBuffer(key));
if (secp256k1) {
// Sign message
sig = secp256k1.sign(msg, key);
// Ensure low S value
sig = secp256k1.signatureNormalize(sig.signature);
// Convert to DER array
sig = secp256k1.signatureExport(sig);
} else {
// Sign message and ensure low S value
sig = ec.elliptic.sign(msg, key, { canonical: true });
// Convert to DER array
sig = new Buffer(sig.toDER());
}
return sig;
};
/**
* Convert DER signature to R/S.
* @param {Buffer} sig
* @returns {Buffer} R/S-formatted signature.
*/
ec.fromDER = function fromDER(sig) {
var out;
assert(Buffer.isBuffer(sig));
if (secp256k1)
return secp256k1.signatureImport(sig);
sig = new ec.signature(sig);
out = new Buffer(64);
sig.r.toArrayLike(Buffer, 'be', 32).copy(out, 0);
sig.s.toArrayLike(Buffer, 'be', 32).copy(out, 32);
return out;
};
/**
* Convert R/S signature to DER.
* @param {Buffer} sig
* @returns {Buffer} DER-formatted signature.
*/
ec.toDER = function toDER(sig) {
var out;
assert(Buffer.isBuffer(sig));
if (secp256k1)
return secp256k1.signatureExport(sig);
out = new ec.signature({
r: new BN(sig.slice(0, 32), 'be'),
s: new BN(sig.slice(32, 64), 'be')
});
return new Buffer(out.toDER());
};
/**
* Normalize the length of a signature
* (only done for historical data).
* @param {Buffer} sig - DER formatted signature.
* @returns {Buffer} Signature.
*/
ec.normalizeLength = function normalizeLength(sig) {
var data = sig;
var p = { place: 0 };
var len, rlen, slen;
if (data[p.place++] !== 0x30)
return sig;
len = getLength(data, p);
if (data.length > len + p.place)
data = data.slice(0, len + p.place);
if (data[p.place++] !== 0x02)
return sig;
rlen = getLength(data, p);
p.place += rlen;
if (data[p.place++] !== 0x02)
return sig;
slen = getLength(data, p);
if (data.length > slen + p.place)
data = data.slice(0, slen + p.place);
return data;
};
/**
* Test whether a signature has a low S value.
* @param {Buffer} sig
* @returns {Boolean}
*/
ec.isLowS = function isLowS(sig) {
var rs, s;
if (secp256k1) {
try {
rs = secp256k1.signatureImport(sig);
s = rs.slice(32, 64);
} catch (e) {
return false;
}
if (utils.equal(s, ZERO_S))
return false;
// If S is greater than half the order,
// it's too high.
if (utils.cmp(s, HALF_ORDER) > 0)
return false;
return true;
}
try {
sig = new ec.signature(sig);
} catch (e) {
return false;
}
if (sig.s.cmpn(0) === 0)
return false;
// If S is greater than half the order,
// it's too high.
if (sig.s.cmp(ec.elliptic.nh) > 0)
return false;
return true;
};
/*
* Helpers
*/
function getLength(buf, p) {
var initial = buf[p.place++];
var octetLen, val, i, off;
if (!(initial & 0x80))
return initial;
octetLen = initial & 0xf;
val = 0;
for (i = 0, off = p.place; i < octetLen; i++, off++) {
val <<= 8;
val |= buf[off];
}
p.place = off;
return val;
}
module.exports = secp256k1
? require('./ec-secp256k1')
: require('./ec-elliptic');

187
lib/crypto/pk-browser.js Normal file
View File

@ -0,0 +1,187 @@
/*!
* pk-browser.js - public key algorithms for bcoin
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var BN = require('bn.js');
var ASN1 = require('../utils/asn1');
var elliptic = require('elliptic');
var crypto = require('../crypto/crypto');
var dsa, rsa, ecdsa;
/*
* DSA
*/
dsa = {};
dsa.verify = function verify(alg, msg, sig, key, params) {
throw new Error('DSA not implemented.');
};
dsa.sign = function sign(alg, msg, key, params) {
throw new Error('DSA not implemented.');
};
/*
* RSA
*/
rsa = {};
rsa.prefixes = {
md5: new Buffer('3020300c06082a864886f70d020505000410', 'hex'),
sha1: new Buffer('3021300906052b0e03021a05000414', 'hex'),
sha224: new Buffer('302d300d06096086480165030402040500041c', 'hex'),
sha256: new Buffer('3031300d060960864801650304020105000420', 'hex'),
sha384: new Buffer('3041300d060960864801650304020205000430', 'hex'),
sha512: new Buffer('3051300d060960864801650304020305000440', 'hex'),
md5sha1: new Buffer(0),
ripemd160: new Buffer('30203008060628cf060300310414', 'hex')
};
rsa.verify = function verify(alg, msg, sig, key) {
var prefix = rsa.prefixes[alg];
var hash, len, pub;
var N, e, k, m, em, ok, i;
if (!prefix)
throw new Error('Unknown PKCS prefix.');
hash = crypto.hash(alg, msg);
len = prefix.length + hash.length;
pub = ASN1.parseRSAPublic(key);
N = new BN(pub.modulus);
e = new BN(pub.publicExponent);
k = Math.ceil(N.bitLength() / 8);
if (k < len + 11)
throw new Error('Message too long.');
m = rsa.encrypt(N, e, sig);
em = leftpad(m, k);
ok = crypto.ceq(em[0], 0x00);
ok &= crypto.ceq(em[1], 0x01);
ok &= crypto.ccmp(em.slice(k - hash.length, k), hash);
ok &= crypto.ccmp(em.slice(k - len, k - hash.length), prefix);
ok &= crypto.ceq(em[k - len - 1], 0x00);
for (i = 2; i < k - len - 1; i++)
ok &= crypto.ceq(em[i], 0xff);
return ok === 1;
};
rsa.sign = function sign(alg, msg, key) {
var prefix = rsa.prefixes[alg];
var hash, len, priv;
var N, D, k, i, em;
if (!prefix)
throw new Error('Unknown PKCS prefix.');
hash = crypto.hash(alg, msg);
len = prefix.length + hash.length;
priv = ASN1.parseRSAPrivate(key);
N = new BN(priv.modulus);
D = new BN(priv.privateExponent);
k = Math.ceil(N.bitLength() / 8);
if (k < len + 11)
throw new Error('Message too long.');
em = new Buffer(k);
em.fill(0);
em[1] = 0x01;
for (i = 2; i < k - len - 1; i++)
em[i] = 0xff;
prefix.copy(em, k - len);
hash.copy(em, k - hash.length);
return rsa.decrypt(N, D, em);
};
rsa.decrypt = function decrypt(N, D, m) {
var c = new BN(m);
if (c.cmp(N) > 0)
throw new Error('Cannot decrypt.');
return c
.toRed(BN.red(N))
.redPow(D)
.fromRed()
.toArrayLike(Buffer, 'be');
};
rsa.encrypt = function encrypt(N, e, m) {
return new BN(m)
.toRed(BN.red(N))
.redPow(e)
.fromRed()
.toArrayLike(Buffer, 'be');
};
/*
* ECDSA
*/
ecdsa = {};
ecdsa.verify = function verify(curve, msg, alg, key, sig) {
var ec, hash;
assert(curve, 'No curve selected.');
ec = elliptic.ec(curve);
hash = crypto.hash(alg, msg);
return ec.verify(hash, sig, key);
};
ecdsa.sign = function sign(curve, msg, alg, key) {
var ec, hash;
assert(curve, 'No curve selected.');
ec = elliptic.ec(curve);
hash = crypto.hash(alg, msg);
return new Buffer(ec.sign(hash, key));
};
/*
* Helpers
*/
function leftpad(input, size) {
var n = input.length;
var out;
if (n > size)
n = size;
out = new Buffer(size);
out.fill(0);
input.copy(out, out.length - n);
return out;
}
/*
* Expose
*/
exports.dsa = dsa;
exports.rsa = rsa;
exports.ecdsa = ecdsa;

142
lib/crypto/pk.js Normal file
View File

@ -0,0 +1,142 @@
/*!
* pk.js - public key algorithms for bcoin
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var PEM = require('../utils/pem');
var elliptic = require('elliptic');
var crypto = require('../crypto/crypto');
var nodeCrypto = require('crypto');
var dsa, rsa, ecdsa;
/*
* DSA
*/
dsa = {};
dsa.verify = function _verify(alg, msg, sig, key, params) {
var pem = toPEM('dsa', key, params, 'public key');
return verify('dsa', alg, msg, sig, pem);
};
dsa.sign = function _sign(alg, msg, key, params) {
var pem = toPEM('dsa', key, params, 'private key');
return sign('dsa', alg, msg, pem);
};
/*
* RSA
*/
rsa = {};
rsa.verify = function _verify(alg, msg, sig, key) {
var pem = toPEM('rsa', key, null, 'public key');
return verify('rsa', alg, msg, sig, pem);
};
rsa.sign = function _sign(alg, msg, key) {
var pem = toPEM('rsa', key, null, 'private key');
return sign('rsa', alg, msg, pem);
};
/*
* ECDSA
*/
ecdsa = {};
ecdsa.verify = function verify(curve, msg, alg, key, sig) {
var ec, hash;
assert(curve, 'No curve selected.');
ec = elliptic.ec(curve);
hash = crypto.hash(alg, msg);
return ec.verify(hash, sig, key);
};
ecdsa.sign = function sign(curve, msg, alg, key) {
var ec, hash;
assert(curve, 'No curve selected.');
ec = elliptic.ec(curve);
hash = crypto.hash(alg, msg);
return new Buffer(ec.sign(hash, key));
};
/*
* Helpers
*/
function verify(alg, hash, msg, sig, key) {
var algo = normalizeAlg(alg, hash);
var verifier = nodeCrypto.createVerify(algo);
verifier.update(msg);
return verifier.verify(key, sig);
}
function sign(alg, hash, msg, key) {
var algo = normalizeAlg(alg, hash);
var sig = nodeCrypto.createSign(algo);
sig.update(msg);
return sig.sign(key);
}
function toPEM(alg, key, params, type) {
var tag, pem;
switch (alg) {
case 'dsa':
tag = 'DSA';
break;
case 'rsa':
tag = 'RSA';
break;
case 'ecdsa':
tag = 'EC';
break;
default:
throw new Error('Unsupported algorithm.');
}
pem = PEM.encode(key, tag, type);
// Key parameters, usually present
// if selecting an EC curve.
if (params)
pem += PEM.encode(params, tag, 'parameters');
return pem;
}
function normalizeAlg(alg, hash) {
var name = alg.toUpperCase() + '-' + hash.toUpperCase();
switch (name) {
case 'ECDSA-SHA1':
name = 'ecdsa-with-SHA1';
break;
case 'ECDSA-SHA256':
name = 'ecdsa-with-SHA256';
break;
}
return name;
}
/*
* Expose
*/
exports.dsa = dsa;
exports.rsa = rsa;
exports.ecdsa = ecdsa;

View File

@ -1,76 +0,0 @@
/*!
* 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).
*/
/* jshint worker: true */
var randomBytes, crypto, global;
try {
crypto = require('crypto');
} catch (e) {
;
}
if (crypto) {
randomBytes = function randomBytes(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) {
randomBytes = function randomBytes(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
randomBytes = function randomBytes(n) {
var data = new Buffer(n);
var i;
for (i = 0; i < data.length; i++)
data[i] = Math.floor(Math.random() * 256);
return data;
};
}
}
function randomInt() {
return randomBytes(4).readUInt32LE(0, true);
}
function randomRange(min, max) {
var num = randomInt();
return Math.floor((num / 0x100000000) * (max - min) + min);
}
/*
* Expose
*/
exports = randomBytes;
exports.randomBytes = randomBytes;
exports.randomInt = randomInt;
exports.randomRange = randomRange;
module.exports = randomBytes;

View File

@ -10,9 +10,11 @@ var BN = require('bn.js');
var elliptic = require('elliptic');
var Signature = require('elliptic/lib/elliptic/ec/signature');
var hmacDRBG = require('elliptic/lib/elliptic/hmac-drbg');
var curves = elliptic.curves;
var curve = elliptic.ec('secp256k1').curve;
var sha256 = require('./crypto').sha256;
var secp256k1 = elliptic.ec('secp256k1');
var curve = secp256k1.curve;
var curves = elliptic.curves;
var hash = curves.secp256k1.hash;
/**
* @exports schnorr
@ -335,7 +337,7 @@ schnorr.drbg = function drbg(msg, priv, data) {
pers = toArray(kdata.slice(64));
return new hmacDRBG({
hash: curves.secp256k1.hash,
hash: hash,
entropy: prv,
nonce: msg,
pers: pers

View File

@ -35,7 +35,7 @@
var utils = require('../utils/utils');
var crypto = require('./crypto');
var native = require('../utils/native');
var native = require('../utils/native').binding;
var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
/**

View File

@ -34,7 +34,7 @@
'use strict';
var crypto = require('./crypto');
var native = require('../utils/native');
var native = require('../utils/native').binding;
var U32Array = typeof Uint32Array === 'function' ? Uint32Array : Array;
/**

View File

@ -9,7 +9,7 @@
'use strict';
var native = require('../utils/native');
var native = require('../utils/native').binding;
/**
* Javascript siphash implementation. Used for compact block relay.

View File

@ -0,0 +1,16 @@
/**
* backends-browser.js - database backends for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var level = require('./level');
var RBT = require('./rbt');
exports.get = function get(name) {
if (name === 'rbt')
return RBT;
return level;
};

18
lib/db/backends.js Normal file
View File

@ -0,0 +1,18 @@
/**
* backends.js - database backends for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
exports.get = function get(name) {
if (name === 'rbt')
return require('./rbt');
try {
return require(name);
} catch (e) {
throw new Error('Database backend "' + name + '" not found.');
}
};

View File

@ -1,7 +1,5 @@
/**
* global ldb tracker
* @module ldb
* @license
* ldb.js - database backend for bcoin
* Copyright (c) 2014-2015, Fedor Indutny (MIT License)
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
@ -9,9 +7,10 @@
'use strict';
var assert = require('assert');
var LowlevelUp = require('./lowlevelup');
var utils = require('../utils/utils');
var assert = require('assert');
var backends = require('./backends');
/**
* @param {Object} options
@ -28,8 +27,8 @@ var assert = require('assert');
* @returns {LowlevelUp}
*/
function ldb(options) {
var target = ldb.getTarget(options);
function LDB(options) {
var target = LDB.getTarget(options);
if (target.backend !== 'rbt')
utils.mkdir(target.location, true);
@ -66,7 +65,7 @@ function ldb(options) {
* @returns {Object}
*/
ldb.getBackend = function getBackend(db) {
LDB.getBackend = function getBackend(db) {
var name, ext;
if (!db)
@ -111,17 +110,10 @@ ldb.getBackend = function getBackend(db) {
* @returns {Object}
*/
ldb.getTarget = function getTarget(options) {
var backend = ldb.getBackend(options.db);
LDB.getTarget = function getTarget(options) {
var backend = LDB.getBackend(options.db);
var location = options.location;
var db;
if (backend.name === 'rbt')
db = require('./rbt');
else if (utils.isBrowser)
db = require('./level');
else
db = require(backend.name);
var db = backends.get(backend.name);
if (typeof location !== 'string') {
assert(backend.name === 'rbt', 'Location required.');
@ -139,4 +131,4 @@ ldb.getTarget = function getTarget(options) {
* Expose
*/
module.exports = ldb;
module.exports = LDB;

View File

@ -13,7 +13,8 @@ var constants = require('../protocol/constants');
var BufferWriter = require('../utils/writer');
var BufferReader = require('../utils/reader');
var HD = require('./hd');
var unorm;
var wordlist = require('./wordlist');
var nfkd = require('../utils/nfkd');
/**
* HD Mnemonic
@ -368,22 +369,7 @@ Mnemonic.getLanguage = function getLanguage(word) {
*/
Mnemonic.getWordlist = function getWordlist(language) {
switch (language) {
case 'simplified chinese':
return require('./words/chinese-simplified.js');
case 'traditional chinese':
return require('./words/chinese-traditional.js');
case 'english':
return require('./words/english.js');
case 'french':
return require('./words/french.js');
case 'italian':
return require('./words/italian.js');
case 'japanese':
return require('./words/japanese.js');
default:
throw new Error('Unknown language: ' + language);
}
return wordlist.get(language);
};
/**
@ -523,20 +509,6 @@ Mnemonic.isMnemonic = function isMnemonic(obj) {
&& typeof obj.toSeed === 'function';
};
/*
* Helpers
*/
function nfkd(str) {
if (str.normalize)
return str.normalize('NFKD');
if (!unorm)
unorm = require('../../vendor/unorm');
return unorm.nfkd(str);
}
/*
* Expose
*/

View File

@ -0,0 +1,28 @@
/*!
* wordlist.js - wordlists for bcoin
* Copyright (c) 2015-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var words = require('./words');
exports.get = function get(name) {
switch (name) {
case 'simplified chinese':
return words.chinese.simplified;
case 'traditional chinese':
return words.chinese.traditional;
case 'english':
return words.english;
case 'french':
return words.french;
case 'italian':
return words.italian;
case 'japanese':
return words.japanese;
default:
throw new Error('Unknown language: ' + name);
}
};

26
lib/hd/wordlist.js Normal file
View File

@ -0,0 +1,26 @@
/*!
* wordlist.js - wordlists for bcoin
* Copyright (c) 2015-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
exports.get = function get(name) {
switch (name) {
case 'simplified chinese':
return require('./words/chinese-simplified.js');
case 'traditional chinese':
return require('./words/chinese-traditional.js');
case 'english':
return require('./words/english.js');
case 'french':
return require('./words/french.js');
case 'italian':
return require('./words/italian.js');
case 'japanese':
return require('./words/japanese.js');
default:
throw new Error('Unknown language: ' + name);
}
};

17
lib/hd/words/index.js Normal file
View File

@ -0,0 +1,17 @@
/*!
* index.js - wordlists for bcoin
* Copyright (c) 2015-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
exports.chinese = {
simplified: require('./chinese-simplified.js'),
traditional: require('./chinese-traditional.js')
};
exports.english = require('./english.js');
exports.french = require('./french.js');
exports.italian = require('./italian.js');
exports.japanese = require('./japanese.js');

View File

@ -7,16 +7,10 @@
'use strict';
var utils = require('../utils/utils');
if (!utils.isBrowser) {
exports.request = require('./request');
exports.Client = require('./client');
exports.RPCClient = require('./rpcclient');
exports.Wallet = require('./wallet');
exports.Base = require('./base');
exports.RPC = require('./rpc');
exports.Server = require('./server');
} else {
exports.RPC = require('./rpc');
}
exports.request = require('./request');
exports.Client = require('./client');
exports.RPCClient = require('./rpcclient');
exports.Wallet = require('./wallet');
exports.Base = require('./base');
exports.RPC = require('./rpc');
exports.Server = require('./server');

View File

@ -31,13 +31,7 @@ var BufferReader = require('../utils/reader');
var TX = require('../primitives/tx');
var Logger = require('../node/logger');
var EventEmitter = require('events').EventEmitter;
var fs;
try {
fs = require('fs');
} catch (e) {
;
}
var fs = require('fs');
function RPC(node) {
if (!(this instanceof RPC))
@ -2794,7 +2788,7 @@ RPC.prototype.dumpwallet = co(function* dumpwallet(args) {
out = out.join('\n');
if (!fs)
if (fs.unsupported)
return out;
yield writeFile(file, out);
@ -3216,7 +3210,7 @@ RPC.prototype.importwallet = co(function* importwallet(args) {
file = toString(args[0]);
if (!fs)
if (fs.unsupported)
throw new RPCError('FS not available.');
data = yield readFile(file, 'utf8');

View File

@ -7,7 +7,9 @@
'use strict';
var assert = require('assert');
var EventEmitter = require('events').EventEmitter;
var tcp = require('./tcp');
var utils = require('../utils/utils');
var co = require('../utils/co');
var Parser = require('./parser');
@ -15,7 +17,6 @@ var Framer = require('./framer');
var packets = require('./packets');
var packetTypes = packets.types;
var NetworkAddress = require('../primitives/netaddress');
var assert = require('assert');
var constants = require('../protocol/constants');
var InvItem = require('../primitives/invitem');
var Locker = require('../utils/locker');
@ -249,21 +250,15 @@ Peer.prototype._init = function init() {
Peer.prototype.connect = function connect(port, host) {
var self = this;
var socket, proxy, net;
var proxy = this.pool.proxyServer;
var socket;
assert(!this.socket);
if (this.createSocket) {
socket = this.createSocket(port, host);
} else {
if (utils.isBrowser) {
proxy = require('./proxysocket');
socket = proxy.connect(this.pool.proxyServer, port, host);
} else {
net = require('net');
socket = net.connect(port, host);
}
}
if (this.createSocket)
socket = this.createSocket(port, host, proxy);
else
socket = tcp.connect(port, host, proxy);
this.logger.debug('Connecting to %s.', this.hostname);

View File

@ -7,12 +7,12 @@
'use strict';
var AsyncObject = require('../utils/async');
var assert = require('assert');
var EventEmitter = require('events').EventEmitter;
var AsyncObject = require('../utils/async');
var utils = require('../utils/utils');
var IP = require('../utils/ip');
var co = require('../utils/co');
var assert = require('assert');
var constants = require('../protocol/constants');
var VerifyError = require('../utils/errors').VerifyError;
var NetworkAddress = require('../primitives/netaddress');
@ -27,6 +27,8 @@ var Network = require('../protocol/network');
var time = require('./timedata');
var Peer = require('./peer');
var TX = require('../primitives/tx');
var tcp = require('./tcp');
var request = require('../http/request');
/**
* A pool of peers for handling all network activity.
@ -396,7 +398,6 @@ Pool.prototype.connect = function connect() {
Pool.prototype.listen = function listen() {
var self = this;
var net;
if (this.server)
return Promise.resolve();
@ -404,10 +405,9 @@ Pool.prototype.listen = function listen() {
if (this.createServer) {
this.server = this.createServer();
} else {
if (utils.isBrowser)
if (!tcp.Server)
return;
net = require('net');
this.server = new net.Server();
this.server = new tcp.Server();
}
this.server.on('connection', function(socket) {
@ -1871,13 +1871,11 @@ Pool.prototype.isIgnored = function isIgnored(addr) {
*/
Pool.prototype.getIP = co(function* getIP() {
var request, res, ip;
var res, ip;
if (utils.isBrowser)
if (request.unsupported)
throw new Error('Could not find IP.');
request = require('../http/request');
try {
res = yield request.promise({
method: 'GET',
@ -1903,13 +1901,11 @@ Pool.prototype.getIP = co(function* getIP() {
*/
Pool.prototype.getIP2 = co(function* getIP2() {
var request, res, ip;
var res, ip;
if (utils.isBrowser)
if (request.unsupported)
throw new Error('Could not find IP.');
request = require('../http/request');
res = yield request.promise({
method: 'GET',
uri: 'http://checkip.dyndns.org',

16
lib/net/tcp-browser.js Normal file
View File

@ -0,0 +1,16 @@
/*!
* tcp.js - tcp backend for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var ProxySocket = require('./proxysocket');
var tcp = exports;
tcp.connect = function connect(port, host, uri) {
return ProxySocket.connect(uri, port, host);
};
tcp.Server = null;

16
lib/net/tcp.js Normal file
View File

@ -0,0 +1,16 @@
/*!
* tcp.js - tcp backend for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var net = require('net');
var tcp = exports;
tcp.connect = function connect(port, host) {
return net.connect(port, host);
};
tcp.Server = net.Server;

View File

@ -9,10 +9,7 @@
var Network = require('../protocol/network');
var utils = require('../utils/utils');
var assert = require('assert');
var fs;
if (!utils.isBrowser)
fs = require('fs');
var fs = require('fs');
/**
* @exports config
@ -660,7 +657,7 @@ function boolpath(value, prefix, dirname) {
}
function file(value, prefix, dirname, enc) {
if (!fs)
if (fs.unsupported)
return null;
value = path(value, prefix, dirname);
@ -684,7 +681,7 @@ function resolve(a, b) {
}
function readFile(file) {
if (!fs)
if (fs.unsupported)
return '';
if (!file)

View File

@ -17,13 +17,7 @@ var Mempool = require('../mempool/mempool');
var Pool = require('../net/pool');
var Miner = require('../miner/miner');
var WalletDB = require('../wallet/walletdb');
var HTTPServer;
try {
HTTPServer = require('../http/server');
} catch (e) {
;
}
var HTTPServer = require('../http/server');
/**
* Create a fullnode complete with a chain,
@ -155,7 +149,7 @@ function FullNode(options) {
});
// HTTP needs access to the node.
if (!utils.isBrowser) {
if (!HTTPServer.unsupported) {
this.http = new HTTPServer({
network: this.network,
logger: this.logger,

View File

@ -8,10 +8,7 @@
var utils = require('../utils/utils');
var assert = require('assert');
var fs;
if (!utils.isBrowser)
fs = require('fs');
var fs = require('fs');
/**
* Basic stdout and file logger.
@ -287,9 +284,12 @@ Logger.prototype.writeStream = function writeStream(level, args) {
if (!this.stream) {
if (!this.file)
return;
if (utils.isBrowser)
if (fs.unsupported)
return;
utils.mkdir(this.file, true);
this.stream = fs.createWriteStream(this.file, { flags: 'a' });
this.stream.on('error', function() {});
}

View File

@ -13,13 +13,7 @@ var Node = require('./node');
var Chain = require('../chain/chain');
var Pool = require('../net/pool');
var WalletDB = require('../wallet/walletdb');
var HTTPServer;
try {
HTTPServer = require('../http/server');
} catch (e) {
;
}
var HTTPServer = require('../http/server');
/**
* Create an spv node which only maintains
@ -95,7 +89,7 @@ function SPVNode(options) {
verify: true
});
if (!utils.isBrowser) {
if (!HTTPServer.unsupported) {
this.http = new HTTPServer({
network: this.network,
logger: this.logger,

View File

@ -31,9 +31,9 @@
var assert = require('assert');
var BufferReader = require('../utils/reader');
var asn1 = exports;
var ASN1 = exports;
asn1.parseTag = function parseTag(p) {
ASN1.parseTag = function parseTag(p) {
var tag = p.readU8();
var primitive = (tag & 0x20) === 0;
var oct;
@ -53,11 +53,11 @@ asn1.parseTag = function parseTag(p) {
return {
primitive: primitive,
tag: tag,
len: asn1.parseLen(p, primitive)
len: ASN1.parseLen(p, primitive)
};
};
asn1.parseLen = function parseLen(p, primitive) {
ASN1.parseLen = function parseLen(p, primitive) {
var len = p.readU8();
var num, i, j;
@ -85,52 +85,52 @@ asn1.parseLen = function parseLen(p, primitive) {
return len;
};
asn1.parseCert = function parseCert(data) {
ASN1.parseCert = function parseCert(data) {
var d = BufferReader(data);
var p;
d.start();
p = BufferReader(asn1.parseSeq(d));
p = BufferReader(ASN1.parseSeq(d));
return {
tbs: asn1.parseTBS(p),
sigAlg: asn1.parseAlgIdent(p),
sig: asn1.parseBitstr(p),
tbs: ASN1.parseTBS(p),
sigAlg: ASN1.parseAlgIdent(p),
sig: ASN1.parseBitstr(p),
raw: d.endData(true)
};
};
asn1.parseTBS = function parseTBS(data) {
ASN1.parseTBS = function parseTBS(data) {
var d = BufferReader(data);
var p;
d.start();
p = BufferReader(asn1.parseSeq(d));
p = BufferReader(ASN1.parseSeq(d));
return {
version: asn1.parseExplicitInt(p, 0, true),
serial: asn1.parseInt(p),
sig: asn1.parseAlgIdent(p),
issuer: asn1.parseName(p),
validity: asn1.parseValidity(p),
subject: asn1.parseName(p),
pubkey: asn1.parsePubkey(p),
version: ASN1.parseExplicitInt(p, 0, true),
serial: ASN1.parseInt(p),
sig: ASN1.parseAlgIdent(p),
issuer: ASN1.parseName(p),
validity: ASN1.parseValidity(p),
subject: ASN1.parseName(p),
pubkey: ASN1.parsePubkey(p),
raw: d.endData(true)
};
};
asn1.parseSeq = function parseSeq(data) {
ASN1.parseSeq = function parseSeq(data) {
var p = BufferReader(data);
var tag = asn1.parseTag(p);
var tag = ASN1.parseTag(p);
assert.equal(tag.tag, 0x10); // seq
return p.readBytes(tag.len, true);
};
asn1.parseInt = function parseInt(data, readNum) {
ASN1.parseInt = function parseInt(data, readNum) {
var p = BufferReader(data);
var tag = asn1.parseTag(p);
var tag = ASN1.parseTag(p);
var num;
assert.equal(tag.tag, 0x02); // int
@ -143,30 +143,30 @@ asn1.parseInt = function parseInt(data, readNum) {
return num;
};
asn1.parseExplicitInt = function parseExplicitInt(data, i, readNum) {
ASN1.parseExplicitInt = function parseExplicitInt(data, i, readNum) {
var p = BufferReader(data);
var off = p.offset;
var tag = asn1.parseTag(p);
var tag = ASN1.parseTag(p);
if (tag.tag !== i) {
p.seek(-(p.offset - off));
return -1;
}
return asn1.parseInt(p, readNum);
return ASN1.parseInt(p, readNum);
};
asn1.parseBitstr = function parseBitstr(data) {
ASN1.parseBitstr = function parseBitstr(data) {
var p = BufferReader(data);
var tag = asn1.parseTag(p);
var tag = ASN1.parseTag(p);
assert.equal(tag.tag, 0x03); // bitstr
return asn1.alignBitstr(p.readBytes(tag.len, true));
return ASN1.alignBitstr(p.readBytes(tag.len, true));
};
asn1.parseString = function parseString(data) {
ASN1.parseString = function parseString(data) {
var p = BufferReader(data);
var tag = asn1.parseTag(p);
var tag = ASN1.parseTag(p);
switch (tag.tag) {
case 0x03: // bitstr
return asn1.alignBitstr(p.readBytes(tag.len, true));
return ASN1.alignBitstr(p.readBytes(tag.len, true));
case 0x04: // octstr
case 0x12: // numstr
case 0x13: // prinstr
@ -186,7 +186,7 @@ asn1.parseString = function parseString(data) {
}
};
asn1.alignBitstr = function(data) {
ASN1.alignBitstr = function(data) {
var padding = data[0];
var bits = (data.length - 1) * 8 - padding;
var buf = data.slice(1);
@ -207,48 +207,48 @@ asn1.alignBitstr = function(data) {
return out;
};
asn1.parsePubkey = function parsePubkey(data) {
ASN1.parsePubkey = function parsePubkey(data) {
var p = BufferReader(data);
p = BufferReader(asn1.parseSeq(p));
p = BufferReader(ASN1.parseSeq(p));
return {
alg: asn1.parseAlgIdent(p),
pubkey: asn1.parseBitstr(p)
alg: ASN1.parseAlgIdent(p),
pubkey: ASN1.parseBitstr(p)
};
};
asn1.parseName = function parseName(data) {
ASN1.parseName = function parseName(data) {
var p = BufferReader(data);
var values = [];
var tag;
p = BufferReader(asn1.parseSeq(p));
p = BufferReader(ASN1.parseSeq(p));
while (p.left()) {
tag = asn1.parseTag(p);
tag = ASN1.parseTag(p);
assert.equal(tag.tag, 0x11); // set
tag = asn1.parseTag(p);
tag = ASN1.parseTag(p);
assert.equal(tag.tag, 0x10); // seq
values.push({
type: asn1.parseOID(p),
value: asn1.parseString(p)
type: ASN1.parseOID(p),
value: ASN1.parseString(p)
});
}
return values;
};
asn1.parseValidity = function parseValidity(data) {
ASN1.parseValidity = function parseValidity(data) {
var p = BufferReader(data);
p = BufferReader(asn1.parseSeq(p));
p = BufferReader(ASN1.parseSeq(p));
return {
notBefore: asn1.parseTime(p),
notAfter: asn1.parseTime(p)
notBefore: ASN1.parseTime(p),
notAfter: ASN1.parseTime(p)
};
};
asn1.parseTime = function parseTime(data) {
ASN1.parseTime = function parseTime(data) {
var p = BufferReader(data);
var tag = asn1.parseTag(p);
var tag = ASN1.parseTag(p);
var str = p.readString('ascii', tag.len);
var year, mon, day, hour, min, sec;
@ -281,9 +281,9 @@ asn1.parseTime = function parseTime(data) {
return Date.UTC(year, mon - 1, day, hour, min, sec, 0) / 1000;
};
asn1.parseOID = function parseOID(data) {
ASN1.parseOID = function parseOID(data) {
var p = BufferReader(data);
var tag = asn1.parseTag(p);
var tag = ASN1.parseTag(p);
var ids = [];
var ident = 0;
var subident = 0;
@ -314,17 +314,17 @@ asn1.parseOID = function parseOID(data) {
return result.join('.');
};
asn1.parseAlgIdent = function parseAlgIdent(data) {
ASN1.parseAlgIdent = function parseAlgIdent(data) {
var p = BufferReader(data);
var params = null;
var alg;
p = BufferReader(asn1.parseSeq(p));
p = BufferReader(ASN1.parseSeq(p));
alg = asn1.parseOID(p);
alg = ASN1.parseOID(p);
if (p.left() > 0) {
params = p.readBytes(asn1.parseTag(p).len, true);
params = p.readBytes(ASN1.parseTag(p).len, true);
if (params.length === 0)
params = null;
}
@ -335,117 +335,27 @@ asn1.parseAlgIdent = function parseAlgIdent(data) {
};
};
asn1.parseRSAPublic = function parseRSAPublic(data) {
ASN1.parseRSAPublic = function parseRSAPublic(data) {
var p = BufferReader(data);
p = BufferReader(asn1.parseSeq(p));
p = BufferReader(ASN1.parseSeq(p));
return {
modulus: asn1.parseInt(p),
publicExponent: asn1.parseInt(p)
modulus: ASN1.parseInt(p),
publicExponent: ASN1.parseInt(p)
};
};
asn1.parseRSAPrivate = function parseRSAPrivate(data) {
ASN1.parseRSAPrivate = function parseRSAPrivate(data) {
var p = BufferReader(data);
p = BufferReader(asn1.parseSeq(p));
p = BufferReader(ASN1.parseSeq(p));
return {
version: asn1.parseInt(p, true),
modulus: asn1.parseInt(p),
publicExponent: asn1.parseInt(p),
privateExponent: asn1.parseInt(p),
prime1: asn1.parseInt(p),
prime2: asn1.parseInt(p),
exponent1: asn1.parseInt(p),
exponent2: asn1.parseInt(p),
coefficient: asn1.parseInt(p)
version: ASN1.parseInt(p, true),
modulus: ASN1.parseInt(p),
publicExponent: ASN1.parseInt(p),
privateExponent: ASN1.parseInt(p),
prime1: ASN1.parseInt(p),
prime2: ASN1.parseInt(p),
exponent1: ASN1.parseInt(p),
exponent2: ASN1.parseInt(p),
coefficient: ASN1.parseInt(p)
};
};
asn1.parsePEM = function parsePEM(pem) {
var buf = '';
var chunks = [];
var s, tag, type;
while (pem.length) {
if (s = /^-----BEGIN ([^\-]+)-----/.exec(pem)) {
pem = pem.substring(s[0].length);
tag = s[1];
continue;
}
if (s = /^-----END ([^\-]+)-----/.exec(pem)) {
pem = pem.substring(s[0].length);
assert(tag === s[1], 'Tag mismatch.');
buf = new Buffer(buf, 'base64');
type = tag.split(' ')[0].toLowerCase();
chunks.push({ tag: tag, type: type, data: buf });
buf = '';
tag = null;
continue;
}
if (s = /^[a-zA-Z0-9\+=\/]+/.exec(pem)) {
pem = pem.substring(s[0].length);
buf += s[0];
continue;
}
if (s = /^\s+/.exec(pem)) {
pem = pem.substring(s[0].length);
continue;
}
throw new Error('PEM parse error.');
}
assert(chunks.length !== 0, 'PEM parse error.');
assert(!tag, 'Un-ended tag.');
assert(buf.length === 0, 'Trailing data.');
return chunks;
};
asn1.fromPEM = function fromPEM(pem) {
var chunks = asn1.parsePEM(pem);
var body = chunks[0];
var extra = chunks[1];
var params, alg;
if (extra) {
if (extra.tag.indexOf('PARAMETERS') !== -1)
params = extra.data;
}
switch (body.type) {
case 'dsa':
alg = 'dsa';
break;
case 'rsa':
alg = 'rsa';
break;
case 'ec':
alg = 'ecdsa';
break;
}
return {
type: body.type,
alg: alg,
data: body.data,
params: params
};
};
asn1.toPEM = function toPEM(der, type, suffix) {
var pem = '';
var i;
if (suffix)
type += ' ' + suffix;
type = type.toUpperCase();
der = der.toString('base64');
for (i = 0; i < der.length; i += 64)
pem += der.slice(i, i + 64) + '\r\n';
return ''
+ '-----BEGIN ' + type + '-----\r\n'
+ pem
+ '-----END ' + type + '-----\r\n';
};

View File

@ -7,7 +7,7 @@
'use strict';
var native = require('./native');
var native = require('./native').binding;
var assert = require('assert');
/*

View File

@ -7,7 +7,7 @@
'use strict';
var native = require('./native');
var native = require('./native').binding;
/**
* Murmur3 hash.

View File

@ -6,15 +6,11 @@
'use strict';
var isBrowser =
(typeof process !== 'undefined' && process.browser)
|| typeof window !== 'undefined';
exports.binding = null;
module.exports = null;
if (!isBrowser && +process.env.BCOIN_NO_NATIVE !== 1) {
if (+process.env.BCOIN_NO_NATIVE !== 1) {
try {
module.exports = require('bcoin-native');
exports.binding = require('bcoin-native');
} catch (e) {
;
}

View File

@ -0,0 +1,7 @@
/*!
* nexttick.js - setimmediate for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
module.exports = require('../../vendor/setimmediate');

9
lib/utils/nexttick.js Normal file
View File

@ -0,0 +1,9 @@
/*!
* nexttick.js - setimmediate for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
module.exports = typeof setImmediate !== 'function'
? process.nextTick
: setImmediate;

20
lib/utils/nfkd-browser.js Normal file
View File

@ -0,0 +1,20 @@
/**
* nfkd-browser.js - unicode normalization for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
var unorm = require('../../vendor/unorm');
function nfkd(str) {
if (str.normalize)
return str.normalize('NFKD');
return unorm.nfkd(str);
}
/*
* Expose
*/
module.exports = nfkd;

23
lib/utils/nfkd.js Normal file
View File

@ -0,0 +1,23 @@
/**
* nfkd.js - unicode normalization for bcoin
* Copyright (c) 2014-2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
var unorm;
function nfkd(str) {
if (str.normalize)
return str.normalize('NFKD');
if (!unorm)
unorm = require('../../vendor/unorm');
return unorm.nfkd(str);
}
/*
* Expose
*/
module.exports = nfkd;

100
lib/utils/pem.js Normal file
View File

@ -0,0 +1,100 @@
/*!
* pem.js - pem parsing for bcoin
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
* https://github.com/bcoin-org/bcoin
*/
'use strict';
var assert = require('assert');
var PEM = exports;
PEM.parse = function parse(pem) {
var buf = '';
var chunks = [];
var s, tag, type;
while (pem.length) {
if (s = /^-----BEGIN ([^\-]+)-----/.exec(pem)) {
pem = pem.substring(s[0].length);
tag = s[1];
continue;
}
if (s = /^-----END ([^\-]+)-----/.exec(pem)) {
pem = pem.substring(s[0].length);
assert(tag === s[1], 'Tag mismatch.');
buf = new Buffer(buf, 'base64');
type = tag.split(' ')[0].toLowerCase();
chunks.push({ tag: tag, type: type, data: buf });
buf = '';
tag = null;
continue;
}
if (s = /^[a-zA-Z0-9\+=\/]+/.exec(pem)) {
pem = pem.substring(s[0].length);
buf += s[0];
continue;
}
if (s = /^\s+/.exec(pem)) {
pem = pem.substring(s[0].length);
continue;
}
throw new Error('PEM parse error.');
}
assert(chunks.length !== 0, 'PEM parse error.');
assert(!tag, 'Un-ended tag.');
assert(buf.length === 0, 'Trailing data.');
return chunks;
};
PEM.decode = function decode(pem) {
var chunks = PEM.parse(pem);
var body = chunks[0];
var extra = chunks[1];
var params, alg;
if (extra) {
if (extra.tag.indexOf('PARAMETERS') !== -1)
params = extra.data;
}
switch (body.type) {
case 'dsa':
alg = 'dsa';
break;
case 'rsa':
alg = 'rsa';
break;
case 'ec':
alg = 'ecdsa';
break;
}
return {
type: body.type,
alg: alg,
data: body.data,
params: params
};
};
PEM.encode = function encode(der, type, suffix) {
var pem = '';
var i;
if (suffix)
type += ' ' + suffix;
type = type.toUpperCase();
der = der.toString('base64');
for (i = 0; i < der.length; i += 64)
pem += der.slice(i, i + 64) + '\n';
return ''
+ '-----BEGIN ' + type + '-----\n'
+ pem
+ '-----END ' + type + '-----\n';
};

View File

@ -19,8 +19,10 @@ var assert = require('assert');
var base58 = require('./base58');
var BN = require('bn.js');
var util = require('util');
var fs = require('fs');
var os = require('os');
var Number, Math, Date;
var fs, lazy;
var lazy;
/**
* Reference to the global object.
@ -52,9 +54,6 @@ utils.isBrowser =
(typeof process !== 'undefined' && process.browser)
|| typeof window !== 'undefined';
if (!utils.isBrowser)
fs = require('fs');
Number = utils.global.Number;
Math = utils.global.Math;
Date = utils.global.Date;
@ -64,9 +63,9 @@ Date = utils.global.Date;
* @const {String}
*/
try {
utils.HOME = require('os').homedir();
} catch (e) {
if (os.homedir) {
utils.HOME = os.homedir();
} else {
utils.HOME = process.env.HOME
|| process.env.USERPROFILE
|| process.env.HOMEPATH
@ -149,6 +148,17 @@ utils.isBase58 = function isBase58(obj) {
return typeof obj === 'string' && /^[1-9a-zA-Z]+$/.test(obj);
};
/**
* Return uptime (shim for browser).
* @returns {Number}
*/
utils.uptime = function uptime() {
if (!process.uptime)
return 0;
return process.uptime();
};
/**
* Return hrtime (shim for browser).
* @param {Array} time
@ -227,18 +237,7 @@ utils.equal = function equal(a, b) {
* @returns {Promise}
*/
if (utils.isBrowser)
require('../../vendor/setimmediate');
if (typeof setImmediate === 'function') {
utils.nextTick = setImmediate;
} else if (!utils.isBrowser) {
utils.nextTick = process.nextTick;
} else {
utils.nextTick = function nextTick(fn) {
setTimeout(fn, 1);
};
}
utils.nextTick = require('./nexttick');
/**
* Reverse a hex-string (used because of
@ -1826,7 +1825,7 @@ utils.normalize = function normalize(path, dirname) {
utils.mkdirp = function mkdirp(path) {
var i, parts, stat;
if (!fs)
if (fs.unsupported)
return;
path = path.replace(/\\/g, '/');
@ -1964,3 +1963,7 @@ lazy('co', './co');
lazy('uri', './uri');
lazy('BufferReader', './reader');
lazy('BufferWriter', './writer');
lazy('protobuf', './protobuf');
lazy('pem', './pem');
lazy('asn1', './asn1');
lazy('nfkd', './nfkd');

View File

@ -15,6 +15,8 @@ var Network = require('../protocol/network');
var jobs = require('./jobs');
var Parser = require('./parser');
var Framer = require('./framer');
var os = require('os');
var cp = require('child_process');
/**
* A worker pool.
@ -396,7 +398,7 @@ utils.inherits(Worker, EventEmitter);
Worker.prototype._init = function _init() {
var self = this;
var penv, cp;
var penv;
penv = {
BCOIN_WORKER_NETWORK: Network.type
@ -423,8 +425,6 @@ Worker.prototype._init = function _init() {
this.child.postMessage(JSON.stringify(penv));
} else {
cp = require('child_process');
this.child = cp.spawn(process.argv[0], [__dirname + '/worker.js'], {
stdio: 'pipe',
env: utils.merge({}, process.env, penv)
@ -835,13 +835,8 @@ Master.listen = function listen() {
*/
function getCores() {
var os;
if (utils.isBrowser)
if (os.unsupported)
return 2;
os = require('os');
return os.cpus().length;
}

View File

@ -67,6 +67,16 @@
"./lib/http/rpcclient": "./browser/empty.js",
"./lib/http/server": "./browser/empty.js",
"./lib/http/wallet": "./browser/empty.js",
"./lib/utils/lazy": "./browser/empty.js",
"./lib/crypto/native": "./lib/crypto/empty.js",
"./lib/utils/nfkd": "./lib/utils/nfkd-browser.js",
"./lib/utils/nexttick": "./lib/utils/nexttick-browser.js",
"./lib/crypto/backend": "./lib/crypto/backend-browser.js",
"./lib/crypto/ec": "./lib/crypto/ec-elliptic.js",
"./lib/crypto/pk": "./lib/crypto/pk-browser.js",
"./lib/db/backends": "./lib/db/backends-browser.js",
"./lib/hd/wordlist": "./lib/hd/wordlist-browser.js",
"./lib/net/tcp": "./lib/net/tcp-browser.js",
"./lib/chain/layout": "./lib/chain/layout-browser.js",
"./lib/wallet/layout": "./lib/wallet/layout-browser.js",
"fs": "./browser/empty.js",

9
vendor/ip.js vendored
View File

@ -26,6 +26,7 @@
* IN THE SOFTWARE.
*/
var os = require('os');
var ip = exports;
ip.toBuffer = function(ip, buff, offset) {
@ -374,16 +375,10 @@ ip.loopback = function(family) {
// * undefined: First address with `ipv4` or loopback address `127.0.0.1`.
//
ip.address = function(name, family) {
var os;
try {
os = require('os');
} catch (e) {
if (os.unsupported)
return '127.0.0.1';
}
var interfaces = os.networkInterfaces();
var all;
//
// Default to `ipv4`

View File

@ -20,11 +20,24 @@
* DEALINGS IN THE SOFTWARE.
*/
(function (global, undefined) {
"use strict";
(function(root, undefined) {
"use strict";
var global;
if (typeof window !== "undefined")
global = window;
else if (typeof self !== "undefined")
global = self;
else
global = root;
if (!global)
throw new Error("Global not found.");
function install() {
if (global.setImmediate) {
return;
return global.setImmediate;
}
var nextHandle = 1; // Spec says greater than zero
@ -166,10 +179,6 @@
};
}
// If supported, we should attach to the prototype of global, since that is where setTimeout et al. live.
var attachTo = Object.getPrototypeOf && Object.getPrototypeOf(global);
attachTo = attachTo && attachTo.setTimeout ? attachTo : global;
// Don't get fooled by e.g. browserify environments.
if ({}.toString.call(global.process) === "[object process]") {
// For Node.js before 0.9
@ -192,6 +201,8 @@
installSetTimeoutImplementation();
}
attachTo.setImmediate = setImmediate;
attachTo.clearImmediate = clearImmediate;
}(typeof self === "undefined" ? typeof global === "undefined" ? this : global : self));
return setImmediate;
}
module.exports = install();
})(this);

61
vendor/unorm.js vendored
View File

@ -425,64 +425,5 @@ UChar.udata={
nfkd: nfkd
};
/*globals module:true,define:true*/
// CommonJS
if (typeof module === "object") {
module.exports = unorm;
// AMD
} else if (typeof define === "function" && define.amd) {
define("unorm", function () {
return unorm;
});
// Global
} else {
root.unorm = unorm;
}
/***** Export as shim for String::normalize method *****/
/*
http://wiki.ecmascript.org/doku.php?id=harmony:specification_drafts#november_8_2013_draft_rev_21
21.1.3.12 String.prototype.normalize(form="NFC")
When the normalize method is called with one argument form, the following steps are taken:
1. Let O be CheckObjectCoercible(this value).
2. Let S be ToString(O).
3. ReturnIfAbrupt(S).
4. If form is not provided or undefined let form be "NFC".
5. Let f be ToString(form).
6. ReturnIfAbrupt(f).
7. If f is not one of "NFC", "NFD", "NFKC", or "NFKD", then throw a RangeError Exception.
8. Let ns be the String value is the result of normalizing S into the normalization form named by f as specified in Unicode Standard Annex #15, UnicodeNormalizatoin Forms.
9. Return ns.
The length property of the normalize method is 0.
*NOTE* The normalize function is intentionally generic; it does not require that its this value be a String object. Therefore it can be transferred to other kinds of objects for use as a method.
*/
unorm.shimApplied = false;
if (!String.prototype.normalize) {
String.prototype.normalize = function(form) {
var str = "" + this;
form = form === undefined ? "NFC" : form;
if (form === "NFC") {
return unorm.nfc(str);
} else if (form === "NFD") {
return unorm.nfd(str);
} else if (form === "NFKC") {
return unorm.nfkc(str);
} else if (form === "NFKD") {
return unorm.nfkd(str);
} else {
throw new RangeError("Invalid normalization form: " + form);
}
};
unorm.shimApplied = true;
}
module.exports = unorm;
}(this));