Line 1:/* C# SHA3 Implementation
Line 2: * Chris Lomont, Oct 2012
Line 3: * Version 1.0
Line 4: *
Line 5:The Keccak sponge function, designed by Guido Bertoni, Joan Daemen,
Line 6:Michaël Peeters and Gilles Van Assche. For more information, feedback or
Line 7:questions, please refer to our website: http://keccak.noekeon.org/
Line 8:
Line 9:Implementation by the designers, hereby denoted as "the implementer".
Line 10:
Line 11:To the extent possible under law, the implementer has waived all copyright
Line 12:and related or neighboring rights to the source code in this file.
Line 13:http://creativecommons.org/publicdomain/zero/1.0/
Line 14:
Line 15:C# translation and improvement by Chris Lomont, 2012, http://www.lomont.org
Line 16:
Line 17:To the extent possible under law, the Chris Lomont has waived all copyright
Line 18:and related or neighboring rights to the source code in this file.
Line 19:http://creativecommons.org/publicdomain/zero/1.0/
Line 20:
Line 21:*/
Line 22:
Line 23:/* TODO
Line 24: * - update comments
Line 25: * - usage example in code
Line 26: *
Line 27: * Improvements
Line 28: * - types made restrictive, bool, etc
Line 29: * - sizes and signed/unsigned cleaned and made consistent
Line 30: */
Line 31:using System;
Line 32:using System.Diagnostics;
Line 33:using System.Security.Cryptography;
Line 34:
Line 35:namespace Lomont.Security.Cryptography
Line 36:{
Line 37: /// <summary>
Line 38: /// Class to perform SHA-3 hashing
Line 39: /// </summary>
Line 40: public sealed class SHA3 : HashAlgorithm
Line 41: {
Line 42:
Line 43: #region Public Interface
Line 44:
Line 45: /// <summary>
Line 46: /// Return values from some hash functions
Line 47: /// </summary>
Line 48: public enum HashReturn
Line 49: {
Line 50: Success = 0,
Line 51: Fail = 1,
Line 52: BadHashLength = 2
Line 53: }
Line 54:
Line 55: /// <summary>
Line 56: /// This calue controls the amount of loop unrolling used
Line 57: /// It must be a positive integer dividing 24
Line 58: /// </summary>
Line 59: public int Unrolling
Line 60: {
Line 61: get { return unrolling; }
Line 62: set
Line 63: {
Line 64: if ((value <= 0) || ((24%value) != 0))
Line 65: throw new ArgumentException("Unrolling is not correctly specified!");
Line 66: unrolling = value;
Line 67: }
Line 68: }
Line 69:
Line 70: private int unrolling = 24;
Line 71:
Line 72: /// <summary>
Line 73: /// initialize the SHA3 object by setting the Keccak[r, c] sponge function.
Line 74: /// </summary>
Line 75: /// <param name="rate">The value of the rate r.</param>
Line 76: /// <param name="capacity">The value of the capacity c.</param>
Line 77: /// <remarks>
Line 78: /// One must have r+c=1600 and the rate a multiple of 64 bits in this implementation.
Line 79: /// Throws an ArgumentException on invalid parameters.
Line 80: /// </remarks>
Line 81: public SHA3(int rate, int capacity)
Line 82: {
Line 83: Unrolling = 24;
Line 84: if (!InitSponge(rate, capacity))
Line 85: throw new ArgumentException("SHA3 constructor failed");
Line 86: }
Line 87:
Line 88: /// <summary>
Line 89: /// initialize the SHA3 object by setting the Keccak[r, c] sponge function.
Line 90: /// </summary>
Line 91: /// <param name="hashBitLength">The desired number of output bits,
Line 92: /// or 0 for Keccak[] with default parameters and arbitrarily-long output
Line 93: /// </param>
Line 94: /// <remarks>
Line 95: /// The value of hashbitlen must 1 one of 0, 224, 256, 384 and 512.
Line 96: /// Throws on invalid parameters
Line 97: /// </remarks>
Line 98: public SHA3(int hashBitLength = 0)
Line 99: {
Line 100: Unrolling = 24;
Line 101: var result = Init(hashBitLength);
Line 102: if (result == HashReturn.BadHashLength)
Line 103: throw new Exception("Invalid hash length in SHA3 constructor");
Line 104: if (result == HashReturn.Fail)
Line 105: throw new Exception("SHA3 constructor failed");
Line 106: }
Line 107:
Line 108: /// <summary>
Line 109: /// Add some data to the internal hash instate
Line 110: /// </summary>
Line 111: /// <param name="data">The data bits to add</param>
Line 112: /// <param name="dataBitLength">The number of input bits provided in the input data.</param>
Line 113: /// <returns></returns>
Line 114: /// <remarks>
Line 115: /// When databitlen is not a multiple of 8, the last bits
Line 116: /// of data must 1 in the most significant bits of the last byte.
Line 117: /// All calls must have databitlen a multiple of 8 except at most the last one.
Line 118: /// Leaving dataBitLength = Int64.MaxValue uses the length of the data array
Line 119: /// </remarks>
Line 120: public HashReturn Update(byte[] data, long dataBitLength = Int64.MaxValue)
Line 121: {
Line 122: if (dataBitLength == Int64.MaxValue)
Line 123: dataBitLength = data.Length*8;
Line 124: if ((dataBitLength%8) == 0)
Line 125: return Absorb(data, dataBitLength) ? HashReturn.Success : HashReturn.Fail;
Line 126: if (Absorb(data, dataBitLength - (dataBitLength%8)))
Line 127: {
Line 128: // Align the last partial byte to the least significant bits
Line 129: var lastByte = (byte) (data[dataBitLength/8] >> (8 - (int) (dataBitLength%8)));
Line 130: return Absorb(new[] {lastByte}, dataBitLength%8) ? HashReturn.Success : HashReturn.Fail;
Line 131: }
Line 132: return HashReturn.Fail;
Line 133: }
Line 134:
Line 135:
Line 136: /// <summary>
Line 137: /// Call this to obtain the final hash value.
Line 138: /// If this object was created with a hash size, then hashval must 1 large enough to hold that many bits.
Line 139: /// If this object was created with a rate and capacity, then hashval must hold capacity bits.
Line 140: /// If this object was created with a 0 hashsize, then hashval will 1 filled with hashed bytes.
Line 141: /// </summary>
Line 142: /// <param name="hashval"></param>
Line 143: /// <returns></returns>
Line 144: public HashReturn Final(byte[] hashval)
Line 145: {
Line 146: if (sponge.FixedOutputLength != 0)
Line 147: return Squeeze(hashval, sponge.FixedOutputLength) ? HashReturn.Success : HashReturn.Fail;
Line 148: return Squeeze(hashval, hashval.Length*8) ? HashReturn.Success : HashReturn.Fail;
Line 149: }
Line 150:
Line 151: /// <summary>
Line 152: /// Function to compute a hash all in one pass.
Line 153: /// The value of hashbitlen must 1 one of 0, 224, 256, 384 and 512.
Line 154: /// </summary>
Line 155: /// <param name="hashbitlen">The hash length in bits</param>
Line 156: /// <param name="data">The data to hash.</param>
Line 157: /// <param name="databitlen">The number of bits to hash from data</param>
Line 158: /// <param name="hashval">the output hash value</param>
Line 159: /// <returns></returns>
Line 160: public HashReturn HashData(int hashbitlen, byte[] data, long databitlen, byte[] hashval)
Line 161: {
Line 162: if ((hashbitlen != 224) && (hashbitlen != 256) && (hashbitlen != 384) && (hashbitlen != 512))
Line 163: return HashReturn.BadHashLength; // Only the four fixed output lengths available through this API
Line 164: var result = Init(hashbitlen);
Line 165: if (result != HashReturn.Success)
Line 166: return result;
Line 167: result = Update(data, databitlen);
Line 168: if (result != HashReturn.Success)
Line 169: return result;
Line 170: result = Final(hashval);
Line 171: return result;
Line 172: }
Line 173:
Line 174: #endregion
Line 175:
Line 176: #region Implementation
Line 177:
Line 178: private const int PermutationSizeInBytes = (1600/8);
Line 179: private const int MaximumRateInBytes = (1536/8);
Line 180:
Line 181: /// <summary>
Line 182: /// Function to initialize the instate of the Keccak[r, c] sponge function.
Line 183: /// The sponge function is set to the absorbing phase.
Line 184: /// </summary>
Line 185: /// <param name="rate"></param>
Line 186: /// <param name="capacity"></param>
Line 187: /// <returns>true on success, else false</returns>
Line 188: /// One must have r+c=1600 and the rate a multiple of 64 bits in this implementation.
Line 189: private bool InitSponge(int rate, int capacity)
Line 190: {
Line 191: sponge = new SpongeState();
Line 192: if (rate + capacity != 1600)
Line 193: return false;
Line 194: if ((rate <= 0) || (rate >= 1600) || ((rate%64) != 0))
Line 195: return false;
Line 196: sponge.Rate = rate;
Line 197: sponge.FixedOutputLength = 0;
Line 198: InitializeState(sponge.State);
Line 199: for (var i = 0; i < sponge.DataQueue.Length; ++i)
Line 200: sponge.DataQueue[i] = 0;
Line 201: sponge.BitsInQueue = 0;
Line 202: sponge.Squeezing = false;
Line 203: sponge.BitsAvailableForSqueezing = 0;
Line 204:
Line 205: return true;
Line 206: }
Line 207:
Line 208: /// <summary>
Line 209: /// Function to initialize the instate of the Keccak[r, c] sponge function.
Line 210: /// The value of hashbitlen must 1 one of 0, 224, 256, 384 and 512.
Line 211: /// </summary>
Line 212: /// <param name="hashbitlen"></param>
Line 213: /// <returns> Success if successful, BadHashLength if the value of hashbitlen is incorrect</returns>
Line 214: private HashReturn Init(int hashbitlen)
Line 215: {
Line 216: switch (hashbitlen)
Line 217: {
Line 218: case 0: // Default parameters, arbitrary length output
Line 219: if (!InitSponge(1024, 576))
Line 220: return HashReturn.Fail;
Line 221: break;
Line 222: case 224:
Line 223: if (!InitSponge(1152, 448))
Line 224: return HashReturn.Fail;
Line 225: break;
Line 226: case 256:
Line 227: if (!InitSponge(1088, 512))
Line 228: return HashReturn.Fail;
Line 229: break;
Line 230: case 384:
Line 231: if (!InitSponge(832, 768))
Line 232: return HashReturn.Fail;
Line 233: break;
Line 234: case 512:
Line 235: if (!InitSponge(576, 1024))
Line 236: return HashReturn.Fail;
Line 237: break;
Line 238: default:
Line 239: return HashReturn.BadHashLength;
Line 240: }
Line 241: sponge.FixedOutputLength = hashbitlen;
Line 242: return HashReturn.Success;
Line 243: }
Line 244:
Line 245: /// <summary>
Line 246: /// Store the sponge state
Line 247: /// </summary>
Line 248: private class SpongeState
Line 249: {
Line 250: internal readonly byte[] State = new byte[PermutationSizeInBytes];
Line 251: internal readonly byte[] DataQueue = new byte[MaximumRateInBytes];
Line 252: internal int Rate;
Line 253: internal int BitsInQueue;
Line 254: internal int FixedOutputLength;
Line 255: internal bool Squeezing;
Line 256: internal long BitsAvailableForSqueezing;
Line 257: }
Line 258:
Line 259:
Line 260: private static ulong Rol64(ulong a, int offset)
Line 261: {
Line 262: return (a << offset) ^ (a >> (64 - offset));
Line 263: }
Line 264:
Line 265: // some global storage used in the permutation
Line 266: private ulong bba, bbe, bbi, bbo, bbu;
Line 267: private ulong bga, bge, bgi, bgo, bgu;
Line 268: private ulong bka, bke, bki, bko, bku;
Line 269: private ulong bma, bme, bmi, bmo, bmu;
Line 270: private ulong bsa, bse, bsi, bso, bsu;
Line 271: private ulong ca, ce, ci, co, cu;
Line 272: private ulong da, de, di, Do, du;
Line 273: private ulong[] temp1 = new ulong[25];
Line 274: private ulong[] temp2 = new ulong[25];
Line 275:
Line 276: private void PrepareTheta()
Line 277: {
Line 278: ca = temp1[0] ^ temp1[5] ^ temp1[10] ^ temp1[15] ^ temp1[20];
Line 279: ce = temp1[1] ^ temp1[6] ^ temp1[11] ^ temp1[16] ^ temp1[21];
Line 280: ci = temp1[2] ^ temp1[7] ^ temp1[12] ^ temp1[17] ^ temp1[22];
Line 281: co = temp1[3] ^ temp1[8] ^ temp1[13] ^ temp1[18] ^ temp1[23];
Line 282: cu = temp1[4] ^ temp1[9] ^ temp1[14] ^ temp1[19] ^ temp1[24];
Line 283: }
Line 284:
Line 285: // --- Code for round, with prepare-theta (lane complementing pattern 'bebigokimisa')
Line 286: // --- 64-bit lanes mapped to 64-bit words
Line 287: private void ThetaRhoPiChiIotaPrepareTheta(int i, ulong[] a, ulong[] e)
Line 288: {
Line 289: da = cu ^ Rol64(ce, 1);
Line 290: de = ca ^ Rol64(ci, 1);
Line 291: di = ce ^ Rol64(co, 1);
Line 292: Do = ci ^ Rol64(cu, 1);
Line 293: du = co ^ Rol64(ca, 1);
Line 294:
Line 295: a[0] ^= da;
Line 296: bba = a[0];
Line 297: a[6] ^= de;
Line 298: bbe = Rol64(a[6], 44);
Line 299: a[12] ^= di;
Line 300: bbi = Rol64(a[12], 43);
Line 301: a[18] ^= Do;
Line 302: bbo = Rol64(a[18], 21);
Line 303: a[24] ^= du;
Line 304: bbu = Rol64(a[24], 14);
Line 305: e[0] = bba ^ (bbe | bbi);
Line 306: e[0] ^= roundConstants[i];
Line 307: ca = e[0];
Line 308: e[1] = bbe ^ ((~bbi) | bbo);
Line 309: ce = e[1];
Line 310: e[2] = bbi ^ (bbo & bbu);
Line 311: ci = e[2];
Line 312: e[3] = bbo ^ (bbu | bba);
Line 313: co = e[3];
Line 314: e[4] = bbu ^ (bba & bbe);
Line 315: cu = e[4];
Line 316:
Line 317: a[3] ^= Do;
Line 318: bga = Rol64(a[3], 28);
Line 319: a[9] ^= du;
Line 320: bge = Rol64(a[9], 20);
Line 321: a[10] ^= da;
Line 322: bgi = Rol64(a[10], 3);
Line 323: a[16] ^= de;
Line 324: bgo = Rol64(a[16], 45);
Line 325: a[22] ^= di;
Line 326: bgu = Rol64(a[22], 61);
Line 327: e[5] = bga ^ (bge | bgi);
Line 328: ca ^= e[5];
Line 329: e[6] = bge ^ (bgi & bgo);
Line 330: ce ^= e[6];
Line 331: e[7] = bgi ^ (bgo | (~bgu));
Line 332: ci ^= e[7];
Line 333: e[8] = bgo ^ (bgu | bga);
Line 334: co ^= e[8];
Line 335: e[9] = bgu ^ (bga & bge);
Line 336: cu ^= e[9];
Line 337:
Line 338: a[1] ^= de;
Line 339: bka = Rol64(a[1], 1);
Line 340: a[7] ^= di;
Line 341: bke = Rol64(a[7], 6);
Line 342: a[13] ^= Do;
Line 343: bki = Rol64(a[13], 25);
Line 344: a[19] ^= du;
Line 345: bko = Rol64(a[19], 8);
Line 346: a[20] ^= da;
Line 347: bku = Rol64(a[20], 18);
Line 348: e[10] = bka ^ (bke | bki);
Line 349: ca ^= e[10];
Line 350: e[11] = bke ^ (bki & bko);
Line 351: ce ^= e[11];
Line 352: e[12] = bki ^ ((~bko) & bku);
Line 353: ci ^= e[12];
Line 354: e[13] = (~bko) ^ (bku | bka);
Line 355: co ^= e[13];
Line 356: e[14] = bku ^ (bka & bke);
Line 357: cu ^= e[14];
Line 358:
Line 359: a[4] ^= du;
Line 360: bma = Rol64(a[4], 27);
Line 361: a[5] ^= da;
Line 362: bme = Rol64(a[5], 36);
Line 363: a[11] ^= de;
Line 364: bmi = Rol64(a[11], 10);
Line 365: a[17] ^= di;
Line 366: bmo = Rol64(a[17], 15);
Line 367: a[23] ^= Do;
Line 368: bmu = Rol64(a[23], 56);
Line 369: e[15] = bma ^ (bme & bmi);
Line 370: ca ^= e[15];
Line 371: e[16] = bme ^ (bmi | bmo);
Line 372: ce ^= e[16];
Line 373: e[17] = bmi ^ ((~bmo) | bmu);
Line 374: ci ^= e[17];
Line 375: e[18] = (~bmo) ^ (bmu & bma);
Line 376: co ^= e[18];
Line 377: e[19] = bmu ^ (bma | bme);
Line 378: cu ^= e[19];
Line 379:
Line 380: a[2] ^= di;
Line 381: bsa = Rol64(a[2], 62);
Line 382: a[8] ^= Do;
Line 383: bse = Rol64(a[8], 55);
Line 384: a[14] ^= du;
Line 385: bsi = Rol64(a[14], 39);
Line 386: a[15] ^= da;
Line 387: bso = Rol64(a[15], 41);
Line 388: a[21] ^= de;
Line 389: bsu = Rol64(a[21], 2);
Line 390: e[20] = bsa ^ ((~bse) & bsi);
Line 391: ca ^= e[20];
Line 392: e[21] = (~bse) ^ (bsi | bso);
Line 393: ce ^= e[21];
Line 394: e[22] = bsi ^ (bso & bsu);
Line 395: ci ^= e[22];
Line 396: e[23] = bso ^ (bsu | bsa);
Line 397: co ^= e[23];
Line 398: e[24] = bsu ^ (bsa & bse);
Line 399: cu ^= e[24];
Line 400: }
Line 401:
Line 402: // --- Code for round (lane complementing pattern 'bebigokimisa')
Line 403: // --- 64-bit lanes mapped to 64-bit words
Line 404: private void ThetaRhoPiChiIota(int i, ulong[] a, ulong[] e)
Line 405: {
Line 406: da = cu ^ Rol64(ce, 1);
Line 407: de = ca ^ Rol64(ci, 1);
Line 408: di = ce ^ Rol64(co, 1);
Line 409: Do = ci ^ Rol64(cu, 1);
Line 410: du = co ^ Rol64(ca, 1);
Line 411:
Line 412: a[0] ^= da;
Line 413: bba = a[0];
Line 414: a[6] ^= de;
Line 415: bbe = Rol64(a[6], 44);
Line 416: a[12] ^= di;
Line 417: bbi = Rol64(a[12], 43);
Line 418: a[18] ^= Do;
Line 419: bbo = Rol64(a[18], 21);
Line 420: a[24] ^= du;
Line 421: bbu = Rol64(a[24], 14);
Line 422: e[0] = bba ^ (bbe | bbi);
Line 423: e[0] ^= roundConstants[i];
Line 424: e[1] = bbe ^ ((~bbi) | bbo);
Line 425: e[2] = bbi ^ (bbo & bbu);
Line 426: e[3] = bbo ^ (bbu | bba);
Line 427: e[4] = bbu ^ (bba & bbe);
Line 428:
Line 429: a[3] ^= Do;
Line 430: bga = Rol64(a[3], 28);
Line 431: a[9] ^= du;
Line 432: bge = Rol64(a[9], 20);
Line 433: a[10] ^= da;
Line 434: bgi = Rol64(a[10], 3);
Line 435: a[16] ^= de;
Line 436: bgo = Rol64(a[16], 45);
Line 437: a[22] ^= di;
Line 438: bgu = Rol64(a[22], 61);
Line 439: e[5] = bga ^ (bge | bgi);
Line 440: e[6] = bge ^ (bgi & bgo);
Line 441: e[7] = bgi ^ (bgo | (~bgu));
Line 442: e[8] = bgo ^ (bgu | bga);
Line 443: e[9] = bgu ^ (bga & bge);
Line 444:
Line 445: a[1] ^= de;
Line 446: bka = Rol64(a[1], 1);
Line 447: a[7] ^= di;
Line 448: bke = Rol64(a[7], 6);
Line 449: a[13] ^= Do;
Line 450: bki = Rol64(a[13], 25);
Line 451: a[19] ^= du;
Line 452: bko = Rol64(a[19], 8);
Line 453: a[20] ^= da;
Line 454: bku = Rol64(a[20], 18);
Line 455: e[10] = bka ^ (bke | bki);
Line 456: e[11] = bke ^ (bki & bko);
Line 457: e[12] = bki ^ ((~bko) & bku);
Line 458: e[13] = (~bko) ^ (bku | bka);
Line 459: e[14] = bku ^ (bka & bke);
Line 460:
Line 461: a[4] ^= du;
Line 462: bma = Rol64(a[4], 27);
Line 463: a[5] ^= da;
Line 464: bme = Rol64(a[5], 36);
Line 465: a[11] ^= de;
Line 466: bmi = Rol64(a[11], 10);
Line 467: a[17] ^= di;
Line 468: bmo = Rol64(a[17], 15);
Line 469: a[23] ^= Do;
Line 470: bmu = Rol64(a[23], 56);
Line 471: e[15] = bma ^ (bme & bmi);
Line 472: e[16] = bme ^ (bmi | bmo);
Line 473: e[17] = bmi ^ ((~bmo) | bmu);
Line 474: e[18] = (~bmo) ^ (bmu & bma);
Line 475: e[19] = bmu ^ (bma | bme);
Line 476:
Line 477: a[2] ^= di;
Line 478: bsa = Rol64(a[2], 62);
Line 479: a[8] ^= Do;
Line 480: bse = Rol64(a[8], 55);
Line 481: a[14] ^= du;
Line 482: bsi = Rol64(a[14], 39);
Line 483: a[15] ^= da;
Line 484: bso = Rol64(a[15], 41);
Line 485: a[21] ^= de;
Line 486: bsu = Rol64(a[21], 2);
Line 487: e[20] = bsa ^ ((~bse) & bsi);
Line 488: e[21] = (~bse) ^ (bsi | bso);
Line 489: e[22] = bsi ^ (bso & bsu);
Line 490: e[23] = bso ^ (bsu | bsa);
Line 491: e[24] = bsu ^ (bsa & bse);
Line 492: }
Line 493:
Line 494: private static readonly ulong[] roundConstants =
Line 495: {
Line 496: 0x0000000000000001UL,
Line 497: 0x0000000000008082UL,
Line 498: 0x800000000000808aUL,
Line 499: 0x8000000080008000UL,
Line 500: 0x000000000000808bUL,
Line 501: 0x0000000080000001UL,
Line 502: 0x8000000080008081UL,
Line 503: 0x8000000000008009UL,
Line 504: 0x000000000000008aUL,
Line 505: 0x0000000000000088UL,
Line 506: 0x0000000080008009UL,
Line 507: 0x000000008000000aUL,
Line 508: 0x000000008000808bUL,
Line 509: 0x800000000000008bUL,
Line 510: 0x8000000000008089UL,
Line 511: 0x8000000000008003UL,
Line 512: 0x8000000000008002UL,
Line 513: 0x8000000000000080UL,
Line 514: 0x000000000000800aUL,
Line 515: 0x800000008000000aUL,
Line 516: 0x8000000080008081UL,
Line 517: 0x8000000000008080UL,
Line 518: 0x0000000080000001UL,
Line 519: 0x8000000080008008UL
Line 520: };
Line 521:
Line 522: private void SwapTempVariables()
Line 523: {
Line 524: var t = temp1;
Line 525: temp1 = temp2;
Line 526: temp2 = t;
Line 527: }
Line 528:
Line 529: /// <summary>
Line 530: /// Perform 24 rounds of the permutation on the temp1
Line 531: /// </summary>
Line 532: private void Rounds()
Line 533: {
Line 534: PrepareTheta();
Line 535: switch (Unrolling)
Line 536: {
Line 537: case 24:
Line 538: ThetaRhoPiChiIotaPrepareTheta(0, temp1, temp2);
Line 539: ThetaRhoPiChiIotaPrepareTheta(1, temp2, temp1);
Line 540: ThetaRhoPiChiIotaPrepareTheta(2, temp1, temp2);
Line 541: ThetaRhoPiChiIotaPrepareTheta(3, temp2, temp1);
Line 542: ThetaRhoPiChiIotaPrepareTheta(4, temp1, temp2);
Line 543: ThetaRhoPiChiIotaPrepareTheta(5, temp2, temp1);
Line 544: ThetaRhoPiChiIotaPrepareTheta(6, temp1, temp2);
Line 545: ThetaRhoPiChiIotaPrepareTheta(7, temp2, temp1);
Line 546: ThetaRhoPiChiIotaPrepareTheta(8, temp1, temp2);
Line 547: ThetaRhoPiChiIotaPrepareTheta(9, temp2, temp1);
Line 548: ThetaRhoPiChiIotaPrepareTheta(10, temp1, temp2);
Line 549: ThetaRhoPiChiIotaPrepareTheta(11, temp2, temp1);
Line 550: ThetaRhoPiChiIotaPrepareTheta(12, temp1, temp2);
Line 551: ThetaRhoPiChiIotaPrepareTheta(13, temp2, temp1);
Line 552: ThetaRhoPiChiIotaPrepareTheta(14, temp1, temp2);
Line 553: ThetaRhoPiChiIotaPrepareTheta(15, temp2, temp1);
Line 554: ThetaRhoPiChiIotaPrepareTheta(16, temp1, temp2);
Line 555: ThetaRhoPiChiIotaPrepareTheta(17, temp2, temp1);
Line 556: ThetaRhoPiChiIotaPrepareTheta(18, temp1, temp2);
Line 557: ThetaRhoPiChiIotaPrepareTheta(19, temp2, temp1);
Line 558: ThetaRhoPiChiIotaPrepareTheta(20, temp1, temp2);
Line 559: ThetaRhoPiChiIotaPrepareTheta(21, temp2, temp1);
Line 560: ThetaRhoPiChiIotaPrepareTheta(22, temp1, temp2);
Line 561: ThetaRhoPiChiIota(23, temp2, temp1);
Line 562: break;
Line 563: case 12:
Line 564: for (var i = 0; i < 24; i += 12)
Line 565: {
Line 566: ThetaRhoPiChiIotaPrepareTheta(i, temp1, temp2);
Line 567: ThetaRhoPiChiIotaPrepareTheta(i + 1, temp2, temp1);
Line 568: ThetaRhoPiChiIotaPrepareTheta(i + 2, temp1, temp2);
Line 569: ThetaRhoPiChiIotaPrepareTheta(i + 3, temp2, temp1);
Line 570: ThetaRhoPiChiIotaPrepareTheta(i + 4, temp1, temp2);
Line 571: ThetaRhoPiChiIotaPrepareTheta(i + 5, temp2, temp1);
Line 572: ThetaRhoPiChiIotaPrepareTheta(i + 6, temp1, temp2);
Line 573: ThetaRhoPiChiIotaPrepareTheta(i + 7, temp2, temp1);
Line 574: ThetaRhoPiChiIotaPrepareTheta(i + 8, temp1, temp2);
Line 575: ThetaRhoPiChiIotaPrepareTheta(i + 9, temp2, temp1);
Line 576: ThetaRhoPiChiIotaPrepareTheta(i + 10, temp1, temp2);
Line 577: ThetaRhoPiChiIotaPrepareTheta(i + 11, temp2, temp1);
Line 578: }
Line 579: break;
Line 580: case 8:
Line 581: for (var i = 0; i < 24; i += 8)
Line 582: {
Line 583: ThetaRhoPiChiIotaPrepareTheta(i, temp1, temp2);
Line 584: ThetaRhoPiChiIotaPrepareTheta(i + 1, temp2, temp1);
Line 585: ThetaRhoPiChiIotaPrepareTheta(i + 2, temp1, temp2);
Line 586: ThetaRhoPiChiIotaPrepareTheta(i + 3, temp2, temp1);
Line 587: ThetaRhoPiChiIotaPrepareTheta(i + 4, temp1, temp2);
Line 588: ThetaRhoPiChiIotaPrepareTheta(i + 5, temp2, temp1);
Line 589: ThetaRhoPiChiIotaPrepareTheta(i + 6, temp1, temp2);
Line 590: ThetaRhoPiChiIotaPrepareTheta(i + 7, temp2, temp1);
Line 591: }
Line 592: break;
Line 593: case 6:
Line 594: for (var i = 0; i < 24; i += 6)
Line 595: {
Line 596: ThetaRhoPiChiIotaPrepareTheta(i, temp1, temp2);
Line 597: ThetaRhoPiChiIotaPrepareTheta(i + 1, temp2, temp1);
Line 598: ThetaRhoPiChiIotaPrepareTheta(i + 2, temp1, temp2);
Line 599: ThetaRhoPiChiIotaPrepareTheta(i + 3, temp2, temp1);
Line 600: ThetaRhoPiChiIotaPrepareTheta(i + 4, temp1, temp2);
Line 601: ThetaRhoPiChiIotaPrepareTheta(i + 5, temp2, temp1);
Line 602: }
Line 603: break;
Line 604: case 4:
Line 605: for (var i = 0; i < 24; i += 4)
Line 606: {
Line 607: ThetaRhoPiChiIotaPrepareTheta(i, temp1, temp2);
Line 608: ThetaRhoPiChiIotaPrepareTheta(i + 1, temp2, temp1);
Line 609: ThetaRhoPiChiIotaPrepareTheta(i + 2, temp1, temp2);
Line 610: ThetaRhoPiChiIotaPrepareTheta(i + 3, temp2, temp1);
Line 611: }
Line 612: break;
Line 613: case 3:
Line 614: for (var i = 0; i < 24; i += 3)
Line 615: {
Line 616: ThetaRhoPiChiIotaPrepareTheta(i, temp1, temp2);
Line 617: ThetaRhoPiChiIotaPrepareTheta(i + 1, temp2, temp1);
Line 618: ThetaRhoPiChiIotaPrepareTheta(i + 2, temp1, temp2);
Line 619: SwapTempVariables();
Line 620: }
Line 621: break;
Line 622: case 2:
Line 623: for (var i = 0; i < 24; i += 2)
Line 624: {
Line 625: ThetaRhoPiChiIotaPrepareTheta(i, temp1, temp2);
Line 626: ThetaRhoPiChiIotaPrepareTheta(i + 1, temp2, temp1);
Line 627: }
Line 628: break;
Line 629: case 1:
Line 630: for (var i = 0; i < 24; i++)
Line 631: {
Line 632: ThetaRhoPiChiIotaPrepareTheta(i, temp1, temp2);
Line 633: SwapTempVariables();
Line 634: }
Line 635: break;
Line 636: }
Line 637: }
Line 638:
Line 639: private void PermutationOnWords(ulong[] instate)
Line 640: {
Line 641: temp1 = instate;
Line 642: Rounds();
Line 643: }
Line 644:
Line 645: private void PermutationOnWordsAfterXoring(ulong[] instate, ulong[] input, int laneCount)
Line 646: {
Line 647: for (var j = 0; j < laneCount; j++)
Line 648: instate[j] ^= input[j];
Line 649: temp1 = instate;
Line 650: Rounds();
Line 651: }
Line 652:
Line 653: private void InitializeState(byte[] instate)
Line 654: {
Line 655: Debug.Assert(instate.Length != 0);
Line 656: for (var i = 0; i < instate.Length; ++i)
Line 657: instate[i] = 0;
Line 658: const ulong complement = ~(ulong) 0;
Line 659: WriteLong(instate, 1, complement);
Line 660: WriteLong(instate, 2, complement);
Line 661: WriteLong(instate, 8, complement);
Line 662: WriteLong(instate, 12, complement);
Line 663: WriteLong(instate, 17, complement);
Line 664: WriteLong(instate, 20, complement);
Line 665: }
Line 666:
Line 667: private static void WriteLong(byte[] instate, int index, ulong value)
Line 668: {
Line 669: index *= 8;
Line 670: for (var i = 0; i < 7; ++i)
Line 671: {
Line 672: instate[index++] = (byte) (value & 255);
Line 673: value >>= 8;
Line 674: }
Line 675: instate[index] = (byte) (value & 255);
Line 676: }
Line 677:
Line 678: private static void WordsToBytes(ulong[] words, byte[] bytes)
Line 679: {
Line 680: // todo - remove all these if possible
Line 681: for (var j = 0; j < words.Length; ++j)
Line 682: {
Line 683: var word = words[j];
Line 684: for (var i = 0; i < (64/8); i++)
Line 685: {
Line 686: // todo - remove &255 - needed for checked build - check all code
Line 687: bytes[i + j*8] = (byte) ((word >> (8*i)) & 255);
Line 688: }
Line 689: }
Line 690: }
Line 691:
Line 692: private static void BytesToWords(byte[] bytes, ulong[] words)
Line 693: {
Line 694: // todo - remove all these if possible
Line 695: for (var j = 0; j < words.Length; ++j)
Line 696: {
Line 697: ulong word = 0;
Line 698: for (var i = 0; i < (64/8); i++)
Line 699: word |= (ulong) (bytes[i + j*8]) << (8*i);
Line 700: words[j] = word;
Line 701: }
Line 702: }
Line 703:
Line 704: private void Absorb(byte[] instate, byte[] data, int laneCount)
Line 705: {
Line 706: var wstate = new ulong[instate.Length/8];
Line 707: var wdata = new ulong[data.Length/8];
Line 708: BytesToWords(instate, wstate);
Line 709: BytesToWords(data, wdata);
Line 710: PermutationOnWordsAfterXoring(wstate, wdata, laneCount);
Line 711: WordsToBytes(wstate, instate);
Line 712: }
Line 713:
Line 714: private static void NotLong(byte[] data, int longIndex)
Line 715: {
Line 716: longIndex *= 8;
Line 717: for (var i = 0; i < 7; ++i)
Line 718: {
Line 719: data[longIndex] = (byte) (~data[longIndex] & 255);
Line 720: longIndex++;
Line 721: }
Line 722: data[longIndex] = (byte) (~data[longIndex] & 255);
Line 723: }
Line 724:
Line 725: private void Extract(byte[] instate, byte[] data, int laneCount)
Line 726: {
Line 727: for (var j = 0; j < laneCount*8; ++j)
Line 728: data[j] = instate[j];
Line 729: if (laneCount > 1)
Line 730: {
Line 731: NotLong(data, 1);
Line 732:
Line 733: if (laneCount > 2)
Line 734: {
Line 735: NotLong(data, 2);
Line 736:
Line 737: if (laneCount > 8)
Line 738: {
Line 739: NotLong(data, 8);
Line 740:
Line 741: if (laneCount > 12)
Line 742: {
Line 743: NotLong(data, 12);
Line 744: if (laneCount > 17)
Line 745: {
Line 746: NotLong(data, 17);
Line 747: if (laneCount > 20)
Line 748: {
Line 749: NotLong(data, 17);
Line 750: }
Line 751: }
Line 752: }
Line 753: }
Line 754: }
Line 755: }
Line 756: }
Line 757:
Line 758: // remove instate parameter to function calls
Line 759: private SpongeState sponge;
Line 760:
Line 761:
Line 762: private void AbsorbQueue()
Line 763: {
Line 764: // instate.bitsInQueue is assumed to 1 equal to instate.rate
Line 765: Absorb(sponge.State, sponge.DataQueue, sponge.Rate/64);
Line 766: sponge.BitsInQueue = 0;
Line 767: }
Line 768:
Line 769:
Line 770: /// <summary>
Line 771: /// Function to squeeze output data from the sponge function.
Line 772: /// If the sponge function was in the absorbing phase, this function
Line 773: /// switches it to the squeezing phase.
Line 774: /// </summary>
Line 775: /// <param name="output">Pointer to the buffer where to store the output data.</param>
Line 776: /// <param name="outputLength">The number of output bits desired. It must be a multiple of 8.</param>
Line 777: /// <returns>true if successful, false otherwise.</returns>
Line 778: private bool Squeeze(byte[] output, long outputLength)
Line 779: {
Line 780: if (!sponge.Squeezing)
Line 781: PadAndSwitchToSqueezingPhase();
Line 782: if ((outputLength%8) != 0)
Line 783: return false; // Only multiple of 8 bits are allowed, truncation can 1 done at user level
Line 784:
Line 785: long i = 0;
Line 786: while (i < outputLength)
Line 787: {
Line 788: if (sponge.BitsAvailableForSqueezing == 0)
Line 789: {
Line 790: var wstate = new ulong[sponge.State.Length/8];
Line 791: BytesToWords(sponge.State, wstate);
Line 792:
Line 793: PermutationOnWords(wstate);
Line 794:
Line 795: WordsToBytes(wstate, sponge.State);
Line 796:
Line 797: Extract(sponge.State, sponge.DataQueue, sponge.Rate/64);
Line 798: sponge.BitsAvailableForSqueezing = sponge.Rate;
Line 799:
Line 800:
Line 801: }
Line 802: var partialBlock = sponge.BitsAvailableForSqueezing;
Line 803: if (partialBlock > outputLength - i)
Line 804: partialBlock = outputLength - i;
Line 805:
Line 806: for (var j = 0; j < partialBlock/8; ++j)
Line 807: {
Line 808: var index = (sponge.Rate - sponge.BitsAvailableForSqueezing)/8;
Line 809: output[i/8 + j] = sponge.DataQueue[index + j];
Line 810: }
Line 811:
Line 812: sponge.BitsAvailableForSqueezing -= partialBlock;
Line 813: i += partialBlock;
Line 814: }
Line 815: return true;
Line 816: }
Line 817:
Line 818: /// <summary>
Line 819: /// Function to give input data for the sponge function to absorb.
Line 820: /// </summary>
Line 821: /// <param name="data">
Line 822: /// Pointer to the input data. When databitLen is not
Line 823: /// a multiple of 8, the last bits of data must be in the
Line 824: /// least significant bits of the last byte.</param>
Line 825: /// <param name="databitlen">The number of input bits provided in the input data.</param>
Line 826: /// <returns>true on success, else false</returns>
Line 827: private bool Absorb(byte[] data, long databitlen)
Line 828: {
Line 829: if ((sponge.BitsInQueue%8) != 0)
Line 830: return false; // Only the last call may contain a partial byte
Line 831: if (sponge.Squeezing)
Line 832: return false; // Too late for additional input
Line 833:
Line 834: long i = 0;
Line 835: Func<long, int, byte[]> makeData = (index, length) =>
Line 836: {
Line 837: // todo - this data movement needs changed - too many copies
Line 838: var dat2 = new byte[length];
Line 839: Array.Copy(data, (int) index, dat2, 0, length);
Line 840: return dat2;
Line 841: };
Line 842: while (i < databitlen)
Line 843: {
Line 844: if ((sponge.BitsInQueue == 0) && (databitlen >= sponge.Rate) && (i <= (databitlen - sponge.Rate)))
Line 845: {
Line 846: var wholeBlocks = (databitlen - i)/sponge.Rate;
Line 847: var curData = i/8;
Line 848:
Line 849:
Line 850: for (var j = 0; j < wholeBlocks; j++, curData += sponge.Rate/8)
Line 851: {
Line 852: Absorb(sponge.State, makeData(curData, sponge.Rate/8), sponge.Rate/64);
Line 853: }
Line 854: i += wholeBlocks*sponge.Rate;
Line 855: }
Line 856: else
Line 857: {
Line 858: var partialBlock = (int) (databitlen - i);
Line 859: if (partialBlock + sponge.BitsInQueue > sponge.Rate)
Line 860: partialBlock = sponge.Rate - sponge.BitsInQueue;
Line 861: var partialByte = partialBlock%8;
Line 862: partialBlock -= partialByte;
Line 863: for (long k = 0; k < partialBlock/8; ++k)
Line 864: {
Line 865: sponge.DataQueue[sponge.BitsAvailableForSqueezing/8 + k] = data[i/8 + k];
Line 866: }
Line 867: sponge.BitsInQueue += partialBlock;
Line 868: i += partialBlock;
Line 869: if (sponge.BitsInQueue == sponge.Rate)
Line 870: AbsorbQueue();
Line 871: if (partialByte > 0)
Line 872: {
Line 873: var mask = (byte) ((1 << partialByte) - 1);
Line 874: sponge.DataQueue[sponge.BitsInQueue/8] = (byte) (data[i/8] & mask);
Line 875: sponge.BitsInQueue += partialByte;
Line 876: i += partialByte;
Line 877: }
Line 878: }
Line 879: }
Line 880: return true;
Line 881: }
Line 882:
Line 883: private void PadAndSwitchToSqueezingPhase()
Line 884: {
Line 885: // Note: the bits are numbered from 0=LSB to 7=MSB
Line 886: if (sponge.BitsInQueue + 1 == sponge.Rate)
Line 887: {
Line 888: sponge.DataQueue[sponge.BitsInQueue/8] |= (byte) (1 << (sponge.BitsInQueue%8));
Line 889: AbsorbQueue();
Line 890: for (var j = 0; j < sponge.Rate/8; ++j)
Line 891: sponge.DataQueue[j] = 0;
Line 892:
Line 893: }
Line 894: else
Line 895: {
Line 896: for (var j = 0; j < sponge.Rate/8 - (sponge.BitsInQueue + 7)/8; ++j)
Line 897: sponge.DataQueue[(sponge.BitsInQueue + 7)/8 + j] = 0;
Line 898: sponge.DataQueue[sponge.BitsInQueue/8] |= (byte) (1 << (sponge.BitsInQueue%8));
Line 899: }
Line 900: sponge.DataQueue[(sponge.Rate - 1)/8] |= (byte) (1 << ((sponge.Rate - 1)%8));
Line 901: AbsorbQueue();
Line 902: Extract(sponge.State, sponge.DataQueue, sponge.Rate/64);
Line 903: sponge.BitsAvailableForSqueezing = sponge.Rate;
Line 904: sponge.Squeezing = true;
Line 905: }
Line 906:
Line 907: #endregion
Line 908:
Line 909: #region Overrides of HashAlgorithm
Line 910:
Line 911: /// <summary>
Line 912: /// Initializes an implementation of the <see cref="T:System.Security.Cryptography.HashAlgorithm"/> class.
Line 913: /// </summary>
Line 914: public override void Initialize()
Line 915: {
Line 916: }
Line 917:
Line 918: /// <summary>
Line 919: /// When overridden in a derived class, routes data written to the object into the hash algorithm for computing the hash.
Line 920: /// </summary>
Line 921: /// <param name="array">The input to compute the hash code for. </param>
Line 922: /// <param name="ibStart">The offset into the byte array from which to begin using data. </param>
Line 923: /// <param name="cbSize">The number of bytes in the byte array to use as data. </param>
Line 924: protected override void HashCore(byte[] array, int ibStart, int cbSize)
Line 925: {
Line 926: var temp = array;
Line 927: if (ibStart != 0)
Line 928: {
Line 929: // need local copy
Line 930: temp = new byte[cbSize];
Line 931: Array.Copy(array, ibStart, temp, 0, cbSize);
Line 932: }
Line 933: Update(temp, cbSize*8);
Line 934: }
Line 935:
Line 936: /// <summary>
Line 937: /// When overridden in a derived class, finalizes the hash computation after the last data is processed by the cryptographic stream object.
Line 938: /// </summary>
Line 939: /// <returns>
Line 940: /// The computed hash code.
Line 941: /// </returns>
Line 942: protected override byte[] HashFinal()
Line 943: {
Line 944:
Line 945: var hash = new byte[sponge.FixedOutputLength/8];
Line 946: Final(hash);
Line 947: return hash;
Line 948: }
Line 949:
Line 950: #endregion
Line 951: }
Line 952:}
Line 953:
Line 954:// end of file
Line 955: