Generating a Bitcoin address in C#

Published On November 24, 2013

I recently needed to write a C# app to convert a Bitcoin public key to a human usable addresses to send coins to, using the example on

I hate using external libraries, so my main aim with this was to not require any 3rd party libraries, although you"ll need .Net framework 4.5 for the BigInteger classes.

Please note the full process of generating a valid bitcoin address is defined as:

Private Key > Public Key > Address

This tutorial concentrates on the last step. 

If you want to generate a Private/Public pair you can use a bitcoin wallet or look into using to create a valid pair within C#.

9 Steps verbose

Here we have all 9 steps as per the technical background document written in C#. Each step is written to the console to show the progress of making the address.

static void Main()

    string HexHash = "0450863AD64A87AE8A2FE83C1AF1A8403CB53F53E486D8511DAD8A04887E5B23522CD470243453A299FA9E77237716103ABC11A1DF38855ED6F2EE187E9C582BA6";
    byte[] PubKey = HexToByte(HexHash);
    Console.WriteLine("Public Key:" + ByteToHex(PubKey)); //Step 1 
    byte[] PubKeySha = Sha256(PubKey);
    Console.WriteLine("Sha Public Key:" + ByteToHex(PubKeySha)); //Step 2 
    byte[] PubKeyShaRIPE = RipeMD160(PubKeySha);
    Console.WriteLine("Ripe Sha Public Key:" + ByteToHex(PubKeyShaRIPE)); // Step 3 
    byte[] PreHashWNetwork = AppendBitcoinNetwork(PubKeyShaRIPE, 0); // Step4 
    byte[] PublicHash = Sha256(PreHashWNetwork);
    Console.WriteLine("Public Hash:" + ByteToHex(PublicHash)); // Step5 
    byte[] PublicHashHash = Sha256(PublicHash);
    Console.WriteLine("Public HashHash:" + ByteToHex(PublicHashHash));  //Step 6 
    Console.WriteLine("Checksum:" + ByteToHex(PublicHashHash).Substring(0, 4));  //Step 7 
    byte[] Address = ConcatAddress(PreHashWNetwork, PublicHashHash);
    Console.WriteLine("Address:" + ByteToHex(Address)); //Step 8 
    Console.WriteLine("Human Address:" + Base58Encode(Address));    //Step 9 

Shorthand Function

The entire function can be written in short for live (non debug) use:

public static string CreateAddress(string PublicKey)
    byte[] PreHashQ = AppendBitcoinNetwork(RipeMD160(Sha256(HexToByte(PublicKey))), 0);
    return Base58Encode(ConcatAddress(PreHashQ, Sha256(Sha256(PreHashQ))));

Additional Functions

I've used some helper functions along the way, they are very verbose (Some unnecessary) but it make it a lot easier to read and understand.


Hex to Byte converts the Hexidecimal string to a byte array, it"s simple as taking the 2 characters and converting it into base 256.

public static byte[] HexToByte(string HexString)
if (HexString.Length % 2 != 0)
throw new Exception("Invalid HEX");
byte[] retArray = new byte[HexString.Length / 2];
for (int i = 0; i < retArray.Length; ++i)
retArray[i] = byte.Parse(HexString.Substring(i*2, 2), NumberStyles.HexNumber, CultureInfo.InvariantCulture);
return retArray;


Byte to hex converts a byte into a hexadecimal string

byte[] data = { 1, 2, 4, 8, 16, 32 }; 
string hex = BitConverter.ToString(data);


Sha256 uses Microsoft"s security cryptography include, and by default takes a byte array (this function is bad in the sense It creates duplicate instances of the sha manager, which we probably shouldn"t do as we could reuse the same instance for the 3 times)

public static byte[] Sha256(byte [] array) 
SHA256Managed hashstring = new SHA256Managed();
return hashstring.ComputeHash(array);


Again this function uses Microsoft"s security cryptography include and is pretty much identical to the Sha256 function.

public static byte[] RipeMD160(byte[] array) 
RIPEMD160Managed hashstring = new RIPEMD160Managed();
return hashstring.ComputeHash(array);

Append Bitcoin Network

AppendBitcoinNetwork simply pre-appends a byte onto the beginning of an array of bytes

public static byte[] AppendBitcoinNetwork(byte[] RipeHash, byte Network)
byte[] extended = new byte[RipeHash.Length + 1];
extended[0] = (byte)Network;
Array.Copy(RipeHash, 0, extended, 1, RipeHash.Length);
return extended;

Concat Address

Concat address appends the last 4 bytes of the hash onto the end of the RipeMD160 value

public static byte[] ConcatAddress(byte[] RipeHash, byte[] Checksum) 
byte[] ret = new byte[RipeHash.Length + 4];
Array.Copy(RipeHash, ret, RipeHash.Length);
Array.Copy(Checksum, 0, ret, RipeHash.Length, 4);
return ret;


I"ve hacked together my own c# Base58 encoder based off the C++ code by Satoshi, notice it uses BigInterger, this is a new Microsoft class in C# that allows math operation on arbitrary big numbers, so we"re no longer limited to a 32 or 64 bit integer, see more here:
public static string Base58Encode(byte [] array)
const string ALPHABET = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
string retString = string.Empty;
BigInteger encodeSize = ALPHABET.Length;
BigInteger arrayToInt = 0;

for (int i = 0; i < array.Length; ++i)
arrayToInt = arrayToInt * 256 + array[i];
while (arrayToInt > 0)
int rem = (int)(arrayToInt % encodeSize);
arrayToInt /= encodeSize;
retString = ALPHABET[rem] + retString;
for (int i = 0; i < array.Length && array[i] == 0; ++i)
retString = ALPHABET[0] + retString;
return retString;
Note: You"ll have to manually add references to the Microsoft.Numerics library to your project to get the BigInteger class.


Hope this helps anyone looking to write Bitcoin/Litecoin C# applications. Any questions/improvements please leave a comment.