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
相关产品推荐
相关产品推荐

