确定比特币钱包地址是不是“有效”
Posted
技术标签:
【中文标题】确定比特币钱包地址是不是“有效”【英文标题】:Determine if a Bitcoin wallet address is "valid"确定比特币钱包地址是否“有效” 【发布时间】:2014-10-10 04:19:08 【问题描述】:我知道可以使用 Regex (^[13][a-km-zA-HJ-NP-Z0-9]26,33$
) 验证比特币钱包地址 - 但这不是 100% 准确的,并且允许将无效地址检测为有效。
是否有可以验证比特币钱包地址的公开可用的 C# 算法?我一直在谷歌搜索,但找不到任何东西。
【问题讨论】:
这个使用参考客户端的(始终是最新的)RPC API 来确定比特币地址是否有效:github.com/GeorgeKimionis/BitcoinLib/blob/master/CoinWrapper/… 【参考方案1】:是的,Bitcoin-Address-Utility 项目是一个包含此类验证的开源 C# 工具。尤其是Casascius.Bitcoin.Util.Base58CheckToByteArray()
。
【讨论】:
这是一个有效的答案——如果我能找到更轻的东西我会很高兴——不需要这么多额外的 DLL。但是,如果我没有找到更好的东西 - 这个分支已经包含所需的 DLL:github.com/mikepfrank/Bitcoin-Address-Utility【参考方案2】:这里是Util.Bitcoin Git repository that contains only code needed for offline verification of BTC Wallet address。
代码是从其他答案引用的Bitcoin-Address-Utility project 中提取的,但此存储库包含必要的 DLL,而且它是类项目而不是 Windows 应用程序,因此可以直接引用。
【讨论】:
【参考方案3】:我拼凑了一个适用于 dotnet core 2.0 的简单版本的 Casascius.Bitcoin.Util.Base58CheckToByteArray() - 唯一的参考是 -->Org.BouncyCastle.Crypto.Digests;
public class Validator
public static bool IsValidAddress(string Address)
byte[] hex = Base58CheckToByteArray(Address);
if (hex == null || hex.Length != 21)
return false;
else
return true;
public static byte[] Base58CheckToByteArray(string base58)
byte[] bb = Base58.ToByteArray(base58);
if (bb == null || bb.Length < 4) return null;
Sha256Digest bcsha256a = new Sha256Digest();
bcsha256a.BlockUpdate(bb, 0, bb.Length - 4);
byte[] checksum = new byte[32];
bcsha256a.DoFinal(checksum, 0);
bcsha256a.BlockUpdate(checksum, 0, 32);
bcsha256a.DoFinal(checksum, 0);
for (int i = 0; i < 4; i++)
if (checksum[i] != bb[bb.Length - 4 + i]) return null;
byte[] rv = new byte[bb.Length - 4];
Array.Copy(bb, 0, rv, 0, bb.Length - 4);
return rv;
- 从上面借来的
public class Base58
/// <summary>
/// Converts a base-58 string to a byte array, returning null if it wasn't valid.
/// </summary>
public static byte[] ToByteArray(string base58)
Org.BouncyCastle.Math.BigInteger bi2 = new Org.BouncyCastle.Math.BigInteger("0");
string b58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
foreach (char c in base58)
if (b58.IndexOf(c) != -1)
bi2 = bi2.Multiply(new Org.BouncyCastle.Math.BigInteger("58"));
bi2 = bi2.Add(new Org.BouncyCastle.Math.BigInteger(b58.IndexOf(c).ToString()));
else
return null;
byte[] bb = bi2.ToByteArrayUnsigned();
// interpret leading '1's as leading zero bytes
foreach (char c in base58)
if (c != '1') break;
byte[] bbb = new byte[bb.Length + 1];
Array.Copy(bb, 0, bbb, 1, bb.Length);
bb = bbb;
return bb;
public static string FromByteArray(byte[] ba)
Org.BouncyCastle.Math.BigInteger addrremain = new Org.BouncyCastle.Math.BigInteger(1, ba);
Org.BouncyCastle.Math.BigInteger big0 = new Org.BouncyCastle.Math.BigInteger("0");
Org.BouncyCastle.Math.BigInteger big58 = new Org.BouncyCastle.Math.BigInteger("58");
string b58 = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
string rv = "";
while (addrremain.CompareTo(big0) > 0)
int d = Convert.ToInt32(addrremain.Mod(big58).ToString());
addrremain = addrremain.Divide(big58);
rv = b58.Substring(d, 1) + rv;
// handle leading zeroes
foreach (byte b in ba)
if (b != 0) break;
rv = "1" + rv;
return rv;
- 测试
[TestClass]
public class ValidatorTests
[TestMethod]
public void IsValidAddress_Test_AbnCoin()
var Address = "1QF4NgxgF86SH4dizN4JPHMprWBHbKdSmJ";
Assert.IsTrue(Validator.IsValidAddress(Address));
[TestMethod]
public void IsValidAddress_Test_BitCoin()
var Address = "1QF4NgxgF86SH4dizN4JPHMprWBHbKdSmJ";
Assert.IsTrue(Validator.IsValidAddress(Address));
[TestMethod]
public void IsValidAddress_Test_BitCoinTestnet()
var Address = "mpMwtvqaLQ4rCJsnoceAoLShKb4inV8uUi";
Assert.IsTrue(Validator.IsValidAddress(Address));
[TestMethod]
public void IsValidAddress_Test_BitCoinGold()
var Address = "GRiDm3LEjXAMMJhWaYqN8nSjuU7PSqZMUe";
Assert.IsTrue(Validator.IsValidAddress(Address));
[TestMethod]
public void IsValidAddress_Test_Dash()
var Address = "Xb9Edf28eYR9RRDwj7MBBVBc5vgGgT2vLV";
Assert.IsTrue(Validator.IsValidAddress(Address));
[TestMethod]
public void IsValidAddress_Test_Litecoin()
var Address = "LUdpZosHDP3M97ZSfvj3p1qygNFMNpXBr3";
Assert.IsTrue(Validator.IsValidAddress(Address));
[TestMethod]
public void IsValidAddress_Test_False_TooShort()
var Address = "1QF4NgxgF86SH4dizN4JPHMprWBHbKdSm";
Assert.IsFalse(Validator.IsValidAddress(Address));
[TestMethod]
public void IsValidAddress_Test_False_TooLong()
var Address = "1QF4NgxgF86SH4dizN4JPHMprWBHbKdSmJS";
Assert.IsFalse(Validator.IsValidAddress(Address));
[TestMethod]
public void IsValidAddress_Test_False_BadChecksum()
var Address = "1QF5NgxgF86SH4dizN4JPHMprWBHbKdSmJ";
Assert.IsFalse(Validator.IsValidAddress(Address));
[TestMethod]
public void IsValidAddress_False_NotBase58()
var Address = "lQF4NgxgF86SH4dizN4JPHMprWBHbKdSmJ";
Assert.IsFalse(Validator.IsValidAddress(Address));
【讨论】:
【参考方案4】:tl;博士: 遇到了同样的问题,因此构建了适合我(希望您的)需求的东西: https://github.com/Sofoca/CoinUtils
我的具体要求是……
支持比特币和莱特币(未来可能还有其他类似的山寨币) 支持所有地址类型(P2SH 和 P2PKH)和编码(Base58 和 Bech32) 最好没有外部(想想 NuGet)依赖项虽然上述替代方案都没有满足所有这些要求,但我从以前的答案和参考项目中获得了一些灵感。谢谢!
希望这可以帮助那些正在寻找一个完整而轻量级的解决方案来解决这个问题的人。
【讨论】:
以上是关于确定比特币钱包地址是不是“有效”的主要内容,如果未能解决你的问题,请参考以下文章