确定比特币钱包地址是否有效"

时间:2014-08-16 19:29:00

标签: c# bitcoin

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

是否有公开的C#算法可以验证比特币钱包地址?我一直在谷歌搜索,但找不到任何东西。

4 个答案:

答案 0 :(得分:3)

是的,Bitcoin-Address-Utility项目是一个包含此类验证的开源C#工具。请特别注意Casascius.Bitcoin.Util.Base58CheckToByteArray()

答案 1 :(得分: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));
    }
}

}

答案 2 :(得分:1)

tl; dr: 遇到同样的问题,因此构建了一些适合我(并希望您)需要的东西: https://github.com/Sofoca/CoinUtils

我的具体要求是……

  • 支持比特币和Litecoin(以及将来可能的其他类似Altcoins)
  • 支持所有地址类型(P2SH和P2PKH)和编码(Base58和Bech32)
  • 最好没有外部(如NuGet)依赖项

虽然以上提到的替代方法都无法满足我的所有需求,但我从先前的答案和参考项目中获得了一些启发。谢谢你!

希望这对那些寻求完整但轻便的解决方案的人有所帮助。

答案 3 :(得分:0)

这是Util.Bitcoin Git repository that contains only code needed for offline verification of BTC Wallet address

代码是从其他答案引用的Bitcoin-Address-Utility project中提取的,但是此存储库包含必需的DLL,而且它是类项目而不是Windows应用程序,因此可以直接引用它。