From a67f74cf2cebcadf6c5f0084f8c5cd332f4a69c6 Mon Sep 17 00:00:00 2001 From: Yi-Cyuan Chen Date: Fri, 7 Aug 2026 08:18:38 +0800 Subject: [PATCH] ### Added - ParallelHash128, ParallelHash256, ParallelHashXOF128, and ParallelHashXOF256 (NIST SP 800-185) --- CHANGELOG.md | 4 + README.md | 29 ++++- bower.json | 2 +- build/sha3.min.js | 4 +- build/sha3.min.mjs | 4 +- build/sha3.mjs | 135 +++++++++++++++++++- index.d.ts | 89 +++++++++++++ package.json | 5 +- src/sha3.js | 122 +++++++++++++++++- src/sha3.mjs | 11 +- tests/node-test.js | 13 ++ tests/test-parallelhash.js | 251 +++++++++++++++++++++++++++++++++++++ 12 files changed, 654 insertions(+), 15 deletions(-) create mode 100644 tests/test-parallelhash.js diff --git a/CHANGELOG.md b/CHANGELOG.md index 24172d7..138c42e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,9 @@ # Change Log +## v0.13.0 / 2026-08-07 +### Added +- ParallelHash128, ParallelHash256, ParallelHashXOF128, and ParallelHashXOF256 (NIST SP 800-185) + ## v0.12.0 / 2026-07-18 ### Added - KMACXOF128 and KMACXOF256 (NIST SP 800-185) diff --git a/README.md b/README.md index f435de9..549ce83 100644 --- a/README.md +++ b/README.md @@ -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 / cSHAKE / KMAC / TupleHash hash function for JavaScript supports UTF-8 encoding. +A simple SHA-3 / Keccak / SHAKE / cSHAKE / KMAC / TupleHash / ParallelHash hash function for JavaScript supports UTF-8 encoding. ## Notice * v0.8.0+ will throw an error if try to update hash after finalize. @@ -32,6 +32,10 @@ A simple SHA-3 / Keccak / SHAKE / cSHAKE / KMAC / TupleHash hash function for Ja [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/) +[ParallelHash128 Online](http://emn178.github.io/online-tools/parallelhash128/) +[ParallelHash256 Online](http://emn178.github.io/online-tools/parallelhash256/) +[ParallelHashXOF128 Online](http://emn178.github.io/online-tools/parallelhashxof128/) +[ParallelHashXOF256 Online](http://emn178.github.io/online-tools/parallelhashxof256/) ## Download [Compress](https://raw.github.com/emn178/js-sha3/master/build/sha3.min.js) @@ -69,6 +73,10 @@ tuplehash128(['abc', 'd'], 256, 'customization'); tuplehash256(['abc', 'd'], 512, 'customization'); tuplehashxof128(['abc', 'd'], 256, 'customization'); tuplehashxof256(['abc', 'd'], 512, 'customization'); +parallelhash128('Message to hash', 8, 256, 'customization'); +parallelhash256('Message to hash', 8, 512, 'customization'); +parallelhashxof128('Message to hash', 8, 256, 'customization'); +parallelhashxof256('Message to hash', 8, 512, 'customization'); // Support ArrayBuffer output var arrayBuffer = keccak224.arrayBuffer('Message to hash'); @@ -122,6 +130,13 @@ tupleHash.updateChunk([0x63]); tupleHash.beginInput(1); tupleHash.updateChunk([0x64]); tupleHash.hex(); + +// ParallelHash: hash one large input in fixed-size blocks. +parallelhash128('Message to hash', 8, 256, ''); +parallelhash128.create(8, 256, '') + .update('Message ') + .update('to hash') + .hex(); ``` ### Node.js If you use node.js, you should require the module first: @@ -146,7 +161,11 @@ const { tuplehash128, tuplehash256, tuplehashxof128, - tuplehashxof256 + tuplehashxof256, + parallelhash128, + parallelhash256, + parallelhashxof128, + parallelhashxof256 } = require('js-sha3'); ``` @@ -173,7 +192,11 @@ import { tuplehash128, tuplehash256, tuplehashxof128, - tuplehashxof256 + tuplehashxof256, + parallelhash128, + parallelhash256, + parallelhashxof128, + parallelhashxof256 } from 'js-sha3'; ``` diff --git a/bower.json b/bower.json index cb5c582..b9d57a9 100644 --- a/bower.json +++ b/bower.json @@ -1,6 +1,6 @@ { "name": "js-sha3", - "version": "0.12.0", + "version": "0.13.0", "main": ["src/sha3.js"], "ignore": [ "samples", diff --git a/build/sha3.min.js b/build/sha3.min.js index 97bb320..ccf471b 100644 --- a/build/sha3.min.js +++ b/build/sha3.min.js @@ -1,9 +1,9 @@ /** * [js-sha3]{@link https://github.com/emn178/js-sha3} * - * @version 0.12.0 + * @version 0.13.0 * @author Chen, Yi-Cyuan [emn178@gmail.com] * @copyright Chen, Yi-Cyuan 2015-2026 * @license MIT */ -!function(){"use strict";function t(t,e,r){this.blocks=[],this.s=[],this.padding=e,this.outputBits=r,this.reset=!0,this.finalized=!1,this.block=0,this.start=0,this.blockCount=1600-(t<<1)>>5,this.byteCount=this.blockCount<<2,this.outputBlocks=r>>5,this.extraBytes=(31&r)>>3;for(var n=0;n<50;++n)this.s[n]=0}function e(e,r,n,i){t.call(this,e,r,n),this.xof=i}function r(t,r,n,i){e.call(this,t,r,n,i),this.inputActive=!1,this.inputBytesRemaining=0}var n="input is invalid type",i="tuple input is incomplete",o="object"==typeof window,u=o?window:{};u.JS_SHA3_NO_WINDOW&&(o=!1);var a=!o&&"object"==typeof self;!u.JS_SHA3_NO_NODE_JS&&"object"==typeof process&&process.versions&&process.versions.node?u=global:a&&(u=self);for(var s=!u.JS_SHA3_NO_COMMON_JS&&"object"==typeof module&&module.exports,f="function"==typeof define&&define.amd,h=!u.JS_SHA3_NO_ARRAY_BUFFER&&"undefined"!=typeof ArrayBuffer,c="0123456789abcdef".split(""),p=[4,1024,262144,67108864],d=[0,8,16,24],l=[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],y=[224,256,384,512],g=[128,256],v=["hex","buffer","arrayBuffer","array","digest"],b={128:168,256:136},w=u.JS_SHA3_NO_NODE_JS||!Array.isArray?function(t){return"[object Array]"===Object.prototype.toString.call(t)}:Array.isArray,A=!h||!u.JS_SHA3_NO_ARRAY_BUFFER_IS_VIEW&&ArrayBuffer.isView?ArrayBuffer.isView:function(t){return"object"==typeof t&&t.buffer&&t.buffer.constructor===ArrayBuffer},B=function(t){var e=typeof t;if("string"===e)return[t,!0];if("object"!==e||null===t)throw new Error(n);if(h&&t.constructor===ArrayBuffer)return[new Uint8Array(t),!1];if(!w(t)&&!A(t))throw new Error(n);return[t,!1]},k=function(t){return 0===B(t)[0].length},_=function(t){for(var e=[],r=0;r>2]|=n<>2]|=(192|n>>6)<>2]|=(128|63&n)<=57344?(o[r>>2]|=(224|n>>12)<>2]|=(128|n>>6&63)<>2]|=(128|63&n)<>2]|=(240|n>>18)<>2]|=(128|n>>12&63)<>2]|=(128|n>>6&63)<>2]|=(128|63&n)<>2]|=t[f]<=u){for(this.start=r-u,this.block=o[s],r=0;r>=8);n>0;)o.unshift(n),n=255&(e>>=8),++i;return r?o.push(i):o.unshift(i),t.prototype.update.call(this,o),o.length},t.prototype.encodeString=function(e){var r=B(e);e=r[0];var n=r[1],i=0,o=e.length;if(n)for(var u=0;u=57344?i+=3:(a=65536+((1023&a)<<10|1023&e.charCodeAt(++u)),i+=4)}else i=o;return i+=this.encode(8*i),t.prototype.update.call(this,e),i},t.prototype.bytepad=function(e,r){for(var n=this.encode(r),i=0;i>2]|=this.padding[3&e],this.lastByteIndex===this.byteCount)for(t[0]=t[r],e=1;e>4&15]+c[15&t]+c[t>>12&15]+c[t>>8&15]+c[t>>20&15]+c[t>>16&15]+c[t>>28&15]+c[t>>24&15];u%e==0&&(r=_(r),V(r),o=0)}return i&&(t=r[o],a+=c[t>>4&15]+c[15&t],i>1&&(a+=c[t>>12&15]+c[t>>8&15]),i>2&&(a+=c[t>>20&15]+c[t>>16&15])),a},t.prototype.arrayBuffer=function(){this.finalize();var t,e=this.blockCount,r=this.s,n=this.outputBlocks,i=this.extraBytes,o=0,u=0,a=this.outputBits>>3;t=i?new ArrayBuffer(n+1<<2):new ArrayBuffer(a);for(var s=new Uint32Array(t);u>8&255,s[t+2]=e>>16&255,s[t+3]=e>>24&255;a%r==0&&(n=_(n),V(n))}return o&&(t=a<<2,e=n[u],s[t]=255&e,o>1&&(s[t+1]=e>>8&255),o>2&&(s[t+2]=e>>16&255)),s},(e.prototype=new t).finalize=function(){return this.finalized||this.encode(this.xof?0:this.outputBits,!0),t.prototype.finalize.call(this)},(r.prototype=new e).getMessageByteLength=function(t){var e=B(t);if(t=e[0],!e[1])return t.length;for(var r=0,n=0;n=57344?r+=3:(++n,r+=4)}return r},r.prototype.beginInput=function(t){if(this.inputActive)throw new Error(i);if("number"!=typeof t||!isFinite(t)||t<0||Math.floor(t)!==t||t>268435455)throw new Error("tuple input byte length is invalid");return this.encode(8*t,!1),0!==t&&(this.inputActive=!0,this.inputBytesRemaining=t),this},r.prototype._updateChunk=function(t,r){return e.prototype.update.call(this,t),this.inputBytesRemaining-=r,0===this.inputBytesRemaining&&(this.inputActive=!1),this},r.prototype.updateChunk=function(t){if(!this.inputActive)throw new Error("no active tuple input");var e=this.getMessageByteLength(t);if(e>this.inputBytesRemaining)throw new Error("tuple input exceeds declared length");return this._updateChunk(t,e)},r.prototype.update=function(t){var e=this.getMessageByteLength(t);return this.beginInput(e),this._updateChunk(t,e)},r.prototype.finalize=function(){if(this.inputActive)throw new Error(i);return e.prototype.finalize.call(this)};var V=function(t){var e,r,n,i,o,u,a,s,f,h,c,p,d,y,g,v,b,w,A,B,k,_,m,x,C,S,M,z,E,O,R,N,J,j,I,H,F,U,D,L,V,W,Y,K,T,q,G,P,Q,X,Z,$,tt,et,rt,nt,it,ot,ut,at,st,ft,ht;for(n=0;n<48;n+=2)i=t[0]^t[10]^t[20]^t[30]^t[40],o=t[1]^t[11]^t[21]^t[31]^t[41],u=t[2]^t[12]^t[22]^t[32]^t[42],a=t[3]^t[13]^t[23]^t[33]^t[43],s=t[4]^t[14]^t[24]^t[34]^t[44],f=t[5]^t[15]^t[25]^t[35]^t[45],h=t[6]^t[16]^t[26]^t[36]^t[46],c=t[7]^t[17]^t[27]^t[37]^t[47],e=(p=t[8]^t[18]^t[28]^t[38]^t[48])^(u<<1|a>>>31),r=(d=t[9]^t[19]^t[29]^t[39]^t[49])^(a<<1|u>>>31),t[0]^=e,t[1]^=r,t[10]^=e,t[11]^=r,t[20]^=e,t[21]^=r,t[30]^=e,t[31]^=r,t[40]^=e,t[41]^=r,e=i^(s<<1|f>>>31),r=o^(f<<1|s>>>31),t[2]^=e,t[3]^=r,t[12]^=e,t[13]^=r,t[22]^=e,t[23]^=r,t[32]^=e,t[33]^=r,t[42]^=e,t[43]^=r,e=u^(h<<1|c>>>31),r=a^(c<<1|h>>>31),t[4]^=e,t[5]^=r,t[14]^=e,t[15]^=r,t[24]^=e,t[25]^=r,t[34]^=e,t[35]^=r,t[44]^=e,t[45]^=r,e=s^(p<<1|d>>>31),r=f^(d<<1|p>>>31),t[6]^=e,t[7]^=r,t[16]^=e,t[17]^=r,t[26]^=e,t[27]^=r,t[36]^=e,t[37]^=r,t[46]^=e,t[47]^=r,e=h^(i<<1|o>>>31),r=c^(o<<1|i>>>31),t[8]^=e,t[9]^=r,t[18]^=e,t[19]^=r,t[28]^=e,t[29]^=r,t[38]^=e,t[39]^=r,t[48]^=e,t[49]^=r,y=t[0],g=t[1],q=t[11]<<4|t[10]>>>28,G=t[10]<<4|t[11]>>>28,z=t[20]<<3|t[21]>>>29,E=t[21]<<3|t[20]>>>29,at=t[31]<<9|t[30]>>>23,st=t[30]<<9|t[31]>>>23,W=t[40]<<18|t[41]>>>14,Y=t[41]<<18|t[40]>>>14,j=t[2]<<1|t[3]>>>31,I=t[3]<<1|t[2]>>>31,v=t[13]<<12|t[12]>>>20,b=t[12]<<12|t[13]>>>20,P=t[22]<<10|t[23]>>>22,Q=t[23]<<10|t[22]>>>22,O=t[33]<<13|t[32]>>>19,R=t[32]<<13|t[33]>>>19,ft=t[42]<<2|t[43]>>>30,ht=t[43]<<2|t[42]>>>30,et=t[5]<<30|t[4]>>>2,rt=t[4]<<30|t[5]>>>2,H=t[14]<<6|t[15]>>>26,F=t[15]<<6|t[14]>>>26,w=t[25]<<11|t[24]>>>21,A=t[24]<<11|t[25]>>>21,X=t[34]<<15|t[35]>>>17,Z=t[35]<<15|t[34]>>>17,N=t[45]<<29|t[44]>>>3,J=t[44]<<29|t[45]>>>3,x=t[6]<<28|t[7]>>>4,C=t[7]<<28|t[6]>>>4,nt=t[17]<<23|t[16]>>>9,it=t[16]<<23|t[17]>>>9,U=t[26]<<25|t[27]>>>7,D=t[27]<<25|t[26]>>>7,B=t[36]<<21|t[37]>>>11,k=t[37]<<21|t[36]>>>11,$=t[47]<<24|t[46]>>>8,tt=t[46]<<24|t[47]>>>8,K=t[8]<<27|t[9]>>>5,T=t[9]<<27|t[8]>>>5,S=t[18]<<20|t[19]>>>12,M=t[19]<<20|t[18]>>>12,ot=t[29]<<7|t[28]>>>25,ut=t[28]<<7|t[29]>>>25,L=t[38]<<8|t[39]>>>24,V=t[39]<<8|t[38]>>>24,_=t[48]<<14|t[49]>>>18,m=t[49]<<14|t[48]>>>18,t[0]=y^~v&w,t[1]=g^~b&A,t[10]=x^~S&z,t[11]=C^~M&E,t[20]=j^~H&U,t[21]=I^~F&D,t[30]=K^~q&P,t[31]=T^~G&Q,t[40]=et^~nt&ot,t[41]=rt^~it&ut,t[2]=v^~w&B,t[3]=b^~A&k,t[12]=S^~z&O,t[13]=M^~E&R,t[22]=H^~U&L,t[23]=F^~D&V,t[32]=q^~P&X,t[33]=G^~Q&Z,t[42]=nt^~ot&at,t[43]=it^~ut&st,t[4]=w^~B&_,t[5]=A^~k&m,t[14]=z^~O&N,t[15]=E^~R&J,t[24]=U^~L&W,t[25]=D^~V&Y,t[34]=P^~X&$,t[35]=Q^~Z&tt,t[44]=ot^~at&ft,t[45]=ut^~st&ht,t[6]=B^~_&y,t[7]=k^~m&g,t[16]=O^~N&x,t[17]=R^~J&C,t[26]=L^~W&j,t[27]=V^~Y&I,t[36]=X^~$&K,t[37]=Z^~tt&T,t[46]=at^~ft&et,t[47]=st^~ht&rt,t[8]=_^~y&v,t[9]=m^~g&b,t[18]=N^~x&S,t[19]=J^~C&M,t[28]=W^~j&H,t[29]=Y^~I&F,t[38]=$^~K&q,t[39]=tt^~T&G,t[48]=ft^~et&nt,t[49]=ht^~rt&it,t[0]^=l[n],t[1]^=l[n+1]};if(s)module.exports=J;else{for(I=0;I>5,this.byteCount=this.blockCount<<2,this.outputBlocks=n>>5,this.extraBytes=(31&n)>>3;for(var r=0;r<50;++r)this.s[r]=0}function e(e,n,r,i){t.call(this,e,n,r),this.xof=i}function n(t,n,r,i){e.call(this,t,n,r,i),this.inputActive=!1,this.inputBytesRemaining=0}function r(t,n,r,i,o){e.call(this,t,n,r,i),this.bits=t,this.blockSize=o,this.inner=null,this.innerBytes=0,this.blockNumber=0}var i="input is invalid type",o="finalize already called",a="tuple input is incomplete",u="object"==typeof window,s=u?window:{};s.JS_SHA3_NO_WINDOW&&(u=!1);var h=!u&&"object"==typeof self;!s.JS_SHA3_NO_NODE_JS&&"object"==typeof process&&process.versions&&process.versions.node?s=global:h&&(s=self);for(var f=!s.JS_SHA3_NO_COMMON_JS&&"object"==typeof module&&module.exports,c="function"==typeof define&&define.amd,p=!s.JS_SHA3_NO_ARRAY_BUFFER&&"undefined"!=typeof ArrayBuffer,l="0123456789abcdef".split(""),d=[31,7936,2031616,520093696],y=[4,1024,262144,67108864],b=[0,8,16,24],v=[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],g=[224,256,384,512],w=[128,256],B=["hex","buffer","arrayBuffer","array","digest"],A={128:168,256:136},k=s.JS_SHA3_NO_NODE_JS||!Array.isArray?function(t){return"[object Array]"===Object.prototype.toString.call(t)}:Array.isArray,_=!p||!s.JS_SHA3_NO_ARRAY_BUFFER_IS_VIEW&&ArrayBuffer.isView?ArrayBuffer.isView:function(t){return"object"==typeof t&&t.buffer&&t.buffer.constructor===ArrayBuffer},m=function(t){var e=typeof t;if("string"===e)return[t,!0];if("object"!==e||null===t)throw new Error(i);if(p&&t.constructor===ArrayBuffer)return[new Uint8Array(t),!1];if(!k(t)&&!_(t))throw new Error(i);return[t,!1]},x=function(t){return 0===m(t)[0].length},C=function(t){for(var e=[],n=0;n268435455)throw new Error("block size is invalid");var s=new r(t,e,a,n,o).bytepad(["ParallelHash",u],i);return s.encode(o,!1),s},o.update=function(t,e,n,r){return o.create(e,n,r).update(t)},I(o,function(t,e,r){return O(t,0,n,r)},t,e)},F=[{name:"keccak",padding:[1,256,65536,16777216],bits:g,createMethod:R},{name:"sha3",padding:[6,1536,393216,100663296],bits:g,createMethod:R},{name:"shake",padding:d,bits:w,createMethod:function(e,n){var r=z(e,n,"hex");return r.create=function(r){return new t(e,n,r)},r.update=function(t,e){return r.create(e).update(t)},I(r,z,e,n)}},{name:"cshake",padding:y,bits:w,createMethod:function(e,n){var r=A[e],i=M(e,0,"hex");return i.create=function(i,o,a){return x(o)&&x(a)?U["shake"+e].create(i):new t(e,n,i).bytepad([o,a],r)},i.update=function(t,e,n,r){return i.create(e,n,r).update(t)},I(i,M,e,n)}},{name:"kmac",padding:y,bits:w,createMethod:function(t,e){return J(t,e,!1)}},{name:"kmacxof",padding:y,bits:w,createMethod:function(t,e){return J(t,e,!0)}},{name:"tuplehash",padding:y,bits:w,createMethod:function(t,e){return j(t,e,!1)}},{name:"tuplehashxof",padding:y,bits:w,createMethod:function(t,e){return j(t,e,!0)}},{name:"parallelhash",padding:y,bits:w,createMethod:function(t,e){return H(t,e,!1)}},{name:"parallelhashxof",padding:y,bits:w,createMethod:function(t,e){return H(t,e,!0)}}],U={},D=[],L=0;L>2]|=r<>2]|=(192|r>>6)<>2]|=(128|63&r)<=57344?(a[n>>2]|=(224|r>>12)<>2]|=(128|r>>6&63)<>2]|=(128|63&r)<>2]|=(240|r>>18)<>2]|=(128|r>>12&63)<>2]|=(128|r>>6&63)<>2]|=(128|63&r)<>2]|=t[f]<=u){for(this.start=n-u,this.block=a[h],n=0;n>=8);r>0;)o.unshift(r),r=255&(e>>=8),++i;return n?o.push(i):o.unshift(i),t.prototype.update.call(this,o),o.length},t.prototype.encodeString=function(e){var n=m(e);e=n[0];var r=n[1],i=0,o=e.length;if(r)for(var a=0;a=57344?i+=3:(u=65536+((1023&u)<<10|1023&e.charCodeAt(++a)),i+=4)}else i=o;return i+=this.encode(8*i),t.prototype.update.call(this,e),i},t.prototype.bytepad=function(e,n){for(var r=this.encode(n),i=0;i>2]|=this.padding[3&e],this.lastByteIndex===this.byteCount)for(t[0]=t[n],e=1;e>4&15]+l[15&t]+l[t>>12&15]+l[t>>8&15]+l[t>>20&15]+l[t>>16&15]+l[t>>28&15]+l[t>>24&15];a%e==0&&(n=C(n),T(n),o=0)}return i&&(t=n[o],u+=l[t>>4&15]+l[15&t],i>1&&(u+=l[t>>12&15]+l[t>>8&15]),i>2&&(u+=l[t>>20&15]+l[t>>16&15])),u},t.prototype.arrayBuffer=function(){this.finalize();var t,e=this.blockCount,n=this.s,r=this.outputBlocks,i=this.extraBytes,o=0,a=0,u=this.outputBits>>3;t=i?new ArrayBuffer(r+1<<2):new ArrayBuffer(u);for(var s=new Uint32Array(t);a>8&255,s[t+2]=e>>16&255,s[t+3]=e>>24&255;u%n==0&&(r=C(r),T(r))}return o&&(t=u<<2,e=r[a],s[t]=255&e,o>1&&(s[t+1]=e>>8&255),o>2&&(s[t+2]=e>>16&255)),s},(e.prototype=new t).finalize=function(){return this.finalized||this.encode(this.xof?0:this.outputBits,!0),t.prototype.finalize.call(this)},(n.prototype=new e).getMessageByteLength=function(t){var e=m(t);if(t=e[0],!e[1])return t.length;for(var n=0,r=0;r=57344?n+=3:(++r,n+=4)}return n},n.prototype.beginInput=function(t){if(this.inputActive)throw new Error(a);if("number"!=typeof t||!isFinite(t)||t<0||Math.floor(t)!==t||t>268435455)throw new Error("tuple input byte length is invalid");return this.encode(8*t,!1),0!==t&&(this.inputActive=!0,this.inputBytesRemaining=t),this},n.prototype._updateChunk=function(t,n){return e.prototype.update.call(this,t),this.inputBytesRemaining-=n,0===this.inputBytesRemaining&&(this.inputActive=!1),this},n.prototype.updateChunk=function(t){if(!this.inputActive)throw new Error("no active tuple input");var e=this.getMessageByteLength(t);if(e>this.inputBytesRemaining)throw new Error("tuple input exceeds declared length");return this._updateChunk(t,e)},n.prototype.update=function(t){var e=this.getMessageByteLength(t);return this.beginInput(e),this._updateChunk(t,e)},n.prototype.finalize=function(){if(this.inputActive)throw new Error(a);return e.prototype.finalize.call(this)},(r.prototype=new e)._finishInner=function(){e.prototype.update.call(this,this.inner.array()),this.inner=null,this.innerBytes=0,++this.blockNumber},r.prototype._updateBytes=function(e){var n=e.length;if(n)for(var r=e.subarray||e.slice,i=this.blockSize,o=0;o>>6,i[u++]=128|63&n):n<55296||n>=57344?(i[u++]=224|n>>>12,i[u++]=128|n>>>6&63,i[u++]=128|63&n):(n=65536+((1023&n)<<10|1023&t.charCodeAt(++r)),i[u++]=240|n>>>18,i[u++]=128|n>>>12&63,i[u++]=128|n>>>6&63,i[u++]=128|63&n);t=i}return this._updateBytes(t),this},r.prototype.finalize=function(){return this.finalized||(this.inner&&this._finishInner(),this.encode(this.blockNumber,!0)),e.prototype.finalize.call(this)};var T=function(t){var e,n,r,i,o,a,u,s,h,f,c,p,l,d,y,b,g,w,B,A,k,_,m,x,C,S,z,M,E,N,O,I,R,J,j,H,F,U,D,L,V,W,Y,K,P,T,q,G,Q,X,Z,$,tt,et,nt,rt,it,ot,at,ut,st,ht,ft;for(r=0;r<48;r+=2)i=t[0]^t[10]^t[20]^t[30]^t[40],o=t[1]^t[11]^t[21]^t[31]^t[41],a=t[2]^t[12]^t[22]^t[32]^t[42],u=t[3]^t[13]^t[23]^t[33]^t[43],s=t[4]^t[14]^t[24]^t[34]^t[44],h=t[5]^t[15]^t[25]^t[35]^t[45],f=t[6]^t[16]^t[26]^t[36]^t[46],c=t[7]^t[17]^t[27]^t[37]^t[47],e=(p=t[8]^t[18]^t[28]^t[38]^t[48])^(a<<1|u>>>31),n=(l=t[9]^t[19]^t[29]^t[39]^t[49])^(u<<1|a>>>31),t[0]^=e,t[1]^=n,t[10]^=e,t[11]^=n,t[20]^=e,t[21]^=n,t[30]^=e,t[31]^=n,t[40]^=e,t[41]^=n,e=i^(s<<1|h>>>31),n=o^(h<<1|s>>>31),t[2]^=e,t[3]^=n,t[12]^=e,t[13]^=n,t[22]^=e,t[23]^=n,t[32]^=e,t[33]^=n,t[42]^=e,t[43]^=n,e=a^(f<<1|c>>>31),n=u^(c<<1|f>>>31),t[4]^=e,t[5]^=n,t[14]^=e,t[15]^=n,t[24]^=e,t[25]^=n,t[34]^=e,t[35]^=n,t[44]^=e,t[45]^=n,e=s^(p<<1|l>>>31),n=h^(l<<1|p>>>31),t[6]^=e,t[7]^=n,t[16]^=e,t[17]^=n,t[26]^=e,t[27]^=n,t[36]^=e,t[37]^=n,t[46]^=e,t[47]^=n,e=f^(i<<1|o>>>31),n=c^(o<<1|i>>>31),t[8]^=e,t[9]^=n,t[18]^=e,t[19]^=n,t[28]^=e,t[29]^=n,t[38]^=e,t[39]^=n,t[48]^=e,t[49]^=n,d=t[0],y=t[1],T=t[11]<<4|t[10]>>>28,q=t[10]<<4|t[11]>>>28,M=t[20]<<3|t[21]>>>29,E=t[21]<<3|t[20]>>>29,ut=t[31]<<9|t[30]>>>23,st=t[30]<<9|t[31]>>>23,W=t[40]<<18|t[41]>>>14,Y=t[41]<<18|t[40]>>>14,J=t[2]<<1|t[3]>>>31,j=t[3]<<1|t[2]>>>31,b=t[13]<<12|t[12]>>>20,g=t[12]<<12|t[13]>>>20,G=t[22]<<10|t[23]>>>22,Q=t[23]<<10|t[22]>>>22,N=t[33]<<13|t[32]>>>19,O=t[32]<<13|t[33]>>>19,ht=t[42]<<2|t[43]>>>30,ft=t[43]<<2|t[42]>>>30,et=t[5]<<30|t[4]>>>2,nt=t[4]<<30|t[5]>>>2,H=t[14]<<6|t[15]>>>26,F=t[15]<<6|t[14]>>>26,w=t[25]<<11|t[24]>>>21,B=t[24]<<11|t[25]>>>21,X=t[34]<<15|t[35]>>>17,Z=t[35]<<15|t[34]>>>17,I=t[45]<<29|t[44]>>>3,R=t[44]<<29|t[45]>>>3,x=t[6]<<28|t[7]>>>4,C=t[7]<<28|t[6]>>>4,rt=t[17]<<23|t[16]>>>9,it=t[16]<<23|t[17]>>>9,U=t[26]<<25|t[27]>>>7,D=t[27]<<25|t[26]>>>7,A=t[36]<<21|t[37]>>>11,k=t[37]<<21|t[36]>>>11,$=t[47]<<24|t[46]>>>8,tt=t[46]<<24|t[47]>>>8,K=t[8]<<27|t[9]>>>5,P=t[9]<<27|t[8]>>>5,S=t[18]<<20|t[19]>>>12,z=t[19]<<20|t[18]>>>12,ot=t[29]<<7|t[28]>>>25,at=t[28]<<7|t[29]>>>25,L=t[38]<<8|t[39]>>>24,V=t[39]<<8|t[38]>>>24,_=t[48]<<14|t[49]>>>18,m=t[49]<<14|t[48]>>>18,t[0]=d^~b&w,t[1]=y^~g&B,t[10]=x^~S&M,t[11]=C^~z&E,t[20]=J^~H&U,t[21]=j^~F&D,t[30]=K^~T&G,t[31]=P^~q&Q,t[40]=et^~rt&ot,t[41]=nt^~it&at,t[2]=b^~w&A,t[3]=g^~B&k,t[12]=S^~M&N,t[13]=z^~E&O,t[22]=H^~U&L,t[23]=F^~D&V,t[32]=T^~G&X,t[33]=q^~Q&Z,t[42]=rt^~ot&ut,t[43]=it^~at&st,t[4]=w^~A&_,t[5]=B^~k&m,t[14]=M^~N&I,t[15]=E^~O&R,t[24]=U^~L&W,t[25]=D^~V&Y,t[34]=G^~X&$,t[35]=Q^~Z&tt,t[44]=ot^~ut&ht,t[45]=at^~st&ft,t[6]=A^~_&d,t[7]=k^~m&y,t[16]=N^~I&x,t[17]=O^~R&C,t[26]=L^~W&J,t[27]=V^~Y&j,t[36]=X^~$&K,t[37]=Z^~tt&P,t[46]=ut^~ht&et,t[47]=st^~ft&nt,t[8]=_^~d&b,t[9]=m^~y&g,t[18]=I^~x&S,t[19]=R^~C&z,t[28]=W^~J&H,t[29]=Y^~j&F,t[38]=$^~K&T,t[39]=tt^~P&q,t[48]=ht^~et&rt,t[49]=ft^~nt&it,t[0]^=v[r],t[1]^=v[r+1]};if(f)module.exports=U;else{for(L=0;L>5,this.byteCount=this.blockCount<<2,this.outputBlocks=r>>5,this.extraBytes=(31&r)>>3;for(var n=0;n<50;++n)this.s[n]=0}function L(t,e,r,n){D.call(this,t,e,r),this.xof=n}function T(t,e,r,n){L.call(this,t,e,r,n),this.inputActive=!1,this.inputBytesRemaining=0}D.prototype.update=function(t){if(this.finalized)throw new Error("finalize already called");var e=b(t);t=e[0];for(var r,n,i=e[1],o=this.blocks,a=this.byteCount,u=t.length,s=this.blockCount,h=0,f=this.s;h>2]|=n<>2]|=(192|n>>6)<>2]|=(128|63&n)<=57344?(o[r>>2]|=(224|n>>12)<>2]|=(128|n>>6&63)<>2]|=(128|63&n)<>2]|=(240|n>>18)<>2]|=(128|n>>12&63)<>2]|=(128|n>>6&63)<>2]|=(128|63&n)<>2]|=t[h]<=a){for(this.start=r-a,this.block=o[s],r=0;r>=8);r>0;)i.unshift(r),r=255&(t>>=8),++n;return e?i.push(n):i.unshift(n),D.prototype.update.call(this,i),i.length},D.prototype.encodeString=function(t){var e=b(t);t=e[0];var r=e[1],n=0,i=t.length;if(r)for(var o=0;o=57344?n+=3:(a=65536+((1023&a)<<10|1023&t.charCodeAt(++o)),n+=4)}else n=i;return n+=this.encode(8*n),D.prototype.update.call(this,t),n},D.prototype.bytepad=function(t,e){for(var r=this.encode(e),n=0;n>2]|=this.padding[3&e],this.lastByteIndex===this.byteCount)for(t[0]=t[r],e=1;e>4&15]+h[15&t]+h[t>>12&15]+h[t>>8&15]+h[t>>20&15]+h[t>>16&15]+h[t>>28&15]+h[t>>24&15];a%e===0&&(r=w(r),V(r),o=0)}return i&&(t=r[o],u+=h[t>>4&15]+h[15&t],i>1&&(u+=h[t>>12&15]+h[t>>8&15]),i>2&&(u+=h[t>>20&15]+h[t>>16&15])),u},D.prototype.arrayBuffer=function(){this.finalize();var t,e=this.blockCount,r=this.s,n=this.outputBlocks,i=this.extraBytes,o=0,a=0,u=this.outputBits>>3;t=i?new ArrayBuffer(n+1<<2):new ArrayBuffer(u);for(var s=new Uint32Array(t);a>8&255,s[t+2]=e>>16&255,s[t+3]=e>>24&255;u%r===0&&(n=w(n),V(n))}return o&&(t=u<<2,e=n[a],s[t]=255&e,o>1&&(s[t+1]=e>>8&255),o>2&&(s[t+2]=e>>16&255)),s},L.prototype=new D,L.prototype.finalize=function(){return this.finalized||this.encode(this.xof?0:this.outputBits,!0),D.prototype.finalize.call(this)},T.prototype=new L,T.prototype.getMessageByteLength=function(t){var e=b(t);if(t=e[0],!e[1])return t.length;for(var r=0,n=0;n=57344?r+=3:(++n,r+=4)}return r},T.prototype.beginInput=function(t){if(this.inputActive)throw new Error(n);if("number"!=typeof t||!isFinite(t)||t<0||Math.floor(t)!==t||t>268435455)throw new Error("tuple input byte length is invalid");return this.encode(8*t,!1),0!==t&&(this.inputActive=!0,this.inputBytesRemaining=t),this},T.prototype._updateChunk=function(t,e){return L.prototype.update.call(this,t),this.inputBytesRemaining-=e,0===this.inputBytesRemaining&&(this.inputActive=!1),this},T.prototype.updateChunk=function(t){if(!this.inputActive)throw new Error("no active tuple input");var e=this.getMessageByteLength(t);if(e>this.inputBytesRemaining)throw new Error("tuple input exceeds declared length");return this._updateChunk(t,e)},T.prototype.update=function(t){var e=this.getMessageByteLength(t);return this.beginInput(e),this._updateChunk(t,e)},T.prototype.finalize=function(){if(this.inputActive)throw new Error(n);return L.prototype.finalize.call(this)};var V=function(t){var e,r,n,i,o,a,u,s,h,f,c,l,d,y,k,g,v,b,_,w,A,x,B,m,C,S,M,z,E,O,R,N,J,j,I,H,F,U,D,L,T,V,W,Y,K,P,q,G,Q,X,Z,$,tt,et,rt,nt,it,ot,at,ut,st,ht,ft;for(n=0;n<48;n+=2)i=t[0]^t[10]^t[20]^t[30]^t[40],o=t[1]^t[11]^t[21]^t[31]^t[41],a=t[2]^t[12]^t[22]^t[32]^t[42],u=t[3]^t[13]^t[23]^t[33]^t[43],s=t[4]^t[14]^t[24]^t[34]^t[44],h=t[5]^t[15]^t[25]^t[35]^t[45],f=t[6]^t[16]^t[26]^t[36]^t[46],c=t[7]^t[17]^t[27]^t[37]^t[47],e=(l=t[8]^t[18]^t[28]^t[38]^t[48])^(a<<1|u>>>31),r=(d=t[9]^t[19]^t[29]^t[39]^t[49])^(u<<1|a>>>31),t[0]^=e,t[1]^=r,t[10]^=e,t[11]^=r,t[20]^=e,t[21]^=r,t[30]^=e,t[31]^=r,t[40]^=e,t[41]^=r,e=i^(s<<1|h>>>31),r=o^(h<<1|s>>>31),t[2]^=e,t[3]^=r,t[12]^=e,t[13]^=r,t[22]^=e,t[23]^=r,t[32]^=e,t[33]^=r,t[42]^=e,t[43]^=r,e=a^(f<<1|c>>>31),r=u^(c<<1|f>>>31),t[4]^=e,t[5]^=r,t[14]^=e,t[15]^=r,t[24]^=e,t[25]^=r,t[34]^=e,t[35]^=r,t[44]^=e,t[45]^=r,e=s^(l<<1|d>>>31),r=h^(d<<1|l>>>31),t[6]^=e,t[7]^=r,t[16]^=e,t[17]^=r,t[26]^=e,t[27]^=r,t[36]^=e,t[37]^=r,t[46]^=e,t[47]^=r,e=f^(i<<1|o>>>31),r=c^(o<<1|i>>>31),t[8]^=e,t[9]^=r,t[18]^=e,t[19]^=r,t[28]^=e,t[29]^=r,t[38]^=e,t[39]^=r,t[48]^=e,t[49]^=r,y=t[0],k=t[1],P=t[11]<<4|t[10]>>>28,q=t[10]<<4|t[11]>>>28,z=t[20]<<3|t[21]>>>29,E=t[21]<<3|t[20]>>>29,ut=t[31]<<9|t[30]>>>23,st=t[30]<<9|t[31]>>>23,V=t[40]<<18|t[41]>>>14,W=t[41]<<18|t[40]>>>14,j=t[2]<<1|t[3]>>>31,I=t[3]<<1|t[2]>>>31,g=t[13]<<12|t[12]>>>20,v=t[12]<<12|t[13]>>>20,G=t[22]<<10|t[23]>>>22,Q=t[23]<<10|t[22]>>>22,O=t[33]<<13|t[32]>>>19,R=t[32]<<13|t[33]>>>19,ht=t[42]<<2|t[43]>>>30,ft=t[43]<<2|t[42]>>>30,et=t[5]<<30|t[4]>>>2,rt=t[4]<<30|t[5]>>>2,H=t[14]<<6|t[15]>>>26,F=t[15]<<6|t[14]>>>26,b=t[25]<<11|t[24]>>>21,_=t[24]<<11|t[25]>>>21,X=t[34]<<15|t[35]>>>17,Z=t[35]<<15|t[34]>>>17,N=t[45]<<29|t[44]>>>3,J=t[44]<<29|t[45]>>>3,m=t[6]<<28|t[7]>>>4,C=t[7]<<28|t[6]>>>4,nt=t[17]<<23|t[16]>>>9,it=t[16]<<23|t[17]>>>9,U=t[26]<<25|t[27]>>>7,D=t[27]<<25|t[26]>>>7,w=t[36]<<21|t[37]>>>11,A=t[37]<<21|t[36]>>>11,$=t[47]<<24|t[46]>>>8,tt=t[46]<<24|t[47]>>>8,Y=t[8]<<27|t[9]>>>5,K=t[9]<<27|t[8]>>>5,S=t[18]<<20|t[19]>>>12,M=t[19]<<20|t[18]>>>12,ot=t[29]<<7|t[28]>>>25,at=t[28]<<7|t[29]>>>25,L=t[38]<<8|t[39]>>>24,T=t[39]<<8|t[38]>>>24,x=t[48]<<14|t[49]>>>18,B=t[49]<<14|t[48]>>>18,t[0]=y^~g&b,t[1]=k^~v&_,t[10]=m^~S&z,t[11]=C^~M&E,t[20]=j^~H&U,t[21]=I^~F&D,t[30]=Y^~P&G,t[31]=K^~q&Q,t[40]=et^~nt&ot,t[41]=rt^~it&at,t[2]=g^~b&w,t[3]=v^~_&A,t[12]=S^~z&O,t[13]=M^~E&R,t[22]=H^~U&L,t[23]=F^~D&T,t[32]=P^~G&X,t[33]=q^~Q&Z,t[42]=nt^~ot&ut,t[43]=it^~at&st,t[4]=b^~w&x,t[5]=_^~A&B,t[14]=z^~O&N,t[15]=E^~R&J,t[24]=U^~L&V,t[25]=D^~T&W,t[34]=G^~X&$,t[35]=Q^~Z&tt,t[44]=ot^~ut&ht,t[45]=at^~st&ft,t[6]=w^~x&y,t[7]=A^~B&k,t[16]=O^~N&m,t[17]=R^~J&C,t[26]=L^~V&j,t[27]=T^~W&I,t[36]=X^~$&Y,t[37]=Z^~tt&K,t[46]=ut^~ht&et,t[47]=st^~ft&rt,t[8]=x^~y&g,t[9]=B^~k&v,t[18]=N^~m&S,t[19]=J^~C&M,t[28]=V^~j&H,t[29]=W^~I&F,t[38]=$^~Y&P,t[39]=tt^~K&q,t[48]=ht^~et&nt,t[49]=ft^~rt&it,t[0]^=p[n],t[1]^=p[n+1]};if(u)r.exports=R;else for(J=0;J268435455)throw new Error("block size is invalid");var s=new K(t,e,a,r,i).bytepad(["ParallelHash",o],n);return s.encode(i,!1),s},i.update=function(t,e,r,n){return i.create(e,r,n).update(t)},E(i,function(t,e,n){return M(t,0,r,n)},t,e)},J=[{name:"keccak",padding:[1,256,65536,16777216],bits:y,createMethod:O},{name:"sha3",padding:[6,1536,393216,100663296],bits:y,createMethod:O},{name:"shake",padding:c,bits:k,createMethod:function(t,e){var r=m(t,e,"hex");return r.create=function(r){return new W(t,e,r)},r.update=function(t,e){return r.create(e).update(t)},E(r,m,t,e)}},{name:"cshake",padding:p,bits:k,createMethod:function(t,e){var r=v[t],n=C(t,0,"hex");return n.create=function(n,i,a){return x(i)&&x(a)?j["shake"+t].create(n):new W(t,e,n).bytepad([i,a],r)},n.update=function(t,e,r,i){return n.create(e,r,i).update(t)},E(n,C,t,e)}},{name:"kmac",padding:p,bits:k,createMethod:function(t,e){return N(t,e,!1)}},{name:"kmacxof",padding:p,bits:k,createMethod:function(t,e){return N(t,e,!0)}},{name:"tuplehash",padding:p,bits:k,createMethod:function(t,e){return I(t,e,!1)}},{name:"tuplehashxof",padding:p,bits:k,createMethod:function(t,e){return I(t,e,!0)}},{name:"parallelhash",padding:p,bits:k,createMethod:function(t,e){return R(t,e,!1)}},{name:"parallelhashxof",padding:p,bits:k,createMethod:function(t,e){return R(t,e,!0)}}],j={},H=[],F=0;F>5,this.byteCount=this.blockCount<<2,this.outputBlocks=r>>5,this.extraBytes=(31&r)>>3;for(var n=0;n<50;++n)this.s[n]=0}function P(t,e,r,n){W.call(this,t,e,r),this.xof=n}function Y(t,e,r,n){P.call(this,t,e,r,n),this.inputActive=!1,this.inputBytesRemaining=0}function K(t,e,r,n,i){P.call(this,t,e,r,n),this.bits=t,this.blockSize=i,this.inner=null,this.innerBytes=0,this.blockNumber=0}W.prototype.update=function(t){if(this.finalized)throw new Error(n);var e=w(t);t=e[0];for(var r,i,a=e[1],o=this.blocks,s=this.byteCount,u=t.length,h=this.blockCount,f=0,c=this.s;f>2]|=i<>2]|=(192|i>>6)<>2]|=(128|63&i)<=57344?(o[r>>2]|=(224|i>>12)<>2]|=(128|i>>6&63)<>2]|=(128|63&i)<>2]|=(240|i>>18)<>2]|=(128|i>>12&63)<>2]|=(128|i>>6&63)<>2]|=(128|63&i)<>2]|=t[f]<=s){for(this.start=r-s,this.block=o[h],r=0;r>=8);r>0;)i.unshift(r),r=255&(t>>=8),++n;return e?i.push(n):i.unshift(n),W.prototype.update.call(this,i),i.length},W.prototype.encodeString=function(t){var e=w(t);t=e[0];var r=e[1],n=0,i=t.length;if(r)for(var a=0;a=57344?n+=3:(o=65536+((1023&o)<<10|1023&t.charCodeAt(++a)),n+=4)}else n=i;return n+=this.encode(8*n),W.prototype.update.call(this,t),n},W.prototype.bytepad=function(t,e){for(var r=this.encode(e),n=0;n>2]|=this.padding[3&e],this.lastByteIndex===this.byteCount)for(t[0]=t[r],e=1;e>4&15]+f[15&t]+f[t>>12&15]+f[t>>8&15]+f[t>>20&15]+f[t>>16&15]+f[t>>28&15]+f[t>>24&15];o%e===0&&(r=B(r),q(r),a=0)}return i&&(t=r[a],s+=f[t>>4&15]+f[15&t],i>1&&(s+=f[t>>12&15]+f[t>>8&15]),i>2&&(s+=f[t>>20&15]+f[t>>16&15])),s},W.prototype.arrayBuffer=function(){this.finalize();var t,e=this.blockCount,r=this.s,n=this.outputBlocks,i=this.extraBytes,a=0,o=0,s=this.outputBits>>3;t=i?new ArrayBuffer(n+1<<2):new ArrayBuffer(s);for(var u=new Uint32Array(t);o>8&255,u[t+2]=e>>16&255,u[t+3]=e>>24&255;s%r===0&&(n=B(n),q(n))}return a&&(t=s<<2,e=n[o],u[t]=255&e,a>1&&(u[t+1]=e>>8&255),a>2&&(u[t+2]=e>>16&255)),u},P.prototype=new W,P.prototype.finalize=function(){return this.finalized||this.encode(this.xof?0:this.outputBits,!0),W.prototype.finalize.call(this)},Y.prototype=new P,Y.prototype.getMessageByteLength=function(t){var e=w(t);if(t=e[0],!e[1])return t.length;for(var r=0,n=0;n=57344?r+=3:(++n,r+=4)}return r},Y.prototype.beginInput=function(t){if(this.inputActive)throw new Error(i);if("number"!=typeof t||!isFinite(t)||t<0||Math.floor(t)!==t||t>268435455)throw new Error("tuple input byte length is invalid");return this.encode(8*t,!1),0!==t&&(this.inputActive=!0,this.inputBytesRemaining=t),this},Y.prototype._updateChunk=function(t,e){return P.prototype.update.call(this,t),this.inputBytesRemaining-=e,0===this.inputBytesRemaining&&(this.inputActive=!1),this},Y.prototype.updateChunk=function(t){if(!this.inputActive)throw new Error("no active tuple input");var e=this.getMessageByteLength(t);if(e>this.inputBytesRemaining)throw new Error("tuple input exceeds declared length");return this._updateChunk(t,e)},Y.prototype.update=function(t){var e=this.getMessageByteLength(t);return this.beginInput(e),this._updateChunk(t,e)},Y.prototype.finalize=function(){if(this.inputActive)throw new Error(i);return P.prototype.finalize.call(this)},K.prototype=new P,K.prototype._finishInner=function(){P.prototype.update.call(this,this.inner.array()),this.inner=null,this.innerBytes=0,++this.blockNumber},K.prototype._updateBytes=function(t){var e=t.length;if(e)for(var r=t.subarray||t.slice,n=this.blockSize,i=0;i>>6,a[s++]=128|63&r):r<55296||r>=57344?(a[s++]=224|r>>>12,a[s++]=128|r>>>6&63,a[s++]=128|63&r):(r=65536+((1023&r)<<10|1023&t.charCodeAt(++i)),a[s++]=240|r>>>18,a[s++]=128|r>>>12&63,a[s++]=128|r>>>6&63,a[s++]=128|63&r);t=a}return this._updateBytes(t),this},K.prototype.finalize=function(){return this.finalized||(this.inner&&this._finishInner(),this.encode(this.blockNumber,!0)),P.prototype.finalize.call(this)};var q=function(t){var e,r,n,i,a,o,s,u,h,f,c,p,l,y,k,b,v,_,g,w,x,B,A,m,C,S,z,M,E,O,N,I,R,J,j,H,F,U,D,L,T,V,W,P,Y,K,q,G,Q,X,Z,$,tt,et,rt,nt,it,at,ot,st,ut,ht,ft;for(n=0;n<48;n+=2)i=t[0]^t[10]^t[20]^t[30]^t[40],a=t[1]^t[11]^t[21]^t[31]^t[41],o=t[2]^t[12]^t[22]^t[32]^t[42],s=t[3]^t[13]^t[23]^t[33]^t[43],u=t[4]^t[14]^t[24]^t[34]^t[44],h=t[5]^t[15]^t[25]^t[35]^t[45],f=t[6]^t[16]^t[26]^t[36]^t[46],c=t[7]^t[17]^t[27]^t[37]^t[47],e=(p=t[8]^t[18]^t[28]^t[38]^t[48])^(o<<1|s>>>31),r=(l=t[9]^t[19]^t[29]^t[39]^t[49])^(s<<1|o>>>31),t[0]^=e,t[1]^=r,t[10]^=e,t[11]^=r,t[20]^=e,t[21]^=r,t[30]^=e,t[31]^=r,t[40]^=e,t[41]^=r,e=i^(u<<1|h>>>31),r=a^(h<<1|u>>>31),t[2]^=e,t[3]^=r,t[12]^=e,t[13]^=r,t[22]^=e,t[23]^=r,t[32]^=e,t[33]^=r,t[42]^=e,t[43]^=r,e=o^(f<<1|c>>>31),r=s^(c<<1|f>>>31),t[4]^=e,t[5]^=r,t[14]^=e,t[15]^=r,t[24]^=e,t[25]^=r,t[34]^=e,t[35]^=r,t[44]^=e,t[45]^=r,e=u^(p<<1|l>>>31),r=h^(l<<1|p>>>31),t[6]^=e,t[7]^=r,t[16]^=e,t[17]^=r,t[26]^=e,t[27]^=r,t[36]^=e,t[37]^=r,t[46]^=e,t[47]^=r,e=f^(i<<1|a>>>31),r=c^(a<<1|i>>>31),t[8]^=e,t[9]^=r,t[18]^=e,t[19]^=r,t[28]^=e,t[29]^=r,t[38]^=e,t[39]^=r,t[48]^=e,t[49]^=r,y=t[0],k=t[1],K=t[11]<<4|t[10]>>>28,q=t[10]<<4|t[11]>>>28,M=t[20]<<3|t[21]>>>29,E=t[21]<<3|t[20]>>>29,st=t[31]<<9|t[30]>>>23,ut=t[30]<<9|t[31]>>>23,V=t[40]<<18|t[41]>>>14,W=t[41]<<18|t[40]>>>14,J=t[2]<<1|t[3]>>>31,j=t[3]<<1|t[2]>>>31,b=t[13]<<12|t[12]>>>20,v=t[12]<<12|t[13]>>>20,G=t[22]<<10|t[23]>>>22,Q=t[23]<<10|t[22]>>>22,O=t[33]<<13|t[32]>>>19,N=t[32]<<13|t[33]>>>19,ht=t[42]<<2|t[43]>>>30,ft=t[43]<<2|t[42]>>>30,et=t[5]<<30|t[4]>>>2,rt=t[4]<<30|t[5]>>>2,H=t[14]<<6|t[15]>>>26,F=t[15]<<6|t[14]>>>26,_=t[25]<<11|t[24]>>>21,g=t[24]<<11|t[25]>>>21,X=t[34]<<15|t[35]>>>17,Z=t[35]<<15|t[34]>>>17,I=t[45]<<29|t[44]>>>3,R=t[44]<<29|t[45]>>>3,m=t[6]<<28|t[7]>>>4,C=t[7]<<28|t[6]>>>4,nt=t[17]<<23|t[16]>>>9,it=t[16]<<23|t[17]>>>9,U=t[26]<<25|t[27]>>>7,D=t[27]<<25|t[26]>>>7,w=t[36]<<21|t[37]>>>11,x=t[37]<<21|t[36]>>>11,$=t[47]<<24|t[46]>>>8,tt=t[46]<<24|t[47]>>>8,P=t[8]<<27|t[9]>>>5,Y=t[9]<<27|t[8]>>>5,S=t[18]<<20|t[19]>>>12,z=t[19]<<20|t[18]>>>12,at=t[29]<<7|t[28]>>>25,ot=t[28]<<7|t[29]>>>25,L=t[38]<<8|t[39]>>>24,T=t[39]<<8|t[38]>>>24,B=t[48]<<14|t[49]>>>18,A=t[49]<<14|t[48]>>>18,t[0]=y^~b&_,t[1]=k^~v&g,t[10]=m^~S&M,t[11]=C^~z&E,t[20]=J^~H&U,t[21]=j^~F&D,t[30]=P^~K&G,t[31]=Y^~q&Q,t[40]=et^~nt&at,t[41]=rt^~it&ot,t[2]=b^~_&w,t[3]=v^~g&x,t[12]=S^~M&O,t[13]=z^~E&N,t[22]=H^~U&L,t[23]=F^~D&T,t[32]=K^~G&X,t[33]=q^~Q&Z,t[42]=nt^~at&st,t[43]=it^~ot&ut,t[4]=_^~w&B,t[5]=g^~x&A,t[14]=M^~O&I,t[15]=E^~N&R,t[24]=U^~L&V,t[25]=D^~T&W,t[34]=G^~X&$,t[35]=Q^~Z&tt,t[44]=at^~st&ht,t[45]=ot^~ut&ft,t[6]=w^~B&y,t[7]=x^~A&k,t[16]=O^~I&m,t[17]=N^~R&C,t[26]=L^~V&J,t[27]=T^~W&j,t[36]=X^~$&P,t[37]=Z^~tt&Y,t[46]=st^~ht&et,t[47]=ut^~ft&rt,t[8]=B^~y&b,t[9]=A^~k&v,t[18]=I^~m&S,t[19]=R^~C&z,t[28]=V^~J&H,t[29]=W^~j&F,t[38]=$^~P&K,t[39]=tt^~Y&q,t[48]=ht^~et&nt,t[49]=ft^~rt&it,t[0]^=d[n],t[1]^=d[n+1]};if(u)r.exports=j;else for(F=0;F 0x0fffffff) { + throw new Error(BLOCK_SIZE_ERROR); + } + var hash = new ParallelHash(bits, padding, outputBits, xof, blockSize).bytepad(['ParallelHash', s], w); + hash.encode(blockSize, false); + return hash; + }; + method.update = function (message, blockSize, outputBits, s) { + return method.create(blockSize, outputBits, s).update(message); + }; + return createOutputMethods(method, function (b, p, outputType) { + return createParallelHashOutputMethod(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 }, @@ -228,6 +255,12 @@ var sha3$1 = {exports: {}}; }}, { name: 'tuplehashxof', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) { return createTupleHashMethod(bits, padding, true); + }}, + { name: 'parallelhash', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) { + return createParallelHashMethod(bits, padding, false); + }}, + { name: 'parallelhashxof', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) { + return createParallelHashMethod(bits, padding, true); }} ]; @@ -597,6 +630,93 @@ var sha3$1 = {exports: {}}; return Kmac.prototype.finalize.call(this); }; + function ParallelHash(bits, padding, outputBits, xof, blockSize) { + Kmac.call(this, bits, padding, outputBits, xof); + this.bits = bits; + this.blockSize = blockSize; + this.inner = null; + this.innerBytes = 0; + this.blockNumber = 0; + } + + ParallelHash.prototype = new Kmac(); + + ParallelHash.prototype._finishInner = function () { + Kmac.prototype.update.call(this, this.inner.array()); + this.inner = null; + this.innerBytes = 0; + ++this.blockNumber; + }; + + ParallelHash.prototype._updateBytes = function (message) { + var length = message.length; + if (!length) { + return; + } + + var slice = message.subarray || message.slice; + var blockSize = this.blockSize; + var index = 0; + while (index < length) { + if (!this.inner) { + this.inner = new Keccak(this.bits, SHAKE_PADDING, this.bits << 1); + } + var take = blockSize - this.innerBytes; + if (length - index < take) { + take = length - index; + } + this.inner.update(slice.call(message, index, index + take)); + this.innerBytes += take; + index += take; + if (this.innerBytes === blockSize) { + this._finishInner(); + } + } + }; + + ParallelHash.prototype.update = function (message) { + if (this.finalized) { + throw new Error(FINALIZE_ERROR); + } + var result = formatMessage(message); + message = result[0]; + if (result[1]) { + var bytes = [], length = message.length, index = 0, code, i; + for (i = 0; i < length; ++i) { + code = message.charCodeAt(i); + if (code < 0x80) { + bytes[index++] = code; + } else if (code < 0x800) { + bytes[index++] = (0xc0 | (code >>> 6)); + bytes[index++] = (0x80 | (code & 0x3f)); + } else if (code < 0xd800 || code >= 0xe000) { + bytes[index++] = (0xe0 | (code >>> 12)); + bytes[index++] = (0x80 | ((code >>> 6) & 0x3f)); + bytes[index++] = (0x80 | (code & 0x3f)); + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++i) & 0x3ff)); + bytes[index++] = (0xf0 | (code >>> 18)); + bytes[index++] = (0x80 | ((code >>> 12) & 0x3f)); + bytes[index++] = (0x80 | ((code >>> 6) & 0x3f)); + bytes[index++] = (0x80 | (code & 0x3f)); + } + } + message = bytes; + } + this._updateBytes(message); + return this; + }; + + ParallelHash.prototype.finalize = function () { + if (!this.finalized) { + if (this.inner) { + this._finishInner(); + } + this.encode(this.blockNumber, true); + } + 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, @@ -836,7 +956,16 @@ const { tuplehashxof_128, tuplehashxof_256, tuplehashxof128, - tuplehashxof256 + tuplehashxof256, + + parallelhash_128, + parallelhash_256, + parallelhash128, + parallelhash256, + parallelhashxof_128, + parallelhashxof_256, + parallelhashxof128, + parallelhashxof256 } = 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 }; +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, parallelhash128, parallelhash256, parallelhash_128, parallelhash_256, parallelhashxof128, parallelhashxof256, parallelhashxof_128, parallelhashxof_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 }; diff --git a/index.d.ts b/index.d.ts index 0cde75a..0fd3f7a 100644 --- a/index.d.ts +++ b/index.d.ts @@ -417,3 +417,92 @@ export var tuplehashxof_128: TupleHashMethod; export var tuplehashxof_256: TupleHashMethod; export var tuplehashxof128: TupleHashMethod; export var tuplehashxof256: TupleHashMethod; + +interface ParallelHash extends Hasher { + /** + * Absorb message bytes into ParallelHash blocks. + * + * @param message The next message chunk. + */ + update(message: Message): ParallelHash; +} + +interface ParallelHashMethod { + /** + * Hash and return hex string. + * + * @param message The message you want to hash. + * @param blockSize The ParallelHash block size in bytes. + * @param outputBits The length of output. + * @param customization The customization string. + */ + (message: Message, blockSize: number, outputBits: number, customization: Message): string; + + /** + * Hash and return hex string. + * + * @param message The message you want to hash. + * @param blockSize The ParallelHash block size in bytes. + * @param outputBits The length of output. + * @param customization The customization string. + */ + hex(message: Message, blockSize: number, outputBits: number, customization: Message): string; + + /** + * Hash and return ArrayBuffer. + * + * @param message The message you want to hash. + * @param blockSize The ParallelHash block size in bytes. + * @param outputBits The length of output. + * @param customization The customization string. + */ + arrayBuffer(message: Message, blockSize: number, outputBits: number, customization: Message): ArrayBuffer; + + /** + * Hash and return integer array. + * + * @param message The message you want to hash. + * @param blockSize The ParallelHash block size in bytes. + * @param outputBits The length of output. + * @param customization The customization string. + */ + digest(message: Message, blockSize: number, outputBits: number, customization: Message): number[]; + + /** + * Hash and return integer array. + * + * @param message The message you want to hash. + * @param blockSize The ParallelHash block size in bytes. + * @param outputBits The length of output. + * @param customization The customization string. + */ + array(message: Message, blockSize: number, outputBits: number, customization: Message): number[]; + + /** + * Create a ParallelHash object. + * + * @param blockSize The ParallelHash block size in bytes. + * @param outputBits The length of output. + * @param customization The customization string. + */ + create(blockSize: number, outputBits: number, customization: Message): ParallelHash; + + /** + * Create a ParallelHash object and hash message. + * + * @param message The message you want to hash. + * @param blockSize The ParallelHash block size in bytes. + * @param outputBits The length of output. + * @param customization The customization string. + */ + update(message: Message, blockSize: number, outputBits: number, customization: Message): ParallelHash; +} + +export var parallelhash_128: ParallelHashMethod; +export var parallelhash_256: ParallelHashMethod; +export var parallelhash128: ParallelHashMethod; +export var parallelhash256: ParallelHashMethod; +export var parallelhashxof_128: ParallelHashMethod; +export var parallelhashxof_256: ParallelHashMethod; +export var parallelhashxof128: ParallelHashMethod; +export var parallelhashxof256: ParallelHashMethod; diff --git a/package.json b/package.json index 630ed45..75c7d6b 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "js-sha3", - "version": "0.12.0", - "description": "A simple SHA-3 / Keccak / SHAKE / cSHAKE / KMAC / TupleHash hash function for JavaScript supports UTF-8 encoding.", + "version": "0.13.0", + "description": "A simple SHA-3 / Keccak / SHAKE / cSHAKE / KMAC / TupleHash / ParallelHash hash function for JavaScript supports UTF-8 encoding.", "main": "src/sha3.js", "module": "build/sha3.mjs", "exports": { @@ -45,6 +45,7 @@ "cshake", "kmac", "tuplehash", + "parallelhash", "hash", "encryption", "cryptography", diff --git a/src/sha3.js b/src/sha3.js index 598d4a1..7cf1b25 100644 --- a/src/sha3.js +++ b/src/sha3.js @@ -1,7 +1,7 @@ /** * [js-sha3]{@link https://github.com/emn178/js-sha3} * - * @version 0.12.0 + * @version 0.13.0 * @author Chen, Yi-Cyuan [emn178@gmail.com] * @copyright Chen, Yi-Cyuan 2015-2026 * @license MIT @@ -16,6 +16,7 @@ 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 BLOCK_SIZE_ERROR = 'block size is invalid'; var WINDOW = typeof window === 'object'; var root = WINDOW ? window : {}; if (root.JS_SHA3_NO_WINDOW) { @@ -123,6 +124,12 @@ }; }; + var createParallelHashOutputMethod = function (bits, padding, xof, outputType) { + return function (message, blockSize, outputBits, s) { + return methods[(xof ? 'parallelhashxof' : 'parallelhash') + bits].update(message, blockSize, outputBits, s)[outputType](); + }; + }; + var createOutputMethods = function (method, createMethod, bits, padding) { for (var i = 0; i < OUTPUT_TYPES.length; ++i) { var type = OUTPUT_TYPES[i]; @@ -204,6 +211,26 @@ }, bits, padding); }; + var createParallelHashMethod = function (bits, padding, xof) { + var w = CSHAKE_BYTEPAD[bits]; + var method = createParallelHashOutputMethod(bits, padding, xof, 'hex'); + method.create = function (blockSize, outputBits, s) { + if (typeof blockSize !== 'number' || !isFinite(blockSize) || blockSize < 1 || + Math.floor(blockSize) !== blockSize || blockSize > 0x0fffffff) { + throw new Error(BLOCK_SIZE_ERROR); + } + var hash = new ParallelHash(bits, padding, outputBits, xof, blockSize).bytepad(['ParallelHash', s], w); + hash.encode(blockSize, false); + return hash; + }; + method.update = function (message, blockSize, outputBits, s) { + return method.create(blockSize, outputBits, s).update(message); + }; + return createOutputMethods(method, function (b, p, outputType) { + return createParallelHashOutputMethod(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 }, @@ -220,6 +247,12 @@ }}, { name: 'tuplehashxof', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) { return createTupleHashMethod(bits, padding, true); + }}, + { name: 'parallelhash', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) { + return createParallelHashMethod(bits, padding, false); + }}, + { name: 'parallelhashxof', padding: CSHAKE_PADDING, bits: SHAKE_BITS, createMethod: function (bits, padding) { + return createParallelHashMethod(bits, padding, true); }} ]; @@ -589,6 +622,93 @@ return Kmac.prototype.finalize.call(this); }; + function ParallelHash(bits, padding, outputBits, xof, blockSize) { + Kmac.call(this, bits, padding, outputBits, xof); + this.bits = bits; + this.blockSize = blockSize; + this.inner = null; + this.innerBytes = 0; + this.blockNumber = 0; + } + + ParallelHash.prototype = new Kmac(); + + ParallelHash.prototype._finishInner = function () { + Kmac.prototype.update.call(this, this.inner.array()); + this.inner = null; + this.innerBytes = 0; + ++this.blockNumber; + }; + + ParallelHash.prototype._updateBytes = function (message) { + var length = message.length; + if (!length) { + return; + } + + var slice = message.subarray || message.slice; + var blockSize = this.blockSize; + var index = 0; + while (index < length) { + if (!this.inner) { + this.inner = new Keccak(this.bits, SHAKE_PADDING, this.bits << 1); + } + var take = blockSize - this.innerBytes; + if (length - index < take) { + take = length - index; + } + this.inner.update(slice.call(message, index, index + take)); + this.innerBytes += take; + index += take; + if (this.innerBytes === blockSize) { + this._finishInner(); + } + } + }; + + ParallelHash.prototype.update = function (message) { + if (this.finalized) { + throw new Error(FINALIZE_ERROR); + } + var result = formatMessage(message); + message = result[0]; + if (result[1]) { + var bytes = [], length = message.length, index = 0, code, i; + for (i = 0; i < length; ++i) { + code = message.charCodeAt(i); + if (code < 0x80) { + bytes[index++] = code; + } else if (code < 0x800) { + bytes[index++] = (0xc0 | (code >>> 6)); + bytes[index++] = (0x80 | (code & 0x3f)); + } else if (code < 0xd800 || code >= 0xe000) { + bytes[index++] = (0xe0 | (code >>> 12)); + bytes[index++] = (0x80 | ((code >>> 6) & 0x3f)); + bytes[index++] = (0x80 | (code & 0x3f)); + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++i) & 0x3ff)); + bytes[index++] = (0xf0 | (code >>> 18)); + bytes[index++] = (0x80 | ((code >>> 12) & 0x3f)); + bytes[index++] = (0x80 | ((code >>> 6) & 0x3f)); + bytes[index++] = (0x80 | (code & 0x3f)); + } + } + message = bytes; + } + this._updateBytes(message); + return this; + }; + + ParallelHash.prototype.finalize = function () { + if (!this.finalized) { + if (this.inner) { + this._finishInner(); + } + this.encode(this.blockNumber, true); + } + 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, diff --git a/src/sha3.mjs b/src/sha3.mjs index 7ddb2a5..3aea0d3 100644 --- a/src/sha3.mjs +++ b/src/sha3.mjs @@ -41,7 +41,16 @@ export const { tuplehashxof_128, tuplehashxof_256, tuplehashxof128, - tuplehashxof256 + tuplehashxof256, + + parallelhash_128, + parallelhash_256, + parallelhash128, + parallelhash256, + parallelhashxof_128, + parallelhashxof_256, + parallelhashxof128, + parallelhashxof256 } = sha3; export default sha3; diff --git a/tests/node-test.js b/tests/node-test.js index 969cbf8..4fd141e 100644 --- a/tests/node-test.js +++ b/tests/node-test.js @@ -22,6 +22,10 @@ function unset() { tuplehash256 = null; tuplehashxof128 = null; tuplehashxof256 = null; + parallelhash128 = null; + parallelhash256 = null; + parallelhashxof128 = null; + parallelhashxof256 = null; BUFFER = undefined; JS_SHA3_NO_WINDOW = undefined; JS_SHA3_NO_NODE_JS = undefined; @@ -53,6 +57,10 @@ function requireToGlobal() { tuplehash256 = sha3.tuplehash256; tuplehashxof128 = sha3.tuplehashxof128; tuplehashxof256 = sha3.tuplehashxof256; + parallelhash128 = sha3.parallelhash128; + parallelhash256 = sha3.parallelhash256; + parallelhashxof128 = sha3.parallelhashxof128; + parallelhashxof256 = sha3.parallelhashxof256; } function runCommonJsTest() { @@ -70,6 +78,7 @@ function runWindowTest(extra) { require('./test-cshake.js'); require('./test-kmac.js'); require('./test-tuplehash.js'); + require('./test-parallelhash.js'); } unset(); } @@ -127,6 +136,10 @@ define = function (func) { tuplehash256 = sha3.tuplehash256; tuplehashxof128 = sha3.tuplehashxof128; tuplehashxof256 = sha3.tuplehashxof256; + parallelhash128 = sha3.parallelhash128; + parallelhash256 = sha3.parallelhash256; + parallelhashxof128 = sha3.parallelhashxof128; + parallelhashxof256 = sha3.parallelhashxof256; require('./test.js'); }; define.amd = true; diff --git a/tests/test-parallelhash.js b/tests/test-parallelhash.js new file mode 100644 index 0000000..da23852 --- /dev/null +++ b/tests/test-parallelhash.js @@ -0,0 +1,251 @@ +(function (parallelhash256, parallelhash128, parallelhashxof256, parallelhashxof128) { + // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/ParallelHash_samples.pdf + // https://csrc.nist.gov/CSRC/media/Projects/Cryptographic-Standards-and-Guidelines/documents/examples/ParallelHashXOF_samples.pdf + var d1 = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27 + ]; + var d2 = [ + 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, + 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, + 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, + 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, + 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b + ]; + + var testCases = [ + { + name: 'parallelhash128', + method: parallelhash128, + cases: [ + { + message: d1, + blockSize: 8, + bits: 256, + s: '', + output: 'ba8dc1d1d979331d3f813603c67f72609ab5e44b94a0b8f9af46514454a2b4f5' + }, + { + message: d1, + blockSize: 8, + bits: 256, + s: 'Parallel Data', + output: 'fc484dcb3f84dceedc353438151bee58157d6efed0445a81f165e495795b7206' + }, + { + message: d2, + blockSize: 12, + bits: 256, + s: 'Parallel Data', + output: 'f7fd5312896c6685c828af7e2adb97e393e7f8d54e3c2ea4b95e5aca3796e8fc' + } + ] + }, + { + name: 'parallelhash256', + method: parallelhash256, + cases: [ + { + message: d1, + blockSize: 8, + bits: 512, + s: '', + output: 'bc1ef124da34495e948ead207dd9842235da432d2bbc54b4c110e64c451105531b7f2a3e0ce055c02805e7c2de1fb746af97a1dd01f43b824e31b87612410429' + }, + { + message: d1, + blockSize: 8, + bits: 512, + s: 'Parallel Data', + output: 'cdf15289b54f6212b4bc270528b49526006dd9b54e2b6add1ef6900dda3963bb33a72491f236969ca8afaea29c682d47a393c065b38e29fae651a2091c833110' + }, + { + message: d2, + blockSize: 12, + bits: 512, + s: 'Parallel Data', + output: '69d0fcb764ea055dd09334bc6021cb7e4b61348dff375da262671cdec3effa8d1b4568a6cce16b1cad946ddde27f6ce2b8dee4cd1b24851ebf00eb90d43813e9' + } + ] + }, + { + name: 'parallelhashxof128', + method: parallelhashxof128, + cases: [ + { + message: d1, + blockSize: 8, + bits: 256, + s: '', + output: 'fe47d661e49ffe5b7d999922c062356750caf552985b8e8ce6667f2727c3c8d3' + }, + { + message: d1, + blockSize: 8, + bits: 256, + s: 'Parallel Data', + output: 'ea2a793140820f7a128b8eb70a9439f93257c6e6e79b4a540d291d6dae7098d7' + }, + { + message: d2, + blockSize: 12, + bits: 256, + s: 'Parallel Data', + output: '0127ad9772ab904691987fcc4a24888f341fa0db2145e872d4efd255376602f0' + } + ] + }, + { + name: 'parallelhashxof256', + method: parallelhashxof256, + cases: [ + { + message: d1, + blockSize: 8, + bits: 512, + s: '', + output: 'c10a052722614684144d28474850b410757e3cba87651ba167a5cbddff7f466675fbf84bcae7378ac444be681d729499afca667fb879348bfdda427863c82f1c' + }, + { + message: d1, + blockSize: 8, + bits: 512, + s: 'Parallel Data', + output: '538e105f1a22f44ed2f5cc1674fbd40be803d9c99bf5f8d90a2c8193f3fe6ea768e5c1a20987e2c9c65febed03887a51d35624ed12377594b5585541dc377efc' + }, + { + message: d2, + blockSize: 12, + bits: 512, + s: 'Parallel Data', + output: '6b3e790b330c889a204c2fbc728d809f19367328d852f4002dc829f73afd6bcefb7fe5b607b13a801c0be5c1170bdb794e339458fdb0e62a6af3d42558970249' + } + ] + } + ]; + + testCases.forEach(function (testCase) { + describe('#' + testCase.name, function () { + testCase.cases.forEach(function (c) { + it('should match NIST sample vector', function () { + expect(testCase.method(c.message, c.blockSize, c.bits, c.s)).to.be(c.output); + }); + }); + }); + }); + + describe('#parallelhash API', function () { + it('should match instance update and method update with one-shot', function () { + var expected = parallelhash128(d1, 8, 256, 'cache'); + var incremental = parallelhash128.create(8, 256, 'cache').update(d1.slice(0, 10)).update(d1.slice(10)).hex(); + var methodUpdate = parallelhash128.update(d1.slice(0, 5), 8, 256, 'cache').update(d1.slice(5)).hex(); + expect(incremental).to.be(expected); + expect(methodUpdate).to.be(expected); + expect(parallelhash128.update(d1, 8, 256, 'cache').hex()).to.be(expected); + }); + + it('should stream binary messages in irregular chunks', function () { + var expected = parallelhash128(d2, 12, 256, ''); + var hash = parallelhash128.create(12, 256, ''); + hash.update(d2.slice(0, 1)); + hash.update(d2.slice(1, 17)); + hash.update(d2.slice(17, 50)); + hash.update(d2.slice(50)); + expect(hash.hex()).to.be(expected); + }); + + it('should stream ArrayBuffer and Uint8Array views', function () { + var expected = parallelhash128(d1, 8, 256, ''); + var buffer = new Uint8Array(d1).buffer; + var view = new Uint8Array(new Uint8Array(d1).buffer, 0, d1.length); + expect(parallelhash128.create(8, 256, '').update(buffer).hex()).to.be(expected); + expect(parallelhash128.create(8, 256, '').update(view).hex()).to.be(expected); + }); + + it('should hash empty message with n = 0', function () { + var empty = parallelhash128([], 8, 256, ''); + var emptyString = parallelhash128('', 8, 256, ''); + expect(empty).to.be(emptyString); + expect(empty).to.not.be(parallelhash128([0x00], 8, 256, '')); + }); + + it('should handle UTF-8 strings across block boundaries', function () { + var message = 'åbc'; // 2 + 1 + 1 = 4 UTF-8 bytes + var expected = parallelhash128(message, 3, 256, ''); + var hash = parallelhash128.create(3, 256, ''); + hash.update('å').update('bc'); + expect(hash.hex()).to.be(expected); + }); + + it('should encode 3-byte and 4-byte UTF-8 characters', function () { + var message = '中\uE000\uD83D\uDE00'; // 3 + 3 + 4 = 10 UTF-8 bytes + var expected = parallelhash128(message, 4, 256, ''); + var hash = parallelhash128.create(4, 256, ''); + hash.update('中').update('\uE000').update('\uD83D\uDE00'); + expect(hash.hex()).to.be(expected); + expect(hash.array().length).to.be(32); + }); + + it('should keep absorbing when update is shorter than remaining block space', function () { + var expected = parallelhash128(d1, 8, 256, ''); + var hash = parallelhash128.create(8, 256, ''); + hash.update(d1.slice(0, 3)); // partial inner block, need 5 more + hash.update(d1.slice(3, 5)); // still short, continue same inner SHAKE + hash.update(d1.slice(5)); // finish remaining blocks + expect(hash.hex()).to.be(expected); + }); + + it('should not be affected by mutating input after update', function () { + var expected = parallelhash128(d1, 8, 256, ''); + var chunk = new Uint8Array(d1.slice(0, 3)); + var rest = new Uint8Array(d1.slice(3)); + var hash = parallelhash128.create(8, 256, ''); + hash.update(chunk); + chunk[0] = 0xff; + chunk[1] = 0xff; + chunk[2] = 0xff; + hash.update(rest); + expect(hash.hex()).to.be(expected); + }); + + it('should allow repeated output representations', function () { + var hash = parallelhash128.create(8, 256, '').update(d1); + 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(d1); }).to.throwError(/finalize already called/); + }); + + it('should require customization like KMAC', function () { + expect(function () { parallelhash128(d1, 8, 256); }).to.throwError(/input is invalid type/); + }); + + it('should reject invalid block sizes', function () { + expect(function () { parallelhash128.create(0, 256, ''); }).to.throwError(/block size is invalid/); + expect(function () { parallelhash128.create(-1, 256, ''); }).to.throwError(/block size is invalid/); + expect(function () { parallelhash128.create(1.5, 256, ''); }).to.throwError(/block size is invalid/); + expect(function () { parallelhash128.create(NaN, 256, ''); }).to.throwError(/block size is invalid/); + expect(function () { parallelhash128.create(0x20000000, 256, ''); }).to.throwError(/block size is invalid/); + }); + + it('should export identical aliases', function () { + var sha3 = require('../src/sha3.js'); + expect(sha3.parallelhash128).to.be(sha3.parallelhash_128); + expect(sha3.parallelhash256).to.be(sha3.parallelhash_256); + expect(sha3.parallelhashxof128).to.be(sha3.parallelhashxof_128); + expect(sha3.parallelhashxof256).to.be(sha3.parallelhashxof_256); + }); + + it('should reject update after finalize', function () { + var hash = parallelhash128.create(8, 256, '').update([0x00]); + hash.hex(); + expect(function () { hash.update([0x01]); }).to.throwError(/finalize already called/); + }); + }); +})(parallelhash256, parallelhash128, parallelhashxof256, parallelhashxof128);