Remove Hash, Hash256, Hash160 and ScryptHash256 classes.
[NovacoinLibrary.git] / Novacoin / AddressTools.cs
1 \feffusing System;
2 using System.Linq;
3 using System.Text;
4
5 using Org.BouncyCastle.Math;
6
7 namespace Novacoin
8 {
9     [Serializable]
10     public class Base58Exception : Exception
11     {
12         public Base58Exception()
13         {
14         }
15
16         public Base58Exception(string message)
17             : base(message)
18         {
19         }
20
21         public Base58Exception(string message, Exception inner)
22             : base(message, inner)
23         {
24         }
25     }
26
27     public class AddressTools
28     {
29         private const string strDigits = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
30         private static readonly BigInteger _base = BigInteger.ValueOf(58);
31
32         /// <summary>
33         /// Encode a byte sequence as a base58-encoded string
34         /// </summary>
35         /// <param name="bytes">Byte sequence</param>
36         /// <returns>Encoding result</returns>
37         public static string Base58Encode(byte[] input)
38         {
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)
43             {
44                 var mod = bi.Mod(_base);
45                 s.Insert(0, new[] { strDigits[mod.IntValue] });
46                 bi = bi.Subtract(mod).Divide(_base);
47             }
48             s.Insert(0, new[] { strDigits[bi.IntValue] });
49             // Convert leading zeros too.
50             foreach (var anInput in input)
51             {
52                 if (anInput == 0)
53                     s.Insert(0, new[] { strDigits[0] });
54                 else
55                     break;
56             }
57             return s.ToString();
58         }
59
60
61         /// <summary>
62         /// Encode a byte sequence to a base58-encoded string, including checksum
63         /// </summary>
64         /// <param name="bytes">Byte sequence</param>
65         /// <returns>Base58(data+checksum)</returns>
66         public static string Base58EncodeCheck(byte[] bytes)
67         {
68             var dataBytes = new byte[bytes.Length + 4];
69             bytes.CopyTo(dataBytes, 0);
70             var checkSum = CryptoUtils.ComputeHash256(bytes).Take(4).ToArray();
71             checkSum.CopyTo(dataBytes, dataBytes.Length - 4); // add 4-byte hash check to the end
72
73             return Base58Encode(dataBytes);
74         }
75
76         /// <summary>
77         /// // Decode a base58-encoded string into byte array
78         /// </summary>
79         /// <param name="strBase58">Base58 data string</param>
80         /// <returns>Byte array</returns>
81         public static byte[] Base58Decode(string input)
82         {
83             var bytes = DecodeToBigInteger(input).ToByteArray();
84             // We may have got one more byte than we wanted, if the high bit of the next-to-last byte was not zero. This
85             // is because BigIntegers are represented with twos-compliment notation, thus if the high bit of the last
86             // byte happens to be 1 another 8 zero bits will be added to ensure the number parses as positive. Detect
87             // that case here and chop it off.
88             var stripSignByte = bytes.Length > 1 && bytes[0] == 0 && bytes[1] >= 0x80;
89             // Count the leading zeros, if any.
90             var leadingZeros = 0;
91             for (var i = 0; input[i] == strDigits[0]; i++)
92             {
93                 leadingZeros++;
94             }
95             var tmp = new byte[bytes.Length - (stripSignByte ? 1 : 0) + leadingZeros];
96             Array.Copy(bytes, stripSignByte ? 1 : 0, tmp, leadingZeros, tmp.Length - leadingZeros);
97             return tmp;
98         }
99
100         public static BigInteger DecodeToBigInteger(string input)
101         {
102             var bi = BigInteger.ValueOf(0);
103             // Work backwards through the string.
104             for (var i = input.Length - 1; i >= 0; i--)
105             {
106                 var alphaIndex = strDigits.IndexOf(input[i]);
107                 if (alphaIndex == -1)
108                 {
109                     throw new FormatException("Illegal character " + input[i] + " at " + i);
110                 }
111                 bi = bi.Add(BigInteger.ValueOf(alphaIndex).Multiply(_base.Pow(input.Length - 1 - i)));
112             }
113             return bi;
114         }
115
116         public static byte[] Base58DecodeCheck(string strBase58Check)
117         {
118             var rawData = Base58Decode(strBase58Check).ToArray();
119
120             if (rawData.Length < 4)
121             {
122                 throw new Base58Exception("Data is too short.");
123             }
124
125             var result = new byte[rawData.Length - 4];
126             var resultCheckSum = new byte[4];
127
128             Array.Copy(rawData, result, result.Length);
129             Array.Copy(rawData, result.Length, resultCheckSum, 0, 4);
130
131             var checkSum = CryptoUtils.ComputeHash256(result).Take(4).ToArray();
132
133             if (!checkSum.SequenceEqual(resultCheckSum))
134             {
135                 throw new Base58Exception("Incorrect checksum.");
136             }
137
138             return result;
139         }
140     }
141 }