You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C# 离线验证Legacy、Nested SegWit、Native SegWit类比特币地址方案

C# 离线比特币地址验证实现方案

实现说明

  • 完全离线运行,无任何外部API依赖,所有校验逻辑均在本地完成
  • 覆盖三类比特币主网地址:Legacy(1开头)、Nested SegWit(3开头)、Native SegWit(bc1开头)
  • 无需手动区分地址类型,调用单个方法即可直接返回合法性校验结果

完整实现代码

using System;
using System.Linq;
using System.Security.Cryptography;

public static class BitcoinAddressValidator
{
    private const string Base58Alphabet = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz";
    private const string Bech32Charset = "qpzry9x8gf2tvdw0s3jn54khce6mua7l";
    private static readonly uint[] Bech32Generator = { 0x3b6a57b2, 0x26508e6d, 0x1ea119fa, 0x3d4233dd, 0x2a1462b3 };

    /// <summary>
    /// 验证比特币地址合法性
    /// </summary>
    /// <param name="address">待验证的地址字符串</param>
    /// <returns>合法返回true,非法返回false</returns>
    public static bool IsValid(string address)
    {
        if (string.IsNullOrWhiteSpace(address))
            return false;

        // 校验Native SegWit(Bech32编码,主网bc1开头)
        if (address.StartsWith("bc1", StringComparison.OrdinalIgnoreCase))
            return ValidateBech32Address(address);

        // 校验Legacy和Nested SegWit(Base58Check编码)
        return ValidateBase58Address(address);
    }

    private static bool ValidateBase58Address(string address)
    {
        try
        {
            byte[] decoded = DecodeBase58(address);
            if (decoded.Length < 4)
                return false;

            // 提取校验和(最后4字节)
            byte[] checksum = decoded.Skip(decoded.Length - 4).Take(4).ToArray();
            // 计算数据部分的双重SHA256校验和
            byte[] data = decoded.Take(decoded.Length - 4).ToArray();
            byte[] hash1 = SHA256.HashData(data);
            byte[] hash2 = SHA256.HashData(hash1);
            byte[] computedChecksum = hash2.Take(4).ToArray();

            if (!checksum.SequenceEqual(computedChecksum))
                return false;

            // 校验地址版本前缀:主网Legacy(0x00)、Nested SegWit(0x05)
            byte version = data[0];
            return version is 0x00 or 0x05;
        }
        catch
        {
            return false;
        }
    }

    private static byte[] DecodeBase58(string input)
    {
        var result = new byte[25];
        foreach (char c in input)
        {
            int digit = Base58Alphabet.IndexOf(c);
            if (digit < 0)
                throw new ArgumentException("Invalid Base58 character");

            ulong carry = (ulong)digit;
            for (int i = result.Length - 1; i >= 0; i--)
            {
                carry += (ulong)result[i] * 58;
                result[i] = (byte)(carry % 256);
                carry /= 256;
            }
            if (carry > 0)
                throw new ArgumentException("Base58 input too long");
        }

        // 处理前导1对应的前导零
        int leadingZeros = input.TakeWhile(c => c == '1').Count();
        var temp = new byte[leadingZeros + result.Length];
        Buffer.BlockCopy(result, 0, temp, leadingZeros, result.Length);
        return temp.SkipWhile(b => b == 0).ToArray().Length == 0 ? temp : temp.SkipWhile((b, i) => i < leadingZeros && b == 0).ToArray();
    }

    private static bool ValidateBech32Address(string address)
    {
        address = address.ToLowerInvariant();
        int separatorPos = address.LastIndexOf('1');
        if (separatorPos < 1 || separatorPos + 7 > address.Length || address.Length > 90)
            return false;

        string hrp = address[..separatorPos];
        if (hrp != "bc")
            return false;

        string dataPart = address[(separatorPos + 1)..];
        if (dataPart.Any(c => Bech32Charset.IndexOf(c) == -1))
            return false;

        byte[] data = dataPart.Select(c => (byte)Bech32Charset.IndexOf(c)).ToArray();
        if (!Bech32VerifyChecksum(hrp, data))
            return false;

        byte witnessVersion = data[0];
        if (witnessVersion > 16)
            return false;

        int witnessProgramLength = data.Length - 6;
        return witnessProgramLength is >= 2 and <= 40;
    }

    private static bool Bech32VerifyChecksum(string hrp, byte[] data)
    {
        byte[] hrpExpanded = ExpandHrp(hrp);
        byte[] combined = new byte[hrpExpanded.Length + data.Length];
        Buffer.BlockCopy(hrpExpanded, 0, combined, 0, hrpExpanded.Length);
        Buffer.BlockCopy(data, 0, combined, hrpExpanded.Length, data.Length);
        return PolyMod(combined) == 1;
    }

    private static uint PolyMod(byte[] values)
    {
        uint chk = 1;
        foreach (byte v in values)
        {
            uint top = chk >> 25;
            chk = (chk & 0x1ffffff) << 5 ^ v;
            for (int i = 0; i < 5; i++)
            {
                chk ^= ((top >> i) & 1) != 0 ? Bech32Generator[i] : 0;
            }
        }
        return chk;
    }

    private static byte[] ExpandHrp(string hrp)
    {
        byte[] ret = new byte[hrp.Length * 2 + 1];
        for (int i = 0; i < hrp.Length; i++)
        {
            ret[i] = (byte)(hrp[i] >> 5);
            ret[i + hrp.Length + 1] = (byte)(hrp[i] & 31);
        }
        ret[hrp.Length] = 0;
        return ret;
    }
}

使用示例

// 验证合法Legacy地址
bool isValidLegacy = BitcoinAddressValidator.IsValid("1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa"); // 返回true
// 验证合法Nested SegWit地址
bool isValidNestedSegWit = BitcoinAddressValidator.IsValid("3J98t1WpEZ73CNmQviecrnyiWrnqRhWNLy"); // 返回true
// 验证合法Native SegWit地址
bool isValidNativeSegWit = BitcoinAddressValidator.IsValid("bc1qxy2kgdygjrsqtzq2n0yrf2493p83kkfjhx0wlh"); // 返回true
// 验证非法地址
bool isInvalid = BitcoinAddressValidator.IsValid("invalidAddr12345"); // 返回false

兼容说明

  • 代码默认适配.NET 5+版本,若需在.NET Framework环境运行,将代码中SHA256.HashData方法替换为SHA256.Create().ComputeHash即可
  • 默认仅验证比特币主网地址,如需支持测试网,可按以下规则修改对应校验逻辑:
    • 测试网Legacy地址版本前缀改为0x6F
    • 测试网Nested SegWit地址版本前缀改为0xC4
    • 测试网Native SegWit地址HRP前缀改为"tb"

内容的提问来源于stack exchange,提问作者SilverLight

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.07 14:57:01