public BlsPublicKey BlsAggregatePublicKeys(IEnumerable<BlsPublicKey> publicKeys) { // TKS: added an extension here as an example to discuss - I have been avoiding passing IEnumerable // for the performance reasons - to avoid multiple runs // and opted for passing either arrays or lists and keep it consistent // it sometimes / very rarely has an issue of having to cast list to an array // but usually we have a full control over the flow so it ends up being much better // what do you think? // TODO: [SG] yes. Change IEnumerable to IList in most places to avoid double-enumeration. Span<byte> publicKeysSpan = new Span<byte>(new byte[publicKeys.Count() * BlsPublicKey.Length]); int publicKeysSpanIndex = 0; foreach (BlsPublicKey publicKey in publicKeys) { publicKey.AsSpan().CopyTo(publicKeysSpan.Slice(publicKeysSpanIndex)); publicKeysSpanIndex += BlsPublicKey.Length; } using BLS signatureAlgorithm = SignatureAlgorithmFactory(new BLSParameters()); byte[] aggregatePublicKey = new byte[BlsPublicKey.Length]; bool success = signatureAlgorithm.TryAggregatePublicKeys(publicKeysSpan, aggregatePublicKey, out int bytesWritten); if (!success || bytesWritten != BlsPublicKey.Length) { throw new Exception("Error generating aggregate public key."); } return new BlsPublicKey(aggregatePublicKey); }
public IList <BlsPublicKey> GetPublicKeys() { if (_publicKeyToBls.Count == 0) { QuickStartParameters _quickStartParameters = _quickStartParameterOptions.CurrentValue; ulong endIndex = _quickStartParameters.ValidatorStartIndex + _quickStartParameters.NumberOfValidators; for (ulong validatorIndex = _quickStartParameters.ValidatorStartIndex; validatorIndex < endIndex; validatorIndex++) { byte[] privateKey = GeneratePrivateKey(validatorIndex); BLSParameters blsParameters = new BLSParameters() { PrivateKey = privateKey }; BLS bls = BLS.Create(blsParameters); byte[] publicKeyBytes = new byte[BlsPublicKey.Length]; bls.TryExportBlsPublicKey(publicKeyBytes, out int publicKeyBytesWritten); BlsPublicKey publicKey = new BlsPublicKey(publicKeyBytes); // Cache the BLS class, for easy signing _publicKeyToBls[publicKey] = bls; } } return(_publicKeyToBls.Keys.ToList()); }
public bool BlsVerifyMultiple(IEnumerable <BlsPublicKey> publicKeys, IEnumerable <Hash32> messageHashes, BlsSignature signature, Domain domain) { int count = publicKeys.Count(); Span <byte> publicKeysSpan = new Span <byte>(new byte[count * BlsPublicKey.Length]); int publicKeysSpanIndex = 0; foreach (BlsPublicKey publicKey in publicKeys) { publicKey.AsSpan().CopyTo(publicKeysSpan.Slice(publicKeysSpanIndex)); publicKeysSpanIndex += BlsPublicKey.Length; } Span <byte> messageHashesSpan = new Span <byte>(new byte[count * Hash32.Length]); int messageHashesSpanIndex = 0; foreach (Hash32 messageHash in messageHashes) { messageHash.AsSpan().CopyTo(messageHashesSpan.Slice(messageHashesSpanIndex)); messageHashesSpanIndex += Hash32.Length; } using BLS signatureAlgorithm = SignatureAlgorithmFactory(new BLSParameters()); return(signatureAlgorithm.VerifyAggregate(publicKeysSpan, messageHashesSpan, signature.AsSpan(), domain.AsSpan())); }
public bool BlsAggregateVerify(IList <BlsPublicKey> publicKeys, IList <Root> signingRoots, BlsSignature signature) { int count = publicKeys.Count(); Span <byte> publicKeysSpan = new Span <byte>(new byte[count * BlsPublicKey.Length]); int publicKeysSpanIndex = 0; foreach (BlsPublicKey publicKey in publicKeys) { publicKey.AsSpan().CopyTo(publicKeysSpan.Slice(publicKeysSpanIndex)); publicKeysSpanIndex += BlsPublicKey.Length; } Span <byte> signingRootsSpan = new Span <byte>(new byte[count * Root.Length]); int signingRootsSpanIndex = 0; foreach (Root signingRoot in signingRoots) { signingRoot.AsSpan().CopyTo(signingRootsSpan.Slice(signingRootsSpanIndex)); signingRootsSpanIndex += Root.Length; } using BLS signatureAlgorithm = SignatureAlgorithmFactory(new BLSParameters()); return(signatureAlgorithm.AggregateVerifyHashes(publicKeysSpan, signingRootsSpan, signature.AsSpan())); }
public bool BlsVerify(BlsPublicKey publicKey, Root signingRoot, BlsSignature signature) { BLSParameters blsParameters = new BLSParameters() { PublicKey = publicKey.AsSpan().ToArray() }; using BLS signatureAlgorithm = SignatureAlgorithmFactory(blsParameters); return(signatureAlgorithm.VerifyHash(signingRoot.AsSpan(), signature.AsSpan())); }
public bool BlsVerify(BlsPublicKey publicKey, Hash32 messageHash, BlsSignature signature, Domain domain) { BLSParameters blsParameters = new BLSParameters() { PublicKey = publicKey.AsSpan().ToArray() }; using BLS signatureAlgorithm = SignatureAlgorithmFactory(blsParameters); return(signatureAlgorithm.VerifyHash(messageHash.AsSpan(), signature.AsSpan(), domain.AsSpan())); }
public CryptographyService(ChainConstants chainConstants, IOptionsMonitor <MiscellaneousParameters> miscellaneousParameterOptions, IOptionsMonitor <TimeParameters> timeParameterOptions, IOptionsMonitor <StateListLengths> stateListLengthOptions, IOptionsMonitor <MaxOperationsPerBlock> maxOperationsPerBlockOptions) { _chainConstants = chainConstants; _miscellaneousParameterOptions = miscellaneousParameterOptions; _timeParameterOptions = timeParameterOptions; _stateListLengthOptions = stateListLengthOptions; _maxOperationsPerBlockOptions = maxOperationsPerBlockOptions; MiscellaneousParameters miscellaneousParameters = miscellaneousParameterOptions.CurrentValue; TimeParameters timeParameters = timeParameterOptions.CurrentValue; StateListLengths stateListLengths = stateListLengthOptions.CurrentValue; MaxOperationsPerBlock maxOperationsPerBlock = maxOperationsPerBlockOptions.CurrentValue; BLSParameters blsParameters = new BLSParameters(); _bls = BLS.Create(blsParameters); Nethermind.Ssz.Ssz.Init( chainConstants.DepositContractTreeDepth, chainConstants.JustificationBitsLength, miscellaneousParameters.MaximumValidatorsPerCommittee, timeParameters.SlotsPerEpoch, timeParameters.SlotsPerEth1VotingPeriod, timeParameters.SlotsPerHistoricalRoot, stateListLengths.EpochsPerHistoricalVector, stateListLengths.EpochsPerSlashingsVector, stateListLengths.HistoricalRootsLimit, stateListLengths.ValidatorRegistryLimit, maxOperationsPerBlock.MaximumProposerSlashings, maxOperationsPerBlock.MaximumAttesterSlashings, maxOperationsPerBlock.MaximumAttestations, maxOperationsPerBlock.MaximumDeposits, maxOperationsPerBlock.MaximumVoluntaryExits); Nethermind.Ssz.Ssz.Init( chainConstants.DepositContractTreeDepth, chainConstants.JustificationBitsLength, miscellaneousParameters.MaximumValidatorsPerCommittee, timeParameters.SlotsPerEpoch, timeParameters.SlotsPerEth1VotingPeriod, timeParameters.SlotsPerHistoricalRoot, stateListLengths.EpochsPerHistoricalVector, stateListLengths.EpochsPerSlashingsVector, stateListLengths.HistoricalRootsLimit, stateListLengths.ValidatorRegistryLimit, maxOperationsPerBlock.MaximumProposerSlashings, maxOperationsPerBlock.MaximumAttesterSlashings, maxOperationsPerBlock.MaximumAttestations, maxOperationsPerBlock.MaximumDeposits, maxOperationsPerBlock.MaximumVoluntaryExits); }
private DepositData BuildAndSignDepositData(ulong validatorIndex, Gwei amount, SignatureDomains signatureDomains) { InitialValues initialValues = _initialValueOptions.CurrentValue; 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 Bytes32 withdrawalCredentials = _crypto.Hash(publicKey.AsSpan()); withdrawalCredentials.Unwrap()[0] = initialValues.BlsWithdrawalPrefix; // Build deposit data DepositData depositData = new DepositData(publicKey, withdrawalCredentials, amount, BlsSignature.Zero); // Sign deposit data Domain domain = _beaconChainUtility.ComputeDomain(signatureDomains.Deposit); DepositMessage depositMessage = new DepositMessage( depositData.PublicKey, depositData.WithdrawalCredentials, depositData.Amount); Root depositMessageRoot = _crypto.HashTreeRoot(depositMessage); Root depositDataSigningRoot = _beaconChainUtility.ComputeSigningRoot(depositMessageRoot, domain); byte[] signatureBytes = new byte[96]; bls.TrySignData(depositDataSigningRoot.AsSpan(), signatureBytes, out int bytesWritten); BlsSignature depositDataSignature = new BlsSignature(signatureBytes); depositData.SetSignature(depositDataSignature); if (_logger.IsEnabled(LogLevel.Debug)) { LogDebug.QuickStartAddValidator(_logger, validatorIndex, publicKey.ToString().Substring(0, 12), null); } return(depositData); }
public BlsSignature SignRoot(BlsPublicKey blsPublicKey, Root root) { if (_publicKeyToBls.Count == 0) { var keyCount = GetPublicKeys().Count(); } BLS bls = _publicKeyToBls[blsPublicKey]; byte[] destination = new byte[BlsSignature.Length]; bool success = bls.TrySignData(root.AsSpan(), destination, out int bytesWritten); if (!success || bytesWritten != BlsSignature.Length) { throw new Exception($"Failure signing hash {root} for public key {blsPublicKey}."); } BlsSignature blsSignature = new BlsSignature(destination); return(blsSignature); }
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); }
private static void EnsureKeys(TimeParameters timeParameters) { var keysRequired = (int)(ulong)timeParameters.SlotsPerEpoch * 16; if (_testKeys.Count == keysRequired) { return; } _testKeys.Clear(); _privateKeys.Clear(); _publicKeys.Clear(); // Private key is ~255 bits (32 bytes) long for (var keyNumber = 0; keyNumber < keysRequired; keyNumber++) { var privateKeySpan = new Span <byte>(new byte[32]); // Key is big endian number, so write Int32 to last 4 bytes. BitConverter.TryWriteBytes(privateKeySpan.Slice(28), keyNumber + 1); if (BitConverter.IsLittleEndian) { // And reverse if necessary privateKeySpan.Slice(28).Reverse(); } var privateKey = privateKeySpan.ToArray(); var blsParameters = new BLSParameters() { PrivateKey = privateKey }; using var bls = BLS.Create(blsParameters); var publicKeyBytes = new byte[BlsPublicKey.Length]; bls.TryExportBLSPublicKey(publicKeyBytes, out var bytesWritten); var publicKey = new BlsPublicKey(publicKeyBytes); _privateKeys.Add(privateKey); _publicKeys.Add(publicKey); _testKeys[publicKey] = privateKey; } }
public BlsPublicKey BlsAggregatePublicKeys(IList <BlsPublicKey> publicKeys) { Span <byte> publicKeysSpan = new Span <byte>(new byte[publicKeys.Count() * BlsPublicKey.Length]); int publicKeysSpanIndex = 0; foreach (BlsPublicKey publicKey in publicKeys) { publicKey.AsSpan().CopyTo(publicKeysSpan.Slice(publicKeysSpanIndex)); publicKeysSpanIndex += BlsPublicKey.Length; } using BLS signatureAlgorithm = SignatureAlgorithmFactory(new BLSParameters()); byte[] aggregatePublicKey = new byte[BlsPublicKey.Length]; bool success = signatureAlgorithm.TryAggregatePublicKeys(publicKeysSpan, aggregatePublicKey, out int bytesWritten); if (!success || bytesWritten != BlsPublicKey.Length) { throw new Exception("Error generating aggregate public key."); } return(new BlsPublicKey(aggregatePublicKey)); }
private BlsSignature GetEpochSignature(IServiceProvider testServiceProvider, byte[] privateKey, ForkVersion forkVersion, Slot slot) { SignatureDomains signatureDomains = testServiceProvider.GetService <IOptions <SignatureDomains> >().Value; BeaconChainUtility beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); var domain = beaconChainUtility.ComputeDomain(signatureDomains.Randao, forkVersion); var epoch = beaconChainUtility.ComputeEpochAtSlot(slot); var epochRoot = epoch.HashTreeRoot(); BLSParameters parameters = new BLSParameters() { PrivateKey = privateKey }; BLS bls = BLS.Create(parameters); var destination = new Span <byte>(new byte[96]); bls.TrySignHash(epochRoot.AsSpan(), destination, out var bytesWritten, domain.AsSpan()); var signature = new BlsSignature(destination.ToArray()); return(signature); }
public void QuickStartGenesis() { var quickStartParameters = _quickStartParameterOptions.CurrentValue; _logger.LogWarning(0, "Mocked quick start with genesis time {GenesisTime} and {ValidatorCount} validators.", quickStartParameters.GenesisTime, quickStartParameters.ValidatorCount); var miscellaneousParameters = _miscellaneousParameterOptions.CurrentValue; var gweiValues = _gweiValueOptions.CurrentValue; var initialValues = _initialValueOptions.CurrentValue; var timeParameters = _timeParameterOptions.CurrentValue; var stateListLengths = _stateListLengthOptions.CurrentValue; var maxOperationsPerBlock = _maxOperationsPerBlockOptions.CurrentValue; var signatureDomains = _signatureDomainOptions.CurrentValue; // Fixed amount var amount = gweiValues.MaximumEffectiveBalance; // Build deposits var depositDataList = new List <DepositData>(); var deposits = new List <Deposit>(); for (var validatorIndex = 0uL; validatorIndex < quickStartParameters.ValidatorCount; validatorIndex++) { var privateKey = GeneratePrivateKey(validatorIndex); // Public Key var blsParameters = new BLSParameters() { PrivateKey = privateKey }; using var bls = BLS.Create(blsParameters); var publicKeyBytes = new Span <byte>(new byte[BlsPublicKey.Length]); bls.TryExportBLSPublicKey(publicKeyBytes, out var publicKeybytesWritten); var publicKey = new BlsPublicKey(publicKeyBytes); // Withdrawal Credentials var withdrawalCredentialBytes = _cryptographyService.Hash(publicKey.AsSpan()).AsSpan().ToArray(); withdrawalCredentialBytes[0] = initialValues.BlsWithdrawalPrefix; var withdrawalCredentials = new Hash32(withdrawalCredentialBytes); // Build deposit data var depositData = new DepositData(publicKey, withdrawalCredentials, amount); // Sign deposit data var depositDataSigningRoot = depositData.SigningRoot(); var domain = _beaconChainUtility.ComputeDomain(signatureDomains.Deposit); var destination = new Span <byte>(new byte[96]); bls.TrySignHash(depositDataSigningRoot.AsSpan(), destination, out var bytesWritten, domain.AsSpan()); var 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 var index = depositDataList.Count; depositDataList.Add(depositData); var root = depositDataList.HashTreeRoot((ulong)1 << _chainConstants.DepositContractTreeDepth); var allLeaves = depositDataList.Select(x => x.HashTreeRoot()); var tree = CalculateMerkleTreeFromLeaves(allLeaves); var merkleProof = GetMerkleProof(tree, index, 32); var proof = new List <Hash32>(merkleProof); var indexBytes = new Span <byte>(new byte[32]); BitConverter.TryWriteBytes(indexBytes, (ulong)index + 1); if (!BitConverter.IsLittleEndian) { indexBytes.Slice(0, 8).Reverse(); } var indexHash = new Hash32(indexBytes); proof.Add(indexHash); var leaf = depositData.HashTreeRoot(); _beaconChainUtility.IsValidMerkleBranch(leaf, proof, _chainConstants.DepositContractTreeDepth + 1, (ulong)index, root); var deposit = new Deposit(proof, depositData); _logger.LogDebug("Quick start adding deposit for mocked validator {ValidatorIndex} with public key {PublicKey}.", validatorIndex, publicKey); deposits.Add(deposit); } var genesisState = _beaconChain.InitializeBeaconStateFromEth1(quickStartParameters.Eth1BlockHash, quickStartParameters.Eth1Timestamp, deposits); // We use the state directly, and don't test IsValid genesisState.SetGenesisTime(quickStartParameters.GenesisTime); var store = _forkChoice.GetGenesisStore(genesisState); _logger.LogDebug("Quick start genesis store created with genesis time {GenesisTime}.", store.GenesisTime); }
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); } }
public Task <Eth1GenesisData> GetEth1GenesisDataAsync(CancellationToken cancellationToken) { QuickStartParameters quickStartParameters = _quickStartParameterOptions.CurrentValue; if (_logger.IsWarn()) { Log.MockedQuickStart(_logger, quickStartParameters.GenesisTime, quickStartParameters.ValidatorCount, null); } GweiValues gweiValues = _gweiValueOptions.CurrentValue; InitialValues initialValues = _initialValueOptions.CurrentValue; TimeParameters timeParameters = _timeParameterOptions.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; Bytes32 withdrawalCredentials = new Bytes32(withdrawalCredentialBytes); // Build deposit data DepositData depositData = new DepositData(publicKey, withdrawalCredentials, amount, BlsSignature.Zero); // Sign deposit data Domain domain = _beaconChainUtility.ComputeDomain(signatureDomains.Deposit); DepositMessage depositMessage = new DepositMessage(depositData.PublicKey, depositData.WithdrawalCredentials, depositData.Amount); Root depositMessageRoot = _cryptographyService.HashTreeRoot(depositMessage); Root depositDataSigningRoot = _beaconChainUtility.ComputeSigningRoot(depositMessageRoot, domain); byte[] destination = new byte[96]; bls.TrySignData(depositDataSigningRoot.AsSpan(), destination, out int bytesWritten); 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; Root root = _cryptographyService.HashTreeRoot(depositDataList); IEnumerable <Bytes32> allLeaves = depositDataList.Select(x => new Bytes32(_cryptographyService.HashTreeRoot((DepositData)x).AsSpan())); IList <IList <Bytes32> > tree = CalculateMerkleTreeFromLeaves(allLeaves); IList <Bytes32> merkleProof = GetMerkleProof(tree, index, 32); List <Bytes32> proof = new List <Bytes32>(merkleProof); byte[] indexBytes = new byte[32]; BinaryPrimitives.WriteInt32LittleEndian(indexBytes, index + 1); Bytes32 indexHash = new Bytes32(indexBytes); proof.Add(indexHash); Bytes32 leaf = new Bytes32(_cryptographyService.HashTreeRoot(depositData).AsSpan()); _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); } ulong eth1Timestamp = quickStartParameters.Eth1Timestamp; if (eth1Timestamp == 0) { eth1Timestamp = quickStartParameters.GenesisTime - (ulong)(1.5 * timeParameters.MinimumGenesisDelay); } else { ulong minimumEth1TimestampInclusive = quickStartParameters.GenesisTime - 2 * timeParameters.MinimumGenesisDelay; ulong maximumEth1TimestampInclusive = quickStartParameters.GenesisTime - timeParameters.MinimumGenesisDelay - 1; if (eth1Timestamp < minimumEth1TimestampInclusive) { if (_logger.IsEnabled(LogLevel.Warning)) { Log.QuickStartEth1TimestampTooLow(_logger, eth1Timestamp, quickStartParameters.GenesisTime, minimumEth1TimestampInclusive, null); } eth1Timestamp = minimumEth1TimestampInclusive; } else if (eth1Timestamp > maximumEth1TimestampInclusive) { if (_logger.IsEnabled(LogLevel.Warning)) { Log.QuickStartEth1TimestampTooHigh(_logger, eth1Timestamp, quickStartParameters.GenesisTime, maximumEth1TimestampInclusive, null); } eth1Timestamp = maximumEth1TimestampInclusive; } } var eth1GenesisData = new Eth1GenesisData(quickStartParameters.Eth1BlockHash, eth1Timestamp, deposits); if (_logger.IsEnabled(LogLevel.Debug)) { LogDebug.QuickStartGenesisDataCreated(_logger, eth1GenesisData.BlockHash, eth1GenesisData.Timestamp, eth1GenesisData.Deposits.Count, null); } return(Task.FromResult(eth1GenesisData)); }