private byte[] CreateChecksum(byte[] data, int offset, int count, Bech32EncodingType encodingType) #endif { #if HAS_SPAN Span <byte> values = _HrpExpand.Length + data.Length + 6 is int v && v > 256 ? new byte[v] : stackalloc byte[v]; #else var values = new byte[_HrpExpand.Length + count + 6]; #endif var valuesOffset = 0; #if HAS_SPAN _HrpExpand.AsSpan().CopyTo(values.Slice(valuesOffset)); #else Array.Copy(_HrpExpand, 0, values, valuesOffset, _HrpExpand.Length); #endif valuesOffset += _HrpExpand.Length; #if HAS_SPAN data.CopyTo(values.Slice(valuesOffset)); #else Array.Copy(data, offset, values, valuesOffset, count); #endif valuesOffset += data.Length; var polymod = Polymod(values) ^ encodingType.EncodingConstant; #if !HAS_SPAN var ret = new byte[6]; #endif foreach (var i in Enumerable.Range(0, 6)) { ret[i] = (byte)((polymod >> 5 * (5 - i)) & 31); } #if !HAS_SPAN return(ret); #endif }
public virtual string EncodeData(ReadOnlySpan <byte> data, Bech32EncodingType encodingType) #endif { if (encodingType == null) { throw new ArgumentNullException(nameof(encodingType)); } #if HAS_SPAN Span <byte> combined = _Hrp.Length + 1 + data.Length + 6 is int v && v > 256 ? new byte[v] : stackalloc byte[v]; #else var combined = new byte[_Hrp.Length + 1 + count + 6]; #endif int combinedOffset = 0; #if HAS_SPAN _Hrp.CopyTo(combined); #else Array.Copy(_Hrp, 0, combined, 0, _Hrp.Length); #endif combinedOffset += _Hrp.Length; combined[combinedOffset] = 49; combinedOffset++; #if HAS_SPAN data.CopyTo(combined.Slice(combinedOffset)); #else Array.Copy(data, offset, combined, combinedOffset, count); #endif combinedOffset += data.Length; #if HAS_SPAN Span <byte> checkSum = stackalloc byte[6]; CreateChecksum(data, encodingType, checkSum); #else var checkSum = CreateChecksum(data, offset, count, encodingType); #endif #if HAS_SPAN checkSum.CopyTo(combined.Slice(combinedOffset, 6)); combinedOffset += 6; for (int i = 0; i < data.Length + 6; i++) #else Array.Copy(checkSum, 0, combined, combinedOffset, 6); combinedOffset += 6; for (int i = 0; i < count + 6; i++) #endif { combined[_Hrp.Length + 1 + i] = Byteset[combined[_Hrp.Length + 1 + i]]; } return(Encoders.ASCII.EncodeData(combined)); }
protected virtual bool VerifyChecksum(byte[] data, int bechStringLen, out Bech32EncodingType encodingType, out int[] errorPosition) #endif { errorPosition = null; #if HAS_SPAN Span <byte> values = _HrpExpand.Length + data.Length is int v && v > 256 ? new byte[v] : stackalloc byte[v]; _HrpExpand.CopyTo(values); data.CopyTo(values.Slice(_HrpExpand.Length)); #else var values = _HrpExpand.Concat(data); #endif var polymod = Polymod(values); if (polymod == Bech32EncodingType.BECH32.EncodingConstant) { encodingType = Bech32EncodingType.BECH32; } else if (polymod == Bech32EncodingType.BECH32M.EncodingConstant) { encodingType = Bech32EncodingType.BECH32M; } else { encodingType = null; var epos = Bech32EncodingType.All .Select(e => locate_errors(polymod ^ (uint)e.EncodingConstant, bechStringLen - 1)) .Where(e => e.Length != 0) .OrderByDescending(e => e.Length) .FirstOrDefault(); errorPosition = epos; if (epos is null || epos.Length == 0) { return(false); } for (var ep = 0; ep < epos.Length; ++ep) { epos[ep] = bechStringLen - epos[ep] - (epos[ep] >= data.Length ? 2 : 1); } return(false); } return(true); }
public string EncodeRaw(byte[] data, Bech32EncodingType encodingType) { return(EncodeData(data, 0, data.Length, encodingType)); }
public string EncodeRaw(ReadOnlySpan <byte> data, Bech32EncodingType encodingType) { return(EncodeData(data, encodingType)); }
public string EncodeRaw(byte[] data, Bech32EncodingType encodingType) { return(EncodeData(data.AsSpan(), encodingType)); }
protected virtual byte[] DecodeDataCore(string encoded, out Bech32EncodingType encodingType) { if (encoded == null) { throw new ArgumentNullException(nameof(encoded)); } CheckCase(encoded); encoded = encoded.ToLowerInvariant(); #if HAS_SPAN Span <byte> buffer = encoded.Length is int v && v > 256 ? new byte[v] : stackalloc byte[v]; ((ASCIIEncoder)Encoders.ASCII).DecodeData(encoded, buffer); #else var buffer = Encoders.ASCII.DecodeData(encoded); #endif var pos = encoded.LastIndexOf("1", StringComparison.OrdinalIgnoreCase); if (pos < 1) { throw new FormatException("The Bech32 string is missing separator '1'"); } else if (pos + 7 > encoded.Length) { throw new FormatException("The Bech32 string is too short"); } else if (StrictLength && encoded.Length > 90) { throw new FormatException("The Bech32 string is too long"); } if (pos != _Hrp.Length) { throw new FormatException("Mismatching human readable part"); } for (int i = 0; i < _Hrp.Length; i++) { if (buffer[i] != _Hrp[i]) { throw new FormatException("Mismatching human readable part"); } } #if HAS_SPAN Span <byte> data = encoded.Length - pos - 1 is int v2 && v2 > 256 ? new byte[v2] : stackalloc byte[v2]; #else var data = new byte[encoded.Length - pos - 1]; #endif for (int j = 0, i = pos + 1; i < encoded.Length; i++, j++) { int index = Array.IndexOf(Byteset, buffer[i]); if (index == -1) { throw new FormatException("bech chars are out of range"); } data[j] = (byte)index; } int[] error; if (!VerifyChecksum(data, encoded.Length, out encodingType, out error)) { if (error == null || error.Length == 0) { throw new FormatException("Error while verifying Bech32 checksum"); } else { throw new Bech32FormatException($"Error in Bech32 string at {String.Join(",", error)}", error); } } #if HAS_SPAN return(data.Slice(0, data.Length - 6).ToArray()); #else return(data.Take(data.Length - 6).ToArray()); #endif }
public byte[] DecodeDataRaw(string encoded, out Bech32EncodingType encodingType) { return(DecodeDataCore(encoded, out encodingType)); }
public virtual string EncodeData(byte[] data, int offset, int count, Bech32EncodingType encodingType)
private void CreateChecksum(ReadOnlySpan <byte> data, Bech32EncodingType encodingType, Span <byte> ret)
protected virtual bool VerifyChecksum(ReadOnlySpan <byte> data, int bechStringLen, out Bech32EncodingType encodingType, out int[] errorPosition)
protected virtual bool VerifyChecksum(byte[] data, int bechStringLen, out Bech32EncodingType encodingType, out int[] errorPosition) { return(VerifyChecksum(data.AsSpan(), bechStringLen, out encodingType, out errorPosition)); }
static Bech32EncodingType() { BECH32 = new Bech32EncodingType(1); BECH32M = new Bech32EncodingType(0x2bc830a3); All = new Bech32EncodingType[] { BECH32, BECH32M }; }