Support update interface.

This commit is contained in:
Yi-Cyuan
2015-09-23 17:13:07 +08:00
parent ca56f2ac21
commit 09db28deed
6 changed files with 257 additions and 144 deletions
+193 -131
View File
@@ -1,5 +1,5 @@
/*
* js-sha3 v0.4.1
* js-sha3 v0.5.0
* https://github.com/emn178/js-sha3
*
* Copyright 2015, emn178@gmail.com
@@ -31,69 +31,106 @@
var SHAKE_BITS = [128, 256];
var OUTPUT_TYPES = ['hex', 'buffer', 'array'];
var createMethod = function(bits, padding, outputType) {
var createOutputMethod = function(bits, padding, outputType) {
return function(message) {
return keccak(message, bits, padding, bits, outputType);
return new Keccak(bits, padding, bits).update(message)[outputType]();
}
};
var createShakeMethod = function(bits, padding, outputType) {
var createShakeOutputMethod = function(bits, padding, outputType) {
return function(message, outputBits) {
return keccak(message, bits, padding, outputBits, outputType);
return new Keccak(bits, padding, outputBits).update(message)[outputType]();
}
};
var createMethod = function(bits, padding) {
var method = createOutputMethod(bits, padding, 'hex');
method.create = function() {
return new Keccak(bits, padding, bits);
};
method.update = function(message) {
return method.create().update(message);
};
for(var i = 0;i < OUTPUT_TYPES.length;++i) {
var type = OUTPUT_TYPES[i];
method[type] = createOutputMethod(bits, padding, type);
}
return method;
};
var createShakeMethod = function(bits, padding) {
var method = createShakeOutputMethod(bits, padding, 'hex');
method.create = function(outputBits) {
return new Keccak(bits, padding, outputBits);
};
method.update = function(message, outputBits) {
return method.create(outputBits).update(message);
};
for(var i = 0;i < OUTPUT_TYPES.length;++i) {
var type = OUTPUT_TYPES[i];
method[type] = createShakeOutputMethod(bits, padding, type);
}
return method;
};
var algorithms = [
{name: 'keccak', padding: KECCAK_PADDING, bits: BITS, createMethod: createMethod},
{name: 'sha3', padding: PADDING, bits: BITS, createMethod: createMethod},
{name: 'shake', padding: SHAKE_PADDING, bits: SHAKE_BITS, createMethod: createShakeMethod}
];
var blocks = [], s = [], methods = {};
var methods = {};
for(var i = 0;i < algorithms.length;++i) {
var algorithm = algorithms[i];
var bits = algorithm.bits;
var createMethod = algorithm.createMethod;
for(var j = 0;j < bits.length;++j) {
(function(algorithm, bits) {
var method = createMethod(bits, algorithm.padding, 'hex');
methods[algorithm.name +'_' + bits] = method;
for(var k = 0;k < OUTPUT_TYPES.length;++k) {
var type = OUTPUT_TYPES[k];
method[type] = createMethod(bits, algorithm.padding, type);
}
})(algorithm, bits[j]);
var method = algorithm.createMethod(bits[j], algorithm.padding);
methods[algorithm.name +'_' + bits[j]] = method;
}
}
var keccak = function(message, bits, padding, outputBits, outputType) {
function Keccak(bits, padding, outputBits) {
this.blocks = [];
this.s = [];
this.padding = padding;
this.outputBits = outputBits;
this.reset = true;
this.block = 0;
this.start = 0;
this.blockCount = (1600 - (bits << 1)) >> 5;
this.byteCount = this.blockCount << 2;
this.outputBlocks = outputBits >> 5;
this.extraBytes = (outputBits & 31) >> 3;
for(i = 0;i < 50;++i) {
this.s[i] = 0;
}
};
Keccak.prototype.update = function(message) {
var notString = typeof(message) != 'string';
if(notString && message.constructor == root.ArrayBuffer) {
message = new Uint8Array(message);
}
var block, code, end = false, index = 0, start = 0, length = message.length,
i, j, h;
var blockCount = (1600 - (bits << 1)) >> 5;
var byteCount = blockCount << 2;
for(i = 0;i < 50;++i) {
s[i] = 0;
}
block = 0;
do {
blocks[0] = block;
for(i = 1;i < blockCount + 1;++i) {
blocks[i] = 0;
var length = message.length, blocks = this.blocks, byteCount = this.byteCount,
blockCount = this.blockCount, index = 0, s = this.s, i, code;
while(index < length) {
if(this.reset) {
this.reset = false;
blocks[0] = this.block;
for(i = 1;i < blockCount + 1;++i) {
blocks[i] = 0;
}
}
if(notString) {
for (i = start;index < length && i < byteCount; ++index) {
for (i = this.start;index < length && i < byteCount; ++index) {
blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
}
} else {
for (i = start;index < length && i < byteCount; ++index) {
for (i = this.start;index < length && i < byteCount; ++index) {
code = message.charCodeAt(index);
if (code < 0x80) {
blocks[i >> 2] |= code << SHIFT[i++ & 3];
@@ -113,109 +150,135 @@
}
}
}
start = i - byteCount;
if(index == length) {
blocks[i >> 2] |= padding[i & 3];
++index;
}
block = blocks[blockCount];
if(index > length && i < byteCount) {
blocks[blockCount - 1] |= 0x80000000;
end = true;
}
for(i = 0;i < blockCount;++i) {
s[i] ^= blocks[i];
}
f();
} while(!end);
var outputBlocks = outputBits >> 5;
var extraBytes = (outputBits & 31) >> 3;
j = 0, i = 0;
if(outputType == 'buffer') {
var bytes = outputBits >> 3;
var buffer;
if(extraBytes) {
buffer = new ArrayBuffer((outputBlocks + 1) << 2);
this.lastByteIndex = i;
if(i >= byteCount) {
this.start = i - byteCount;
this.block = blocks[blockCount];
for(i = 0;i < blockCount;++i) {
s[i] ^= blocks[i];
}
f(s);
this.reset = true;
} else {
buffer = new ArrayBuffer(bytes);
this.start = i;
}
var array = new Uint32Array(buffer);
while(j < outputBlocks) {
for(i = 0;i < blockCount && j < outputBlocks;++i, ++j) {
array[j] = s[i];
}
if(j % blockCount == 0) {
f();
}
}
if(extraBytes) {
array[i] = s[i];
buffer = buffer.slice(0, bytes);
}
return buffer;
} else if(outputType == 'array') {
var array = [], offset;
while(j < outputBlocks) {
for(i = 0;i < blockCount && j < outputBlocks;++i, ++j) {
offset = j << 2;
h = s[i];
array[offset] = h & 0xFF;
array[offset + 1] = (h >> 8) & 0xFF;
array[offset + 2] = (h >> 16) & 0xFF;
array[offset + 3] = (h >> 24) & 0xFF;
}
if(j % blockCount == 0) {
f();
}
}
if(extraBytes) {
offset = j << 2;
h = s[i];
if(extraBytes > 0) {
array[offset] = h & 0xFF;
}
if(extraBytes > 1) {
array[offset + 1] = (h >> 8) & 0xFF;
}
if(extraBytes > 2) {
array[offset + 2] = (h >> 16) & 0xFF;
}
}
return array;
} else {
var hex = '';
while(j < outputBlocks) {
for(i = 0;i < blockCount && j < outputBlocks;++i, ++j) {
h = s[i];
hex += HEX_CHARS[(h >> 4) & 0x0F] + HEX_CHARS[h & 0x0F] +
HEX_CHARS[(h >> 12) & 0x0F] + HEX_CHARS[(h >> 8) & 0x0F] +
HEX_CHARS[(h >> 20) & 0x0F] + HEX_CHARS[(h >> 16) & 0x0F] +
HEX_CHARS[(h >> 28) & 0x0F] + HEX_CHARS[(h >> 24) & 0x0F];
}
if(j % blockCount == 0) {
f();
}
}
if(extraBytes) {
h = s[i];
if(extraBytes > 0) {
hex += HEX_CHARS[(h >> 4) & 0x0F] + HEX_CHARS[h & 0x0F];
}
if(extraBytes > 1) {
hex += HEX_CHARS[(h >> 12) & 0x0F] + HEX_CHARS[(h >> 8) & 0x0F];
}
if(extraBytes > 2) {
hex += HEX_CHARS[(h >> 20) & 0x0F] + HEX_CHARS[(h >> 16) & 0x0F];
}
}
return hex;
}
return this;
};
var f = function() {
Keccak.prototype.finalize = function() {
var blocks = this.blocks, i = this.lastByteIndex, blockCount = this.blockCount, s = this.s;
blocks[i >> 2] |= this.padding[i & 3];
if(this.lastByteIndex == this.byteCount) {
blocks[0] = blocks[blockCount];
for(i = 1;i < blockCount + 1;++i) {
blocks[i] = 0;
}
}
blocks[blockCount - 1] |= 0x80000000;
for(i = 0;i < blockCount;++i) {
s[i] ^= blocks[i];
}
f(s);
};
Keccak.prototype.toString = Keccak.prototype.hex = function() {
this.finalize();
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
extraBytes = this.extraBytes, i = 0, j = 0;
var hex = '', block;
while(j < outputBlocks) {
for(i = 0;i < blockCount && j < outputBlocks;++i, ++j) {
block = s[i];
hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F] +
HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F] +
HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F] +
HEX_CHARS[(block >> 28) & 0x0F] + HEX_CHARS[(block >> 24) & 0x0F];
}
if(j % blockCount == 0) {
f(s);
}
}
if(extraBytes) {
block = s[i];
if(extraBytes > 0) {
hex += HEX_CHARS[(block >> 4) & 0x0F] + HEX_CHARS[block & 0x0F];
}
if(extraBytes > 1) {
hex += HEX_CHARS[(block >> 12) & 0x0F] + HEX_CHARS[(block >> 8) & 0x0F];
}
if(extraBytes > 2) {
hex += HEX_CHARS[(block >> 20) & 0x0F] + HEX_CHARS[(block >> 16) & 0x0F];
}
}
return hex;
};
Keccak.prototype.buffer = function() {
this.finalize();
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
extraBytes = this.extraBytes, i = 0, j = 0;
var bytes = this.outputBits >> 3;
var buffer;
if(extraBytes) {
buffer = new ArrayBuffer((outputBlocks + 1) << 2);
} else {
buffer = new ArrayBuffer(bytes);
}
var array = new Uint32Array(buffer);
while(j < outputBlocks) {
for(i = 0;i < blockCount && j < outputBlocks;++i, ++j) {
array[j] = s[i];
}
if(j % blockCount == 0) {
f(s);
}
}
if(extraBytes) {
array[i] = s[i];
buffer = buffer.slice(0, bytes);
}
return buffer;
};
Keccak.prototype.digest = Keccak.prototype.array = function() {
this.finalize();
var blockCount = this.blockCount, s = this.s, outputBlocks = this.outputBlocks,
extraBytes = this.extraBytes, i = 0, j = 0;
var array = [], offset, block;
while(j < outputBlocks) {
for(i = 0;i < blockCount && j < outputBlocks;++i, ++j) {
offset = j << 2;
block = s[i];
array[offset] = block & 0xFF;
array[offset + 1] = (block >> 8) & 0xFF;
array[offset + 2] = (block >> 16) & 0xFF;
array[offset + 3] = (block >> 24) & 0xFF;
}
if(j % blockCount == 0) {
f(s);
}
}
if(extraBytes) {
offset = j << 2;
block = s[i];
if(extraBytes > 0) {
array[offset] = block & 0xFF;
}
if(extraBytes > 1) {
array[offset + 1] = (block >> 8) & 0xFF;
}
if(extraBytes > 2) {
array[offset + 2] = (block >> 16) & 0xFF;
}
}
return array;
};
var f = function(s) {
var h, l, n, c0, c1, c2, c3, c4, c5, c6, c7, c8, c9,
b0, b1, b2, b3, b4, b5, b6, b7, b8, b9, b10, b11, b12, b13, b14, b15, b16, b17,
b18, b19, b20, b21, b22, b23, b24, b25, b26, b27, b28, b29, b30, b31, b32, b33,
@@ -400,7 +463,6 @@
}
}
if(!root.JS_SHA3_TEST && NODE_JS) {
module.exports = methods;
} else if(root) {