sha3.js 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. import {
  2. WordArray,
  3. Hasher,
  4. } from './core.js';
  5. import { X64Word } from './x64-core.js';
  6. // Constants tables
  7. const RHO_OFFSETS = [];
  8. const PI_INDEXES = [];
  9. const ROUND_CONSTANTS = [];
  10. // Compute Constants
  11. // Compute rho offset constants
  12. let _x = 1;
  13. let _y = 0;
  14. for (let t = 0; t < 24; t += 1) {
  15. RHO_OFFSETS[_x + 5 * _y] = ((t + 1) * (t + 2) / 2) % 64;
  16. const newX = _y % 5;
  17. const newY = (2 * _x + 3 * _y) % 5;
  18. _x = newX;
  19. _y = newY;
  20. }
  21. // Compute pi index constants
  22. for (let x = 0; x < 5; x += 1) {
  23. for (let y = 0; y < 5; y += 1) {
  24. PI_INDEXES[x + 5 * y] = y + ((2 * x + 3 * y) % 5) * 5;
  25. }
  26. }
  27. // Compute round constants
  28. let LFSR = 0x01;
  29. for (let i = 0; i < 24; i += 1) {
  30. let roundConstantMsw = 0;
  31. let roundConstantLsw = 0;
  32. for (let j = 0; j < 7; j += 1) {
  33. if (LFSR & 0x01) {
  34. const bitPosition = (1 << j) - 1;
  35. if (bitPosition < 32) {
  36. roundConstantLsw ^= 1 << bitPosition;
  37. } else /* if (bitPosition >= 32) */ {
  38. roundConstantMsw ^= 1 << (bitPosition - 32);
  39. }
  40. }
  41. // Compute next LFSR
  42. if (LFSR & 0x80) {
  43. // Primitive polynomial over GF(2): x^8 + x^6 + x^5 + x^4 + 1
  44. LFSR = (LFSR << 1) ^ 0x71;
  45. } else {
  46. LFSR <<= 1;
  47. }
  48. }
  49. ROUND_CONSTANTS[i] = X64Word.create(roundConstantMsw, roundConstantLsw);
  50. }
  51. // Reusable objects for temporary values
  52. const T = [];
  53. for (let i = 0; i < 25; i += 1) {
  54. T[i] = X64Word.create();
  55. }
  56. /**
  57. * SHA-3 hash algorithm.
  58. */
  59. export class SHA3Algo extends Hasher {
  60. constructor(cfg) {
  61. /**
  62. * Configuration options.
  63. *
  64. * @property {number} outputLength
  65. * The desired number of bits in the output hash.
  66. * Only values permitted are: 224, 256, 384, 512.
  67. * Default: 512
  68. */
  69. super(Object.assign(
  70. { outputLength: 512 },
  71. cfg,
  72. ));
  73. }
  74. _doReset() {
  75. this._state = [];
  76. const state = this._state;
  77. for (let i = 0; i < 25; i += 1) {
  78. state[i] = new X64Word();
  79. }
  80. this.blockSize = (1600 - 2 * this.cfg.outputLength) / 32;
  81. }
  82. _doProcessBlock(M, offset) {
  83. // Shortcuts
  84. const state = this._state;
  85. const nBlockSizeLanes = this.blockSize / 2;
  86. // Absorb
  87. for (let i = 0; i < nBlockSizeLanes; i += 1) {
  88. // Shortcuts
  89. let M2i = M[offset + 2 * i];
  90. let M2i1 = M[offset + 2 * i + 1];
  91. // Swap endian
  92. M2i = (((M2i << 8) | (M2i >>> 24)) & 0x00ff00ff)
  93. | (((M2i << 24) | (M2i >>> 8)) & 0xff00ff00);
  94. M2i1 = (((M2i1 << 8) | (M2i1 >>> 24)) & 0x00ff00ff)
  95. | (((M2i1 << 24) | (M2i1 >>> 8)) & 0xff00ff00);
  96. // Absorb message into state
  97. const lane = state[i];
  98. lane.high ^= M2i1;
  99. lane.low ^= M2i;
  100. }
  101. // Rounds
  102. for (let round = 0; round < 24; round += 1) {
  103. // Theta
  104. for (let x = 0; x < 5; x += 1) {
  105. // Mix column lanes
  106. let tMsw = 0;
  107. let tLsw = 0;
  108. for (let y = 0; y < 5; y += 1) {
  109. const lane = state[x + 5 * y];
  110. tMsw ^= lane.high;
  111. tLsw ^= lane.low;
  112. }
  113. // Temporary values
  114. const Tx = T[x];
  115. Tx.high = tMsw;
  116. Tx.low = tLsw;
  117. }
  118. for (let x = 0; x < 5; x += 1) {
  119. // Shortcuts
  120. const Tx4 = T[(x + 4) % 5];
  121. const Tx1 = T[(x + 1) % 5];
  122. const Tx1Msw = Tx1.high;
  123. const Tx1Lsw = Tx1.low;
  124. // Mix surrounding columns
  125. const tMsw = Tx4.high ^ ((Tx1Msw << 1) | (Tx1Lsw >>> 31));
  126. const tLsw = Tx4.low ^ ((Tx1Lsw << 1) | (Tx1Msw >>> 31));
  127. for (let y = 0; y < 5; y += 1) {
  128. const lane = state[x + 5 * y];
  129. lane.high ^= tMsw;
  130. lane.low ^= tLsw;
  131. }
  132. }
  133. // Rho Pi
  134. for (let laneIndex = 1; laneIndex < 25; laneIndex += 1) {
  135. let tMsw;
  136. let tLsw;
  137. // Shortcuts
  138. const lane = state[laneIndex];
  139. const laneMsw = lane.high;
  140. const laneLsw = lane.low;
  141. const rhoOffset = RHO_OFFSETS[laneIndex];
  142. // Rotate lanes
  143. if (rhoOffset < 32) {
  144. tMsw = (laneMsw << rhoOffset) | (laneLsw >>> (32 - rhoOffset));
  145. tLsw = (laneLsw << rhoOffset) | (laneMsw >>> (32 - rhoOffset));
  146. } else /* if (rhoOffset >= 32) */ {
  147. tMsw = (laneLsw << (rhoOffset - 32)) | (laneMsw >>> (64 - rhoOffset));
  148. tLsw = (laneMsw << (rhoOffset - 32)) | (laneLsw >>> (64 - rhoOffset));
  149. }
  150. // Transpose lanes
  151. const TPiLane = T[PI_INDEXES[laneIndex]];
  152. TPiLane.high = tMsw;
  153. TPiLane.low = tLsw;
  154. }
  155. // Rho pi at x = y = 0
  156. const T0 = T[0];
  157. const state0 = state[0];
  158. T0.high = state0.high;
  159. T0.low = state0.low;
  160. // Chi
  161. for (let x = 0; x < 5; x += 1) {
  162. for (let y = 0; y < 5; y += 1) {
  163. // Shortcuts
  164. const laneIndex = x + 5 * y;
  165. const lane = state[laneIndex];
  166. const TLane = T[laneIndex];
  167. const Tx1Lane = T[((x + 1) % 5) + 5 * y];
  168. const Tx2Lane = T[((x + 2) % 5) + 5 * y];
  169. // Mix rows
  170. lane.high = TLane.high ^ (~Tx1Lane.high & Tx2Lane.high);
  171. lane.low = TLane.low ^ (~Tx1Lane.low & Tx2Lane.low);
  172. }
  173. }
  174. // Iota
  175. const lane = state[0];
  176. const roundConstant = ROUND_CONSTANTS[round];
  177. lane.high ^= roundConstant.high;
  178. lane.low ^= roundConstant.low;
  179. }
  180. }
  181. _doFinalize() {
  182. // Shortcuts
  183. const data = this._data;
  184. const dataWords = data.words;
  185. const nBitsLeft = data.sigBytes * 8;
  186. const blockSizeBits = this.blockSize * 32;
  187. // Add padding
  188. dataWords[nBitsLeft >>> 5] |= 0x1 << (24 - (nBitsLeft % 32));
  189. dataWords[((Math.ceil((nBitsLeft + 1) / blockSizeBits) * blockSizeBits) >>> 5) - 1] |= 0x80;
  190. data.sigBytes = dataWords.length * 4;
  191. // Hash final blocks
  192. this._process();
  193. // Shortcuts
  194. const state = this._state;
  195. const outputLengthBytes = this.cfg.outputLength / 8;
  196. const outputLengthLanes = outputLengthBytes / 8;
  197. // Squeeze
  198. const hashWords = [];
  199. for (let i = 0; i < outputLengthLanes; i += 1) {
  200. // Shortcuts
  201. const lane = state[i];
  202. let laneMsw = lane.high;
  203. let laneLsw = lane.low;
  204. // Swap endian
  205. laneMsw = (((laneMsw << 8) | (laneMsw >>> 24)) & 0x00ff00ff)
  206. | (((laneMsw << 24) | (laneMsw >>> 8)) & 0xff00ff00);
  207. laneLsw = (((laneLsw << 8) | (laneLsw >>> 24)) & 0x00ff00ff)
  208. | (((laneLsw << 24) | (laneLsw >>> 8)) & 0xff00ff00);
  209. // Squeeze state to retrieve hash
  210. hashWords.push(laneLsw);
  211. hashWords.push(laneMsw);
  212. }
  213. // Return final computed hash
  214. return new WordArray(hashWords, outputLengthBytes);
  215. }
  216. clone() {
  217. const clone = super.clone.call(this);
  218. clone._state = this._state.slice(0);
  219. const state = clone._state;
  220. for (let i = 0; i < 25; i += 1) {
  221. state[i] = state[i].clone();
  222. }
  223. return clone;
  224. }
  225. }
  226. /**
  227. * Shortcut function to the hasher's object interface.
  228. *
  229. * @param {WordArray|string} message The message to hash.
  230. *
  231. * @return {WordArray} The hash.
  232. *
  233. * @static
  234. *
  235. * @example
  236. *
  237. * var hash = CryptoJS.SHA3('message');
  238. * var hash = CryptoJS.SHA3(wordArray);
  239. */
  240. export const SHA3 = Hasher._createHelper(SHA3Algo);
  241. /**
  242. * Shortcut function to the HMAC's object interface.
  243. *
  244. * @param {WordArray|string} message The message to hash.
  245. * @param {WordArray|string} key The secret key.
  246. *
  247. * @return {WordArray} The HMAC.
  248. *
  249. * @static
  250. *
  251. * @example
  252. *
  253. * var hmac = CryptoJS.HmacSHA3(message, key);
  254. */
  255. export const HmacSHA3 = Hasher._createHmacHelper(SHA3Algo);