示例#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);
        }
示例#2
0
        public byte[] GeneratePrivateKey(ulong index)
        {
            Span <byte> input             = new Span <byte>(new byte[32]);
            BigInteger  bigIndex          = new BigInteger(index);
            bool        indexWriteSuccess = bigIndex.TryWriteBytes(input, out int indexBytesWritten, isUnsigned: true, isBigEndian: false);

            if (!indexWriteSuccess || indexBytesWritten == 0)
            {
                throw new Exception("Error getting input for quick start private key generation.");
            }

            Hash32 hash32            = _cryptographyService.Hash(input);
            ReadOnlySpan <byte> hash = hash32.AsSpan();
            // Mocked start interop specifies to convert the hash as little endian (which is the default for BigInteger)
            BigInteger value      = new BigInteger(hash.ToArray(), isUnsigned: true);
            BigInteger privateKey = value % s_curveOrder;

            // Note that the private key is an *unsigned*, *big endian* number
            // However, we want to pad the big endian on the left to get 32 bytes.
            // So, write as little endian (will pad to right), then reverse.
            // NOTE: Alternative, write to Span 64, and then slice based on bytesWritten to get the padding.
            Span <byte> privateKeySpan  = new Span <byte>(new byte[32]);
            bool        keyWriteSuccess = privateKey.TryWriteBytes(privateKeySpan, out int keyBytesWritten, isUnsigned: true, isBigEndian: false);

            if (!keyWriteSuccess)
            {
                throw new Exception("Error generating quick start private key.");
            }
            privateKeySpan.Reverse();

            return(privateKeySpan.ToArray());
        }
 public Hash32 Hash(Hash32 a, Hash32 b)
 {
     Span<byte> input = new Span<byte>(new byte[Hash32.Length * 2]);
     a.AsSpan().CopyTo(input);
     b.AsSpan().CopyTo(input.Slice(Hash32.Length));
     return Hash(input);
 }
示例#4
0
        /// <summary>
        /// Return from ``indices`` a random index sampled by effective balance.
        /// </summary>
        public ValidatorIndex ComputeProposerIndex(BeaconState state, IList<ValidatorIndex> indices, Hash32 seed)
        {
            if (!indices.Any())
            {
                throw new ArgumentException("Indices can not be empty", nameof(indices));
            }

            ulong indexCount = (ulong) indices.Count;
            ValidatorIndex index = 0UL;
            Span<byte> randomInputBytes = stackalloc byte[40];
            seed.AsSpan().CopyTo(randomInputBytes);
            while (true)
            {
                ValidatorIndex initialValidatorIndex = (ValidatorIndex)(index % indexCount);
                ValidatorIndex shuffledIndex = ComputeShuffledIndex(initialValidatorIndex, indexCount, seed);
                ValidatorIndex candidateIndex = indices[(int) shuffledIndex];

                BinaryPrimitives.WriteUInt64LittleEndian(randomInputBytes.Slice(32), index / 32);
                Hash32 randomHash = _cryptographyService.Hash(randomInputBytes);
                byte random = randomHash.AsSpan()[(int) (index % 32)];

                Gwei effectiveBalance = state.Validators[(int) candidateIndex].EffectiveBalance;
                if ((effectiveBalance * byte.MaxValue) >=
                    (_gweiValueOptions.CurrentValue.MaximumEffectiveBalance * random))
                {
                    return candidateIndex;
                }

                index++;
            }
        }
        public bool BlsVerify(BlsPublicKey publicKey, Hash32 messageHash, BlsSignature signature, Domain domain)
        {
            var blsParameters = new BLSParameters()
            {
                PublicKey = publicKey.AsSpan().ToArray()
            };

            using var signatureAlgorithm = SignatureAlgorithmFactory(blsParameters);
            return(signatureAlgorithm.VerifyHash(messageHash.AsSpan(), signature.AsSpan(), domain.AsSpan()));
        }
示例#6
0
        public static BlsSignature BlsSign(Hash32 messageHash, byte[] privateKey, Domain domain)
        {
            var parameters = new BLSParameters()
            {
                PrivateKey = privateKey
            };

            using var signingAlgorithm = SignatureAlgorithmFactory(parameters);
            var destination = new Span <byte>(new byte[96]);
            var success     = signingAlgorithm.TrySignHash(messageHash.AsSpan(), destination, out var bytesWritten, domain.AsSpan().ToArray());

            return(new BlsSignature(destination));
        }
        /// <summary>
        /// Return the seed at ``epoch``.
        /// </summary>
        public Hash32 GetSeed(BeaconState state, Epoch epoch, DomainType domainType)
        {
            Epoch mixEpoch = (Epoch)(epoch + _stateListLengthOptions.CurrentValue.EpochsPerHistoricalVector
                                     - _timeParameterOptions.CurrentValue.MinimumSeedLookahead - 1UL);
            // # Avoid underflow
            Hash32 mix = GetRandaoMix(state, mixEpoch);

            Span <byte> seedHashInput = stackalloc byte[DomainType.Length + sizeof(ulong) + Hash32.Length];

            domainType.AsSpan().CopyTo(seedHashInput);
            BinaryPrimitives.WriteUInt64LittleEndian(seedHashInput.Slice(DomainType.Length), epoch);
            mix.AsSpan().CopyTo(seedHashInput.Slice(DomainType.Length + sizeof(ulong)));
            Hash32 seed = _cryptographyService.Hash(seedHashInput);

            return(seed);
        }
        /// <summary>
        /// Return the beacon proposer index at the current slot.
        /// </summary>
        public ValidatorIndex GetBeaconProposerIndex(BeaconState state)
        {
            Epoch epoch = GetCurrentEpoch(state);

            Span <byte> seedBytes   = stackalloc byte[40];
            Hash32      initialSeed = GetSeed(state, epoch, _signatureDomainOptions.CurrentValue.BeaconProposer);

            initialSeed.AsSpan().CopyTo(seedBytes);
            BinaryPrimitives.WriteUInt64LittleEndian(seedBytes.Slice(32), (ulong)state.Slot);
            Hash32 seed = _cryptographyService.Hash(seedBytes);

            IList <ValidatorIndex> indices       = GetActiveValidatorIndices(state, epoch);
            ValidatorIndex         proposerIndex = _beaconChainUtility.ComputeProposerIndex(state, indices, seed);

            return(proposerIndex);
        }
示例#9
0
        public Eth1Data GetEth1DataStub(BeaconState state, Epoch currentEpoch)
        {
            TimeParameters timeParameters = _timeParameterOptions.CurrentValue;

            uint        epochsPerPeriod   = timeParameters.SlotsPerEth1VotingPeriod / timeParameters.SlotsPerEpoch;
            ulong       votingPeriod      = (ulong)currentEpoch / epochsPerPeriod;
            Span <byte> votingPeriodBytes = stackalloc byte[32];

            BinaryPrimitives.WriteUInt64LittleEndian(votingPeriodBytes, votingPeriod);
            Hash32 depositRoot = _cryptographyService.Hash(votingPeriodBytes);

            ulong  depositCount = state.Eth1DepositIndex;
            Hash32 blockHash    = _cryptographyService.Hash(depositRoot.AsSpan());

            Eth1Data eth1Data = new Eth1Data(depositRoot, depositCount, blockHash);

            return(eth1Data);
        }
示例#10
0
        public BlsSignature SignHashWithDomain(BlsPublicKey blsPublicKey, Hash32 hash, Domain domain)
        {
            if (_publicKeyToBls.Count == 0)
            {
                var keyCount = GetPublicKeys().Count();
            }

            BLS bls = _publicKeyToBls[blsPublicKey];

            Span <byte> destination = stackalloc byte[BlsSignature.Length];
            bool        success     = bls.TrySignHash(hash.AsSpan(), destination, out int bytesWritten, domain.AsSpan());

            if (!success || bytesWritten != BlsSignature.Length)
            {
                throw new Exception($"Failure signing hash {hash}, domain {domain} for public key {blsPublicKey}.");
            }
            BlsSignature blsSignature = new BlsSignature(destination.ToArray());

            return(blsSignature);
        }
示例#11
0
        /// <summary>
        /// Return from ``indices`` a random index sampled by effective balance.
        /// </summary>
        public ValidatorIndex ComputeProposerIndex(BeaconState state, IList <ValidatorIndex> indices, Hash32 seed)
        {
            if (!indices.Any())
            {
                throw new ArgumentException("Indices can not be empty", nameof(indices));
            }

            const ulong maxRandomByte = (1 << 8) - 1;
            var         indexCount    = (ulong)indices.Count();
            var         index         = (ulong)0;

            while (true)
            {
                var initialValidatorIndex = new ValidatorIndex(index % indexCount);
                var shuffledIndex         = ComputeShuffledIndex(initialValidatorIndex, indexCount, seed);
                var candidateIndex        = indices[(int)(ulong)shuffledIndex];

                var randomInputBytes = new Span <byte>(new byte[40]);
                seed.AsSpan().CopyTo(randomInputBytes);
                BitConverter.TryWriteBytes(randomInputBytes.Slice(32), index / 32);
                if (!BitConverter.IsLittleEndian)
                {
                    randomInputBytes.Slice(32).Reverse();
                }
                var randomHash = _cryptographyService.Hash(randomInputBytes);
                var random     = randomHash.AsSpan()[(int)(index % 32)];

                var effectiveBalance = state.Validators[(int)(ulong)candidateIndex].EffectiveBalance;
                if ((effectiveBalance * maxRandomByte) >=
                    (_gweiValueOptions.CurrentValue.MaximumEffectiveBalance * random))
                {
                    return(candidateIndex);
                }
                index++;
            }
        }
示例#12
0
 public static SszBasicVector ToSszBasicVector(this Hash32 item)
 {
     return(new SszBasicVector(item.AsSpan()));
 }
示例#13
0
        public void QuickStartGenesis()
        {
            QuickStartParameters quickStartParameters = _quickStartParameterOptions.CurrentValue;

            if (_logger.IsWarn())
            {
                Log.MockedQuickStart(_logger, quickStartParameters.GenesisTime, quickStartParameters.ValidatorCount, null);
            }

            GweiValues       gweiValues       = _gweiValueOptions.CurrentValue;
            InitialValues    initialValues    = _initialValueOptions.CurrentValue;
            SignatureDomains signatureDomains = _signatureDomainOptions.CurrentValue;

            // Fixed amount
            Gwei amount = gweiValues.MaximumEffectiveBalance;

            // Build deposits
            List <DepositData> depositDataList = new List <DepositData>();
            List <Deposit>     deposits        = new List <Deposit>();

            for (ulong validatorIndex = 0uL; validatorIndex < quickStartParameters.ValidatorCount; validatorIndex++)
            {
                byte[] privateKey = GeneratePrivateKey(validatorIndex);

                // Public Key
                BLSParameters blsParameters = new BLSParameters()
                {
                    PrivateKey = privateKey
                };
                using BLS bls = BLS.Create(blsParameters);
                byte[] publicKeyBytes = new byte[BlsPublicKey.Length];
                bls.TryExportBLSPublicKey(publicKeyBytes, out int publicKeyBytesWritten);
                BlsPublicKey publicKey = new BlsPublicKey(publicKeyBytes);

                // Withdrawal Credentials
                byte[] withdrawalCredentialBytes = _cryptographyService.Hash(publicKey.AsSpan()).AsSpan().ToArray();
                withdrawalCredentialBytes[0] = initialValues.BlsWithdrawalPrefix;
                Hash32 withdrawalCredentials = new Hash32(withdrawalCredentialBytes);

                // Build deposit data
                DepositData depositData = new DepositData(publicKey, withdrawalCredentials, amount);

                // Sign deposit data
                Hash32 depositDataSigningRoot = _cryptographyService.SigningRoot(depositData);
                Domain domain      = _beaconChainUtility.ComputeDomain(signatureDomains.Deposit);
                byte[] destination = new byte[96];
                bls.TrySignHash(depositDataSigningRoot.AsSpan(), destination, out int bytesWritten, domain.AsSpan());
                BlsSignature depositDataSignature = new BlsSignature(destination);
                depositData.SetSignature(depositDataSignature);

                // Deposit

                // TODO: This seems a very inefficient way (copied from tests) as it recalculates the merkle tree each time
                // (you only need to add one node)

                // TODO: Add some tests around quick start, then improve

                int index = depositDataList.Count;
                depositDataList.Add(depositData);
                //int depositDataLength = (ulong) 1 << _chainConstants.DepositContractTreeDepth;
                Hash32 root = _cryptographyService.HashTreeRoot(depositDataList);
                IEnumerable <Hash32>    allLeaves = depositDataList.Select(x => _cryptographyService.HashTreeRoot(x));
                IList <IList <Hash32> > tree      = CalculateMerkleTreeFromLeaves(allLeaves);


                IList <Hash32> merkleProof = GetMerkleProof(tree, index, 32);
                List <Hash32>  proof       = new List <Hash32>(merkleProof);
                Span <byte>    indexBytes  = new Span <byte>(new byte[32]);
                BitConverter.TryWriteBytes(indexBytes, (ulong)index + 1);
                if (!BitConverter.IsLittleEndian)
                {
                    indexBytes.Slice(0, 8).Reverse();
                }

                Hash32 indexHash = new Hash32(indexBytes);
                proof.Add(indexHash);
                Hash32 leaf = _cryptographyService.HashTreeRoot(depositData);
                _beaconChainUtility.IsValidMerkleBranch(leaf, proof, _chainConstants.DepositContractTreeDepth + 1, (ulong)index, root);
                Deposit deposit = new Deposit(proof, depositData);

                if (_logger.IsEnabled(LogLevel.Debug))
                {
                    LogDebug.QuickStartAddValidator(_logger, validatorIndex, publicKey.ToString().Substring(0, 12),
                                                    null);
                }

                deposits.Add(deposit);
            }

            BeaconState genesisState = _beaconChain.InitializeBeaconStateFromEth1(quickStartParameters.Eth1BlockHash, quickStartParameters.Eth1Timestamp, deposits);

            // We use the state directly, and don't test IsValid
            genesisState.SetGenesisTime(quickStartParameters.GenesisTime);
            IStore store = _forkChoice.GetGenesisStore(genesisState);

            if (_logger.IsEnabled(LogLevel.Debug))
            {
                LogDebug.QuickStartStoreCreated(_logger, store.GenesisTime, null);
            }
        }