Beispiel #1
0
        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());
        }
Beispiel #2
0
        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());
        }
Beispiel #3
0
        /// <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);
        }
Beispiel #4
0
 public DepositData(BlsPublicKey publicKey, Hash32 withdrawalCredentials, Gwei amount)
 {
     PublicKey             = publicKey;
     WithdrawalCredentials = withdrawalCredentials;
     Amount    = amount;
     Signature = BlsSignature.Empty;
 }
Beispiel #5
0
        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);
        }
Beispiel #6
0
 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()));
        }
Beispiel #9
0
 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>());
 }
Beispiel #10
0
 public BeaconBlockHeader(
     Slot slot,
     Hash32 parentRoot,
     Hash32 stateRoot,
     Hash32 bodyRoot,
     BlsSignature signature)
 {
     Slot       = slot;
     ParentRoot = parentRoot;
     StateRoot  = stateRoot;
     BodyRoot   = bodyRoot;
     Signature  = signature;
 }
Beispiel #11
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 byte[96];
            var success     = signingAlgorithm.TrySignHash(messageHash.AsSpan(), destination, out var bytesWritten, domain.AsSpan().ToArray());

            return(new BlsSignature(destination));
        }
Beispiel #12
0
        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);
        }
Beispiel #13
0
        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 !);
        }
Beispiel #14
0
 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;
 }
Beispiel #15
0
        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));
        }
Beispiel #16
0
        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);
        }
Beispiel #17
0
        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;
            }
Beispiel #18
0
        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);
        }
Beispiel #19
0
 public bool BlsVerify(BlsPublicKey publicKey, Hash32 signingRoot, BlsSignature signature, Domain domain)
 {
     return(true);
 }
Beispiel #20
0
 public Hash32 Hash(Hash32 a, Hash32 b)
 {
     return(_cryptographyService.Hash(a, b));
 }
Beispiel #21
0
 public void SetStateRoot(Hash32 stateRoot) => StateRoot = stateRoot;
Beispiel #22
0
        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);
        }
Beispiel #23
0
 public BeaconBlockHeader(Hash32 bodyRoot)
     : this(Slot.Zero, Hash32.Zero, Hash32.Zero, bodyRoot, BlsSignature.Empty)
 {
 }