确定比特币钱包地址是否“有效”。

7

我知道使用正则表达式可以验证比特币钱包地址(^[13][a-km-zA-HJ-NP-Z0-9]{26,33}$),但这并不是100%准确的,会将无效地址检测为有效。

是否有公开可用的C#算法可以验证比特币钱包地址?我已经在谷歌搜索了很久,但没有找到任何内容。


这个程序使用参考客户端(始终处于最新状态)的RPC API来确定比特币地址是否有效:https://github.com/GeorgeKimionis/BitcoinLib/blob/master/CoinWrapper/Services/RpcServices/RpcService/RpcService.cs#L577 - user1413338
4个回答

3

我拼凑出了一个简化版的 Casascius.Bitcoin.Util.Base58CheckToByteArray(),可以在 dotnet core 2.0 中使用——唯一的参考是 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));
    }
}

}


3

简而言之:我曾遇到同样的问题,因此构建了适合我(也希望适合你)的东西:https://github.com/Sofoca/CoinUtils

我的具体要求是:

  • 支持比特币和莱特币(未来可能还有其他类似的Altcoins)
  • 支持所有地址类型(P2SH 和 P2PKH)和编码(Base58 和 Bech32)
  • 最好不依赖外部(例如 NuGet)组件

虽然上述提到的解决方案都不能满足上述所有要求,但我从先前的答案和参考项目中获得了一些灵感。感谢那些贡献者!

希望这可以帮助那些寻找完整而轻便的解决方案的人。


3

这是一个有效的答案 - 只是我希望能找到一些更轻量级的东西 - 不需要这么多额外的DLL。但是,如果我找不到更好的东西 - 这个分支已经包含了所需的DLL:https://github.com/mikepfrank/Bitcoin-Address-Utility - nikib3ro

2
这里是一个Util.Bitcoin Git代码库,其中包含仅用于离线验证BTC钱包地址的代码。
该代码从其他答案引用的Bitcoin-Address-Utility项目中提取,但这个代码库包含必要的DLL并且是类项目而不是Windows应用程序,因此可以直接引用。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接