## 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 1) Add the version number to the header. 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[64]; // First source: OpenSSL's RNG RandAddSeedPerfmon(); 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) { AssertLockHeld(cs_wallet); // mapKeyMetadata bool fCompressed = CanSupportFeature(FEATURE_COMPRPUBKEY); // default to compressed public keys if we want 0.6.0 wallets CKey secret; // Create new metadata int64_t nCreationTime = GetTime(); CKeyMetadata metadata(nCreationTime); // 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)); mapKeyMetadata[pubkey.GetID()] = metadata; UpdateTimeFirstKey(nCreationTime); if (!AddKeyPubKeyWithDB(walletdb, secret, pubkey)) { 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(); pwallet->SetAddressBook(keyID, strAccount, "receive"); 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 { std::vector<unsigned char> data = m_params.Base58Prefix(CChainParams::PUBKEY_ADDRESS); data.insert(data.end(), id.begin(), id.end()); // Add version number to header 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 > >

*Note: This article is only for personal notes. If there is something wrong, please correct it.

Welcome to the public attention [lazy idling] public number, looking forward to sharing technology with you.