crypto: optimized sha256 for browser.
This commit is contained in:
parent
fc2827a5bd
commit
096d348791
@ -10,6 +10,7 @@ var assert = require('assert');
|
||||
var hashjs = require('hash.js');
|
||||
var util = require('../utils/util');
|
||||
var aes = require('./aes');
|
||||
var sha256 = require('./sha256');
|
||||
var global = util.global;
|
||||
var crypto = global.crypto || global.msCrypto || {};
|
||||
var subtle = crypto.subtle && crypto.subtle.importKey ? crypto.subtle : {};
|
||||
@ -19,14 +20,17 @@ var backend = exports;
|
||||
* Hashing
|
||||
*/
|
||||
|
||||
backend._hash = function _hash(alg, data) {
|
||||
var hash = hashjs[alg];
|
||||
assert(hash != null, 'Unknown algorithm.');
|
||||
return hash().update(data).digest();
|
||||
};
|
||||
backend.hash = function hash(alg, data) {
|
||||
var hash;
|
||||
|
||||
backend.hash = function _hash(alg, data) {
|
||||
return new Buffer(backend._hash(alg, data));
|
||||
if (alg === 'sha256')
|
||||
return sha256.digest(data);
|
||||
|
||||
hash = hashjs[alg];
|
||||
|
||||
assert(hash != null, 'Unknown algorithm.');
|
||||
|
||||
return new Buffer(hash().update(data).digest());
|
||||
};
|
||||
|
||||
backend.ripemd160 = function ripemd160(data) {
|
||||
@ -37,18 +41,16 @@ backend.sha1 = function sha1(data) {
|
||||
return backend.hash('sha1', data);
|
||||
};
|
||||
|
||||
backend.sha256 = function sha256(data) {
|
||||
return backend.hash('sha256', data);
|
||||
backend.sha256 = function _sha256(data) {
|
||||
return sha256.digest(data);
|
||||
};
|
||||
|
||||
backend.hash160 = function hash160(data) {
|
||||
var hash = backend._hash('sha256', data);
|
||||
return backend.hash('ripemd160', hash);
|
||||
return backend.hash('ripemd160', sha256.digest(hash));
|
||||
};
|
||||
|
||||
backend.hash256 = function hash256(data) {
|
||||
var hash = backend._hash('sha256', data);
|
||||
return backend.hash('sha256', hash);
|
||||
return sha256.hash256(data);
|
||||
};
|
||||
|
||||
backend.hmac = function _hmac(alg, data, key) {
|
||||
|
||||
377
lib/crypto/sha256.js
Normal file
377
lib/crypto/sha256.js
Normal file
@ -0,0 +1,377 @@
|
||||
/*!
|
||||
* sha256.js - SHA256 implementation for bcoin
|
||||
* Copyright (c) 2016, Christopher Jeffrey (MIT License).
|
||||
* https://github.com/bcoin-org/bcoin
|
||||
* Parts of this software based on hash.js.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
|
||||
var DESC = new Buffer(8);
|
||||
var BUFFER64 = new Buffer(64);
|
||||
var K, PADDING;
|
||||
var ctx, mctx;
|
||||
|
||||
PADDING = new Buffer(64);
|
||||
PADDING.fill(0);
|
||||
PADDING[0] = 0x80;
|
||||
|
||||
K = [
|
||||
0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5,
|
||||
0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5,
|
||||
0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3,
|
||||
0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174,
|
||||
0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc,
|
||||
0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da,
|
||||
0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7,
|
||||
0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967,
|
||||
0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13,
|
||||
0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85,
|
||||
0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3,
|
||||
0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070,
|
||||
0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5,
|
||||
0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3,
|
||||
0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208,
|
||||
0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2
|
||||
];
|
||||
|
||||
/**
|
||||
* SHA256
|
||||
* @constructor
|
||||
* @property {Number[]} s
|
||||
* @property {Number[]} w
|
||||
* @property {Buffer} block
|
||||
* @property {Number} bytes
|
||||
*/
|
||||
|
||||
function SHA256() {
|
||||
if (!(this instanceof SHA256))
|
||||
return new SHA256();
|
||||
|
||||
this.s = new Array(8);
|
||||
this.w = new Array(64);
|
||||
this.block = new Buffer(64);
|
||||
this.bytes = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize SHA256 context.
|
||||
*/
|
||||
|
||||
SHA256.prototype.init = function init() {
|
||||
this.s[0] = 0x6a09e667;
|
||||
this.s[1] = 0xbb67ae85;
|
||||
this.s[2] = 0x3c6ef372;
|
||||
this.s[3] = 0xa54ff53a;
|
||||
this.s[4] = 0x510e527f;
|
||||
this.s[5] = 0x9b05688c;
|
||||
this.s[6] = 0x1f83d9ab;
|
||||
this.s[7] = 0x5be0cd19;
|
||||
this.bytes = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* Update SHA256 context.
|
||||
* @param {Buffer} data
|
||||
*/
|
||||
|
||||
SHA256.prototype.update = function update(data) {
|
||||
return this._update(data, data.length);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finalize SHA256 context.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
SHA256.prototype.finish = function finish() {
|
||||
return this._finish(new Buffer(32));
|
||||
};
|
||||
|
||||
/**
|
||||
* Update SHA256 context.
|
||||
* @private
|
||||
* @param {Buffer} data
|
||||
* @param {Number} len
|
||||
*/
|
||||
|
||||
SHA256.prototype._update = function update(data, len) {
|
||||
var size = this.bytes & 0x3f;
|
||||
var pos = 0;
|
||||
var i, want;
|
||||
|
||||
this.bytes += len;
|
||||
|
||||
if (size > 0) {
|
||||
want = 64 - size;
|
||||
|
||||
if (want > len)
|
||||
want = len;
|
||||
|
||||
for (i = 0; i < want; i++)
|
||||
this.block[size + i] = data[i];
|
||||
|
||||
size += want;
|
||||
len -= want;
|
||||
pos += want;
|
||||
|
||||
if (size < 64)
|
||||
return;
|
||||
|
||||
this.transform(this.block, 0);
|
||||
}
|
||||
|
||||
while (len >= 64) {
|
||||
this.transform(data, pos);
|
||||
pos += 64;
|
||||
len -= 64;
|
||||
}
|
||||
|
||||
for (i = 0; i < len; i++)
|
||||
this.block[i] = data[pos + i];
|
||||
};
|
||||
|
||||
/**
|
||||
* Finalize SHA256 context.
|
||||
* @private
|
||||
* @param {Buffer} out
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
SHA256.prototype._finish = function _finish(out) {
|
||||
var i;
|
||||
|
||||
writeU32(DESC, this.bytes >>> 29, 0);
|
||||
writeU32(DESC, this.bytes << 3, 4);
|
||||
|
||||
this._update(PADDING, 1 + ((119 - (this.bytes % 64)) % 64));
|
||||
this._update(DESC, 8);
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
writeU32(out, this.s[i], i * 4);
|
||||
this.s[i] = 0;
|
||||
}
|
||||
|
||||
return out;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform SHA256 block.
|
||||
* @param {Buffer} chunk
|
||||
* @param {Number} pos
|
||||
*/
|
||||
|
||||
SHA256.prototype.transform = function transform(chunk, pos) {
|
||||
var a = this.s[0];
|
||||
var b = this.s[1];
|
||||
var c = this.s[2];
|
||||
var d = this.s[3];
|
||||
var e = this.s[4];
|
||||
var f = this.s[5];
|
||||
var g = this.s[6];
|
||||
var h = this.s[7];
|
||||
var w = this.w;
|
||||
var i, t1, t2;
|
||||
|
||||
for (i = 0; i < 16; i++)
|
||||
w[i] = readU32(chunk, pos + i * 4);
|
||||
|
||||
for (; i < 64; i++)
|
||||
w[i] = sigma1(w[i - 2]) + w[i - 7] + sigma0(w[i - 15]) + w[i - 16];
|
||||
|
||||
for (i = 0; i < 64; i++) {
|
||||
t1 = h + Sigma1(e);
|
||||
t1 += Ch(e, f, g);
|
||||
t1 += K[i] + w[i];
|
||||
|
||||
t2 = Sigma0(a);
|
||||
t2 += Maj(a, b, c);
|
||||
|
||||
h = g;
|
||||
g = f;
|
||||
f = e;
|
||||
|
||||
e = d + t1;
|
||||
|
||||
d = c;
|
||||
c = b;
|
||||
b = a;
|
||||
|
||||
a = t1 + t2;
|
||||
}
|
||||
|
||||
this.s[0] += a;
|
||||
this.s[1] += b;
|
||||
this.s[2] += c;
|
||||
this.s[3] += d;
|
||||
this.s[4] += e;
|
||||
this.s[5] += f;
|
||||
this.s[6] += g;
|
||||
this.s[7] += h;
|
||||
|
||||
this.s[0] >>>= 0;
|
||||
this.s[1] >>>= 0;
|
||||
this.s[2] >>>= 0;
|
||||
this.s[3] >>>= 0;
|
||||
this.s[4] >>>= 0;
|
||||
this.s[5] >>>= 0;
|
||||
this.s[6] >>>= 0;
|
||||
this.s[7] >>>= 0;
|
||||
};
|
||||
|
||||
/**
|
||||
* SHA256Hmac
|
||||
* @constructor
|
||||
* @property {SHA256} inner
|
||||
* @property {SHA256} outer
|
||||
*/
|
||||
|
||||
function SHA256Hmac() {
|
||||
if (!(this instanceof SHA256Hmac))
|
||||
return new SHA256Hmac();
|
||||
|
||||
this.inner = new SHA256();
|
||||
this.outer = new SHA256();
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize HMAC context.
|
||||
* @param {Buffer} data
|
||||
*/
|
||||
|
||||
SHA256Hmac.prototype.init = function init(data) {
|
||||
var key = BUFFER64;
|
||||
var i;
|
||||
|
||||
if (data.length > 64) {
|
||||
this.inner.init();
|
||||
this.inner.update(data);
|
||||
this.inner._finish(key);
|
||||
key.fill(0, 32);
|
||||
} else {
|
||||
data.copy(key, 0);
|
||||
key.fill(0, data.length, 64);
|
||||
}
|
||||
|
||||
this.inner.init();
|
||||
this.outer.init();
|
||||
|
||||
for (i = 0; i < key.length; i++)
|
||||
key[i] ^= 0x36;
|
||||
|
||||
this.inner.update(key);
|
||||
|
||||
for (i = 0; i < key.length; i++)
|
||||
key[i] ^= 0x6a;
|
||||
|
||||
this.outer.update(key);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update HMAC context.
|
||||
* @param {Buffer} data
|
||||
*/
|
||||
|
||||
SHA256Hmac.prototype.update = function update(data) {
|
||||
this.inner.update(data);
|
||||
};
|
||||
|
||||
/**
|
||||
* Finalize HMAC context.
|
||||
* @returns {Buffer}
|
||||
*/
|
||||
|
||||
SHA256Hmac.prototype.finish = function finish() {
|
||||
this.outer.update(this.inner.finish());
|
||||
return this.outer.finish();
|
||||
};
|
||||
|
||||
/*
|
||||
* Helpers
|
||||
* @see https://github.com/bitcoin-core/secp256k1/blob/master/src/hash_impl.h
|
||||
*/
|
||||
|
||||
function Sigma0(x) {
|
||||
return (x >>> 2 | x << 30) ^ (x >>> 13 | x << 19) ^ (x >>> 22 | x << 10);
|
||||
}
|
||||
|
||||
function Sigma1(x) {
|
||||
return (x >>> 6 | x << 26) ^ (x >>> 11 | x << 21) ^ (x >>> 25 | x << 7);
|
||||
}
|
||||
|
||||
function sigma0(x) {
|
||||
return (x >>> 7 | x << 25) ^ (x >>> 18 | x << 14) ^ (x >>> 3);
|
||||
}
|
||||
|
||||
function sigma1(x) {
|
||||
return (x >>> 17 | x << 15) ^ (x >>> 19 | x << 13) ^ (x >>> 10);
|
||||
}
|
||||
|
||||
function Ch(x, y, z) {
|
||||
return z ^ (x & (y ^ z));
|
||||
}
|
||||
|
||||
function Maj(x, y, z) {
|
||||
return (x & y) | (z & (x | y));
|
||||
}
|
||||
|
||||
function writeU32(buf, value, offset) {
|
||||
buf[offset] = value >>> 24;
|
||||
buf[offset + 1] = (value >> 16) & 0xff;
|
||||
buf[offset + 2] = (value >> 8) & 0xff;
|
||||
buf[offset + 3] = value & 0xff;
|
||||
}
|
||||
|
||||
function readU32(buf, offset) {
|
||||
return ((buf[offset] & 0xff) * 0x1000000)
|
||||
+ ((buf[offset + 1] & 0xff) << 16)
|
||||
| ((buf[offset + 2] & 0xff) << 8)
|
||||
| (buf[offset + 3] & 0xff);
|
||||
}
|
||||
|
||||
/*
|
||||
* Context Helpers
|
||||
*/
|
||||
|
||||
ctx = new SHA256();
|
||||
mctx = new SHA256Hmac();
|
||||
|
||||
function sha256(data) {
|
||||
ctx.init();
|
||||
ctx.update(data);
|
||||
return ctx.finish();
|
||||
}
|
||||
|
||||
function hash256(data) {
|
||||
var out = new Buffer(32);
|
||||
ctx.init();
|
||||
ctx.update(data);
|
||||
ctx._finish(out);
|
||||
ctx.init();
|
||||
ctx.update(out);
|
||||
ctx._finish(out);
|
||||
return out;
|
||||
}
|
||||
|
||||
function hmac(data, key) {
|
||||
mctx.init(key);
|
||||
mctx.update(data);
|
||||
return mctx.finish();
|
||||
}
|
||||
|
||||
/*
|
||||
* Expose
|
||||
*/
|
||||
|
||||
exports = SHA256;
|
||||
exports.SHA256 = SHA256;
|
||||
exports.SHA256Hmac = SHA256Hmac;
|
||||
exports.digest = sha256;
|
||||
exports.hmac = hmac;
|
||||
exports.hash256 = hash256;
|
||||
|
||||
module.exports = exports;
|
||||
Loading…
Reference in New Issue
Block a user