## 1, Bitcoin address generation flow chart  A bitcoin wallet contains a series of key pairs, each of which includes a private key and a public key. The private key (k) is a number, usually with
Machine selected. With the private key, we can use the one-way encryption function of elliptic curve multiplication to generate A public key (K). With the public key (K), we can use A one-way encryption hash function to generate the bitcoin address (A).

## 2, Specific steps

```1 generate private key
```
```	More precisely, the private key can be any number between 1 and n-1, where n is a constant (n=1.158 * 10^77, slightly less than 2 ^ 256),
It is defined as the order of the elliptic curve used by bitcoin (see the explanation of elliptic curve cryptography).
1> The core of bitcoin firstly generates a random number m through OpenSSL's RNG random number generator and operating system random number generator.
2> The value k of 256 bits is obtained by SHA256 hash operation on m
3> Verify whether K conforms to secp256k1's private key standard. If it conforms to the standard, it can continue as a private key. If it does not conform to the standard, 1 > will be returned.
```

2 generate the corresponding public key according to the private key

```Starting from the private key k generated above, we multiply it by the predetermined generation point G on the curve to obtain another point on the curve, that is, the corresponding
The public key K. The generation point is a part of secp256k1 standard. The generation points of bitcoin keys are the same: {K = k * G}
Where k is the private key, G is the generating point, and the point K obtained on the curve is the public key. Because all bitcoin users have the same generation point, one
Multiply the private key K by G to get the same public key K. The relationship between K and K is fixed, but only one-way operation, that is, to get k from K. That's what you can do
The reason why a bitcoin address (derived from K) is shared with anyone without revealing the private key (k).
```

3. Process the public key to get the bitcoin address

```1> The hash of public key K is obtained by Hash160 operation.
2> Do the following for the hash of K
2) Two more SHA256 operations are performed on the value containing version number, and the first four bytes are added to the end of the value as the check sum.
3> Base 58 code (version number + K hash + checksum) to get the final bitcoin address.
```

## 3, Corresponding code process

1 generate private key

```getnewaddress() -> CWallet::GetKeyFromPool() -> CWallet::GenerateNewKey() -> CKey::MakeNewKey()
->Getstrongrandbytes() -- this function uses OpenSSL's RNG random number generator and operating system random number generator to get a
Random number (64 bytes)
```
```1> Generate the private key and check whether it meets the standard
```
```void CKey::MakeNewKey(bool fCompressedIn) {
do {
GetStrongRandBytes(keydata.data(), keydata.size()); // Get random number
} while (!Check(keydata.data())); // Check whether the private key meets the standard through secp256k1
fValid = true;
fCompressed = fCompressedIn;
}
```
```2> Generate random number
```
```void GetStrongRandBytes(unsigned char* out, int num)
{
assert(num <= 32);
CSHA512 hasher;
unsigned char buf;

// First source: OpenSSL's RNG
GetRandBytes(buf, 32);
hasher.Write(buf, 32);

// Second source: OS RNG
GetOSRand(buf);
hasher.Write(buf, 32);
...
}
```

2 generate public key based on private key

```CPubKey CWallet::GenerateNewKey(CWalletDB &walletdb, bool internal)
{
bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets

CKey secret;

int64_t nCreationTime = GetTime();

// use HD key derivation if HD was enabled during wallet creation
if (IsHDEnabled()) {
DeriveNewChildKey(walletdb, metadata, secret, (CanSupportFeature(FEATURE_HD_SPLIT) ? internal : false));
} else {
secret.MakeNewKey(fCompressed);
}

// Compressed public keys were introduced in version 0.6.0
if (fCompressed) {
SetMinVersion(FEATURE_COMPRPUBKEY);
}

// Generate public key
CPubKey pubkey = secret.GetPubKey();
assert(secret.VerifyPubKey(pubkey));

UpdateTimeFirstKey(nCreationTime);

throw std::runtime_error(std::string(__func__) + ": AddKey failed");
}
return pubkey;
}
```
```In fact, the process of public key generation is based on secp256k1 library
```
```CPubKey CKey::GetPubKey() const {
assert(fValid);
secp256k1_pubkey pubkey;
size_t clen = 65;
CPubKey result;
int ret = secp256k1_ec_pubkey_create(secp256k1_context_sign, &pubkey, begin());
assert(ret);
secp256k1_ec_pubkey_serialize(secp256k1_context_sign, (unsigned char*)result.begin(), &clen, &pubkey, fCompressed ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED);
...
return result;
}
```

3. Handle the public key accordingly

```UniValue getnewaddress(const JSONRPCRequest& request)
{
CWallet * const pwallet = GetWalletForJSONRPCRequest(request);
if (!EnsureWalletIsAvailable(pwallet, request.fHelp)) {
return NullUniValue;
}

...

// Generate a new key that is added to wallet
CPubKey newKey;
if (!pwallet->GetKeyFromPool(newKey)) {
throw JSONRPCError(RPC_WALLET_KEYPOOL_RAN_OUT, "Error: Keypool ran out, please call keypoolrefill first");
}
// Perform the Hash160 operation on the public key K in the CPubKey::GetID function to get the keyID
CKeyID keyID = newKey.GetID();
return EncodeDestination(keyID);
}
```
```1> Getid function is to Hash160 the public key and return the operation result
```
```CKeyID GetID() const {
return CKeyID(Hash160(vch, vch + size()));
}
```
```2> Add a version number to the header
```
```std::string DestinationEncoder::operator()(const CKeyID& id) const {
return EncodeBase58Check(data);
}
```
```3> Two SHA256 operations are performed on the value with good version, and the first four bytes of the result are added to the end of the value, and then Base58 encoding is performed
```
```std::string EncodeBase58Check(const std::vector<unsigned char>& vchIn)
{
// add 4-byte hash check to the end
std::vector<unsigned char> vch(vchIn);
uint256 hash = Hash(vch.begin(), vch.end());
vch.insert(vch.end(), (unsigned char*)&hash, (unsigned char*)&hash + 4);
return EncodeBase58(vch);
}
```

Base58 is used for encoding to make the address readable. Base58 actually means that Base64 removes some characters that are not easy to recognize. 0 and O in uppercase are easy to be confused, 1 and l are easy to be confused, etc.

Reference books: < mastering bitcoin > >   