2 using System.Collections.Generic;
6 using Org.BouncyCastle.Math;
10 public class Base58Exception : Exception
12 public Base58Exception()
16 public Base58Exception(string message)
21 public Base58Exception(string message, Exception inner)
22 : base(message, inner)
27 public class AddressTools
29 private const string strDigits = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
30 private static readonly BigInteger _base = BigInteger.ValueOf(58);
33 /// Encode a byte sequence as a base58-encoded string
35 /// <param name="bytes">Byte sequence</param>
36 /// <returns>Encoding result</returns>
37 public static string Base58Encode(byte[] input)
39 // TODO: This could be a lot more efficient.
40 var bi = new BigInteger(1, input);
41 var s = new StringBuilder();
42 while (bi.CompareTo(_base) >= 0)
44 var mod = bi.Mod(_base);
45 s.Insert(0, new[] { strDigits[mod.IntValue] });
46 bi = bi.Subtract(mod).Divide(_base);
48 s.Insert(0, new[] { strDigits[bi.IntValue] });
49 // Convert leading zeros too.
50 foreach (var anInput in input)
53 s.Insert(0, new[] { strDigits[0] });
62 /// Encode a byte sequence to a base58-encoded string, including checksum
64 /// <param name="bytes">Byte sequence</param>
65 /// <returns>Base58(data+checksum)</returns>
66 public static string Base58EncodeCheck(IEnumerable<byte> bytes)
68 byte[] dataBytes = bytes.ToArray();
69 Array.Resize(ref dataBytes, dataBytes.Length + 4);
71 byte[] checkSum = Hash256.Compute256(bytes).hashBytes.Take(4).ToArray();
73 checkSum.CopyTo(dataBytes, dataBytes.Length - 4); // add 4-byte hash check to the end
75 return Base58Encode(dataBytes);
79 /// // Decode a base58-encoded string into byte array
81 /// <param name="strBase58">Base58 data string</param>
82 /// <returns>Byte array</returns>
83 public static byte[] Base58Decode(string input)
85 var bytes = DecodeToBigInteger(input).ToByteArray();
86 // We may have got one more byte than we wanted, if the high bit of the next-to-last byte was not zero. This
87 // is because BigIntegers are represented with twos-compliment notation, thus if the high bit of the last
88 // byte happens to be 1 another 8 zero bits will be added to ensure the number parses as positive. Detect
89 // that case here and chop it off.
90 var stripSignByte = bytes.Length > 1 && bytes[0] == 0 && bytes[1] >= 0x80;
91 // Count the leading zeros, if any.
93 for (var i = 0; input[i] == strDigits[0]; i++)
97 var tmp = new byte[bytes.Length - (stripSignByte ? 1 : 0) + leadingZeros];
98 Array.Copy(bytes, stripSignByte ? 1 : 0, tmp, leadingZeros, tmp.Length - leadingZeros);
102 public static BigInteger DecodeToBigInteger(string input)
104 var bi = BigInteger.ValueOf(0);
105 // Work backwards through the string.
106 for (var i = input.Length - 1; i >= 0; i--)
108 var alphaIndex = strDigits.IndexOf(input[i]);
109 if (alphaIndex == -1)
111 throw new FormatException("Illegal character " + input[i] + " at " + i);
113 bi = bi.Add(BigInteger.ValueOf(alphaIndex).Multiply(_base.Pow(input.Length - 1 - i)));
118 public static IEnumerable<byte> Base58DecodeCheck(string strBase58Check)
120 byte[] rawData = Base58Decode(strBase58Check).ToArray();
122 if (rawData.Length < 4)
124 throw new Base58Exception("Data is too short.");
127 byte[] result = new byte[rawData.Length - 4];
128 byte[] resultCheckSum = new byte[4];
130 Array.Copy(rawData, result, result.Length);
131 Array.Copy(rawData, result.Length, resultCheckSum, 0, 4);
133 byte[] checkSum = Hash256.Compute256(result).hashBytes.Take(4).ToArray();
135 if (!checkSum.SequenceEqual(resultCheckSum))
137 throw new Base58Exception("Incorrect checksum.");