Why are all the `genesis.hashMerkleRoot` values the same in the Bitcoin network, yet the `consensus.hashGenesisBlock` values printed are different? How is this implemented?
They all contain same transaction, which is the coin base. That's a reason why they are same.
The difference in consensus.hashGenesisBlock values printed is attributed to the block header fields that are differently set for each block chain.
Why are all the `genesis.hashMerkleRoot` values the same in the Bitcoin network, yet the `consensus.hashGenesisBlock` values printed are different? How is this implemented?
The Merkle root is the same because the genesis block contains the same single coinbase transaction on all Bitcoin networks. Since the Merkle root is derived only from the transactions, it does not change.
What differs is the block header. Each network (mainnet, testnet, regtest, signet) uses different values for fields like nTime, nBits, and nNonce. These header differences produce different block hashes, which is why consensus.hashGenesisBlock is not the same.
In Bitcoin Core, this is handled by creating the same transaction and Merkle root, then varying the header parameters when constructing the genesis block for each network.
You're on point. The block header fields such as the nTime, nBits, etc. are what changes accross mainnet, testnet, regtest and signet. The effect of this is the genesis block hashes. Also, the difference in hashes are what enforce separation of networks.