Blake3Digest.cs 30 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051
  1. #if !BESTHTTP_DISABLE_ALTERNATE_SSL && (!UNITY_WEBGL || UNITY_EDITOR)
  2. #pragma warning disable
  3. using System;
  4. using System.Collections.Generic;
  5. #if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
  6. using System.Runtime.CompilerServices;
  7. #endif
  8. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Parameters;
  9. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Utilities;
  10. using Best.HTTP.SecureProtocol.Org.BouncyCastle.Utilities;
  11. namespace Best.HTTP.SecureProtocol.Org.BouncyCastle.Crypto.Digests
  12. {
  13. public sealed class Blake3Digest
  14. : IDigest, IMemoable, IXof
  15. {
  16. /**
  17. * Already outputting error.
  18. */
  19. private const string ERR_OUTPUTTING = "Already outputting";
  20. /**
  21. * Number of Words.
  22. */
  23. private const int NUMWORDS = 8;
  24. /**
  25. * Number of Rounds.
  26. */
  27. private const int ROUNDS = 7;
  28. /**
  29. * Buffer length.
  30. */
  31. private const int BLOCKLEN = NUMWORDS * Integers.NumBytes * 2;
  32. /**
  33. * Chunk length.
  34. */
  35. private const int CHUNKLEN = 1024;
  36. /**
  37. * ChunkStart Flag.
  38. */
  39. private const int CHUNKSTART = 1;
  40. /**
  41. * ChunkEnd Flag.
  42. */
  43. private const int CHUNKEND = 2;
  44. /**
  45. * Parent Flag.
  46. */
  47. private const int PARENT = 4;
  48. /**
  49. * Root Flag.
  50. */
  51. private const int ROOT = 8;
  52. /**
  53. * KeyedHash Flag.
  54. */
  55. private const int KEYEDHASH = 16;
  56. /**
  57. * DeriveContext Flag.
  58. */
  59. private const int DERIVECONTEXT = 32;
  60. /**
  61. * DeriveKey Flag.
  62. */
  63. private const int DERIVEKEY = 64;
  64. /**
  65. * Chaining0 State Locations.
  66. */
  67. private const int CHAINING0 = 0;
  68. /**
  69. * Chaining1 State Location.
  70. */
  71. private const int CHAINING1 = 1;
  72. /**
  73. * Chaining2 State Location.
  74. */
  75. private const int CHAINING2 = 2;
  76. /**
  77. * Chaining3 State Location.
  78. */
  79. private const int CHAINING3 = 3;
  80. /**
  81. * Chaining4 State Location.
  82. */
  83. private const int CHAINING4 = 4;
  84. /**
  85. * Chaining5 State Location.
  86. */
  87. private const int CHAINING5 = 5;
  88. /**
  89. * Chaining6 State Location.
  90. */
  91. private const int CHAINING6 = 6;
  92. /**
  93. * Chaining7 State Location.
  94. */
  95. private const int CHAINING7 = 7;
  96. /**
  97. * IV0 State Locations.
  98. */
  99. private const int IV0 = 8;
  100. /**
  101. * IV1 State Location.
  102. */
  103. private const int IV1 = 9;
  104. /**
  105. * IV2 State Location.
  106. */
  107. private const int IV2 = 10;
  108. /**
  109. * IV3 State Location.
  110. */
  111. private const int IV3 = 11;
  112. /**
  113. * Count0 State Location.
  114. */
  115. private const int COUNT0 = 12;
  116. /**
  117. * Count1 State Location.
  118. */
  119. private const int COUNT1 = 13;
  120. /**
  121. * DataLen State Location.
  122. */
  123. private const int DATALEN = 14;
  124. /**
  125. * Flags State Location.
  126. */
  127. private const int FLAGS = 15;
  128. /**
  129. * Message word permutations.
  130. */
  131. private static readonly byte[] SIGMA = { 2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8 };
  132. /**
  133. * Blake3 Initialization Vector.
  134. */
  135. private static readonly uint[] IV = {
  136. 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19
  137. };
  138. /**
  139. * The byte input/output buffer.
  140. */
  141. private readonly byte[] m_theBuffer = new byte[BLOCKLEN];
  142. /**
  143. * The key.
  144. */
  145. private readonly uint[] m_theK = new uint[NUMWORDS];
  146. /**
  147. * The chaining value.
  148. */
  149. private readonly uint[] m_theChaining = new uint[NUMWORDS];
  150. /**
  151. * The state.
  152. */
  153. private readonly uint[] m_theV = new uint[NUMWORDS << 1];
  154. /**
  155. * The message Buffer.
  156. */
  157. private readonly uint[] m_theM = new uint[NUMWORDS << 1];
  158. /**
  159. * The indices.
  160. */
  161. private readonly byte[] m_theIndices = new byte[NUMWORDS << 1];
  162. /**
  163. * The chainingStack.
  164. */
  165. private readonly List<uint[]> m_theStack = new List<uint[]>();
  166. /**
  167. * The default digestLength.
  168. */
  169. private readonly int m_theDigestLen;
  170. /**
  171. * Are we outputting?
  172. */
  173. private bool m_outputting;
  174. /**
  175. * How many more bytes can we output?
  176. */
  177. private long m_outputAvailable;
  178. /**
  179. * The current mode.
  180. */
  181. private int m_theMode;
  182. /**
  183. * The output mode.
  184. */
  185. private int m_theOutputMode;
  186. /**
  187. * The output dataLen.
  188. */
  189. private int m_theOutputDataLen;
  190. /**
  191. * The block counter.
  192. */
  193. private long m_theCounter;
  194. /**
  195. * The # of bytes in the current block.
  196. */
  197. private int m_theCurrBytes;
  198. /**
  199. * The position of the next byte in the buffer.
  200. */
  201. private int m_thePos;
  202. public Blake3Digest()
  203. : this((BLOCKLEN >> 1) * 8)
  204. {
  205. }
  206. /// <param name="pDigestSize">the default digest size (in bits)</param>
  207. public Blake3Digest(int pDigestSize)
  208. {
  209. m_theDigestLen = pDigestSize / 8;
  210. Init(null);
  211. }
  212. /**
  213. * Constructor.
  214. *
  215. * @param pSource the source digest.
  216. */
  217. public Blake3Digest(Blake3Digest pSource)
  218. {
  219. /* Copy default digest length */
  220. m_theDigestLen = pSource.m_theDigestLen;
  221. /* Initialise from source */
  222. Reset(pSource);
  223. }
  224. public int GetByteLength() => BLOCKLEN;
  225. public string AlgorithmName => "BLAKE3";
  226. public int GetDigestSize() => m_theDigestLen;
  227. /**
  228. * Initialise.
  229. *
  230. * @param pParams the parameters.
  231. */
  232. public void Init(Blake3Parameters pParams)
  233. {
  234. /* Access key/context */
  235. byte[] myKey = pParams?.GetKey();
  236. byte[] myContext = pParams?.GetContext();
  237. /* Reset the digest */
  238. Reset();
  239. /* If we have a key */
  240. if (myKey != null)
  241. {
  242. /* Initialise with the key */
  243. InitKey(myKey);
  244. Arrays.Fill(myKey, 0);
  245. /* else if we have a context */
  246. }
  247. else if (myContext != null)
  248. {
  249. /* Initialise for deriving context */
  250. InitNullKey();
  251. m_theMode = DERIVECONTEXT;
  252. /* Derive key from context */
  253. BlockUpdate(myContext, 0, myContext.Length);
  254. DoFinal(m_theBuffer, 0);
  255. InitKeyFromContext();
  256. Reset();
  257. /* Else init null key and reset mode */
  258. }
  259. else
  260. {
  261. InitNullKey();
  262. m_theMode = 0;
  263. }
  264. }
  265. public void Update(byte b)
  266. {
  267. /* Check that we are not outputting */
  268. if (m_outputting)
  269. throw new InvalidOperationException(ERR_OUTPUTTING);
  270. /* If the buffer is full */
  271. int blockLen = m_theBuffer.Length;
  272. int remainingLength = blockLen - m_thePos;
  273. if (remainingLength == 0)
  274. {
  275. /* Process the buffer */
  276. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  277. CompressBlock(m_theBuffer);
  278. #else
  279. CompressBlock(m_theBuffer, 0);
  280. #endif
  281. /* Reset the buffer */
  282. Arrays.Fill(m_theBuffer, 0);
  283. m_thePos = 0;
  284. }
  285. /* Store the byte */
  286. m_theBuffer[m_thePos] = b;
  287. m_thePos++;
  288. }
  289. public void BlockUpdate(byte[] pMessage, int pOffset, int pLen)
  290. {
  291. /* Ignore null operation */
  292. if (pMessage == null)
  293. return;
  294. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  295. BlockUpdate(pMessage.AsSpan(pOffset, pLen));
  296. #else
  297. if (pLen == 0)
  298. return;
  299. /* Check that we are not outputting */
  300. if (m_outputting)
  301. throw new InvalidOperationException(ERR_OUTPUTTING);
  302. /* Process any bytes currently in the buffer */
  303. int remainingLen = 0; // left bytes of buffer
  304. if (m_thePos != 0)
  305. {
  306. /* Calculate space remaining in the buffer */
  307. remainingLen = BLOCKLEN - m_thePos;
  308. /* If there is sufficient space in the buffer */
  309. if (remainingLen >= pLen)
  310. {
  311. /* Copy data into buffer and return */
  312. Array.Copy(pMessage, pOffset, m_theBuffer, m_thePos, pLen);
  313. m_thePos += pLen;
  314. return;
  315. }
  316. /* Fill the buffer */
  317. Array.Copy(pMessage, pOffset, m_theBuffer, m_thePos, remainingLen);
  318. /* Process the buffer */
  319. CompressBlock(m_theBuffer, 0);
  320. /* Reset the buffer */
  321. m_thePos = 0;
  322. Arrays.Fill(m_theBuffer, 0);
  323. }
  324. /* process all blocks except the last one */
  325. int messagePos;
  326. int blockWiseLastPos = pOffset + pLen - BLOCKLEN;
  327. for (messagePos = pOffset + remainingLen; messagePos < blockWiseLastPos; messagePos += BLOCKLEN)
  328. {
  329. /* Process the buffer */
  330. CompressBlock(pMessage, messagePos);
  331. }
  332. /* Fill the buffer with the remaining bytes of the message */
  333. int len = pLen - messagePos;
  334. Array.Copy(pMessage, messagePos, m_theBuffer, 0, pOffset + len);
  335. m_thePos += pOffset + len;
  336. #endif
  337. }
  338. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  339. public void BlockUpdate(ReadOnlySpan<byte> input)
  340. {
  341. if (input.IsEmpty)
  342. return;
  343. /* Check that we are not outputting */
  344. if (m_outputting)
  345. throw new InvalidOperationException(ERR_OUTPUTTING);
  346. int pLen = input.Length;
  347. /* Process any bytes currently in the buffer */
  348. int remainingLen = 0; // left bytes of buffer
  349. if (m_thePos != 0)
  350. {
  351. /* Calculate space remaining in the buffer */
  352. remainingLen = BLOCKLEN - m_thePos;
  353. /* If there is sufficient space in the buffer */
  354. if (remainingLen >= pLen)
  355. {
  356. /* Copy data into buffer and return */
  357. input.CopyTo(m_theBuffer.AsSpan(m_thePos));
  358. m_thePos += pLen;
  359. return;
  360. }
  361. /* Fill the buffer */
  362. input[..remainingLen].CopyTo(m_theBuffer.AsSpan(m_thePos));
  363. /* Process the buffer */
  364. CompressBlock(m_theBuffer);
  365. /* Reset the buffer */
  366. m_thePos = 0;
  367. Arrays.Fill(m_theBuffer, 0);
  368. }
  369. /* process all blocks except the last one */
  370. int messagePos;
  371. int blockWiseLastPos = pLen - BLOCKLEN;
  372. for (messagePos = remainingLen; messagePos < blockWiseLastPos; messagePos += BLOCKLEN)
  373. {
  374. /* Process the buffer */
  375. CompressBlock(input[messagePos..]);
  376. }
  377. /* Fill the buffer with the remaining bytes of the message */
  378. input[messagePos..].CopyTo(m_theBuffer);
  379. m_thePos += pLen - messagePos;
  380. }
  381. #endif
  382. public int DoFinal(byte[] pOutput, int pOutOffset)
  383. {
  384. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  385. return OutputFinal(pOutput.AsSpan(pOutOffset, GetDigestSize()));
  386. #else
  387. return OutputFinal(pOutput, pOutOffset, GetDigestSize());
  388. #endif
  389. }
  390. public int OutputFinal(byte[] pOut, int pOutOffset, int pOutLen)
  391. {
  392. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  393. return OutputFinal(pOut.AsSpan(pOutOffset, pOutLen));
  394. #else
  395. /* Reject if we are already outputting */
  396. if (m_outputting)
  397. throw new InvalidOperationException(ERR_OUTPUTTING);
  398. /* Build the required output */
  399. int length = Output(pOut, pOutOffset, pOutLen);
  400. /* reset the underlying digest and return the length */
  401. Reset();
  402. return length;
  403. #endif
  404. }
  405. public int Output(byte[] pOut, int pOutOffset, int pOutLen)
  406. {
  407. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  408. return Output(pOut.AsSpan(pOutOffset, pOutLen));
  409. #else
  410. /* If we have not started outputting yet */
  411. if (!m_outputting)
  412. {
  413. /* Process the buffer */
  414. CompressFinalBlock(m_thePos);
  415. }
  416. /* Reject if there is insufficient Xof remaining */
  417. if (pOutLen < 0 || (m_outputAvailable >= 0 && pOutLen > m_outputAvailable))
  418. throw new ArgumentException("Insufficient bytes remaining");
  419. /* If we have some remaining data in the current buffer */
  420. int dataLeft = pOutLen;
  421. int outPos = pOutOffset;
  422. if (m_thePos < BLOCKLEN)
  423. {
  424. /* Copy data from current hash */
  425. int dataToCopy = System.Math.Min(dataLeft, BLOCKLEN - m_thePos);
  426. Array.Copy(m_theBuffer, m_thePos, pOut, outPos, dataToCopy);
  427. /* Adjust counters */
  428. m_thePos += dataToCopy;
  429. outPos += dataToCopy;
  430. dataLeft -= dataToCopy;
  431. }
  432. /* Loop until we have completed the request */
  433. while (dataLeft > 0)
  434. {
  435. /* Calculate the next block */
  436. NextOutputBlock();
  437. /* Copy data from current hash */
  438. int dataToCopy = System.Math.Min(dataLeft, BLOCKLEN);
  439. Array.Copy(m_theBuffer, 0, pOut, outPos, dataToCopy);
  440. /* Adjust counters */
  441. m_thePos += dataToCopy;
  442. outPos += dataToCopy;
  443. dataLeft -= dataToCopy;
  444. }
  445. /* Adjust outputAvailable */
  446. m_outputAvailable -= pOutLen;
  447. /* Return the number of bytes transferred */
  448. return pOutLen;
  449. #endif
  450. }
  451. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  452. public int DoFinal(Span<byte> output)
  453. {
  454. return OutputFinal(output[..GetDigestSize()]);
  455. }
  456. public int OutputFinal(Span<byte> output)
  457. {
  458. /* Reject if we are already outputting */
  459. if (m_outputting)
  460. throw new InvalidOperationException(ERR_OUTPUTTING);
  461. /* Build the required output */
  462. int length = Output(output);
  463. /* reset the underlying digest and return the length */
  464. Reset();
  465. return length;
  466. }
  467. public int Output(Span<byte> output)
  468. {
  469. /* If we have not started outputting yet */
  470. if (!m_outputting)
  471. {
  472. /* Process the buffer */
  473. CompressFinalBlock(m_thePos);
  474. }
  475. int pOutOffset = 0, pOutLen = output.Length;
  476. /* Reject if there is insufficient Xof remaining */
  477. if (pOutLen < 0 || (m_outputAvailable >= 0 && pOutLen > m_outputAvailable))
  478. throw new ArgumentException("Insufficient bytes remaining");
  479. /* If we have some remaining data in the current buffer */
  480. int dataLeft = pOutLen;
  481. int outPos = pOutOffset;
  482. if (m_thePos < BLOCKLEN)
  483. {
  484. /* Copy data from current hash */
  485. int dataToCopy = System.Math.Min(dataLeft, BLOCKLEN - m_thePos);
  486. m_theBuffer.AsSpan(m_thePos, dataToCopy).CopyTo(output[outPos..]);
  487. /* Adjust counters */
  488. m_thePos += dataToCopy;
  489. outPos += dataToCopy;
  490. dataLeft -= dataToCopy;
  491. }
  492. /* Loop until we have completed the request */
  493. while (dataLeft > 0)
  494. {
  495. /* Calculate the next block */
  496. NextOutputBlock();
  497. /* Copy data from current hash */
  498. int dataToCopy = System.Math.Min(dataLeft, BLOCKLEN);
  499. m_theBuffer.AsSpan(0, dataToCopy).CopyTo(output[outPos..]);
  500. /* Adjust counters */
  501. m_thePos += dataToCopy;
  502. outPos += dataToCopy;
  503. dataLeft -= dataToCopy;
  504. }
  505. /* Adjust outputAvailable */
  506. m_outputAvailable -= pOutLen;
  507. /* Return the number of bytes transferred */
  508. return pOutLen;
  509. }
  510. #endif
  511. public void Reset()
  512. {
  513. ResetBlockCount();
  514. m_thePos = 0;
  515. m_outputting = false;
  516. Arrays.Fill(m_theBuffer, 0);
  517. }
  518. public void Reset(IMemoable pSource)
  519. {
  520. /* Access source */
  521. Blake3Digest mySource = (Blake3Digest)pSource;
  522. /* Reset counter */
  523. m_theCounter = mySource.m_theCounter;
  524. m_theCurrBytes = mySource.m_theCurrBytes;
  525. m_theMode = mySource.m_theMode;
  526. /* Reset output state */
  527. m_outputting = mySource.m_outputting;
  528. m_outputAvailable = mySource.m_outputAvailable;
  529. m_theOutputMode = mySource.m_theOutputMode;
  530. m_theOutputDataLen = mySource.m_theOutputDataLen;
  531. /* Copy state */
  532. Array.Copy(mySource.m_theChaining, 0, m_theChaining, 0, m_theChaining.Length);
  533. Array.Copy(mySource.m_theK, 0, m_theK, 0, m_theK.Length);
  534. Array.Copy(mySource.m_theM, 0, m_theM, 0, m_theM.Length);
  535. /* Copy stack */
  536. m_theStack.Clear();
  537. foreach (var element in mySource.m_theStack)
  538. {
  539. m_theStack.Add(Arrays.Clone(element));
  540. }
  541. /* Copy buffer */
  542. Array.Copy(mySource.m_theBuffer, 0, m_theBuffer, 0, m_theBuffer.Length);
  543. m_thePos = mySource.m_thePos;
  544. }
  545. public IMemoable Copy()
  546. {
  547. return new Blake3Digest(this);
  548. }
  549. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  550. private void CompressBlock(ReadOnlySpan<byte> block)
  551. {
  552. /* Initialise state and compress message */
  553. InitChunkBlock(BLOCKLEN, false);
  554. InitM(block);
  555. Compress();
  556. /* Adjust stack if we have completed a block */
  557. if (m_theCurrBytes == 0)
  558. {
  559. AdjustStack();
  560. }
  561. }
  562. private void InitM(ReadOnlySpan<byte> block)
  563. {
  564. /* Copy message bytes into word array */
  565. Pack.LE_To_UInt32(block, m_theM);
  566. }
  567. #else
  568. /**
  569. * Compress next block of the message.
  570. *
  571. * @param pMessage the message buffer
  572. * @param pMsgPos the position within the message buffer
  573. */
  574. private void CompressBlock(byte[] pMessage, int pMsgPos)
  575. {
  576. /* Initialise state and compress message */
  577. InitChunkBlock(BLOCKLEN, false);
  578. InitM(pMessage, pMsgPos);
  579. Compress();
  580. /* Adjust stack if we have completed a block */
  581. if (m_theCurrBytes == 0)
  582. {
  583. AdjustStack();
  584. }
  585. }
  586. /**
  587. * Initialise M from message.
  588. *
  589. * @param pMessage the source message
  590. * @param pMsgPos the message position
  591. */
  592. private void InitM(byte[] pMessage, int pMsgPos)
  593. {
  594. /* Copy message bytes into word array */
  595. Pack.LE_To_UInt32(pMessage, pMsgPos, m_theM);
  596. }
  597. #endif
  598. /**
  599. * Adjust the stack.
  600. */
  601. private void AdjustStack()
  602. {
  603. /* Loop to combine blocks */
  604. long myCount = m_theCounter;
  605. while (myCount > 0)
  606. {
  607. /* Break loop if we are not combining */
  608. if ((myCount & 1) == 1)
  609. break;
  610. /* Build the message to be hashed */
  611. uint[] myLeft = m_theStack[m_theStack.Count - 1];
  612. m_theStack.RemoveAt(m_theStack.Count - 1);
  613. Array.Copy(myLeft, 0, m_theM, 0, NUMWORDS);
  614. Array.Copy(m_theChaining, 0, m_theM, NUMWORDS, NUMWORDS);
  615. /* Create parent block */
  616. InitParentBlock();
  617. Compress();
  618. /* Next block */
  619. myCount >>= 1;
  620. }
  621. /* Add back to the stack */
  622. m_theStack.Add(Arrays.CopyOf(m_theChaining, NUMWORDS));
  623. }
  624. /**
  625. * Compress final block.
  626. *
  627. * @param pDataLen the data length
  628. */
  629. private void CompressFinalBlock(int pDataLen)
  630. {
  631. /* Initialise state and compress message */
  632. InitChunkBlock(pDataLen, true);
  633. #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER || UNITY_2021_2_OR_NEWER
  634. InitM(m_theBuffer);
  635. #else
  636. InitM(m_theBuffer, 0);
  637. #endif
  638. Compress();
  639. /* Finalise stack */
  640. ProcessStack();
  641. }
  642. /**
  643. * Process the stack.
  644. */
  645. private void ProcessStack()
  646. {
  647. /* Finalise stack */
  648. while (m_theStack.Count > 0)
  649. {
  650. /* Build the message to be hashed */
  651. uint[] myLeft = m_theStack[m_theStack.Count - 1];
  652. m_theStack.RemoveAt(m_theStack.Count - 1);
  653. Array.Copy(myLeft, 0, m_theM, 0, NUMWORDS);
  654. Array.Copy(m_theChaining, 0, m_theM, NUMWORDS, NUMWORDS);
  655. /* Create parent block */
  656. InitParentBlock();
  657. if (m_theStack.Count < 1)
  658. {
  659. SetRoot();
  660. }
  661. Compress();
  662. }
  663. }
  664. /**
  665. * Perform compression.
  666. */
  667. private void Compress()
  668. {
  669. /* Initialise the buffers */
  670. InitIndices();
  671. /* Loop through the rounds */
  672. for (int round = 0; round < ROUNDS - 1; round++)
  673. {
  674. /* Perform the round and permuteM */
  675. PerformRound();
  676. PermuteIndices();
  677. }
  678. PerformRound();
  679. AdjustChaining();
  680. }
  681. /**
  682. * Perform a round.
  683. */
  684. #if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
  685. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  686. #endif
  687. private void PerformRound()
  688. {
  689. /* Apply to columns of V */
  690. MixG(0, CHAINING0, CHAINING4, IV0, COUNT0);
  691. MixG(1, CHAINING1, CHAINING5, IV1, COUNT1);
  692. MixG(2, CHAINING2, CHAINING6, IV2, DATALEN);
  693. MixG(3, CHAINING3, CHAINING7, IV3, FLAGS);
  694. /* Apply to diagonals of V */
  695. MixG(4, CHAINING0, CHAINING5, IV2, FLAGS);
  696. MixG(5, CHAINING1, CHAINING6, IV3, COUNT0);
  697. MixG(6, CHAINING2, CHAINING7, IV0, COUNT1);
  698. MixG(7, CHAINING3, CHAINING4, IV1, DATALEN);
  699. }
  700. /**
  701. * Adjust Chaining after compression.
  702. */
  703. private void AdjustChaining()
  704. {
  705. /* If we are outputting */
  706. if (m_outputting)
  707. {
  708. /* Adjust full state */
  709. for (int i = 0; i < NUMWORDS; i++)
  710. {
  711. m_theV[i] ^= m_theV[i + NUMWORDS];
  712. m_theV[i + NUMWORDS] ^= m_theChaining[i];
  713. }
  714. /* Output state to buffer */
  715. Pack.UInt32_To_LE(m_theV, m_theBuffer, 0);
  716. m_thePos = 0;
  717. /* Else just build chain value */
  718. }
  719. else
  720. {
  721. /* Combine V into Chaining */
  722. for (int i = 0; i < NUMWORDS; i++)
  723. {
  724. m_theChaining[i] = m_theV[i] ^ m_theV[i + NUMWORDS];
  725. }
  726. }
  727. }
  728. /**
  729. * Mix function G.
  730. *
  731. * @param msgIdx the message index
  732. * @param posA position A in V
  733. * @param posB position B in V
  734. * @param posC position C in V
  735. * @param posD poistion D in V
  736. */
  737. #if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER || UNITY_2021_2_OR_NEWER
  738. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  739. #endif
  740. private void MixG(int msgIdx, int posA, int posB, int posC, int posD)
  741. {
  742. /* Determine indices */
  743. int msg = msgIdx << 1;
  744. /* Perform the Round */
  745. m_theV[posA] += m_theV[posB] + m_theM[m_theIndices[msg++]];
  746. m_theV[posD] = Integers.RotateRight(m_theV[posD] ^ m_theV[posA], 16);
  747. m_theV[posC] += m_theV[posD];
  748. m_theV[posB] = Integers.RotateRight(m_theV[posB] ^ m_theV[posC], 12);
  749. m_theV[posA] += m_theV[posB] + m_theM[m_theIndices[msg]];
  750. m_theV[posD] = Integers.RotateRight(m_theV[posD] ^ m_theV[posA], 8);
  751. m_theV[posC] += m_theV[posD];
  752. m_theV[posB] = Integers.RotateRight(m_theV[posB] ^ m_theV[posC], 7);
  753. }
  754. /**
  755. * initialise the indices.
  756. */
  757. private void InitIndices()
  758. {
  759. for (byte i = 0; i < m_theIndices.Length; i++)
  760. {
  761. m_theIndices[i] = i;
  762. }
  763. }
  764. /**
  765. * PermuteIndices.
  766. */
  767. private void PermuteIndices()
  768. {
  769. for (byte i = 0; i < m_theIndices.Length; i++)
  770. {
  771. m_theIndices[i] = SIGMA[m_theIndices[i]];
  772. }
  773. }
  774. /**
  775. * Initialise null key.
  776. */
  777. private void InitNullKey()
  778. {
  779. Array.Copy(IV, 0, m_theK, 0, NUMWORDS);
  780. }
  781. /**
  782. * Initialise key.
  783. *
  784. * @param pKey the keyBytes
  785. */
  786. private void InitKey(byte[] pKey)
  787. {
  788. /* Copy message bytes into word array */
  789. Pack.LE_To_UInt32(pKey, 0, m_theK);
  790. m_theMode = KEYEDHASH;
  791. }
  792. /**
  793. * Initialise key from context.
  794. */
  795. private void InitKeyFromContext()
  796. {
  797. Array.Copy(m_theV, 0, m_theK, 0, NUMWORDS);
  798. m_theMode = DERIVEKEY;
  799. }
  800. /**
  801. * Initialise chunk block.
  802. *
  803. * @param pDataLen the dataLength
  804. * @param pFinal is this the final chunk?
  805. */
  806. private void InitChunkBlock(int pDataLen, bool pFinal)
  807. {
  808. /* Initialise the block */
  809. Array.Copy(m_theCurrBytes == 0 ? m_theK : m_theChaining, 0, m_theV, 0, NUMWORDS);
  810. Array.Copy(IV, 0, m_theV, NUMWORDS, NUMWORDS >> 1);
  811. m_theV[COUNT0] = (uint)m_theCounter;
  812. m_theV[COUNT1] = (uint)(m_theCounter >> Integers.NumBits);
  813. m_theV[DATALEN] = (uint)pDataLen;
  814. m_theV[FLAGS] = (uint)(m_theMode
  815. + (m_theCurrBytes == 0 ? CHUNKSTART : 0)
  816. + (pFinal ? CHUNKEND : 0));
  817. /* * Adjust block count */
  818. m_theCurrBytes += pDataLen;
  819. if (m_theCurrBytes >= CHUNKLEN)
  820. {
  821. IncrementBlockCount();
  822. m_theV[FLAGS] |= CHUNKEND;
  823. }
  824. /* If we are single chunk */
  825. if (pFinal && m_theStack.Count < 1)
  826. {
  827. SetRoot();
  828. }
  829. }
  830. /**
  831. * Initialise parent block.
  832. */
  833. private void InitParentBlock()
  834. {
  835. /* Initialise the block */
  836. Array.Copy(m_theK, 0, m_theV, 0, NUMWORDS);
  837. Array.Copy(IV, 0, m_theV, NUMWORDS, NUMWORDS >> 1);
  838. m_theV[COUNT0] = 0;
  839. m_theV[COUNT1] = 0;
  840. m_theV[DATALEN] = BLOCKLEN;
  841. m_theV[FLAGS] = (uint)(m_theMode | PARENT);
  842. }
  843. /**
  844. * Initialise output block.
  845. */
  846. private void NextOutputBlock()
  847. {
  848. /* Increment the counter */
  849. m_theCounter++;
  850. /* Initialise the block */
  851. Array.Copy(m_theChaining, 0, m_theV, 0, NUMWORDS);
  852. Array.Copy(IV, 0, m_theV, NUMWORDS, NUMWORDS >> 1);
  853. m_theV[COUNT0] = (uint)m_theCounter;
  854. m_theV[COUNT1] = (uint)(m_theCounter >> Integers.NumBits);
  855. m_theV[DATALEN] = (uint)m_theOutputDataLen;
  856. m_theV[FLAGS] = (uint)m_theOutputMode;
  857. /* Generate output */
  858. Compress();
  859. }
  860. /**
  861. * IncrementBlockCount.
  862. */
  863. private void IncrementBlockCount()
  864. {
  865. m_theCounter++;
  866. m_theCurrBytes = 0;
  867. }
  868. /**
  869. * ResetBlockCount.
  870. */
  871. private void ResetBlockCount()
  872. {
  873. m_theCounter = 0;
  874. m_theCurrBytes = 0;
  875. }
  876. /**
  877. * Set root indication.
  878. */
  879. private void SetRoot()
  880. {
  881. m_theV[FLAGS] |= ROOT;
  882. m_theOutputMode = (int)m_theV[FLAGS];
  883. m_theOutputDataLen = (int)m_theV[DATALEN];
  884. m_theCounter = 0;
  885. m_outputting = true;
  886. m_outputAvailable = -1;
  887. Array.Copy(m_theV, 0, m_theChaining, 0, NUMWORDS);
  888. }
  889. }
  890. }
  891. #pragma warning restore
  892. #endif