Example #1
0
        /// <summary>
        /// Return the shuffled validator index corresponding to ``seed`` (and ``index_count``).
        /// </summary>
        public ValidatorIndex ComputeShuffledIndex(ValidatorIndex index, ulong indexCount, Hash32 seed)
        {
            if (index >= indexCount)
            {
                throw new ArgumentOutOfRangeException(nameof(index), index, $"Index should be less than indexCount {indexCount}");
            }

            // Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf)
            // See the 'generalized domain' algorithm on page 3

            Span <byte> pivotHashInput = new Span <byte>(new byte[33]);

            seed.AsSpan().CopyTo(pivotHashInput);
            Span <byte> sourceHashInput = new Span <byte>(new byte[37]);

            seed.AsSpan().CopyTo(sourceHashInput);
            for (int currentRound = 0; currentRound < _miscellaneousParameterOptions.CurrentValue.ShuffleRoundCount; currentRound++)
            {
                byte roundByte = (byte)(currentRound & 0xFF);
                pivotHashInput[32] = roundByte;
                Hash32 pivotHash  = _cryptographyService.Hash(pivotHashInput);
                byte[] pivotBytes = pivotHash.AsSpan().Slice(0, 8).ToArray();
                if (!BitConverter.IsLittleEndian)
                {
                    pivotBytes = pivotBytes.Reverse().ToArray();
                }

                ValidatorIndex pivot = BitConverter.ToUInt64(pivotBytes.ToArray()) % indexCount;

                ValidatorIndex flip = (pivot + indexCount - index) % indexCount;

                ValidatorIndex position = ValidatorIndex.Max(index, flip);

                sourceHashInput[32] = roundByte;
                byte[] positionBytes = BitConverter.GetBytes((uint)position / 256);
                if (!BitConverter.IsLittleEndian)
                {
                    positionBytes = positionBytes.Reverse().ToArray();
                }

                positionBytes.CopyTo(sourceHashInput.Slice(33));
                Hash32 source = _cryptographyService.Hash(sourceHashInput.ToArray());

                byte flipByte = source.AsSpan((int)((uint)position % 256 / 8), 1)[0];

                int flipBit = (flipByte >> (int)(position % 8)) % 2;

                if (flipBit == 1)
                {
                    index = flip;
                }
            }

            return(index);
        }
Example #2
0
        /// <summary>
        /// Return the shuffled validator index corresponding to ``seed`` (and ``index_count``).
        /// </summary>
        public ValidatorIndex ComputeShuffledIndex(ValidatorIndex index, ulong indexCount, Bytes32 seed)
        {
            if (index >= indexCount)
            {
                throw new ArgumentOutOfRangeException(nameof(index), index,
                                                      $"Index should be less than indexCount {indexCount}");
            }

            // Swap or not (https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf)
            // See the 'generalized domain' algorithm on page 3

            Span <byte> pivotHashInput = stackalloc byte[33];

            seed.AsSpan().CopyTo(pivotHashInput);
            Span <byte> sourceHashInput = stackalloc byte[37];

            seed.AsSpan().CopyTo(sourceHashInput);
            for (int currentRound = 0;
                 currentRound < _miscellaneousParameterOptions.CurrentValue.ShuffleRoundCount;
                 currentRound++)
            {
                byte roundByte = (byte)(currentRound & 0xFF);
                pivotHashInput[32] = roundByte;
                Bytes32             pivotHash  = _cryptographyService.Hash(pivotHashInput);
                ReadOnlySpan <byte> pivotBytes = pivotHash.AsSpan().Slice(0, 8);
                ValidatorIndex      pivot      = BinaryPrimitives.ReadUInt64LittleEndian(pivotBytes) % indexCount;

                ValidatorIndex flip = (pivot + indexCount - index) % indexCount;

                ValidatorIndex position = ValidatorIndex.Max(index, flip);

                sourceHashInput[32] = roundByte;
                BinaryPrimitives.WriteUInt32LittleEndian(sourceHashInput.Slice(33), (uint)position / 256);
                Bytes32 source = _cryptographyService.Hash(sourceHashInput.ToArray());

                byte flipByte = source.AsSpan()[(int)((position % 256) / 8)];

                int flipBit = (flipByte >> (int)(position % 8)) % 2;

                if (flipBit == 1)
                {
                    index = flip;
                }
            }

            return(index);
        }