Compare commits

..
9 Commits
Author SHA1 Message Date
Yi-Cyuan Chen d506b22f67 update RERADME 2026-08-06 11:38:20 +08:00
Yi-Cyuan Chen 5f95ceb733 ### Added
- KMACXOF128 and KMACXOF256 (NIST SP 800-185)
2026-07-18 10:14:36 +08:00
Yi-Cyuan Chen 01b1baf1e7 ### Added
- TupleHash128, TupleHash256, TupleHashXOF128, and TupleHashXOF256 (NIST SP 800-185)

### Fixed
- KMAC repeated output reads after finalize
2026-07-18 08:52:44 +08:00
Yi-Cyuan Chen f0ab0aec2c Merge branch 'master' of https://github.com/emn178/js-sha3 2026-07-17 16:32:05 +08:00
Yi-Cyuan Chen 951408a3aa - support ESM #42, #38
- types index.d.ts to package.json #32
2026-07-17 16:28:36 +08:00
00d3aa232f fix types (#32)
Co-authored-by: Valery Smirnov <57757211+XantreGodlike@users.noreply.github.com>
Co-authored-by: emn178 <emn178@gmail.com>
2026-07-17 15:47:58 +08:00
gkgoatandGitHub 83e468af79 support ESM (#42)
* support ESM

* Optimize
2026-07-17 15:44:06 +08:00
emn178andGitHub d1ab318829 Update README.md 2025-05-24 15:41:16 +08:00
dependabot[bot]GitHubdependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
6efde1cf1b Bump @babel/traverse from 7.21.2 to 7.23.2 (#35)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.21.2 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-12-16 10:17:14 +08:00
16 changed files with 4121 additions and 954 deletions
+16
View File
@@ -1,5 +1,21 @@
# Change Log
## v0.12.0 / 2026-07-18
### Added
- KMACXOF128 and KMACXOF256 (NIST SP 800-185)
## v0.11.0 / 2026-07-18
### Added
- TupleHash128, TupleHash256, TupleHashXOF128, and TupleHashXOF256 (NIST SP 800-185)
### Fixed
- KMAC repeated output reads after finalize
## v0.10.0 / 2026-07-17
### Added
- support ESM #42, #38
- types index.d.ts to package.json #32
## v0.9.3 / 2023-12-16
### Fixed
- Fix error in arrayBuffer when there are extra bytes #37
+1 -1
View File
@@ -1,4 +1,4 @@
Copyright 2015-2023 Chen, Yi-Cyuan
Copyright 2015-2026 Chen, Yi-Cyuan
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
+56 -5
View File
@@ -4,7 +4,7 @@
[![Coverage Status](https://coveralls.io/repos/emn178/js-sha3/badge.svg?branch=master)](https://coveralls.io/r/emn178/js-sha3?branch=master)
[![NPM](https://nodei.co/npm/js-sha3.png?stars&downloads)](https://nodei.co/npm/js-sha3/)
A simple SHA-3 / Keccak / Shake hash function for JavaScript supports UTF-8 encoding.
A simple SHA-3 / Keccak / SHAKE / cSHAKE / KMAC / TupleHash hash function for JavaScript supports UTF-8 encoding.
## Notice
* v0.8.0+ will throw an error if try to update hash after finalize.
@@ -20,8 +20,18 @@ A simple SHA-3 / Keccak / Shake hash function for JavaScript supports UTF-8 enco
[Keccak-384 Online](http://emn178.github.io/online-tools/keccak_384.html)
[Keccak-256 Online](http://emn178.github.io/online-tools/keccak_256.html)
[Keccak-224 Online](http://emn178.github.io/online-tools/keccak_224.html)
[Shake128 Online](http://emn178.github.io/online-tools/shake_128.html)
[Shake256 Online](http://emn178.github.io/online-tools/shake_256.html)
[Shake128 Online](http://emn178.github.io/online-tools/shake128/)
[Shake256 Online](http://emn178.github.io/online-tools/shake256/)
[cShake128 Online](http://emn178.github.io/online-tools/cshake128/)
[cShake256 Online](http://emn178.github.io/online-tools/cshake256/)
[KMAC128 Online](http://emn178.github.io/online-tools/kmac128/)
[KMAC256 Online](http://emn178.github.io/online-tools/kmac256/)
[KMACXOF128 Online](http://emn178.github.io/online-tools/kmacxof128/)
[KMACXOF256 Online](http://emn178.github.io/online-tools/kmacxof256/)
[TupleHash128 Online](http://emn178.github.io/online-tools/tuplehash128/)
[TupleHash256 Online](http://emn178.github.io/online-tools/tuplehash256/)
[TupleHashXOF128 Online](http://emn178.github.io/online-tools/tuplehashxof128/)
[TupleHashXOF256 Online](http://emn178.github.io/online-tools/tuplehashxof256/)
## Download
[Compress](https://raw.github.com/emn178/js-sha3/master/build/sha3.min.js)
@@ -53,6 +63,12 @@ cshake128('Message to hash', 256, 'function name', 'customization');
cshake256('Message to hash', 512, 'function name', 'customization');
kmac128('key', 'Message to hash', 256, 'customization');
kmac256('key', 'Message to hash', 512, 'customization');
kmacxof128('key', 'Message to hash', 256, 'customization');
kmacxof256('key', 'Message to hash', 512, 'customization');
tuplehash128(['abc', 'd'], 256, 'customization');
tuplehash256(['abc', 'd'], 512, 'customization');
tuplehashxof128(['abc', 'd'], 256, 'customization');
tuplehashxof256(['abc', 'd'], 512, 'customization');
// Support ArrayBuffer output
var arrayBuffer = keccak224.arrayBuffer('Message to hash');
@@ -83,6 +99,29 @@ var hash = cshake128.create(256, 'function name', 'customization');
// specify kmac key, output bits and customization when creating
var hash = kmac128.create('key', 256, 'customization');
// TupleHash: a tuple contains zero or more input strings.
// One-shot and method-level update
tuplehash128(['abc', 'd'], 256, '');
tuplehash128.update(['abc', 'd'], 256, '').hex();
// Incremental complete inputs (each update is one tuple input string)
tuplehash128.create(256, '')
.update('abc')
.update('d')
.hex();
// Streaming a large input when its byte length is known in advance.
// beginInput + updateChunk; no endInput() is needed.
// Inputs are absorbed sequentially. TupleHash does not parallelize tuple inputs;
// use ParallelHash for parallel hashing of one large input.
var tupleHash = tuplehash128.create(256, '');
tupleHash.beginInput(3);
tupleHash.updateChunk([0x61, 0x62]);
tupleHash.updateChunk([0x63]);
tupleHash.beginInput(1);
tupleHash.updateChunk([0x64]);
tupleHash.hex();
```
### Node.js
If you use node.js, you should require the module first:
@@ -101,7 +140,13 @@ const {
cshake128,
cshake256,
kmac128,
kmac25
kmac256,
kmacxof128,
kmacxof256,
tuplehash128,
tuplehash256,
tuplehashxof128,
tuplehashxof256
} = require('js-sha3');
```
@@ -122,7 +167,13 @@ import {
cshake128,
cshake256,
kmac128,
kmac256
kmac256,
kmacxof128,
kmacxof256,
tuplehash128,
tuplehash256,
tuplehashxof128,
tuplehashxof256
} from 'js-sha3';
```
+1 -1
View File
@@ -1,6 +1,6 @@
{
"name": "js-sha3",
"version": "0.9.3",
"version": "0.12.0",
"main": ["src/sha3.js"],
"ignore": [
"samples",
+3 -3
View File
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
+842
View File
@@ -0,0 +1,842 @@
var commonjsGlobal = typeof globalThis !== 'undefined' ? globalThis : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {};
function getDefaultExportFromCjs (x) {
return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, 'default') ? x['default'] : x;
}
var sha3$1 = {exports: {}};
/**
* [js-sha3]{@link https://github.com/emn178/js-sha3}
*
* @version 0.12.0
* @author Chen, Yi-Cyuan [emn178@gmail.com]
* @copyright Chen, Yi-Cyuan 2015-2026
* @license MIT
*/
(function (module) {
/*jslint bitwise: true */
(function () {
var INPUT_ERROR = 'input is invalid type';
var FINALIZE_ERROR = 'finalize already called';
var TUPLE_ACTIVE_ERROR = 'no active tuple input';
var TUPLE_INCOMPLETE_ERROR = 'tuple input is incomplete';
var TUPLE_LENGTH_ERROR = 'tuple input exceeds declared length';
var TUPLE_BYTE_LENGTH_ERROR = 'tuple input byte length is invalid';
var WINDOW = typeof window === 'object';
var root = WINDOW ? window : {};
if (root.JS_SHA3_NO_WINDOW) {
WINDOW = false;
}
var WEB_WORKER = !WINDOW && typeof self === 'object';
var NODE_JS = !root.JS_SHA3_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node;
if (NODE_JS) {
root = commonjsGlobal;
} else if (WEB_WORKER) {
root = self;
}
var COMMON_JS = !root.JS_SHA3_NO_COMMON_JS && 'object' === 'object' && module.exports;
var ARRAY_BUFFER = !root.JS_SHA3_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined';
var HEX_CHARS = '0123456789abcdef'.split('');
var SHAKE_PADDING = [31, 7936, 2031616, 520093696];
var CSHAKE_PADDING = [4, 1024, 262144, 67108864];
var KECCAK_PADDING = [1, 256, 65536, 16777216];
var PADDING = [6, 1536, 393216, 100663296];
var SHIFT = [0, 8, 16, 24];
var RC = [1, 0, 32898, 0, 32906, 2147483648, 2147516416, 2147483648, 32907, 0, 2147483649,
0, 2147516545, 2147483648, 32777, 2147483648, 138, 0, 136, 0, 2147516425, 0,
2147483658, 0, 2147516555, 0, 139, 2147483648, 32905, 2147483648, 32771,
2147483648, 32770, 2147483648, 128, 2147483648, 32778, 0, 2147483658, 2147483648,
2147516545, 2147483648, 32896, 2147483648, 2147483649, 0, 2147516424, 2147483648];
var BITS = [224, 256, 384, 512];
var SHAKE_BITS = [128, 256];
var OUTPUT_TYPES = ['hex', 'buffer', 'arrayBuffer', 'array', 'digest'];
var CSHAKE_BYTEPAD = {
'128': 168,
'256': 136
};
var isArray = root.JS_SHA3_NO_NODE_JS || !Array.isArray
? function (obj) {
return Object.prototype.toString.call(obj) === '[object Array]';
}
: Array.isArray;
var isView = (ARRAY_BUFFER && (root.JS_SHA3_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView))
? function (obj) {
return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer;
}
: ArrayBuffer.isView;
// [message: string, isString: bool]
var formatMessage = function (message) {
var type = typeof message;
if (type === 'string') {
return [message, true];
}
if (type !== 'object' || message === null) {
throw new Error(INPUT_ERROR);
}
if (ARRAY_BUFFER && message.constructor === ArrayBuffer) {
return [new Uint8Array(message), false];
}
if (!isArray(message) && !isView(message)) {
throw new Error(INPUT_ERROR);
}
return [message, false];
};
var empty = function (message) {
return formatMessage(message)[0].length === 0;
};
var cloneArray = function (array) {
var newArray = [];
for (var i = 0; i < array.length; ++i) {
newArray[i] = array[i];
}
return newArray;
};
var createOutputMethod = function (bits, padding, outputType) {
return function (message) {
return new Keccak(bits, padding, bits).update(message)[outputType]();
};
};
var createShakeOutputMethod = function (bits, padding, outputType) {
return function (message, outputBits) {
return new Keccak(bits, padding, outputBits).update(message)[outputType]();
};
};
var createCshakeOutputMethod = function (bits, padding, outputType) {
return function (message, outputBits, n, s) {
return methods['cshake' + bits].update(message, outputBits, n, s)[outputType]();
};
};
var createKmacOutputMethod = function (bits, padding, xof, outputType) {
return function (key, message, outputBits, s) {
return methods[(xof ? 'kmacxof' : 'kmac') + bits].update(key, message, outputBits, s)[outputType]();
};
};
var createTupleHashOutputMethod = function (bits, padding, xof, outputType) {
return function (inputs, outputBits, s) {
return methods[(xof ? 'tuplehashxof' : 'tuplehash') + bits].update(inputs, outputBits, s)[outputType]();
};
};
var createOutputMethods = function (method, createMethod, bits, padding) {
for (var i = 0; i < OUTPUT_TYPES.length; ++i) {
var type = OUTPUT_TYPES[i];
method[type] = createMethod(bits, padding, type);
}
return method;
};
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);
};
return createOutputMethods(method, createOutputMethod, bits, padding);
};
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);
};
return createOutputMethods(method, createShakeOutputMethod, bits, padding);
};
var createCshakeMethod = function (bits, padding) {
var w = CSHAKE_BYTEPAD[bits];
var method = createCshakeOutputMethod(bits, padding, 'hex');
method.create = function (outputBits, n, s) {
if (empty(n) && empty(s)) {
return methods['shake' + bits].create(outputBits);
} else {
return new Keccak(bits, padding, outputBits).bytepad([n, s], w);
}
};
method.update = function (message, outputBits, n, s) {
return method.create(outputBits, n, s).update(message);
};
return createOutputMethods(method, createCshakeOutputMethod, bits, padding);
};
var createKmacMethod = function (bits, padding, xof) {
var w = CSHAKE_BYTEPAD[bits];
var method = createKmacOutputMethod(bits, padding, xof, 'hex');
method.create = function (key, outputBits, s) {
return new Kmac(bits, padding, outputBits, xof).bytepad(['KMAC', s], w).bytepad([key], w);
};
method.update = function (key, message, outputBits, s) {
return method.create(key, outputBits, s).update(message);
};
return createOutputMethods(method, function (b, p, outputType) {
return createKmacOutputMethod(b, p, xof, outputType);
}, bits, padding);
};
var createTupleHashMethod = function (bits, padding, xof) {
var w = CSHAKE_BYTEPAD[bits];
var method = createTupleHashOutputMethod(bits, padding, xof, 'hex');
method.create = function (outputBits, s) {
return new TupleHash(bits, padding, outputBits, xof).bytepad(['TupleHash', s], w);
};
method.update = function (inputs, outputBits, s) {
if (!isArray(inputs)) {
throw new Error(INPUT_ERROR);
}
var hash = method.create(outputBits, s);
for (var i = 0; i < inputs.length; ++i) {
hash.update(inputs[i]);
}
return hash;
};
return createOutputMethods(method, function (b, p, outputType) {
return createTupleHashOutputMethod(b, p, xof, outputType);
}, bits, padding);
};
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 },
{ name: 'cshake', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: createCshakeMethod },
{ name: 'kmac', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) {
return createKmacMethod(bits, padding, false);
}},
{ name: 'kmacxof', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) {
return createKmacMethod(bits, padding, true);
}},
{ name: 'tuplehash', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) {
return createTupleHashMethod(bits, padding, false);
}},
{ name: 'tuplehashxof', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) {
return createTupleHashMethod(bits, padding, true);
}}
];
var methods = {}, methodNames = [];
for (var i = 0; i < algorithms.length; ++i) {
var algorithm = algorithms[i];
var bits = algorithm.bits;
for (var j = 0; j < bits.length; ++j) {
var methodName = algorithm.name + '_' + bits[j];
methodNames.push(methodName);
methods[methodName] = algorithm.createMethod(bits[j], algorithm.padding);
if (algorithm.name !== 'sha3') {
var newMethodName = algorithm.name + bits[j];
methodNames.push(newMethodName);
methods[newMethodName] = methods[methodName];
}
}
}
function Keccak(bits, padding, outputBits) {
this.blocks = [];
this.s = [];
this.padding = padding;
this.outputBits = outputBits;
this.reset = true;
this.finalized = false;
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 (var i = 0; i < 50; ++i) {
this.s[i] = 0;
}
}
Keccak.prototype.update = function (message) {
if (this.finalized) {
throw new Error(FINALIZE_ERROR);
}
var result = formatMessage(message);
message = result[0];
var isString = result[1];
var blocks = this.blocks, byteCount = this.byteCount, length = message.length,
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 (isString) {
for (i = this.start; index < length && i < byteCount; ++index) {
code = message.charCodeAt(index);
if (code < 0x80) {
blocks[i >> 2] |= code << SHIFT[i++ & 3];
} else if (code < 0x800) {
blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
} else if (code < 0xd800 || code >= 0xe000) {
blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
} else {
code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff));
blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3];
blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3];
}
}
} else {
for (i = this.start; index < length && i < byteCount; ++index) {
blocks[i >> 2] |= message[index] << SHIFT[i++ & 3];
}
}
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 {
this.start = i;
}
}
return this;
};
Keccak.prototype.encode = function (x, right) {
var o = x & 255, n = 1;
var bytes = [o];
x = x >> 8;
o = x & 255;
while (o > 0) {
bytes.unshift(o);
x = x >> 8;
o = x & 255;
++n;
}
if (right) {
bytes.push(n);
} else {
bytes.unshift(n);
}
Keccak.prototype.update.call(this, bytes);
return bytes.length;
};
Keccak.prototype.encodeString = function (str) {
var result = formatMessage(str);
str = result[0];
var isString = result[1];
var bytes = 0, length = str.length;
if (isString) {
for (var i = 0; i < str.length; ++i) {
var code = str.charCodeAt(i);
if (code < 0x80) {
bytes += 1;
} else if (code < 0x800) {
bytes += 2;
} else if (code < 0xd800 || code >= 0xe000) {
bytes += 3;
} else {
code = 0x10000 + (((code & 0x3ff) << 10) | (str.charCodeAt(++i) & 0x3ff));
bytes += 4;
}
}
} else {
bytes = length;
}
bytes += this.encode(bytes * 8);
Keccak.prototype.update.call(this, str);
return bytes;
};
Keccak.prototype.bytepad = function (strs, w) {
var bytes = this.encode(w);
for (var i = 0; i < strs.length; ++i) {
bytes += this.encodeString(strs[i]);
}
var paddingBytes = (w - bytes % w) % w;
var zeros = [];
zeros.length = paddingBytes;
Keccak.prototype.update.call(this, zeros);
return this;
};
Keccak.prototype.finalize = function () {
if (this.finalized) {
return;
}
this.finalized = true;
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) {
s = cloneArray(s);
f(s);
i = 0;
}
}
if (extraBytes) {
block = s[i];
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.arrayBuffer = 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) {
s = cloneArray(s);
f(s);
}
}
if (extraBytes) {
array[j] = s[i];
buffer = buffer.slice(0, bytes);
}
return buffer;
};
Keccak.prototype.buffer = Keccak.prototype.arrayBuffer;
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) {
s = cloneArray(s);
f(s);
}
}
if (extraBytes) {
offset = j << 2;
block = s[i];
array[offset] = block & 0xFF;
if (extraBytes > 1) {
array[offset + 1] = (block >> 8) & 0xFF;
}
if (extraBytes > 2) {
array[offset + 2] = (block >> 16) & 0xFF;
}
}
return array;
};
function Kmac(bits, padding, outputBits, xof) {
Keccak.call(this, bits, padding, outputBits);
this.xof = xof;
}
Kmac.prototype = new Keccak();
Kmac.prototype.finalize = function () {
if (!this.finalized) {
this.encode(this.xof ? 0 : this.outputBits, true);
}
return Keccak.prototype.finalize.call(this);
};
function TupleHash(bits, padding, outputBits, xof) {
Kmac.call(this, bits, padding, outputBits, xof);
this.inputActive = false;
this.inputBytesRemaining = 0;
}
TupleHash.prototype = new Kmac();
TupleHash.prototype.getMessageByteLength = function (message) {
var result = formatMessage(message);
message = result[0];
if (!result[1]) {
return message.length;
}
var bytes = 0;
for (var i = 0; i < message.length; ++i) {
var code = message.charCodeAt(i);
if (code < 0x80) {
bytes += 1;
} else if (code < 0x800) {
bytes += 2;
} else if (code < 0xd800 || code >= 0xe000) {
bytes += 3;
} else {
++i;
bytes += 4;
}
}
return bytes;
};
TupleHash.prototype.beginInput = function (byteLength) {
if (this.inputActive) {
throw new Error(TUPLE_INCOMPLETE_ERROR);
}
if (typeof byteLength !== 'number' || !isFinite(byteLength) || byteLength < 0 ||
Math.floor(byteLength) !== byteLength || byteLength > 0x0fffffff) {
throw new Error(TUPLE_BYTE_LENGTH_ERROR);
}
this.encode(byteLength * 8, false);
if (byteLength !== 0) {
this.inputActive = true;
this.inputBytesRemaining = byteLength;
}
return this;
};
TupleHash.prototype._updateChunk = function (message, byteLength) {
Kmac.prototype.update.call(this, message);
this.inputBytesRemaining -= byteLength;
if (this.inputBytesRemaining === 0) {
this.inputActive = false;
}
return this;
};
TupleHash.prototype.updateChunk = function (message) {
if (!this.inputActive) {
throw new Error(TUPLE_ACTIVE_ERROR);
}
var byteLength = this.getMessageByteLength(message);
if (byteLength > this.inputBytesRemaining) {
throw new Error(TUPLE_LENGTH_ERROR);
}
return this._updateChunk(message, byteLength);
};
TupleHash.prototype.update = function (message) {
var byteLength = this.getMessageByteLength(message);
this.beginInput(byteLength);
return this._updateChunk(message, byteLength);
};
TupleHash.prototype.finalize = function () {
if (this.inputActive) {
throw new Error(TUPLE_INCOMPLETE_ERROR);
}
return Kmac.prototype.finalize.call(this);
};
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,
b34, b35, b36, b37, b38, b39, b40, b41, b42, b43, b44, b45, b46, b47, b48, b49;
for (n = 0; n < 48; n += 2) {
c0 = s[0] ^ s[10] ^ s[20] ^ s[30] ^ s[40];
c1 = s[1] ^ s[11] ^ s[21] ^ s[31] ^ s[41];
c2 = s[2] ^ s[12] ^ s[22] ^ s[32] ^ s[42];
c3 = s[3] ^ s[13] ^ s[23] ^ s[33] ^ s[43];
c4 = s[4] ^ s[14] ^ s[24] ^ s[34] ^ s[44];
c5 = s[5] ^ s[15] ^ s[25] ^ s[35] ^ s[45];
c6 = s[6] ^ s[16] ^ s[26] ^ s[36] ^ s[46];
c7 = s[7] ^ s[17] ^ s[27] ^ s[37] ^ s[47];
c8 = s[8] ^ s[18] ^ s[28] ^ s[38] ^ s[48];
c9 = s[9] ^ s[19] ^ s[29] ^ s[39] ^ s[49];
h = c8 ^ ((c2 << 1) | (c3 >>> 31));
l = c9 ^ ((c3 << 1) | (c2 >>> 31));
s[0] ^= h;
s[1] ^= l;
s[10] ^= h;
s[11] ^= l;
s[20] ^= h;
s[21] ^= l;
s[30] ^= h;
s[31] ^= l;
s[40] ^= h;
s[41] ^= l;
h = c0 ^ ((c4 << 1) | (c5 >>> 31));
l = c1 ^ ((c5 << 1) | (c4 >>> 31));
s[2] ^= h;
s[3] ^= l;
s[12] ^= h;
s[13] ^= l;
s[22] ^= h;
s[23] ^= l;
s[32] ^= h;
s[33] ^= l;
s[42] ^= h;
s[43] ^= l;
h = c2 ^ ((c6 << 1) | (c7 >>> 31));
l = c3 ^ ((c7 << 1) | (c6 >>> 31));
s[4] ^= h;
s[5] ^= l;
s[14] ^= h;
s[15] ^= l;
s[24] ^= h;
s[25] ^= l;
s[34] ^= h;
s[35] ^= l;
s[44] ^= h;
s[45] ^= l;
h = c4 ^ ((c8 << 1) | (c9 >>> 31));
l = c5 ^ ((c9 << 1) | (c8 >>> 31));
s[6] ^= h;
s[7] ^= l;
s[16] ^= h;
s[17] ^= l;
s[26] ^= h;
s[27] ^= l;
s[36] ^= h;
s[37] ^= l;
s[46] ^= h;
s[47] ^= l;
h = c6 ^ ((c0 << 1) | (c1 >>> 31));
l = c7 ^ ((c1 << 1) | (c0 >>> 31));
s[8] ^= h;
s[9] ^= l;
s[18] ^= h;
s[19] ^= l;
s[28] ^= h;
s[29] ^= l;
s[38] ^= h;
s[39] ^= l;
s[48] ^= h;
s[49] ^= l;
b0 = s[0];
b1 = s[1];
b32 = (s[11] << 4) | (s[10] >>> 28);
b33 = (s[10] << 4) | (s[11] >>> 28);
b14 = (s[20] << 3) | (s[21] >>> 29);
b15 = (s[21] << 3) | (s[20] >>> 29);
b46 = (s[31] << 9) | (s[30] >>> 23);
b47 = (s[30] << 9) | (s[31] >>> 23);
b28 = (s[40] << 18) | (s[41] >>> 14);
b29 = (s[41] << 18) | (s[40] >>> 14);
b20 = (s[2] << 1) | (s[3] >>> 31);
b21 = (s[3] << 1) | (s[2] >>> 31);
b2 = (s[13] << 12) | (s[12] >>> 20);
b3 = (s[12] << 12) | (s[13] >>> 20);
b34 = (s[22] << 10) | (s[23] >>> 22);
b35 = (s[23] << 10) | (s[22] >>> 22);
b16 = (s[33] << 13) | (s[32] >>> 19);
b17 = (s[32] << 13) | (s[33] >>> 19);
b48 = (s[42] << 2) | (s[43] >>> 30);
b49 = (s[43] << 2) | (s[42] >>> 30);
b40 = (s[5] << 30) | (s[4] >>> 2);
b41 = (s[4] << 30) | (s[5] >>> 2);
b22 = (s[14] << 6) | (s[15] >>> 26);
b23 = (s[15] << 6) | (s[14] >>> 26);
b4 = (s[25] << 11) | (s[24] >>> 21);
b5 = (s[24] << 11) | (s[25] >>> 21);
b36 = (s[34] << 15) | (s[35] >>> 17);
b37 = (s[35] << 15) | (s[34] >>> 17);
b18 = (s[45] << 29) | (s[44] >>> 3);
b19 = (s[44] << 29) | (s[45] >>> 3);
b10 = (s[6] << 28) | (s[7] >>> 4);
b11 = (s[7] << 28) | (s[6] >>> 4);
b42 = (s[17] << 23) | (s[16] >>> 9);
b43 = (s[16] << 23) | (s[17] >>> 9);
b24 = (s[26] << 25) | (s[27] >>> 7);
b25 = (s[27] << 25) | (s[26] >>> 7);
b6 = (s[36] << 21) | (s[37] >>> 11);
b7 = (s[37] << 21) | (s[36] >>> 11);
b38 = (s[47] << 24) | (s[46] >>> 8);
b39 = (s[46] << 24) | (s[47] >>> 8);
b30 = (s[8] << 27) | (s[9] >>> 5);
b31 = (s[9] << 27) | (s[8] >>> 5);
b12 = (s[18] << 20) | (s[19] >>> 12);
b13 = (s[19] << 20) | (s[18] >>> 12);
b44 = (s[29] << 7) | (s[28] >>> 25);
b45 = (s[28] << 7) | (s[29] >>> 25);
b26 = (s[38] << 8) | (s[39] >>> 24);
b27 = (s[39] << 8) | (s[38] >>> 24);
b8 = (s[48] << 14) | (s[49] >>> 18);
b9 = (s[49] << 14) | (s[48] >>> 18);
s[0] = b0 ^ (~b2 & b4);
s[1] = b1 ^ (~b3 & b5);
s[10] = b10 ^ (~b12 & b14);
s[11] = b11 ^ (~b13 & b15);
s[20] = b20 ^ (~b22 & b24);
s[21] = b21 ^ (~b23 & b25);
s[30] = b30 ^ (~b32 & b34);
s[31] = b31 ^ (~b33 & b35);
s[40] = b40 ^ (~b42 & b44);
s[41] = b41 ^ (~b43 & b45);
s[2] = b2 ^ (~b4 & b6);
s[3] = b3 ^ (~b5 & b7);
s[12] = b12 ^ (~b14 & b16);
s[13] = b13 ^ (~b15 & b17);
s[22] = b22 ^ (~b24 & b26);
s[23] = b23 ^ (~b25 & b27);
s[32] = b32 ^ (~b34 & b36);
s[33] = b33 ^ (~b35 & b37);
s[42] = b42 ^ (~b44 & b46);
s[43] = b43 ^ (~b45 & b47);
s[4] = b4 ^ (~b6 & b8);
s[5] = b5 ^ (~b7 & b9);
s[14] = b14 ^ (~b16 & b18);
s[15] = b15 ^ (~b17 & b19);
s[24] = b24 ^ (~b26 & b28);
s[25] = b25 ^ (~b27 & b29);
s[34] = b34 ^ (~b36 & b38);
s[35] = b35 ^ (~b37 & b39);
s[44] = b44 ^ (~b46 & b48);
s[45] = b45 ^ (~b47 & b49);
s[6] = b6 ^ (~b8 & b0);
s[7] = b7 ^ (~b9 & b1);
s[16] = b16 ^ (~b18 & b10);
s[17] = b17 ^ (~b19 & b11);
s[26] = b26 ^ (~b28 & b20);
s[27] = b27 ^ (~b29 & b21);
s[36] = b36 ^ (~b38 & b30);
s[37] = b37 ^ (~b39 & b31);
s[46] = b46 ^ (~b48 & b40);
s[47] = b47 ^ (~b49 & b41);
s[8] = b8 ^ (~b0 & b2);
s[9] = b9 ^ (~b1 & b3);
s[18] = b18 ^ (~b10 & b12);
s[19] = b19 ^ (~b11 & b13);
s[28] = b28 ^ (~b20 & b22);
s[29] = b29 ^ (~b21 & b23);
s[38] = b38 ^ (~b30 & b32);
s[39] = b39 ^ (~b31 & b33);
s[48] = b48 ^ (~b40 & b42);
s[49] = b49 ^ (~b41 & b43);
s[0] ^= RC[n];
s[1] ^= RC[n + 1];
}
};
if (COMMON_JS) {
module.exports = methods;
} else {
for (i = 0; i < methodNames.length; ++i) {
root[methodNames[i]] = methods[methodNames[i]];
}
}
})();
} (sha3$1));
var sha3Exports = sha3$1.exports;
var sha3 = /*@__PURE__*/getDefaultExportFromCjs(sha3Exports);
const {
sha3_224,
sha3_256,
sha3_384,
sha3_512,
keccak_224,
keccak_256,
keccak_384,
keccak_512,
keccak224,
keccak256,
keccak384,
keccak512,
shake_128,
shake_256,
shake128,
shake256,
cshake_128,
cshake_256,
cshake128,
cshake256,
kmac_128,
kmac_256,
kmac128,
kmac256,
kmacxof_128,
kmacxof_256,
kmacxof128,
kmacxof256,
tuplehash_128,
tuplehash_256,
tuplehash128,
tuplehash256,
tuplehashxof_128,
tuplehashxof_256,
tuplehashxof128,
tuplehashxof256
} = sha3;
export { cshake128, cshake256, cshake_128, cshake_256, sha3 as default, keccak224, keccak256, keccak384, keccak512, keccak_224, keccak_256, keccak_384, keccak_512, kmac128, kmac256, kmac_128, kmac_256, kmacxof128, kmacxof256, kmacxof_128, kmacxof_256, sha3_224, sha3_256, sha3_384, sha3_512, shake128, shake256, shake_128, shake_256, tuplehash128, tuplehash256, tuplehash_128, tuplehash_256, tuplehashxof128, tuplehashxof256, tuplehashxof_128, tuplehashxof_256 };
Vendored
+102
View File
@@ -291,6 +291,96 @@ interface KmacHash {
update(key: Message, message: Message, outputBits: number, customization: Message): Hasher;
}
type TupleInput = Message[];
interface TupleHash extends Hasher {
/**
* Start a streaming tuple input with a known UTF-8/binary byte length.
*
* @param byteLength The byte length of the input that will follow through updateChunk().
*/
beginInput(byteLength: number): TupleHash;
/**
* Absorb part of the active streaming tuple input.
*
* @param message The next message chunk.
*/
updateChunk(message: Message): TupleHash;
/**
* Append one complete tuple input string.
* Equivalent to beginInput(byteLength) followed by updateChunk(message).
*
* @param message The input string to encode and absorb.
*/
update(message: Message): TupleHash;
}
interface TupleHashMethod {
/**
* Hash a tuple and return hex string.
*
* @param inputs The tuple of input strings.
* @param outputBits The length of output.
* @param customization The customization string.
*/
(inputs: TupleInput, outputBits: number, customization: Message): string;
/**
* Hash a tuple and return hex string.
*
* @param inputs The tuple of input strings.
* @param outputBits The length of output.
* @param customization The customization string.
*/
hex(inputs: TupleInput, outputBits: number, customization: Message): string;
/**
* Hash a tuple and return ArrayBuffer.
*
* @param inputs The tuple of input strings.
* @param outputBits The length of output.
* @param customization The customization string.
*/
arrayBuffer(inputs: TupleInput, outputBits: number, customization: Message): ArrayBuffer;
/**
* Hash a tuple and return integer array.
*
* @param inputs The tuple of input strings.
* @param outputBits The length of output.
* @param customization The customization string.
*/
digest(inputs: TupleInput, outputBits: number, customization: Message): number[];
/**
* Hash a tuple and return integer array.
*
* @param inputs The tuple of input strings.
* @param outputBits The length of output.
* @param customization The customization string.
*/
array(inputs: TupleInput, outputBits: number, customization: Message): number[];
/**
* Create a TupleHash object.
*
* @param outputBits The length of output.
* @param customization The customization string.
*/
create(outputBits: number, customization: Message): TupleHash;
/**
* Create a TupleHash object and absorb the given tuple inputs.
*
* @param inputs The tuple of input strings.
* @param outputBits The length of output.
* @param customization The customization string.
*/
update(inputs: TupleInput, outputBits: number, customization: Message): TupleHash;
}
export var sha3_512: Hash;
export var sha3_384: Hash;
export var sha3_256: Hash;
@@ -315,3 +405,15 @@ export var kmac_128: KmacHash;
export var kmac_256: KmacHash;
export var kmac128: KmacHash;
export var kmac256: KmacHash;
export var kmacxof_128: KmacHash;
export var kmacxof_256: KmacHash;
export var kmacxof128: KmacHash;
export var kmacxof256: KmacHash;
export var tuplehash_128: TupleHashMethod;
export var tuplehash_256: TupleHashMethod;
export var tuplehash128: TupleHashMethod;
export var tuplehash256: TupleHashMethod;
export var tuplehashxof_128: TupleHashMethod;
export var tuplehashxof_256: TupleHashMethod;
export var tuplehashxof128: TupleHashMethod;
export var tuplehashxof256: TupleHashMethod;
+2246 -635
View File
File diff suppressed because it is too large Load Diff
+23 -4
View File
@@ -1,12 +1,30 @@
{
"name": "js-sha3",
"version": "0.9.3",
"description": "A simple SHA-3 / Keccak / Shake hash function for JavaScript supports UTF-8 encoding.",
"version": "0.12.0",
"description": "A simple SHA-3 / Keccak / SHAKE / cSHAKE / KMAC / TupleHash hash function for JavaScript supports UTF-8 encoding.",
"main": "src/sha3.js",
"module": "build/sha3.mjs",
"exports": {
".": {
"types": "./index.d.ts",
"import": "./build/sha3.mjs",
"require": "./src/sha3.js",
"default": "./src/sha3.js"
},
"./src/sha3.js": "./src/sha3.js",
"./build/sha3.min.js": "./build/sha3.min.js",
"./build/sha3.mjs": "./build/sha3.mjs",
"./build/sha3.min.mjs": "./build/sha3.min.mjs",
"./package.json": "./package.json"
},
"types": "./index.d.ts",
"devDependencies": {
"@rollup/plugin-commonjs": "^28.0.5",
"@rollup/plugin-terser": "^1.0.0",
"expect.js": "~0.3.1",
"mocha": "~10.2.0",
"mocha": "^11.7.6",
"nyc": "^15.1.0",
"rollup": "^4.43.0",
"tiny-worker": "^2.3.0",
"uglify-js": "^3.1.9"
},
@@ -14,7 +32,7 @@
"test": "nyc mocha tests/node-test.js",
"report": "nyc --reporter=html --reporter=text mocha tests/node-test.js",
"coveralls": "nyc report --reporter=text-lcov | coveralls",
"build": "uglifyjs src/sha3.js -c -m --comments --output build/sha3.min.js"
"build": "rollup -c && uglifyjs src/sha3.js -c -m --comments --output build/sha3.min.js"
},
"repository": {
"type": "git",
@@ -26,6 +44,7 @@
"shake",
"cshake",
"kmac",
"tuplehash",
"hash",
"encryption",
"cryptography",
+23
View File
@@ -0,0 +1,23 @@
import commonjs from '@rollup/plugin-commonjs';
import terser from '@rollup/plugin-terser';
export default [
{
input: 'src/sha3.mjs',
output: {
file: 'build/sha3.mjs',
format: 'es'
},
plugins: [commonjs({
strictRequires: false
})]
},
{
input: 'build/sha3.mjs',
output: {
file: 'build/sha3.min.mjs',
format: 'es'
},
plugins: [terser()]
}
];
+141 -14
View File
@@ -1,9 +1,9 @@
/**
* [js-sha3]{@link https://github.com/emn178/js-sha3}
*
* @version 0.9.3
* @version 0.12.0
* @author Chen, Yi-Cyuan [emn178@gmail.com]
* @copyright Chen, Yi-Cyuan 2015-2023
* @copyright Chen, Yi-Cyuan 2015-2026
* @license MIT
*/
/*jslint bitwise: true */
@@ -12,6 +12,10 @@
var INPUT_ERROR = 'input is invalid type';
var FINALIZE_ERROR = 'finalize already called';
var TUPLE_ACTIVE_ERROR = 'no active tuple input';
var TUPLE_INCOMPLETE_ERROR = 'tuple input is incomplete';
var TUPLE_LENGTH_ERROR = 'tuple input exceeds declared length';
var TUPLE_BYTE_LENGTH_ERROR = 'tuple input byte length is invalid';
var WINDOW = typeof window === 'object';
var root = WINDOW ? window : {};
if (root.JS_SHA3_NO_WINDOW) {
@@ -107,9 +111,15 @@
};
};
var createKmacOutputMethod = function (bits, padding, outputType) {
var createKmacOutputMethod = function (bits, padding, xof, outputType) {
return function (key, message, outputBits, s) {
return methods['kmac' + bits].update(key, message, outputBits, s)[outputType]();
return methods[(xof ? 'kmacxof' : 'kmac') + bits].update(key, message, outputBits, s)[outputType]();
};
};
var createTupleHashOutputMethod = function (bits, padding, xof, outputType) {
return function (inputs, outputBits, s) {
return methods[(xof ? 'tuplehashxof' : 'tuplehash') + bits].update(inputs, outputBits, s)[outputType]();
};
};
@@ -159,16 +169,39 @@
return createOutputMethods(method, createCshakeOutputMethod, bits, padding);
};
var createKmacMethod = function (bits, padding) {
var createKmacMethod = function (bits, padding, xof) {
var w = CSHAKE_BYTEPAD[bits];
var method = createKmacOutputMethod(bits, padding, 'hex');
var method = createKmacOutputMethod(bits, padding, xof, 'hex');
method.create = function (key, outputBits, s) {
return new Kmac(bits, padding, outputBits).bytepad(['KMAC', s], w).bytepad([key], w);
return new Kmac(bits, padding, outputBits, xof).bytepad(['KMAC', s], w).bytepad([key], w);
};
method.update = function (key, message, outputBits, s) {
return method.create(key, outputBits, s).update(message);
};
return createOutputMethods(method, createKmacOutputMethod, bits, padding);
return createOutputMethods(method, function (b, p, outputType) {
return createKmacOutputMethod(b, p, xof, outputType);
}, bits, padding);
};
var createTupleHashMethod = function (bits, padding, xof) {
var w = CSHAKE_BYTEPAD[bits];
var method = createTupleHashOutputMethod(bits, padding, xof, 'hex');
method.create = function (outputBits, s) {
return new TupleHash(bits, padding, outputBits, xof).bytepad(['TupleHash', s], w);
};
method.update = function (inputs, outputBits, s) {
if (!isArray(inputs)) {
throw new Error(INPUT_ERROR);
}
var hash = method.create(outputBits, s);
for (var i = 0; i < inputs.length; ++i) {
hash.update(inputs[i]);
}
return hash;
};
return createOutputMethods(method, function (b, p, outputType) {
return createTupleHashOutputMethod(b, p, xof, outputType);
}, bits, padding);
};
var algorithms = [
@@ -176,7 +209,18 @@
{ name: 'sha3', padding: PADDING, bits: BITS, createMethod: createMethod },
{ name: 'shake', padding: SHAKE_PADDING, bits: SHAKE_BITS, createMethod: createShakeMethod },
{ name: 'cshake', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: createCshakeMethod },
{ name: 'kmac', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: createKmacMethod }
{ name: 'kmac', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) {
return createKmacMethod(bits, padding, false);
}},
{ name: 'kmacxof', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) {
return createKmacMethod(bits, padding, true);
}},
{ name: 'tuplehash', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) {
return createTupleHashMethod(bits, padding, false);
}},
{ name: 'tuplehashxof', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) {
return createTupleHashMethod(bits, padding, true);
}}
];
var methods = {}, methodNames = [];
@@ -290,7 +334,7 @@
} else {
bytes.unshift(n);
}
this.update(bytes);
Keccak.prototype.update.call(this, bytes);
return bytes.length;
};
@@ -317,7 +361,7 @@
bytes = length;
}
bytes += this.encode(bytes * 8);
this.update(str);
Keccak.prototype.update.call(this, str);
return bytes;
};
@@ -329,7 +373,7 @@
var paddingBytes = (w - bytes % w) % w;
var zeros = [];
zeros.length = paddingBytes;
this.update(zeros);
Keccak.prototype.update.call(this, zeros);
return this;
};
@@ -451,17 +495,100 @@
return array;
};
function Kmac(bits, padding, outputBits) {
function Kmac(bits, padding, outputBits, xof) {
Keccak.call(this, bits, padding, outputBits);
this.xof = xof;
}
Kmac.prototype = new Keccak();
Kmac.prototype.finalize = function () {
this.encode(this.outputBits, true);
if (!this.finalized) {
this.encode(this.xof ? 0 : this.outputBits, true);
}
return Keccak.prototype.finalize.call(this);
};
function TupleHash(bits, padding, outputBits, xof) {
Kmac.call(this, bits, padding, outputBits, xof);
this.inputActive = false;
this.inputBytesRemaining = 0;
}
TupleHash.prototype = new Kmac();
TupleHash.prototype.getMessageByteLength = function (message) {
var result = formatMessage(message);
message = result[0];
if (!result[1]) {
return message.length;
}
var bytes = 0;
for (var i = 0; i < message.length; ++i) {
var code = message.charCodeAt(i);
if (code < 0x80) {
bytes += 1;
} else if (code < 0x800) {
bytes += 2;
} else if (code < 0xd800 || code >= 0xe000) {
bytes += 3;
} else {
++i;
bytes += 4;
}
}
return bytes;
};
TupleHash.prototype.beginInput = function (byteLength) {
if (this.inputActive) {
throw new Error(TUPLE_INCOMPLETE_ERROR);
}
if (typeof byteLength !== 'number' || !isFinite(byteLength) || byteLength < 0 ||
Math.floor(byteLength) !== byteLength || byteLength > 0x0fffffff) {
throw new Error(TUPLE_BYTE_LENGTH_ERROR);
}
this.encode(byteLength * 8, false);
if (byteLength !== 0) {
this.inputActive = true;
this.inputBytesRemaining = byteLength;
}
return this;
};
TupleHash.prototype._updateChunk = function (message, byteLength) {
Kmac.prototype.update.call(this, message);
this.inputBytesRemaining -= byteLength;
if (this.inputBytesRemaining === 0) {
this.inputActive = false;
}
return this;
};
TupleHash.prototype.updateChunk = function (message) {
if (!this.inputActive) {
throw new Error(TUPLE_ACTIVE_ERROR);
}
var byteLength = this.getMessageByteLength(message);
if (byteLength > this.inputBytesRemaining) {
throw new Error(TUPLE_LENGTH_ERROR);
}
return this._updateChunk(message, byteLength);
};
TupleHash.prototype.update = function (message) {
var byteLength = this.getMessageByteLength(message);
this.beginInput(byteLength);
return this._updateChunk(message, byteLength);
};
TupleHash.prototype.finalize = function () {
if (this.inputActive) {
throw new Error(TUPLE_INCOMPLETE_ERROR);
}
return Kmac.prototype.finalize.call(this);
};
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,
+47
View File
@@ -0,0 +1,47 @@
import sha3 from './sha3.js';
export const {
sha3_224,
sha3_256,
sha3_384,
sha3_512,
keccak_224,
keccak_256,
keccak_384,
keccak_512,
keccak224,
keccak256,
keccak384,
keccak512,
shake_128,
shake_256,
shake128,
shake256,
cshake_128,
cshake_256,
cshake128,
cshake256,
kmac_128,
kmac_256,
kmac128,
kmac256,
kmacxof_128,
kmacxof_256,
kmacxof128,
kmacxof256,
tuplehash_128,
tuplehash_256,
tuplehash128,
tuplehash256,
tuplehashxof_128,
tuplehashxof_256,
tuplehashxof128,
tuplehashxof256
} = sha3;
export default sha3;
+19
View File
@@ -16,6 +16,12 @@ function unset() {
shake256 = null;
kmac128 = null;
kmac256 = null;
kmacxof128 = null;
kmacxof256 = null;
tuplehash128 = null;
tuplehash256 = null;
tuplehashxof128 = null;
tuplehashxof256 = null;
BUFFER = undefined;
JS_SHA3_NO_WINDOW = undefined;
JS_SHA3_NO_NODE_JS = undefined;
@@ -41,6 +47,12 @@ function requireToGlobal() {
cshake256 = sha3.cshake256;
kmac128 = sha3.kmac128;
kmac256 = sha3.kmac256;
kmacxof128 = sha3.kmacxof128;
kmacxof256 = sha3.kmacxof256;
tuplehash128 = sha3.tuplehash128;
tuplehash256 = sha3.tuplehash256;
tuplehashxof128 = sha3.tuplehashxof128;
tuplehashxof256 = sha3.tuplehashxof256;
}
function runCommonJsTest() {
@@ -57,6 +69,7 @@ function runWindowTest(extra) {
require('./test-shake.js');
require('./test-cshake.js');
require('./test-kmac.js');
require('./test-tuplehash.js');
}
unset();
}
@@ -108,6 +121,12 @@ define = function (func) {
cshake256 = sha3.cshake256;
kmac128 = sha3.kmac128;
kmac256 = sha3.kmac256;
kmacxof128 = sha3.kmacxof128;
kmacxof256 = sha3.kmacxof256;
tuplehash128 = sha3.tuplehash128;
tuplehash256 = sha3.tuplehash256;
tuplehashxof128 = sha3.tuplehashxof128;
tuplehashxof256 = sha3.tuplehashxof256;
require('./test.js');
};
define.amd = true;
+98 -59
View File
@@ -1,26 +1,9 @@
(function (kmac256, kmac128) {
(function (kmac256, kmac128, kmacxof256, kmacxof128) {
// http://csrc.nist.gov/groups/ST/toolkit/documents/Examples/KMAC_samples.pdf
var testCases = [
{
name: 'kmac128',
method: kmac128,
cases: [
{
input: [0x00, 0x01, 0x02, 0x03],
bits: 256,
key: [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F],
s: '',
output: 'e5780b0d3ea6f7d3a429c5706aa43a00fadbd7d49628839e3187243f456ee14e'
},
{
input: [0x00, 0x01, 0x02, 0x03],
bits: 256,
key: [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F],
s: 'My Tagged Application',
output: '3b1fba963cd8b0b59e8c1a6d71888b7143651af8ba0a7070c0979e2811324aa5'
},
{
input: [
// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/KMACXOF_samples.pdf
var key = [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F];
var shortInput = [0x00, 0x01, 0x02, 0x03];
var longInput = [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
@@ -34,9 +17,31 @@
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7
],
];
var testCases = [
{
name: 'kmac128',
method: kmac128,
cases: [
{
input: shortInput,
bits: 256,
key: [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F],
key: key,
s: '',
output: 'e5780b0d3ea6f7d3a429c5706aa43a00fadbd7d49628839e3187243f456ee14e'
},
{
input: shortInput,
bits: 256,
key: key,
s: 'My Tagged Application',
output: '3b1fba963cd8b0b59e8c1a6d71888b7143651af8ba0a7070c0979e2811324aa5'
},
{
input: longInput,
bits: 256,
key: key,
s: 'My Tagged Application',
output: '1f5b4e6cca02209e0dcb5ca635b89a15e271ecc760071dfd805faa38f9729230'
}
@@ -47,51 +52,23 @@
method: kmac256,
cases: [
{
input: [0x00, 0x01, 0x02, 0x03],
input: shortInput,
bits: 512,
key: [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F],
key: key,
s: 'My Tagged Application',
output: '20c570c31346f703c9ac36c61c03cb64c3970d0cfc787e9b79599d273a68d2f7f69d4cc3de9d104a351689f27cf6f5951f0103f33f4f24871024d9c27773a8dd'
},
{
input: [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7
],
input: longInput,
bits: 512,
key: [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F],
key: key,
s: '',
output: '75358cf39e41494e949707927cee0af20a3ff553904c86b08f21cc414bcfd691589d27cf5e15369cbbff8b9a4c2eb17800855d0235ff635da82533ec6b759b69'
},
{
input: [
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F,
0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F,
0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F,
0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F,
0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F,
0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F,
0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F,
0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF,
0xB0, 0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF,
0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7
],
input: longInput,
bits: 512,
key: [0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F],
key: key,
s: 'My Tagged Application',
output: 'b58618f71f92e1d56c1b8c55ddd7cd188b97b4ca4d99831eb2699a837da2e4d970fbacfde50033aea585f1a2708510c32d07880801bd182898fe476876fc8965'
},
@@ -103,6 +80,60 @@
output: '031801b0b50ebeef772fbe7a279bc144'
}
]
},
{
name: 'kmacxof128',
method: kmacxof128,
cases: [
{
input: shortInput,
bits: 256,
key: key,
s: '',
output: 'cd83740bbd92ccc8cf032b1481a0f4460e7ca9dd12b08a0c4031178bacd6ec35'
},
{
input: shortInput,
bits: 256,
key: key,
s: 'My Tagged Application',
output: '31a44527b4ed9f5c6101d11de6d26f0620aa5c341def41299657fe9df1a3b16c'
},
{
input: longInput,
bits: 256,
key: key,
s: 'My Tagged Application',
output: '47026c7cd793084aa0283c253ef658490c0db61438b8326fe9bddf281b83ae0f'
}
]
},
{
name: 'kmacxof256',
method: kmacxof256,
cases: [
{
input: shortInput,
bits: 512,
key: key,
s: 'My Tagged Application',
output: '1755133f1534752aad0748f2c706fb5c784512cab835cd15676b16c0c6647fa96faa7af634a0bf8ff6df39374fa00fad9a39e322a7c92065a64eb1fb0801eb2b'
},
{
input: longInput,
bits: 512,
key: key,
s: '',
output: 'ff7b171f1e8a2b24683eed37830ee797538ba8dc563f6da1e667391a75edc02ca633079f81ce12a25f45615ec89972031d18337331d24ceb8f8ca8e6a19fd98b'
},
{
input: longInput,
bits: 512,
key: key,
s: 'My Tagged Application',
output: 'd5be731c954ed7732846bb59dbe3a8e30f83e77a4bff4459f2f1c2b4ecebb8ce67ba01c62e8ab8578d2d499bd1bb276768781190020a306a97de281dcc30305d'
}
]
}
];
@@ -115,4 +146,12 @@
});
});
});
})(kmac256, kmac128);
describe('#kmacxof aliases', function () {
it('should export identical aliases', function () {
var sha3 = require('../src/sha3.js');
expect(sha3.kmacxof128).to.be(sha3.kmacxof_128);
expect(sha3.kmacxof256).to.be(sha3.kmacxof_256);
});
});
})(kmac256, kmac128, kmacxof256, kmacxof128);
+262
View File
@@ -0,0 +1,262 @@
(function (tuplehash256, tuplehash128, tuplehashxof256, tuplehashxof128, kmac128) {
// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/TupleHash_samples.pdf
// https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/TupleHashXOF_samples.pdf
var t1 = [0x00, 0x01, 0x02];
var t2 = [0x10, 0x11, 0x12, 0x13, 0x14, 0x15];
var t3 = [0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28];
var testCases = [
{
name: 'tuplehash128',
method: tuplehash128,
cases: [
{
inputs: [t1, t2],
bits: 256,
s: '',
output: 'c5d8786c1afb9b82111ab34b65b2c0048fa64e6d48e263264ce1707d3ffc8ed1'
},
{
inputs: [t1, t2],
bits: 256,
s: 'My Tuple App',
output: '75cdb20ff4db1154e841d758e24160c54bae86eb8c13e7f5f40eb35588e96dfb'
},
{
inputs: [t1, t2, t3],
bits: 256,
s: 'My Tuple App',
output: 'e60f202c89a2631eda8d4c588ca5fd07f39e5151998deccf973adb3804bb6e84'
}
]
},
{
name: 'tuplehash256',
method: tuplehash256,
cases: [
{
inputs: [t1, t2],
bits: 512,
s: '',
output: 'cfb7058caca5e668f81a12a20a2195ce97a925f1dba3e7449a56f82201ec607311ac2696b1ab5ea2352df1423bde7bd4bb78c9aed1a853c78672f9eb23bbe194'
},
{
inputs: [t1, t2],
bits: 512,
s: 'My Tuple App',
output: '147c2191d5ed7efd98dbd96d7ab5a11692576f5fe2a5065f3e33de6bba9f3aa1c4e9a068a289c61c95aab30aee1e410b0b607de3620e24a4e3bf9852a1d4367e'
},
{
inputs: [t1, t2, t3],
bits: 512,
s: 'My Tuple App',
output: '45000be63f9b6bfd89f54717670f69a9bc763591a4f05c50d68891a744bcc6e7d6d5b5e82c018da999ed35b0bb49c9678e526abd8e85c13ed254021db9e790ce'
}
]
},
{
name: 'tuplehashxof128',
method: tuplehashxof128,
cases: [
{
inputs: [t1, t2],
bits: 256,
s: '',
output: '2f103cd7c32320353495c68de1a8129245c6325f6f2a3d608d92179c96e68488'
},
{
inputs: [t1, t2],
bits: 256,
s: 'My Tuple App',
output: '3fc8ad69453128292859a18b6c67d7ad85f01b32815e22ce839c49ec374e9b9a'
},
{
inputs: [t1, t2, t3],
bits: 256,
s: 'My Tuple App',
output: '900fe16cad098d28e74d632ed852f99daab7f7df4d99e775657885b4bf76d6f8'
}
]
},
{
name: 'tuplehashxof256',
method: tuplehashxof256,
cases: [
{
inputs: [t1, t2],
bits: 512,
s: '',
output: '03ded4610ed6450a1e3f8bc44951d14fbc384ab0efe57b000df6b6df5aae7cd568e77377daf13f37ec75cf5fc598b6841d51dd207c991cd45d210ba60ac52eb9'
},
{
inputs: [t1, t2],
bits: 512,
s: 'My Tuple App',
output: '6483cb3c9952eb20e830af4785851fc597ee3bf93bb7602c0ef6a65d741aeca7e63c3b128981aa05c6d27438c79d2754bb1b7191f125d6620fca12ce658b2442'
},
{
inputs: [t1, t2, t3],
bits: 512,
s: 'My Tuple App',
output: '0c59b11464f2336c34663ed51b2b950bec743610856f36c28d1d088d8a2446284dd09830a6a178dc752376199fae935d86cfdee5913d4922dfd369b66a53c897'
}
]
}
];
testCases.forEach(function (testCase) {
describe('#' + testCase.name, function () {
testCase.cases.forEach(function (c) {
it('should match NIST sample vector', function () {
expect(testCase.method(c.inputs, c.bits, c.s)).to.be(c.output);
});
});
});
});
describe('#tuplehash API', function () {
it('should treat empty tuple and empty inputs as valid', function () {
var emptyTuple = tuplehash128([], 256, '');
var oneEmpty = tuplehash128([''], 256, '');
var twoEmpty = tuplehash128(['', ''], 256, '');
expect(emptyTuple).to.not.be(oneEmpty);
expect(oneEmpty).to.not.be(twoEmpty);
expect(twoEmpty).to.not.be(tuplehash128(['', '', ''], 256, ''));
expect(tuplehash128.create(256, '').update('').update(t1).hex()).to.be(tuplehash128(['', t1], 256, ''));
});
it('should distinguish tuple boundaries', function () {
expect(tuplehash128(['abc', 'd'], 256, '')).to.not.be(tuplehash128(['ab', 'cd'], 256, ''));
});
it('should match instance update and method update with one-shot', function () {
var expected = tuplehash128(['abc', 'd'], 256, 'cache');
var incremental = tuplehash128.create(256, 'cache').update('abc').update('d').hex();
var methodUpdate = tuplehash128.update(['abc'], 256, 'cache').update('d').hex();
expect(incremental).to.be(expected);
expect(methodUpdate).to.be(expected);
expect(tuplehash128.update(['abc', 'd'], 256, 'cache').hex()).to.be(expected);
});
it('should stream binary messages in irregular chunks', function () {
var bytes = [];
for (var i = 0; i < 200; ++i) {
bytes.push(i & 0xff);
}
var expected = tuplehash128([bytes, t1], 256, '');
var hash = tuplehash128.create(256, '');
hash.beginInput(bytes.length);
hash.updateChunk(bytes.slice(0, 1));
hash.updateChunk(bytes.slice(1, 17));
hash.updateChunk(bytes.slice(17, 168));
hash.updateChunk(bytes.slice(168));
hash.beginInput(t1.length);
hash.updateChunk(t1);
expect(hash.hex()).to.be(expected);
});
it('should stream ArrayBuffer and Uint8Array views', function () {
var expected = tuplehash128([t1, t2], 256, '');
var buffer = new Uint8Array(t1).buffer;
var view = new Uint8Array(new Uint8Array(t2).buffer, 0, t2.length);
var hash = tuplehash128.create(256, '');
hash.beginInput(t1.length).updateChunk(buffer);
hash.beginInput(t2.length).updateChunk(view);
expect(hash.hex()).to.be(expected);
});
it('should support zero-length streaming input', function () {
var expected = tuplehash128(['', t1], 256, '');
var hash = tuplehash128.create(256, '');
hash.beginInput(0);
hash.beginInput(t1.length).updateChunk(t1);
expect(hash.hex()).to.be(expected);
});
it('should reject invalid streaming usage', function () {
var hash = tuplehash128.create(256, '');
expect(function () { hash.updateChunk(t1); }).to.throwError(/no active tuple input/);
hash.beginInput(2);
expect(function () { hash.updateChunk([1, 2, 3]); }).to.throwError(/exceeds declared length/);
expect(function () { hash.beginInput(1); }).to.throwError(/incomplete/);
expect(function () { hash.update(t1); }).to.throwError(/incomplete/);
expect(function () { hash.hex(); }).to.throwError(/incomplete/);
hash.updateChunk([1]);
expect(function () { hash.hex(); }).to.throwError(/incomplete/);
});
it('should reject invalid beginInput lengths', function () {
var hash = tuplehash128.create(256, '');
expect(function () { hash.beginInput(-1); }).to.throwError(/byte length is invalid/);
expect(function () { hash.beginInput(1.5); }).to.throwError(/byte length is invalid/);
expect(function () { hash.beginInput(NaN); }).to.throwError(/byte length is invalid/);
expect(function () { hash.beginInput(0x20000000); }).to.throwError(/byte length is invalid/);
});
it('should allow repeated output representations', function () {
var hash = tuplehash128.create(256, '').update(t1).update(t2);
var hex = hash.hex();
var array = hash.array();
var digest = hash.digest();
var buffer = hash.arrayBuffer();
expect(hash.hex()).to.be(hex);
expect(array).to.eql(digest);
expect(Array.prototype.slice.call(new Uint8Array(buffer))).to.eql(array);
expect(function () { hash.update(t1); }).to.throwError(/finalize already called/);
expect(function () { hash.updateChunk(t1); }).to.throwError(/no active tuple input/);
});
it('should require customization like KMAC', function () {
expect(function () { tuplehash128([t1], 256); }).to.throwError(/input is invalid type/);
});
it('should require inputs to be an array', function () {
expect(function () { tuplehash128('abc', 256, ''); }).to.throwError(/input is invalid type/);
expect(function () { tuplehash128.update(t1, 256, ''); }).to.throwError(/input is invalid type/);
expect(function () { tuplehash128.hex(null, 256, ''); }).to.throwError(/input is invalid type/);
expect(function () { tuplehashxof128(undefined, 256, ''); }).to.throwError(/input is invalid type/);
});
it('should export identical aliases', function () {
var sha3 = require('../src/sha3.js');
expect(sha3.tuplehash128).to.be(sha3.tuplehash_128);
expect(sha3.tuplehash256).to.be(sha3.tuplehash_256);
expect(sha3.tuplehashxof128).to.be(sha3.tuplehashxof_128);
expect(sha3.tuplehashxof256).to.be(sha3.tuplehashxof_256);
});
it('should count UTF-8 string bytes for streaming', function () {
var message = 'åbc'; // 2 + 1 + 1 = 4 UTF-8 bytes
var expected = tuplehash128([message], 256, '');
var hash = tuplehash128.create(256, '');
hash.beginInput(4).updateChunk('å').updateChunk('bc');
expect(hash.hex()).to.be(expected);
expect(message.length).to.be(3);
});
it('should count 3-byte and 4-byte UTF-8 string bytes for streaming', function () {
var message = '中\uE000\uD83D\uDE00'; // 3 + 3 + 4 = 10 UTF-8 bytes
var expected = tuplehash128([message], 256, '');
var hash = tuplehash128.create(256, '');
hash.beginInput(10).updateChunk('中').updateChunk('\uE000').updateChunk('\uD83D\uDE00');
expect(hash.hex()).to.be(expected);
});
it('should reject update and beginInput after finalize', function () {
var hash = tuplehash128.create(256, '').update([0x00]);
hash.hex();
expect(function () { hash.update([0x01]); }).to.throwError(/finalize already called/);
expect(function () { hash.beginInput(1); }).to.throwError(/finalize already called/);
});
});
describe('#kmac repeated output', function () {
it('should allow repeated output reads after finalize fix', function () {
var hash = kmac128.create([0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F], 256, '');
hash.update([0x00, 0x01, 0x02, 0x03]);
var hex = hash.hex();
expect(hash.hex()).to.be(hex);
expect(hash.array().length).to.be(32);
});
});
})(tuplehash256, tuplehash128, tuplehashxof256, tuplehashxof128, kmac128);