private void Body(byte[] data, int start, int length)
        {
            int remainder     = length & 15;
            int alignedLength = start + (length - remainder);

            for (int i = start; i < alignedLength; i += 16)
            {
                uint k1 = data.ToUInt32(i),
                     k2 = data.ToUInt32(i + 4),
                     k3 = data.ToUInt32(i + 8),
                     k4 = data.ToUInt32(i + 12);

                H1 ^= (k1 * C1).RotateLeft(15) * C2;
                H1  = (H1.RotateLeft(19) + H2) * 5 + 0x561ccd1b;

                H2 ^= (k2 * C2).RotateLeft(16) * C3;
                H2  = (H2.RotateLeft(17) + H3) * 5 + 0x0bcaa747;

                H3 ^= (k3 * C3).RotateLeft(17) * C4;
                H3  = (H3.RotateLeft(15) + H4) * 5 + 0x96cd1c35;

                H4 ^= (k4 * C4).RotateLeft(18) * C1;
                H4  = (H4.RotateLeft(13) + H1) * 5 + 0x32ac3b17;
            }

            if (remainder > 0)
            {
                Tail(data, alignedLength, remainder);
            }
        }
        private void Body(byte[] data, int start, int length)
        {
            if (length == 0)
            {
                return;
            }

            int remainder = length & 15;
            int blocks    = length / 16;

            unsafe
            {
                fixed(byte *d = &data[start])
                {
                    // grab a reference to blocks
                    uint *b = (uint *)d;

                    while (blocks-- > 0)
                    {
                        // K1 - consume first integer
                        H1 ^= (*b++ *C1).RotateLeft(15) * C2;
                        H1  = (H1.RotateLeft(19) + H2) * 5 + 0x561ccd1b;

                        // K2 - consume second integer
                        H2 ^= (*b++ *C2).RotateLeft(16) * C3;
                        H2  = (H2.RotateLeft(17) + H3) * 5 + 0x0bcaa747;

                        // K3 - consume third integer
                        H3 ^= (*b++ *C3).RotateLeft(17) * C4;
                        H3  = (H3.RotateLeft(15) + H4) * 5 + 0x96cd1c35;

                        // K4 - consume fourth integer
                        H4 ^= (*b++ *C4).RotateLeft(18) * C1;
                        H4  = (H4.RotateLeft(13) + H1) * 5 + 0x32ac3b17;
                    }

                    if (remainder > 0)
                    {
                        Tail(d + (length - remainder), remainder);
                    }
                }
            }
        }
        private void Body(ReadOnlySpan <byte> source)
        {
            if (source.Length == 0)
            {
                return;
            }

            var remainder = source.Length & 15;
            var blocks    = 4 * (source.Length / 16);

            if (blocks > 0)
            {
                var uintSource = MemoryMarshal.Cast <byte, uint>(source);
                var block      = 0;
                while (block < blocks)
                {
                    var k1 = uintSource[block++];
                    var k2 = uintSource[block++];
                    var k3 = uintSource[block++];
                    var k4 = uintSource[block++];

                    H1 ^= (k1 * C1).RotateLeft(15) * C2;
                    H1  = ((H1.RotateLeft(19) + H2) * 5) + 0x561ccd1b;

                    H2 ^= (k2 * C2).RotateLeft(16) * C3;
                    H2  = ((H2.RotateLeft(17) + H3) * 5) + 0x0bcaa747;

                    H3 ^= (k3 * C3).RotateLeft(17) * C4;
                    H3  = ((H3.RotateLeft(15) + H4) * 5) + 0x96cd1c35;

                    H4 ^= (k4 * C4).RotateLeft(18) * C1;
                    H4  = ((H4.RotateLeft(13) + H1) * 5) + 0x32ac3b17;
                }
            }

            if (remainder > 0)
            {
                Tail(source.Slice(4 * blocks));
            }
        }