Implementation of SipHash as specified in "SipHash: a fast short-input PRF", by Jean-Philippe Aumasson and Daniel J. Bernstein (https://131002.net/siphash/siphash.pdf).
"SipHash is a family of PRFs SipHash-c-d where the integer parameters c and d are the number of compression rounds and the number of finalization rounds. A compression round is identical to a finalization round and this round function is called SipRound. Given a 128-bit key k and a (possibly empty) byte string m, SipHash-c-d returns a 64-bit value..."
Inheritance: IMac
Beispiel #1
0
        public override void PerformTest()
        {
            byte[] key = Hex.Decode("000102030405060708090a0b0c0d0e0f");
            byte[] input = Hex.Decode("000102030405060708090a0b0c0d0e");

            long expected = unchecked((long)0xa129ca6149be45e5);

            SipHash mac = new SipHash();
            mac.Init(new KeyParameter(key));
            mac.BlockUpdate(input, 0, input.Length);

            long result = mac.DoFinal();
            if (expected != result)
            {
                Fail("Result does not match expected value for DoFinal()");
            }

            // NOTE: Little-endian representation of 0xa129ca6149be45e5
            byte[] expectedBytes = Hex.Decode("e545be4961ca29a1");

            mac.BlockUpdate(input, 0, input.Length);

            byte[] output = new byte[mac.GetMacSize()];
            int len = mac.DoFinal(output, 0);
            if (len != output.Length)
            {
                Fail("Result length does not equal GetMacSize() for DoFinal(byte[],int)");
            }
            if (!AreEqual(expectedBytes, output))
            {
                Fail("Result does not match expected value for DoFinal(byte[],int)");
            }
        }
Beispiel #2
0
        protected virtual void ApplySipRounds(int n)
        {
            long num  = this.v0;
            long num2 = this.v1;
            long num3 = this.v2;
            long num4 = this.v3;

            for (int i = 0; i < n; i++)
            {
                num  += num2;
                num3 += num4;
                num2  = SipHash.RotateLeft(num2, 13);
                num4  = SipHash.RotateLeft(num4, 16);
                num2 ^= num;
                num4 ^= num3;
                num   = SipHash.RotateLeft(num, 32);
                num3 += num2;
                num  += num4;
                num2  = SipHash.RotateLeft(num2, 17);
                num4  = SipHash.RotateLeft(num4, 21);
                num2 ^= num3;
                num4 ^= num;
                num3  = SipHash.RotateLeft(num3, 32);
            }
            this.v0 = num;
            this.v1 = num2;
            this.v2 = num3;
            this.v3 = num4;
        }
Beispiel #3
0
        private void RunMac(byte[] key, byte[] input, int updateType)
        {
            long expected = unchecked((long)0xa129ca6149be45e5);

            SipHash mac = new SipHash();
            mac.Init(new KeyParameter(key));

            UpdateMac(mac, input, updateType);

            long result = mac.DoFinal();
            if (expected != result)
            {
                Fail("Result does not match expected value for DoFinal()");
            }

            // NOTE: Little-endian representation of 0xa129ca6149be45e5
            byte[] expectedBytes = Hex.Decode("e545be4961ca29a1");

            UpdateMac(mac, input, updateType);

            byte[] output = new byte[mac.GetMacSize()];
            int len = mac.DoFinal(output, 0);
            if (len != output.Length)
            {
                Fail("Result length does not equal GetMacSize() for DoFinal(byte[],int)");
            }
            if (!AreEqual(expectedBytes, output))
            {
                Fail("Result does not match expected value for DoFinal(byte[],int)");
            }
        }
Beispiel #4
0
        private void RandomTest(SecureRandom random)
        {
            byte[] key = new byte[16];
            random.NextBytes(key);

            int length = 1 + random.Next(1024);
            byte[] input = new byte[length];
            random.NextBytes(input);

            SipHash mac = new SipHash();
            mac.Init(new KeyParameter(key));

            UpdateMac(mac, input, UPDATE_BYTES);
            long result1 = mac.DoFinal();

            UpdateMac(mac, input, UPDATE_FULL);
            long result2 = mac.DoFinal();

            UpdateMac(mac, input, UPDATE_MIX);
            long result3 = mac.DoFinal();

            if (result1 != result2 || result1 != result3)
            {
                Fail("Inconsistent results in random test");
            }
        }
Beispiel #5
0
 private void UpdateMac(SipHash mac, byte[] input, int updateType)
 {
     switch (updateType)
     {
     case UPDATE_BYTES:
     {
         for (int i = 0; i < input.Length; ++i)
         {
             mac.Update(input[i]);
         }
         break;
     }
     case UPDATE_FULL:
     {
         mac.BlockUpdate(input, 0, input.Length);
         break;
     }
     case UPDATE_MIX:
     {
         int step = System.Math.Max(1, input.Length / 3);
         int pos = 0;
         while (pos < input.Length)
         {
             mac.Update(input[pos++]);
             int len = System.Math.Min(input.Length - pos, step);
             mac.BlockUpdate(input, pos, len);
             pos += len;
         }
         break;
     }
     default:
         throw new InvalidOperationException();
     }
 }