Created
November 8, 2017 08:28
-
-
Save savasadar/ead0acf504b9b7befaa6cf2ca7589181 to your computer and use it in GitHub Desktop.
c# BitcoinValidator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Linq; | |
using System.Security.Cryptography; | |
using NUnit.Framework; | |
namespace BitcoinValidator | |
{ | |
public class ValidateTest | |
{ | |
[TestCase] | |
public void ValidateBitcoinAddressTest() | |
{ | |
Assert.IsTrue(ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i")); // VALID | |
Assert.IsTrue(ValidateBitcoinAddress("1Q1pE5vPGEEMqRcVRMbtBK842Y6Pzo6nK9")); // VALID | |
Assert.Throws<Exception>(() => ValidateBitcoinAddress("1AGNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62X")); // checksum changed, original data | |
Assert.Throws<Exception>(() => ValidateBitcoinAddress("1ANNa15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i")); // data changed, original checksum | |
Assert.Throws<Exception>(() => ValidateBitcoinAddress("1A Na15ZQXAZUgFiqJ2i7Z2DPU2J6hW62i")); // invalid chars | |
Assert.Throws<Exception>(() => ValidateBitcoinAddress("BZbvjr")); // checksum is fine, address too short | |
} | |
public static bool ValidateBitcoinAddress(string address) | |
{ | |
if (address.Length < 26 || address.Length > 35) throw new Exception("wrong length"); | |
var decoded = DecodeBase58(address); | |
var d1 = Hash(decoded.SubArray(0, 21)); | |
var d2 = Hash(d1); | |
if (!decoded.SubArray(21, 4).SequenceEqual(d2.SubArray(0, 4))) throw new Exception("bad digest"); | |
return true; | |
} | |
const string Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; | |
const int Size = 25; | |
private static byte[] DecodeBase58(string input) | |
{ | |
var output = new byte[Size]; | |
foreach (var t in input) | |
{ | |
var p = Alphabet.IndexOf(t); | |
if (p == -1) throw new Exception("invalid character found"); | |
var j = Size; | |
while (--j > 0) | |
{ | |
p += 58 * output[j]; | |
output[j] = (byte)(p % 256); | |
p /= 256; | |
} | |
if (p != 0) throw new Exception("address too long"); | |
} | |
return output; | |
} | |
private static byte[] Hash(byte[] bytes) | |
{ | |
var hasher = new SHA256Managed(); | |
return hasher.ComputeHash(bytes); | |
} | |
} | |
public static class ArrayExtensions | |
{ | |
public static T[] SubArray<T>(this T[] data, int index, int length) | |
{ | |
var result = new T[length]; | |
Array.Copy(data, index, result, 0, length); | |
return result; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment