public byte[] GeneratePrivateKey(ulong index) { var 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); var 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. var 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()); }
private byte[] GeneratePrivateKey(ulong index) { var input = new Span <byte>(new byte[32]); BigInteger bigIndex = new BigInteger(index); bool indexWriteSuccess = bigIndex.TryWriteBytes(input, out int indexBytesWritten); if (!indexWriteSuccess || indexBytesWritten == 0) { throw new Exception("Error getting input for quick start private key generation."); } Hash32 hash32 = _cryptographyService.Hash(input); var 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 var privateKeySpan = new Span <byte>(new byte[32]); bool keyWriteSuccess = privateKey.TryWriteBytes(privateKeySpan, out int keyBytesWritten, isUnsigned: true, isBigEndian: true); if (!keyWriteSuccess || keyBytesWritten != 32) { throw new Exception("Error generating quick start private key."); } return(privateKeySpan.ToArray()); }
/// <summary> /// Prepare the state for the deposit, and create a deposit for the given validator, depositing the given amount. /// </summary> public static Deposit PrepareStateAndDeposit(IServiceProvider testServiceProvider, BeaconState state, ValidatorIndex validatorIndex, Gwei amount, Hash32 withdrawalCredentials, bool signed) { var chainConstants = testServiceProvider.GetService <ChainConstants>(); var initialValues = testServiceProvider.GetService <IOptions <InitialValues> >().Value; var timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value; var beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); var beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); var privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray(); var publicKeys = TestKeys.PublicKeys(timeParameters).ToArray(); var privateKey = privateKeys[(int)(ulong)validatorIndex]; var publicKey = publicKeys[(int)(ulong)validatorIndex]; if (withdrawalCredentials == Hash32.Zero) { // insecurely use pubkey as withdrawal key if no credentials provided var withdrawalCredentialBytes = TestSecurity.Hash(publicKey.AsSpan()); withdrawalCredentialBytes[0] = initialValues.BlsWithdrawalPrefix; withdrawalCredentials = new Hash32(withdrawalCredentialBytes); } var depositDataList = new List <DepositData>(); (var deposit, var depositRoot) = BuildDeposit(testServiceProvider, state, depositDataList, publicKey, privateKey, amount, withdrawalCredentials, signed); state.SetEth1DepositIndex(0); state.Eth1Data.SetDepositRoot(depositRoot); state.Eth1Data.SetDepositCount((ulong)depositDataList.Count); return(deposit); }
public DepositData(BlsPublicKey publicKey, Hash32 withdrawalCredentials, Gwei amount) { PublicKey = publicKey; WithdrawalCredentials = withdrawalCredentials; Amount = amount; Signature = BlsSignature.Empty; }
public static (Deposit, Hash32) BuildDeposit(IServiceProvider testServiceProvider, BeaconState?state, IList <DepositData> depositDataList, BlsPublicKey publicKey, byte[] privateKey, Gwei amount, Hash32 withdrawalCredentials, bool signed) { var chainConstants = testServiceProvider.GetService <ChainConstants>(); var beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); var depositData = BuildDepositData(testServiceProvider, publicKey, privateKey, amount, withdrawalCredentials, state, signed); var index = depositDataList.Count; depositDataList.Add(depositData); Hash32 root = depositDataList.HashTreeRoot((ulong)1 << chainConstants.DepositContractTreeDepth); var allLeaves = depositDataList.Select(x => x.HashTreeRoot()); var tree = TestSecurity.CalculateMerkleTreeFromLeaves(allLeaves); var merkleProof = TestSecurity.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); return(deposit, root); }
public BeaconBlock(Hash32 genesisStateRoot) { Slot = new Slot(0); ParentRoot = Hash32.Zero; StateRoot = genesisStateRoot; Body = new BeaconBlockBody(); Signature = BlsSignature.Empty; }
public Hash32 Hash(Hash32 a, Hash32 b) { var input = new Span <byte>(new byte[Hash32.Length * 2]); a.AsSpan().CopyTo(input); b.AsSpan().CopyTo(input.Slice(Hash32.Length)); return(Hash(input)); }
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())); }
public BeaconBlock(Slot slot, Hash32 parentRoot, Hash32 stateRoot, BeaconBlockBody body, BlsSignature signature) { Slot = slot; ParentRoot = parentRoot; StateRoot = stateRoot; Body = body; Signature = signature; //Body = new BeaconBlockBody(randaoReveal, // new Eth1Data(Hash32.Zero, 0), // new Bytes32(), Array.Empty<Deposit>()); }
public BeaconBlockHeader( Slot slot, Hash32 parentRoot, Hash32 stateRoot, Hash32 bodyRoot, BlsSignature signature) { Slot = slot; ParentRoot = parentRoot; StateRoot = stateRoot; BodyRoot = bodyRoot; Signature = signature; }
public static BlsSignature BlsSign(Hash32 messageHash, byte[] privateKey, Domain domain) { var parameters = new BLSParameters() { PrivateKey = privateKey }; using var signingAlgorithm = SignatureAlgorithmFactory(parameters); var destination = new byte[96]; var success = signingAlgorithm.TrySignHash(messageHash.AsSpan(), destination, out var bytesWritten, domain.AsSpan().ToArray()); return(new BlsSignature(destination)); }
private static IList <Hash32> GetMerkleProof(IList <IList <Hash32> > tree, int itemIndex, int?treeLength = null) { var proof = new List <Hash32>(); for (int height = 0; height < (treeLength ?? tree.Count); height++) { int subindex = (itemIndex / (1 << height)) ^ 1; Hash32 value = subindex < tree[height].Count ? tree[height][subindex] : new Hash32(s_zeroHashes[height]); proof.Add(value); } return(proof); }
public async Task <BeaconState> GetHeadStateAsync() { if (!_storeProvider.TryGetStore(out IStore? retrievedStore)) { throw new Exception("Beacon chain is currently syncing or waiting for genesis."); } IStore store = retrievedStore !; Hash32 head = await _forkChoice.GetHeadAsync(store); if (!store.TryGetBlockState(head, out BeaconState? state)) { throw new Exception($"Beacon chain is currently syncing, head state {head} not found."); } return(state !); }
public Validator( BlsPublicKey publicKey, Hash32 withdrawalCredentials, Gwei effectiveBalance, //bool slashed, Epoch activationEligibilityEpoch, Epoch activationEpoch, Epoch exitEpoch, Epoch withdrawableEpoch) { PublicKey = publicKey; WithdrawalCredentials = withdrawalCredentials; EffectiveBalance = effectiveBalance; ActivationEligibilityEpoch = activationEligibilityEpoch; ActivationEpoch = activationEpoch; ExitEpoch = exitEpoch; WithdrawableEpoch = withdrawableEpoch; }
public async Task <BeaconBlock> NewBlockAsync(Slot slot, BlsSignature randaoReveal) { if (!_storeProvider.TryGetStore(out IStore? store)) { throw new Exception("Beacon chain is currently syncing or waiting for genesis."); } Hash32 head = await _forkChoice.GetHeadAsync(store !); // get previous head block, based on the fork choice // get latest state // process outstanding slots for state // get parent header (state root, signature, slot, parent root, body root) BeaconBlockBody body = new BeaconBlockBody(randaoReveal, new Eth1Data(0, Hash32.Zero), new Bytes32(), Array.Empty <ProposerSlashing>(), Array.Empty <AttesterSlashing>(), Array.Empty <Attestation>(), Array.Empty <Deposit>(), Array.Empty <VoluntaryExit>()); BeaconBlock block = new BeaconBlock(slot, Hash32.Zero, Hash32.Zero, body, BlsSignature.Empty); // new block = slot, parent root, // signature = null // body = assemble body // assemble body: // from opPool get proposer slashings, attester slashings, attestations, voluntary exits // get eth1data // generate deposits (based on new data) // -> if eth1data deposit count > state deposit index, then get from op pool, sort and calculate merkle tree // deposit root = merkleRoot // randaoReveal // apply block to state transition // block.stateRoot = new state hash return(await Task.Run(() => block)); }
public static (IEnumerable <Deposit>, Hash32) PrepareGenesisDeposits(IServiceProvider testServiceProvider, int genesisValidatorCount, Gwei amount, bool signed) { var chainConstants = testServiceProvider.GetService <ChainConstants>(); var miscellaneousParameters = testServiceProvider.GetService <IOptions <MiscellaneousParameters> >().Value; var initialValues = testServiceProvider.GetService <IOptions <InitialValues> >().Value; var timeParameters = testServiceProvider.GetService <IOptions <TimeParameters> >().Value; var maxOperationsPerBlock = testServiceProvider.GetService <IOptions <MaxOperationsPerBlock> >().Value; var beaconChainUtility = testServiceProvider.GetService <BeaconChainUtility>(); var beaconStateAccessor = testServiceProvider.GetService <BeaconStateAccessor>(); var beaconStateTransition = testServiceProvider.GetService <BeaconStateTransition>(); var privateKeys = TestKeys.PrivateKeys(timeParameters).ToArray(); BlsPublicKey[] publicKeys; if (signed) { publicKeys = TestKeys.PublicKeys(timeParameters).ToArray(); } else { publicKeys = privateKeys.Select(x => new BlsPublicKey(x)).ToArray(); } var depositDataList = new List <DepositData>(); var genesisDeposits = new List <Deposit>(); var root = Hash32.Zero; for (var validatorIndex = 0; validatorIndex < genesisValidatorCount; validatorIndex++) { var publicKey = publicKeys[validatorIndex]; var privateKey = privateKeys[validatorIndex]; // insecurely use pubkey as withdrawal key if no credentials provided var withdrawalCredentialBytes = TestSecurity.Hash(publicKey.AsSpan()); withdrawalCredentialBytes[0] = initialValues.BlsWithdrawalPrefix; var withdrawalCredentials = new Hash32(withdrawalCredentialBytes); (var deposit, var depositRoot) = BuildDeposit(testServiceProvider, null, depositDataList, publicKey, privateKey, amount, withdrawalCredentials, signed); root = depositRoot; genesisDeposits.Add(deposit); } return(genesisDeposits, root); }
public async Task <BeaconBlock> NewBlockAsync(Slot slot, BlsSignature randaoReveal) { if (slot == Slot.Zero) { throw new ArgumentException("Can't generate new block for slot 0, as it is the genesis block."); } if (!_storeProvider.TryGetStore(out IStore? retrievedStore)) { throw new Exception("Beacon chain is currently syncing or waiting for genesis."); } IStore store = retrievedStore !; Slot previousSlot = slot - Slot.One; Hash32 head = await _forkChoice.GetHeadAsync(store); if (!store.TryGetBlock(head, out BeaconBlock? headBlock)) { throw new Exception($"Cannot find block for head root {head}"); } BeaconBlock parentBlock; BeaconState?retrievedParentState; Hash32 parentRoot; if (headBlock !.Slot > previousSlot) { // Requesting a block for a past slot? Hash32 ancestorSigningRoot = _forkChoice.GetAncestor(store, head, previousSlot); if (!store.TryGetBlock(ancestorSigningRoot, out BeaconBlock? retrievedParentBlock)) { throw new Exception($"Cannot find block for ancestor signing root {ancestorSigningRoot}"); } parentBlock = retrievedParentBlock !; if (!store.TryGetBlockState(ancestorSigningRoot, out retrievedParentState)) { throw new Exception($"Cannot find state for ancestor signing root {ancestorSigningRoot}"); } parentRoot = ancestorSigningRoot; }
public static DepositData BuildDepositData(IServiceProvider testServiceProvider, BlsPublicKey publicKey, byte[] privateKey, Gwei amount, Hash32 withdrawalCredentials, BeaconState?state, bool signed) { var depositData = new DepositData(publicKey, withdrawalCredentials, amount); if (signed) { SignDepositData(testServiceProvider, depositData, privateKey, state); } return(depositData); }
public bool BlsVerify(BlsPublicKey publicKey, Hash32 signingRoot, BlsSignature signature, Domain domain) { return(true); }
public Hash32 Hash(Hash32 a, Hash32 b) { return(_cryptographyService.Hash(a, b)); }
public void SetStateRoot(Hash32 stateRoot) => StateRoot = stateRoot;
public void QuickStartGenesis() { QuickStartParameters quickStartParameters = _quickStartParameterOptions.CurrentValue; _logger.LogWarning(0, "Mocked quick start with genesis time {GenesisTime:n0} and {ValidatorCount} validators.", quickStartParameters.GenesisTime, quickStartParameters.ValidatorCount); GweiValues gweiValues = _gweiValueOptions.CurrentValue; InitialValues initialValues = _initialValueOptions.CurrentValue; SignatureDomains signatureDomains = _signatureDomainOptions.CurrentValue; // Fixed amount Gwei amount = gweiValues.MaximumEffectiveBalance; // Build deposits var depositDataList = new List <DepositData>(); var deposits = new List <Deposit>(); for (ulong validatorIndex = 0uL; validatorIndex < quickStartParameters.ValidatorCount; validatorIndex++) { var privateKey = GeneratePrivateKey(validatorIndex); // Public Key BLSParameters blsParameters = new BLSParameters() { PrivateKey = privateKey }; using BLS bls = BLS.Create(blsParameters); var publicKeyBytes = new byte[BlsPublicKey.Length]; bls.TryExportBLSPublicKey(publicKeyBytes, out int publicKeyBytesWritten); BlsPublicKey publicKey = new BlsPublicKey(publicKeyBytes); // Withdrawal Credentials var 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 = depositData.SigningRoot(); Domain domain = _beaconChainUtility.ComputeDomain(signatureDomains.Deposit); var 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); Hash32 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(); } Hash32 indexHash = new Hash32(indexBytes); proof.Add(indexHash); Hash32 leaf = depositData.HashTreeRoot(); _beaconChainUtility.IsValidMerkleBranch(leaf, proof, _chainConstants.DepositContractTreeDepth + 1, (ulong)index, root); Deposit deposit = new Deposit(proof, depositData); if (_logger.IsEnabled(LogLevel.Debug)) { _logger.LogDebug("Quick start adding deposit for mocked validator {ValidatorIndex} with public key {PublicKey}.", validatorIndex, publicKey.ToString().Substring(0, 12)); } 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); _logger.LogDebug("Quick start genesis store created with genesis time {GenesisTime:n0}.", store.GenesisTime); }
public BeaconBlockHeader(Hash32 bodyRoot) : this(Slot.Zero, Hash32.Zero, Hash32.Zero, bodyRoot, BlsSignature.Empty) { }