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()); }
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 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)); }
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); }