diff --git a/NBitcoin.Altcoins/TDCoin.cs b/NBitcoin.Altcoins/TDCoin.cs new file mode 100644 index 0000000000..d0f49f32de --- /dev/null +++ b/NBitcoin.Altcoins/TDCoin.cs @@ -0,0 +1,266 @@ +using NBitcoin; +using NBitcoin.DataEncoders; +using NBitcoin.Protocol; +using NBitcoin.RPC; +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using System.Net; + +namespace NBitcoin.Altcoins +{ + public class TDCoin : NetworkSetBase + { + public static TDCoin Instance { get; } = new TDCoin(); + + public override string CryptoCode => "TDC"; + + private TDCoin() + { + + } + //Format visual studio + //{({.*?}), (.*?)} + //Tuple.Create(new byte[]$1, $2) + static Tuple[] pnSeed6_main = { + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xab,0x12,0xc5}, 9901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0d,0xd1,0x9a,0x59}, 9901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2c,0xee,0x75,0x1b}, 9901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x7d,0x58,0x03}, 9901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x23,0x9e,0x92,0x65}, 9901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0d,0xea,0x65,0x15}, 9901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x36,0x96,0x57,0x9e}, 9901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x6c,0x80,0x79,0xdf}, 9901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0d,0xec,0x59,0x23}, 9901) +}; + + + static Tuple[] pnSeed6_test = { + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0xc0,0xab,0x12,0xc5}, 19901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x2c,0xee,0x75,0x1b}, 19901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x49,0x7d,0x58,0x03}, 19901), + Tuple.Create(new byte[]{0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xff,0xff,0x0d,0xd1,0x9a,0x59}, 19901) +}; + +#pragma warning disable CS0618 // Type or member is obsolete + public class TDCoinConsensusFactory : ConsensusFactory + { + private TDCoinConsensusFactory() + { + } + + public static TDCoinConsensusFactory Instance { get; } = new TDCoinConsensusFactory(); + + public override BlockHeader CreateBlockHeader() + { + return new TDCoinBlockHeader(); + } + public override Block CreateBlock() + { + return new TDCoinBlock(new TDCoinBlockHeader()); + } + } + + public class TDCoinBlockHeader : BlockHeader + { + public override uint256 GetPoWHash() + { + var headerBytes = this.ToBytes(); + var h = NBitcoin.Crypto.SCrypt.ComputeDerivedKey(headerBytes, headerBytes, 1024, 1, 1, null, 32); + return new uint256(h); + } + } + + public class TDCoinBlock : Block + { + public TDCoinBlock(TDCoinBlockHeader header) : base(header) + { + + } + public override ConsensusFactory GetConsensusFactory() + { + return TDCoinConsensusFactory.Instance; + } + } +/* + public class TDCoinMainnetAddressStringParser : NetworkStringParser + { + public override bool TryParse(string str, Network network, out T result) + { + if(str.StartsWith("Ltpv", StringComparison.OrdinalIgnoreCase) && typeof(T) == typeof(BitcoinExtKey)) + { + try + { + var decoded = Encoders.Base58Check.DecodeData(str); + decoded[0] = 0x04; + decoded[1] = 0x88; + decoded[2] = 0xAD; + decoded[3] = 0xE4; + result = (T)(object)new BitcoinExtKey(Encoders.Base58Check.EncodeData(decoded), network); + return true; + } + catch + { + } + } + if(str.StartsWith("Ltub", StringComparison.OrdinalIgnoreCase) && typeof(T) == typeof(BitcoinExtPubKey)) + { + try + { + var decoded = Encoders.Base58Check.DecodeData(str); + decoded[0] = 0x04; + decoded[1] = 0x88; + decoded[2] = 0xB2; + decoded[3] = 0x1E; + result = (T)(object)new BitcoinExtPubKey(Encoders.Base58Check.EncodeData(decoded), network); + return true; + } + catch + { + } + } + return base.TryParse(str, network, out result); + } + } +*/ +#pragma warning restore CS0618 // Type or member is obsolete + + protected override void PostInit() + { + RegisterDefaultCookiePath("TDCoin", new FolderName() { TestnetFolder = "testnet3" }); + } + + protected override NetworkBuilder CreateMainnet() + { + NetworkBuilder builder = new NetworkBuilder(); + builder.SetConsensus(new Consensus() + { + SubsidyHalvingInterval = 5039370, + MajorityEnforceBlockUpgrade = 750, + MajorityRejectBlockOutdated = 950, + MajorityWindow = 1000, + BIP34Hash = new uint256("000000006bccd4925d01cfdca84c90bffe266cca24629040fa084fb0d1f8dd19"), + PowLimit = new Target(new uint256("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), + PowTargetTimespan = TimeSpan.FromSeconds(7 * 24 * 60 * 60), + PowTargetSpacing = TimeSpan.FromSeconds(10 * 60), + PowAllowMinDifficultyBlocks = false, + PowNoRetargeting = false, + RuleChangeActivationThreshold = 1916, + MinerConfirmationWindow = 2016, + CoinbaseMaturity = 100, + LitecoinWorkCalculation = true, + ConsensusFactory = TDCoinConsensusFactory.Instance + }) + .SetBase58Bytes(Base58Type.PUBKEY_ADDRESS, new byte[] { 65 }) + .SetBase58Bytes(Base58Type.SCRIPT_ADDRESS, new byte[] { 82 }) + .SetBase58Bytes(Base58Type.SECRET_KEY, new byte[] { 107 }) + .SetBase58Bytes(Base58Type.EXT_PUBLIC_KEY, new byte[] { 0x04, 0x88, 0xB2, 0x1E }) + .SetBase58Bytes(Base58Type.EXT_SECRET_KEY, new byte[] { 0x04, 0x88, 0xAD, 0xE4 }) + .SetBech32(Bech32Type.WITNESS_PUBKEY_ADDRESS, Encoders.Bech32("tc")) + .SetBech32(Bech32Type.WITNESS_SCRIPT_ADDRESS, Encoders.Bech32("tc")) + .SetMagic(0x12a6f558) + .SetPort(9901) + .SetRPCPort(9902) + .SetName("tdc-main") + .AddAlias("tdc-mainnet") + .AddAlias("TDCoin-mainnet") + .AddAlias("TDCoin-main") + .AddDNSSeeds(new[] + { + new DNSSeedData("tokyo.nigez.com", "seeds.nigez.com"), + new DNSSeedData("usns.nigez.com", "seeds.nigez.com"), + new DNSSeedData("irns.nigez.com", "seeds4.nigez.com"), + new DNSSeedData("euns.nigez.com", "seeds2.nigez.com"), + new DNSSeedData("krns.nigez.com", "seeds3.nigez.com"), + new DNSSeedData("india.nigez.com", "seeds7.nigez.com"), + }) + .AddSeeds(ToSeed(pnSeed6_main)) + .SetGenesis("0100000000000000000000000000000000000000000000000000000000000000000000004ade933b9e1c7ad4d879f9f56b30ba19ee2fea9a55e184c4ad1008810962ba6c67f6cc5cffff001de1a696090101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4804ffff001d010440342d31322d31392041797261742056205a616b69722c2063726561746f72206f662054415444696720456e67696e6520616e642054616e676b7961206e65742effffffff0100d6117e03000000434104486940951aad21ee9646dd1fc43ec8bf01723cdd95661741034888ffa1f21b837c0a59b9c3b625d66379d35055a389ff3f3d849105ee9da67eb82d13d7cdde67ac00000000"); + return builder; + } + + protected override NetworkBuilder CreateTestnet() + { + var builder = new NetworkBuilder(); + builder.SetConsensus(new Consensus() + { + SubsidyHalvingInterval = 20000000, + MajorityEnforceBlockUpgrade = 51, + MajorityRejectBlockOutdated = 75, + MajorityWindow = 1000, + PowLimit = new Target(new uint256("00000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), + PowTargetTimespan = TimeSpan.FromSeconds(7 * 24 * 60 * 60), + PowTargetSpacing = TimeSpan.FromSeconds(10 * 60), + PowAllowMinDifficultyBlocks = true, + PowNoRetargeting = false, + RuleChangeActivationThreshold = 1512, + MinerConfirmationWindow = 2016, + CoinbaseMaturity = 100, + LitecoinWorkCalculation = true, + ConsensusFactory = TDCoinConsensusFactory.Instance + }) + .SetBase58Bytes(Base58Type.PUBKEY_ADDRESS, new byte[] { 111 }) + .SetBase58Bytes(Base58Type.SCRIPT_ADDRESS, new byte[] { 68 }) + .SetBase58Bytes(Base58Type.SECRET_KEY, new byte[] { 239 }) + .SetBase58Bytes(Base58Type.EXT_PUBLIC_KEY, new byte[] { 0x04, 0x35, 0x87, 0xCF }) + .SetBase58Bytes(Base58Type.EXT_SECRET_KEY, new byte[] { 0x04, 0x35, 0x83, 0x94 }) + .SetBech32(Bech32Type.WITNESS_PUBKEY_ADDRESS, Encoders.Bech32("tt")) + .SetBech32(Bech32Type.WITNESS_SCRIPT_ADDRESS, Encoders.Bech32("tt")) + .SetMagic(0x597b4712) + .SetPort(19901) + .SetRPCPort(19902) + .SetName("tdc-test") + .AddAlias("tdc-testnet") + .AddAlias("TDCoin-test") + .AddAlias("TDCoin-testnet") + .AddDNSSeeds(new[] + { + new DNSSeedData("tokyo.nigez.com", "seeds.nigez.com"), + new DNSSeedData("usns.nigez.com", "seeds.nigez.com"), + }) + .AddSeeds(ToSeed(pnSeed6_test)) + .SetGenesis("0100000000000000000000000000000000000000000000000000000000000000000000004ade933b9e1c7ad4d879f9f56b30ba19ee2fea9a55e184c4ad1008810962ba6c217ab15cffff001d7b4b0c0a0101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4804ffff001d010440342d31322d31392041797261742056205a616b69722c2063726561746f72206f662054415444696720456e67696e6520616e642054616e676b7961206e65742effffffff0100d6117e03000000434104486940951aad21ee9646dd1fc43ec8bf01723cdd95661741034888ffa1f21b837c0a59b9c3b625d66379d35055a389ff3f3d849105ee9da67eb82d13d7cdde67ac00000000"); + return builder; + } + + protected override NetworkBuilder CreateRegtest() + { + var builder = new NetworkBuilder(); + builder.SetConsensus(new Consensus() + { + SubsidyHalvingInterval = 150, + MajorityEnforceBlockUpgrade = 51, + MajorityRejectBlockOutdated = 75, + MajorityWindow = 144, + PowLimit = new Target(new uint256("7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff")), + PowTargetTimespan = TimeSpan.FromSeconds(14 * 24 * 60 * 60), + PowTargetSpacing = TimeSpan.FromSeconds(10 * 60), + PowAllowMinDifficultyBlocks = true, + MinimumChainWork = uint256.Zero, + PowNoRetargeting = true, + RuleChangeActivationThreshold = 108, + MinerConfirmationWindow = 144, + CoinbaseMaturity = 100, + LitecoinWorkCalculation = true, + ConsensusFactory = TDCoinConsensusFactory.Instance + }) + .SetBase58Bytes(Base58Type.PUBKEY_ADDRESS, new byte[] { 111 }) + .SetBase58Bytes(Base58Type.SCRIPT_ADDRESS, new byte[] { 90 }) + .SetBase58Bytes(Base58Type.SECRET_KEY, new byte[] { 239 }) + .SetBase58Bytes(Base58Type.EXT_PUBLIC_KEY, new byte[] { 0x04, 0x35, 0x87, 0xCF }) + .SetBase58Bytes(Base58Type.EXT_SECRET_KEY, new byte[] { 0x04, 0x35, 0x83, 0x94 }) + .SetBech32(Bech32Type.WITNESS_PUBKEY_ADDRESS, Encoders.Bech32("tdrt")) + .SetBech32(Bech32Type.WITNESS_SCRIPT_ADDRESS, Encoders.Bech32("tdrt")) + .SetMagic(0xdab5bffa) + .SetPort(19444) + .SetRPCPort(19443) + .SetName("tdc-reg") + .AddAlias("tdc-regtest") + .AddAlias("TDCoin-reg") + .AddAlias("TDCoin-regtest") + .SetGenesis("0100000000000000000000000000000000000000000000000000000000000000000000004ade933b9e1c7ad4d879f9f56b30ba19ee2fea9a55e184c4ad1008810962ba6c217ab15cffff7f20000000000101000000010000000000000000000000000000000000000000000000000000000000000000ffffffff4804ffff001d010440342d31322d31392041797261742056205a616b69722c2063726561746f72206f662054415444696720456e67696e6520616e642054616e676b7961206e65742effffffff0100d6117e03000000434104486940951aad21ee9646dd1fc43ec8bf01723cdd95661741034888ffa1f21b837c0a59b9c3b625d66379d35055a389ff3f3d849105ee9da67eb82d13d7cdde67ac00000000"); + return builder; + } + } +} diff --git a/NBitcoin/UInt256.cs b/NBitcoin/UInt256.cs index 2d8635d736..14b4150d24 100644 --- a/NBitcoin/UInt256.cs +++ b/NBitcoin/UInt256.cs @@ -1,915 +1,915 @@ - -using System; -using System.Collections; -using System.Linq; -using System.Runtime.InteropServices; -using NBitcoin.DataEncoders; - -namespace NBitcoin -{ - public sealed class uint256 : IComparable, IEquatable, IComparable - { - public class MutableUint256 : IBitcoinSerializable - { - uint256 _Value; - public uint256 Value - { - get - { - return _Value; - } - set - { - _Value = value; - } - } - public MutableUint256() - { - _Value = uint256.Zero; - } - public MutableUint256(uint256 value) - { - _Value = value; - } - - public void ReadWrite(BitcoinStream stream) - { - if (stream.Serializing) - { -#if !HAS_SPAN - var b = Value.ToBytes(); - stream.ReadWrite(ref b); -#else - Span b = stackalloc byte[WIDTH_BYTE]; - Value.ToBytes(b); - stream.ReadWrite(ref b); -#endif - } - else - { -#if !HAS_SPAN - byte[] b = new byte[WIDTH_BYTE]; - stream.ReadWrite(ref b); - _Value = new uint256(b); -#else - Span b = stackalloc byte[WIDTH_BYTE]; - stream.ReadWrite(ref b); - _Value = new uint256(b); -#endif - } - } - } - static readonly uint256 _Zero = new uint256(); - public static uint256 Zero - { - get - { - return _Zero; - } - } - - static readonly uint256 _One = new uint256(1); - public static uint256 One - { - get - { - return _One; - } - } - - public uint256() - { - } - - public uint256(uint256 b) - { - pn0 = b.pn0; - pn1 = b.pn1; - pn2 = b.pn2; - pn3 = b.pn3; - } - - public static uint256 Parse(string hex) - { - return new uint256(hex); - } - public static bool TryParse(string hex, out uint256 result) - { - if (hex == null) - throw new ArgumentNullException(nameof(hex)); - if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) - hex = hex.Substring(2); - result = null; - if (hex.Length != WIDTH_BYTE * 2) - return false; - if (!((HexEncoder)Encoders.Hex).IsValid(hex)) - return false; - result = new uint256(hex); - return true; - } - - private static readonly HexEncoder Encoder = new HexEncoder(); - private const int WIDTH_BYTE = 256 / 8; - internal readonly ulong pn0; - internal readonly ulong pn1; - internal readonly ulong pn2; - internal readonly ulong pn3; - - public byte GetByte(int index) - { -#if HAS_SPAN - if (index < 0 || index > 31) - throw new ArgumentOutOfRangeException("index"); - if (BitConverter.IsLittleEndian) - { - Span temp = stackalloc ulong[4]; - temp[0] = pn0; - temp[1] = pn1; - temp[2] = pn2; - temp[3] = pn3; - Span temp2 = MemoryMarshal.Cast(temp); - return temp2[index]; - } -#endif - - var ulongIndex = index / sizeof(ulong); - var byteIndex = index % sizeof(ulong); - ulong value; - switch (ulongIndex) - { - case 0: - value = pn0; - break; - case 1: - value = pn1; - break; - case 2: - value = pn2; - break; - case 3: - value = pn3; - break; - default: - throw new ArgumentOutOfRangeException("index"); - } - return (byte)(value >> (byteIndex * 8)); - } - public override string ToString() - { - var bytes = ToBytes(); - Array.Reverse(bytes); - return Encoder.EncodeData(bytes); - } - - public uint256(ulong b) - { - pn0 = (uint)b; - pn1 = (uint)(b >> 32); - } - - public uint256(byte[] vch, bool lendian = true) : this(vch, 0, vch.Length, lendian) - { - - } - - public uint256(byte[] vch, int offset, int length, bool lendian = true) - { - if (length != WIDTH_BYTE) - { - throw new FormatException("the byte array should be 32 bytes long"); - } -#if HAS_SPAN - if (BitConverter.IsLittleEndian && lendian) - { - var uints = MemoryMarshal.Cast(vch.AsSpan().Slice(offset, length)); - pn0 = uints[0]; - pn1 = uints[1]; - pn2 = uints[2]; - pn3 = uints[3]; - return; - } -#endif - - if (!lendian) - { - if (length != vch.Length) - vch = vch.Take(32).ToArray(); - vch = vch.Reverse().ToArray(); - } - - pn0 = Utils.ToUInt64(vch, offset + 8 * 0, true); - pn1 = Utils.ToUInt64(vch, offset + 8 * 1, true); - pn2 = Utils.ToUInt64(vch, offset + 8 * 2, true); - pn3 = Utils.ToUInt64(vch, offset + 8 * 3, true); - - } - -#if HAS_SPAN - public uint256(ReadOnlySpan bytes) - { - if (bytes.Length != WIDTH_BYTE) - { - throw new FormatException("the byte array should be 32 bytes long"); - } - if (BitConverter.IsLittleEndian) - { - var uints = MemoryMarshal.Cast(bytes); - pn0 = uints[0]; - pn1 = uints[1]; - pn2 = uints[2]; - pn3 = uints[3]; - return; - } - pn0 = Utils.ToUInt64(bytes.Slice(0), true); - pn1 = Utils.ToUInt64(bytes.Slice(8 * 1), true); - pn2 = Utils.ToUInt64(bytes.Slice(8 * 2), true); - pn3 = Utils.ToUInt64(bytes.Slice(8 * 3), true); - } -#endif - /// - /// Create a uint256 from a string in big endian - /// - /// - public uint256(string str) - { - if (str == null) - throw new ArgumentNullException(nameof(str)); - if (str.Length != 64) - { - if (str.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) - str = str.Substring(2); - str = str.Trim(); - if (str.Length != 64) - throw new FormatException("A uint256 must be 64 characters"); - } - -#if HAS_SPAN - if (BitConverter.IsLittleEndian) - { - Span tmp = stackalloc byte[32]; - Encoder.DecodeData(str, tmp); - tmp.Reverse(); - Span uints = MemoryMarshal.Cast(tmp); - pn0 = uints[0]; - pn1 = uints[1]; - pn2 = uints[2]; - pn3 = uints[3]; - return; - } -#endif - var bytes = Encoder.DecodeData(str); - Array.Reverse(bytes); - pn0 = Utils.ToUInt64(bytes, 8 * 0, true); - pn1 = Utils.ToUInt64(bytes, 8 * 1, true); - pn2 = Utils.ToUInt64(bytes, 8 * 2, true); - pn3 = Utils.ToUInt64(bytes, 8 * 3, true); - } - - public int GetBisCount() - { - if (pn3 != 0) - { - for (int nbits = 63; nbits > 0; nbits--) - { - if ((pn3 & 1UL << nbits) != 0) - return 64 * 3 + nbits + 1; - } - return 64 * 3 + 1; - } - if (pn2 != 0) - { - for (int nbits = 63; nbits > 0; nbits--) - { - if ((pn2 & 1UL << nbits) != 0) - return 64 * 2 + nbits + 1; - } - return 64 * 2 + 1; - } - if (pn1 != 0) - { - for (int nbits = 63; nbits > 0; nbits--) - { - if ((pn1 & 1UL << nbits) != 0) - return 64 * 1 + nbits + 1; - } - return 64 * 1 + 1; - } - if (pn0 != 0) - { - for (int nbits = 63; nbits > 0; nbits--) - { - if ((pn0 & 1UL << nbits) != 0) - return 64 * 0 + nbits + 1; - } - return 64 * 0 + 1; - } - return 0; - } - - public uint256(byte[] vch) - : this(vch, true) - { - } - - public override bool Equals(object obj) - { - var item = obj as uint256; - return Equals(item); - } - - public bool Equals(uint256 other) - { - if (other is null) - { - return false; - } - - bool equals = true; - equals &= pn0 == other.pn0; - equals &= pn1 == other.pn1; - equals &= pn2 == other.pn2; - equals &= pn3 == other.pn3; - return equals; - } - - public int CompareTo(uint256 other) - { - return Comparison(this, other); - } - - public int CompareTo(object obj) - { - return obj is uint256 v ? CompareTo(v) : - obj is null ? CompareTo(null as uint256) : throw new ArgumentException($"Object is not an instance of uint256", nameof(obj)); - } - - public static bool operator ==(uint256 a, uint256 b) - { - if (System.Object.ReferenceEquals(a, b)) - return true; - if (((object)a == null) || ((object)b == null)) - return false; - - bool equals = true; - equals &= a.pn0 == b.pn0; - equals &= a.pn1 == b.pn1; - equals &= a.pn2 == b.pn2; - equals &= a.pn3 == b.pn3; - return equals; - } - - public static bool operator <(uint256 a, uint256 b) - { - return Comparison(a, b) < 0; - } - - public static bool operator >(uint256 a, uint256 b) - { - return Comparison(a, b) > 0; - } - - public static bool operator <=(uint256 a, uint256 b) - { - return Comparison(a, b) <= 0; - } - - public static bool operator >=(uint256 a, uint256 b) - { - return Comparison(a, b) >= 0; - } - - private static int Comparison(uint256 a, uint256 b) - { - if (a is null && b is null) - return 0; - if (a is null && !(b is null)) - return -1; - if (!(a is null) && b is null) - return 1; - if (a.pn3 < b.pn3) - return -1; - if (a.pn3 > b.pn3) - return 1; - if (a.pn2 < b.pn2) - return -1; - if (a.pn2 > b.pn2) - return 1; - if (a.pn1 < b.pn1) - return -1; - if (a.pn1 > b.pn1) - return 1; - if (a.pn0 < b.pn0) - return -1; - if (a.pn0 > b.pn0) - return 1; - return 0; - } - - public static bool operator !=(uint256 a, uint256 b) - { - return !(a == b); - } - - public static bool operator ==(uint256 a, ulong b) - { - return (a == new uint256(b)); - } - - public static bool operator !=(uint256 a, ulong b) - { - return !(a == new uint256(b)); - } - - public static implicit operator uint256(ulong value) - { - return new uint256(value); - } - - - public byte[] ToBytes(bool lendian = true) - { - var arr = new byte[WIDTH_BYTE]; - ToBytes(arr); - if (!lendian) - Array.Reverse(arr); - return arr; - } - - /// - /// Write this instance to the output in little endian - /// - /// - public void ToBytes(byte[] output) - { - ToBytes(output, true); - } - /// - /// Write this instance to the output - /// - /// - /// - public void ToBytes(byte[] output, bool lendian) - { -#if HAS_SPAN - ToBytes(output.AsSpan(), lendian); -#else - if (lendian) - { - Buffer.BlockCopy(Utils.ToBytes(pn0, true), 0, output, 8 * 0, 8); - Buffer.BlockCopy(Utils.ToBytes(pn1, true), 0, output, 8 * 1, 8); - Buffer.BlockCopy(Utils.ToBytes(pn2, true), 0, output, 8 * 2, 8); - Buffer.BlockCopy(Utils.ToBytes(pn3, true), 0, output, 8 * 3, 8); - } - else - { - Buffer.BlockCopy(Utils.ToBytes(pn3, false), 0, output, 8 * 0, 8); - Buffer.BlockCopy(Utils.ToBytes(pn2, false), 0, output, 8 * 1, 8); - Buffer.BlockCopy(Utils.ToBytes(pn1, false), 0, output, 8 * 2, 8); - Buffer.BlockCopy(Utils.ToBytes(pn0, false), 0, output, 8 * 3, 8); - } -#endif - } - -#if HAS_SPAN - public void ToBytes(Span output, bool lendian = true) - { - if (output.Length < WIDTH_BYTE) - throw new ArgumentException(message: $"The array should be at least of size {WIDTH_BYTE}", paramName: nameof(output)); - - if (BitConverter.IsLittleEndian) - { - if (lendian) - { - var ulongOutput = MemoryMarshal.Cast(output); - ulongOutput[0] = pn0; - ulongOutput[1] = pn1; - ulongOutput[2] = pn2; - ulongOutput[3] = pn3; - } - else - { - Span temp = stackalloc ulong[4]; - temp[0] = pn0; - temp[1] = pn1; - temp[2] = pn2; - temp[3] = pn3; - var tempBytes = MemoryMarshal.Cast(temp); - tempBytes.Reverse(); - tempBytes.CopyTo(output); - } - return; - } - var initial = output; - Utils.ToBytes(pn0, true, output); - output = output.Slice(8); - Utils.ToBytes(pn1, true, output); - output = output.Slice(8); - Utils.ToBytes(pn2, true, output); - output = output.Slice(8); - Utils.ToBytes(pn3, true, output); - - if (!lendian) - initial.Reverse(); - } -#endif - public MutableUint256 AsBitcoinSerializable() - { - return new MutableUint256(this); - } - - public int GetSerializeSize(int nType = 0, uint? protocolVersion = null) - { - return WIDTH_BYTE; - } - - public int Size - { - get - { - return WIDTH_BYTE; - } - } - - public ulong GetLow64() - { - return pn0; - } - - public uint GetLow32() - { - return unchecked((uint)(pn0 & 0xFFFFFFFF)); - } - - public override int GetHashCode() - { - long hash = 17; - unchecked - { - hash = hash * 61 + (long)pn0; - hash = hash * 61 + (long)pn1; - hash = hash * 61 + (long)pn2; - hash = hash * 61 + (long)pn3; - return (int)hash; - } - } - } - public sealed class uint160 : IComparable, IEquatable, IComparable - { - public class MutableUint160 : IBitcoinSerializable - { - uint160 _Value; - public uint160 Value - { - get - { - return _Value; - } - set - { - _Value = value; - } - } - public MutableUint160() - { - _Value = uint160.Zero; - } - public MutableUint160(uint160 value) - { - _Value = value; - } - - public void ReadWrite(BitcoinStream stream) - { - if (stream.Serializing) - { - var b = Value.ToBytes(); - stream.ReadWrite(ref b); - } - else - { - byte[] b = new byte[WIDTH_BYTE]; - stream.ReadWrite(ref b); - _Value = new uint160(b); - } - } - } - static readonly uint160 _Zero = new uint160(); - public static uint160 Zero - { - get - { - return _Zero; - } - } - - static readonly uint160 _One = new uint160(1); - public static uint160 One - { - get - { - return _One; - } - } - - public uint160() - { - } - - public uint160(uint160 b) - { - pn0 = b.pn0; - pn1 = b.pn1; - pn2 = b.pn2; - pn3 = b.pn3; - pn4 = b.pn4; - } - - public static uint160 Parse(string hex) - { - return new uint160(hex); - } - public static bool TryParse(string hex, out uint160 result) - { - if (hex == null) - throw new ArgumentNullException(nameof(hex)); - if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) - hex = hex.Substring(2); - result = null; - if (hex.Length != WIDTH_BYTE * 2) - return false; - if (!((HexEncoder)Encoders.Hex).IsValid(hex)) - return false; - result = new uint160(hex); - return true; - } - - private static readonly HexEncoder Encoder = new HexEncoder(); - private const int WIDTH_BYTE = 160 / 8; - internal readonly UInt32 pn0; - internal readonly UInt32 pn1; - internal readonly UInt32 pn2; - internal readonly UInt32 pn3; - internal readonly UInt32 pn4; - - public byte GetByte(int index) - { - var uintIndex = index / sizeof(uint); - var byteIndex = index % sizeof(uint); - UInt32 value; - switch (uintIndex) - { - case 0: - value = pn0; - break; - case 1: - value = pn1; - break; - case 2: - value = pn2; - break; - case 3: - value = pn3; - break; - case 4: - value = pn4; - break; - default: - throw new ArgumentOutOfRangeException("index"); - } - return (byte)(value >> (byteIndex * 8)); - } - - public override string ToString() - { - return Encoder.EncodeData(ToBytes().Reverse().ToArray()); - } - - public uint160(ulong b) - { - pn0 = (uint)b; - pn1 = (uint)(b >> 32); - pn2 = 0; - pn3 = 0; - pn4 = 0; - } - - public uint160(byte[] vch, bool lendian = true) - { - if (vch.Length != WIDTH_BYTE) - { - throw new FormatException("the byte array should be 20 bytes long"); - } - - if (!lendian) - vch = vch.Reverse().ToArray(); - - pn0 = Utils.ToUInt32(vch, 4 * 0, true); - pn1 = Utils.ToUInt32(vch, 4 * 1, true); - pn2 = Utils.ToUInt32(vch, 4 * 2, true); - pn3 = Utils.ToUInt32(vch, 4 * 3, true); - pn4 = Utils.ToUInt32(vch, 4 * 4, true); - - } - - public uint160(string str) - { - pn0 = 0; - pn1 = 0; - pn2 = 0; - pn3 = 0; - pn4 = 0; - str = str.Trim(); - - if (str.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) - str = str.Substring(2); - - var bytes = Encoder.DecodeData(str).Reverse().ToArray(); - if (bytes.Length != WIDTH_BYTE) - throw new FormatException("Invalid hex length"); - pn0 = Utils.ToUInt32(bytes, 4 * 0, true); - pn1 = Utils.ToUInt32(bytes, 4 * 1, true); - pn2 = Utils.ToUInt32(bytes, 4 * 2, true); - pn3 = Utils.ToUInt32(bytes, 4 * 3, true); - pn4 = Utils.ToUInt32(bytes, 4 * 4, true); - - } - - public uint160(byte[] vch) - : this(vch, true) - { - } - - public override bool Equals(object obj) - { - var item = obj as uint160; - return Equals(item); - } - - public bool Equals(uint160 other) - { - if (other is null) - return false; - bool equals = true; - equals &= pn0 == other.pn0; - equals &= pn1 == other.pn1; - equals &= pn2 == other.pn2; - equals &= pn3 == other.pn3; - equals &= pn4 == other.pn4; - return equals; - } - - public int CompareTo(uint160 other) - { - return Comparison(this, other); - } - - public int CompareTo(object obj) - { - return obj is uint160 v ? CompareTo(v) : - obj is null ? CompareTo(null as uint160) : throw new ArgumentException($"Object is not an instance of uint160", nameof(obj)); - } - - public static bool operator ==(uint160 a, uint160 b) - { - if (System.Object.ReferenceEquals(a, b)) - return true; - if (((object)a == null) || ((object)b == null)) - return false; - - bool equals = true; - equals &= a.pn0 == b.pn0; - equals &= a.pn1 == b.pn1; - equals &= a.pn2 == b.pn2; - equals &= a.pn3 == b.pn3; - equals &= a.pn4 == b.pn4; - return equals; - } - - public static bool operator <(uint160 a, uint160 b) - { - return Comparison(a, b) < 0; - } - - public static bool operator >(uint160 a, uint160 b) - { - return Comparison(a, b) > 0; - } - - public static bool operator <=(uint160 a, uint160 b) - { - return Comparison(a, b) <= 0; - } - - public static bool operator >=(uint160 a, uint160 b) - { - return Comparison(a, b) >= 0; - } - - private static int Comparison(uint160 a, uint160 b) - { - if (a is null && b is null) - return 0; - if (a is null && !(b is null)) - return -1; - if (!(a is null) && b is null) - return 1; - if (a.pn4 < b.pn4) - return -1; - if (a.pn4 > b.pn4) - return 1; - if (a.pn3 < b.pn3) - return -1; - if (a.pn3 > b.pn3) - return 1; - if (a.pn2 < b.pn2) - return -1; - if (a.pn2 > b.pn2) - return 1; - if (a.pn1 < b.pn1) - return -1; - if (a.pn1 > b.pn1) - return 1; - if (a.pn0 < b.pn0) - return -1; - if (a.pn0 > b.pn0) - return 1; - return 0; - } - - public static bool operator !=(uint160 a, uint160 b) - { - return !(a == b); - } - - public static bool operator ==(uint160 a, ulong b) - { - return (a == new uint160(b)); - } - - public static bool operator !=(uint160 a, ulong b) - { - return !(a == new uint160(b)); - } - - public static implicit operator uint160(ulong value) - { - return new uint160(value); - } - - - public byte[] ToBytes(bool lendian = true) - { - var arr = new byte[WIDTH_BYTE]; - Buffer.BlockCopy(Utils.ToBytes(pn0, true), 0, arr, 4 * 0, 4); - Buffer.BlockCopy(Utils.ToBytes(pn1, true), 0, arr, 4 * 1, 4); - Buffer.BlockCopy(Utils.ToBytes(pn2, true), 0, arr, 4 * 2, 4); - Buffer.BlockCopy(Utils.ToBytes(pn3, true), 0, arr, 4 * 3, 4); - Buffer.BlockCopy(Utils.ToBytes(pn4, true), 0, arr, 4 * 4, 4); - if (!lendian) - Array.Reverse(arr); - return arr; - } - - public MutableUint160 AsBitcoinSerializable() - { - return new MutableUint160(this); - } - - public int GetSerializeSize(int nType = 0, uint? protocolVersion = null) - { - return WIDTH_BYTE; - } - - public int Size - { - get - { - return WIDTH_BYTE; - } - } - - public ulong GetLow64() - { - return pn0 | (ulong)pn1 << 32; - } - - public uint GetLow32() - { - return pn0; - } - - public override int GetHashCode() - { - int hash = 17; - unchecked - { - hash = hash * 31 + (int)pn0; - hash = hash * 31 + (int)pn1; - hash = hash * 31 + (int)pn2; - hash = hash * 31 + (int)pn3; - hash = hash * 31 + (int)pn4; - } - return hash; - } - } -} + +using System; +using System.Collections; +using System.Linq; +using System.Runtime.InteropServices; +using NBitcoin.DataEncoders; + +namespace NBitcoin +{ + public sealed class uint256 : IComparable, IEquatable, IComparable + { + public class MutableUint256 : IBitcoinSerializable + { + uint256 _Value; + public uint256 Value + { + get + { + return _Value; + } + set + { + _Value = value; + } + } + public MutableUint256() + { + _Value = uint256.Zero; + } + public MutableUint256(uint256 value) + { + _Value = value; + } + + public void ReadWrite(BitcoinStream stream) + { + if (stream.Serializing) + { +#if !HAS_SPAN + var b = Value.ToBytes(); + stream.ReadWrite(ref b); +#else + Span b = stackalloc byte[WIDTH_BYTE]; + Value.ToBytes(b); + stream.ReadWrite(ref b); +#endif + } + else + { +#if !HAS_SPAN + byte[] b = new byte[WIDTH_BYTE]; + stream.ReadWrite(ref b); + _Value = new uint256(b); +#else + Span b = stackalloc byte[WIDTH_BYTE]; + stream.ReadWrite(ref b); + _Value = new uint256(b); +#endif + } + } + } + static readonly uint256 _Zero = new uint256(); + public static uint256 Zero + { + get + { + return _Zero; + } + } + + static readonly uint256 _One = new uint256(1); + public static uint256 One + { + get + { + return _One; + } + } + + public uint256() + { + } + + public uint256(uint256 b) + { + pn0 = b.pn0; + pn1 = b.pn1; + pn2 = b.pn2; + pn3 = b.pn3; + } + + public static uint256 Parse(string hex) + { + return new uint256(hex); + } + public static bool TryParse(string hex, out uint256 result) + { + if (hex == null) + throw new ArgumentNullException(nameof(hex)); + if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + hex = hex.Substring(2); + result = null; + if (hex.Length != WIDTH_BYTE * 2) + return false; + if (!((HexEncoder)Encoders.Hex).IsValid(hex)) + return false; + result = new uint256(hex); + return true; + } + + private static readonly HexEncoder Encoder = new HexEncoder(); + private const int WIDTH_BYTE = 256 / 8; + internal readonly ulong pn0; + internal readonly ulong pn1; + internal readonly ulong pn2; + internal readonly ulong pn3; + + public byte GetByte(int index) + { +#if HAS_SPAN + if (index < 0 || index > 31) + throw new ArgumentOutOfRangeException("index"); + if (BitConverter.IsLittleEndian) + { + Span temp = stackalloc ulong[4]; + temp[0] = pn0; + temp[1] = pn1; + temp[2] = pn2; + temp[3] = pn3; + Span temp2 = MemoryMarshal.Cast(temp); + return temp2[index]; + } +#endif + + var ulongIndex = index / sizeof(ulong); + var byteIndex = index % sizeof(ulong); + ulong value; + switch (ulongIndex) + { + case 0: + value = pn0; + break; + case 1: + value = pn1; + break; + case 2: + value = pn2; + break; + case 3: + value = pn3; + break; + default: + throw new ArgumentOutOfRangeException("index"); + } + return (byte)(value >> (byteIndex * 8)); + } + public override string ToString() + { + var bytes = ToBytes(); + Array.Reverse(bytes); + return Encoder.EncodeData(bytes); + } + + public uint256(ulong b) + { + pn0 = (uint)b; + pn1 = (uint)(b >> 32); + } + + public uint256(byte[] vch, bool lendian = true) : this(vch, 0, vch.Length, lendian) + { + + } + + public uint256(byte[] vch, int offset, int length, bool lendian = true) + { + if (length != WIDTH_BYTE) + { + throw new FormatException("the byte array should be 32 bytes long"); + } +#if HAS_SPAN + if (BitConverter.IsLittleEndian && lendian) + { + var uints = MemoryMarshal.Cast(vch.AsSpan().Slice(offset, length)); + pn0 = uints[0]; + pn1 = uints[1]; + pn2 = uints[2]; + pn3 = uints[3]; + return; + } +#endif + + if (!lendian) + { + if (length != vch.Length) + vch = vch.Take(32).ToArray(); + vch = vch.Reverse().ToArray(); + } + + pn0 = Utils.ToUInt64(vch, offset + 8 * 0, true); + pn1 = Utils.ToUInt64(vch, offset + 8 * 1, true); + pn2 = Utils.ToUInt64(vch, offset + 8 * 2, true); + pn3 = Utils.ToUInt64(vch, offset + 8 * 3, true); + + } + +#if HAS_SPAN + public uint256(ReadOnlySpan bytes) + { + if (bytes.Length != WIDTH_BYTE) + { + throw new FormatException("the byte array should be 32 bytes long"); + } + if (BitConverter.IsLittleEndian) + { + var uints = MemoryMarshal.Cast(bytes); + pn0 = uints[0]; + pn1 = uints[1]; + pn2 = uints[2]; + pn3 = uints[3]; + return; + } + pn0 = Utils.ToUInt64(bytes.Slice(0), true); + pn1 = Utils.ToUInt64(bytes.Slice(8 * 1), true); + pn2 = Utils.ToUInt64(bytes.Slice(8 * 2), true); + pn3 = Utils.ToUInt64(bytes.Slice(8 * 3), true); + } +#endif + /// + /// Create a uint256 from a string in big endian + /// + /// + public uint256(string str) + { + if (str == null) + throw new ArgumentNullException(nameof(str)); + if (str.Length != 64) + { + if (str.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + str = str.Substring(2); + str = str.Trim(); + if (str.Length != 64) + throw new FormatException("A uint256 must be 64 characters"); + } + +#if HAS_SPAN + if (BitConverter.IsLittleEndian) + { + Span tmp = stackalloc byte[32]; + Encoder.DecodeData(str, tmp); + tmp.Reverse(); + Span uints = MemoryMarshal.Cast(tmp); + pn0 = uints[0]; + pn1 = uints[1]; + pn2 = uints[2]; + pn3 = uints[3]; + return; + } +#endif + var bytes = Encoder.DecodeData(str); + Array.Reverse(bytes); + pn0 = Utils.ToUInt64(bytes, 8 * 0, true); + pn1 = Utils.ToUInt64(bytes, 8 * 1, true); + pn2 = Utils.ToUInt64(bytes, 8 * 2, true); + pn3 = Utils.ToUInt64(bytes, 8 * 3, true); + } + + public int GetBisCount() + { + if (pn3 != 0) + { + for (int nbits = 63; nbits > 0; nbits--) + { + if ((pn3 & 1UL << nbits) != 0) + return 64 * 3 + nbits + 1; + } + return 64 * 3 + 1; + } + if (pn2 != 0) + { + for (int nbits = 63; nbits > 0; nbits--) + { + if ((pn2 & 1UL << nbits) != 0) + return 64 * 2 + nbits + 1; + } + return 64 * 2 + 1; + } + if (pn1 != 0) + { + for (int nbits = 63; nbits > 0; nbits--) + { + if ((pn1 & 1UL << nbits) != 0) + return 64 * 1 + nbits + 1; + } + return 64 * 1 + 1; + } + if (pn0 != 0) + { + for (int nbits = 63; nbits > 0; nbits--) + { + if ((pn0 & 1UL << nbits) != 0) + return 64 * 0 + nbits + 1; + } + return 64 * 0 + 1; + } + return 0; + } + + public uint256(byte[] vch) + : this(vch, true) + { + } + + public override bool Equals(object obj) + { + var item = obj as uint256; + return Equals(item); + } + + public bool Equals(uint256 other) + { + if (other is null) + { + return false; + } + + bool equals = true; + equals &= pn0 == other.pn0; + equals &= pn1 == other.pn1; + equals &= pn2 == other.pn2; + equals &= pn3 == other.pn3; + return equals; + } + + public int CompareTo(uint256 other) + { + return Comparison(this, other); + } + + public int CompareTo(object obj) + { + return obj is uint256 v ? CompareTo(v) : + obj is null ? CompareTo(null as uint256) : throw new ArgumentException($"Object is not an instance of uint256", nameof(obj)); + } + + public static bool operator ==(uint256 a, uint256 b) + { + if (System.Object.ReferenceEquals(a, b)) + return true; + if (((object)a == null) || ((object)b == null)) + return false; + + bool equals = true; + equals &= a.pn0 == b.pn0; + equals &= a.pn1 == b.pn1; + equals &= a.pn2 == b.pn2; + equals &= a.pn3 == b.pn3; + return equals; + } + + public static bool operator <(uint256 a, uint256 b) + { + return Comparison(a, b) < 0; + } + + public static bool operator >(uint256 a, uint256 b) + { + return Comparison(a, b) > 0; + } + + public static bool operator <=(uint256 a, uint256 b) + { + return Comparison(a, b) <= 0; + } + + public static bool operator >=(uint256 a, uint256 b) + { + return Comparison(a, b) >= 0; + } + + private static int Comparison(uint256 a, uint256 b) + { + if (a is null && b is null) + return 0; + if (a is null && !(b is null)) + return -1; + if (!(a is null) && b is null) + return 1; + if (a.pn3 < b.pn3) + return -1; + if (a.pn3 > b.pn3) + return 1; + if (a.pn2 < b.pn2) + return -1; + if (a.pn2 > b.pn2) + return 1; + if (a.pn1 < b.pn1) + return -1; + if (a.pn1 > b.pn1) + return 1; + if (a.pn0 < b.pn0) + return -1; + if (a.pn0 > b.pn0) + return 1; + return 0; + } + + public static bool operator !=(uint256 a, uint256 b) + { + return !(a == b); + } + + public static bool operator ==(uint256 a, ulong b) + { + return (a == new uint256(b)); + } + + public static bool operator !=(uint256 a, ulong b) + { + return !(a == new uint256(b)); + } + + public static implicit operator uint256(ulong value) + { + return new uint256(value); + } + + + public byte[] ToBytes(bool lendian = true) + { + var arr = new byte[WIDTH_BYTE]; + ToBytes(arr); + if (!lendian) + Array.Reverse(arr); + return arr; + } + + /// + /// Write this instance to the output in little endian + /// + /// + public void ToBytes(byte[] output) + { + ToBytes(output, true); + } + /// + /// Write this instance to the output + /// + /// + /// + public void ToBytes(byte[] output, bool lendian) + { +#if HAS_SPAN + ToBytes(output.AsSpan(), lendian); +#else + if (lendian) + { + Buffer.BlockCopy(Utils.ToBytes(pn0, true), 0, output, 8 * 0, 8); + Buffer.BlockCopy(Utils.ToBytes(pn1, true), 0, output, 8 * 1, 8); + Buffer.BlockCopy(Utils.ToBytes(pn2, true), 0, output, 8 * 2, 8); + Buffer.BlockCopy(Utils.ToBytes(pn3, true), 0, output, 8 * 3, 8); + } + else + { + Buffer.BlockCopy(Utils.ToBytes(pn3, false), 0, output, 8 * 0, 8); + Buffer.BlockCopy(Utils.ToBytes(pn2, false), 0, output, 8 * 1, 8); + Buffer.BlockCopy(Utils.ToBytes(pn1, false), 0, output, 8 * 2, 8); + Buffer.BlockCopy(Utils.ToBytes(pn0, false), 0, output, 8 * 3, 8); + } +#endif + } + +#if HAS_SPAN + public void ToBytes(Span output, bool lendian = true) + { + if (output.Length < WIDTH_BYTE) + throw new ArgumentException(message: $"The array should be at least of size {WIDTH_BYTE}", paramName: nameof(output)); + + if (BitConverter.IsLittleEndian) + { + if (lendian) + { + var ulongOutput = MemoryMarshal.Cast(output); + ulongOutput[0] = pn0; + ulongOutput[1] = pn1; + ulongOutput[2] = pn2; + ulongOutput[3] = pn3; + } + else + { + Span temp = stackalloc ulong[4]; + temp[0] = pn0; + temp[1] = pn1; + temp[2] = pn2; + temp[3] = pn3; + var tempBytes = MemoryMarshal.Cast(temp); + tempBytes.Reverse(); + tempBytes.CopyTo(output); + } + return; + } + var initial = output; + Utils.ToBytes(pn0, true, output); + output = output.Slice(8); + Utils.ToBytes(pn1, true, output); + output = output.Slice(8); + Utils.ToBytes(pn2, true, output); + output = output.Slice(8); + Utils.ToBytes(pn3, true, output); + + if (!lendian) + initial.Reverse(); + } +#endif + public MutableUint256 AsBitcoinSerializable() + { + return new MutableUint256(this); + } + + public int GetSerializeSize(int nType = 0, uint? protocolVersion = null) + { + return WIDTH_BYTE; + } + + public int Size + { + get + { + return WIDTH_BYTE; + } + } + + public ulong GetLow64() + { + return pn0; + } + + public uint GetLow32() + { + return unchecked((uint)(pn0 & 0xFFFFFFFF)); + } + + public override int GetHashCode() + { + long hash = 17; + unchecked + { + hash = hash * 61 + (long)pn0; + hash = hash * 61 + (long)pn1; + hash = hash * 61 + (long)pn2; + hash = hash * 61 + (long)pn3; + return (int)hash; + } + } + } + public sealed class uint160 : IComparable, IEquatable, IComparable + { + public class MutableUint160 : IBitcoinSerializable + { + uint160 _Value; + public uint160 Value + { + get + { + return _Value; + } + set + { + _Value = value; + } + } + public MutableUint160() + { + _Value = uint160.Zero; + } + public MutableUint160(uint160 value) + { + _Value = value; + } + + public void ReadWrite(BitcoinStream stream) + { + if (stream.Serializing) + { + var b = Value.ToBytes(); + stream.ReadWrite(ref b); + } + else + { + byte[] b = new byte[WIDTH_BYTE]; + stream.ReadWrite(ref b); + _Value = new uint160(b); + } + } + } + static readonly uint160 _Zero = new uint160(); + public static uint160 Zero + { + get + { + return _Zero; + } + } + + static readonly uint160 _One = new uint160(1); + public static uint160 One + { + get + { + return _One; + } + } + + public uint160() + { + } + + public uint160(uint160 b) + { + pn0 = b.pn0; + pn1 = b.pn1; + pn2 = b.pn2; + pn3 = b.pn3; + pn4 = b.pn4; + } + + public static uint160 Parse(string hex) + { + return new uint160(hex); + } + public static bool TryParse(string hex, out uint160 result) + { + if (hex == null) + throw new ArgumentNullException(nameof(hex)); + if (hex.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + hex = hex.Substring(2); + result = null; + if (hex.Length != WIDTH_BYTE * 2) + return false; + if (!((HexEncoder)Encoders.Hex).IsValid(hex)) + return false; + result = new uint160(hex); + return true; + } + + private static readonly HexEncoder Encoder = new HexEncoder(); + private const int WIDTH_BYTE = 160 / 8; + internal readonly UInt32 pn0; + internal readonly UInt32 pn1; + internal readonly UInt32 pn2; + internal readonly UInt32 pn3; + internal readonly UInt32 pn4; + + public byte GetByte(int index) + { + var uintIndex = index / sizeof(uint); + var byteIndex = index % sizeof(uint); + UInt32 value; + switch (uintIndex) + { + case 0: + value = pn0; + break; + case 1: + value = pn1; + break; + case 2: + value = pn2; + break; + case 3: + value = pn3; + break; + case 4: + value = pn4; + break; + default: + throw new ArgumentOutOfRangeException("index"); + } + return (byte)(value >> (byteIndex * 8)); + } + + public override string ToString() + { + return Encoder.EncodeData(ToBytes().Reverse().ToArray()); + } + + public uint160(ulong b) + { + pn0 = (uint)b; + pn1 = (uint)(b >> 32); + pn2 = 0; + pn3 = 0; + pn4 = 0; + } + + public uint160(byte[] vch, bool lendian = true) + { + if (vch.Length != WIDTH_BYTE) + { + throw new FormatException("the byte array should be 20 bytes long"); + } + + if (!lendian) + vch = vch.Reverse().ToArray(); + + pn0 = Utils.ToUInt32(vch, 4 * 0, true); + pn1 = Utils.ToUInt32(vch, 4 * 1, true); + pn2 = Utils.ToUInt32(vch, 4 * 2, true); + pn3 = Utils.ToUInt32(vch, 4 * 3, true); + pn4 = Utils.ToUInt32(vch, 4 * 4, true); + + } + + public uint160(string str) + { + pn0 = 0; + pn1 = 0; + pn2 = 0; + pn3 = 0; + pn4 = 0; + str = str.Trim(); + + if (str.StartsWith("0x", StringComparison.OrdinalIgnoreCase)) + str = str.Substring(2); + + var bytes = Encoder.DecodeData(str).Reverse().ToArray(); + if (bytes.Length != WIDTH_BYTE) + throw new FormatException("Invalid hex length"); + pn0 = Utils.ToUInt32(bytes, 4 * 0, true); + pn1 = Utils.ToUInt32(bytes, 4 * 1, true); + pn2 = Utils.ToUInt32(bytes, 4 * 2, true); + pn3 = Utils.ToUInt32(bytes, 4 * 3, true); + pn4 = Utils.ToUInt32(bytes, 4 * 4, true); + + } + + public uint160(byte[] vch) + : this(vch, true) + { + } + + public override bool Equals(object obj) + { + var item = obj as uint160; + return Equals(item); + } + + public bool Equals(uint160 other) + { + if (other is null) + return false; + bool equals = true; + equals &= pn0 == other.pn0; + equals &= pn1 == other.pn1; + equals &= pn2 == other.pn2; + equals &= pn3 == other.pn3; + equals &= pn4 == other.pn4; + return equals; + } + + public int CompareTo(uint160 other) + { + return Comparison(this, other); + } + + public int CompareTo(object obj) + { + return obj is uint160 v ? CompareTo(v) : + obj is null ? CompareTo(null as uint160) : throw new ArgumentException($"Object is not an instance of uint160", nameof(obj)); + } + + public static bool operator ==(uint160 a, uint160 b) + { + if (System.Object.ReferenceEquals(a, b)) + return true; + if (((object)a == null) || ((object)b == null)) + return false; + + bool equals = true; + equals &= a.pn0 == b.pn0; + equals &= a.pn1 == b.pn1; + equals &= a.pn2 == b.pn2; + equals &= a.pn3 == b.pn3; + equals &= a.pn4 == b.pn4; + return equals; + } + + public static bool operator <(uint160 a, uint160 b) + { + return Comparison(a, b) < 0; + } + + public static bool operator >(uint160 a, uint160 b) + { + return Comparison(a, b) > 0; + } + + public static bool operator <=(uint160 a, uint160 b) + { + return Comparison(a, b) <= 0; + } + + public static bool operator >=(uint160 a, uint160 b) + { + return Comparison(a, b) >= 0; + } + + private static int Comparison(uint160 a, uint160 b) + { + if (a is null && b is null) + return 0; + if (a is null && !(b is null)) + return -1; + if (!(a is null) && b is null) + return 1; + if (a.pn4 < b.pn4) + return -1; + if (a.pn4 > b.pn4) + return 1; + if (a.pn3 < b.pn3) + return -1; + if (a.pn3 > b.pn3) + return 1; + if (a.pn2 < b.pn2) + return -1; + if (a.pn2 > b.pn2) + return 1; + if (a.pn1 < b.pn1) + return -1; + if (a.pn1 > b.pn1) + return 1; + if (a.pn0 < b.pn0) + return -1; + if (a.pn0 > b.pn0) + return 1; + return 0; + } + + public static bool operator !=(uint160 a, uint160 b) + { + return !(a == b); + } + + public static bool operator ==(uint160 a, ulong b) + { + return (a == new uint160(b)); + } + + public static bool operator !=(uint160 a, ulong b) + { + return !(a == new uint160(b)); + } + + public static implicit operator uint160(ulong value) + { + return new uint160(value); + } + + + public byte[] ToBytes(bool lendian = true) + { + var arr = new byte[WIDTH_BYTE]; + Buffer.BlockCopy(Utils.ToBytes(pn0, true), 0, arr, 4 * 0, 4); + Buffer.BlockCopy(Utils.ToBytes(pn1, true), 0, arr, 4 * 1, 4); + Buffer.BlockCopy(Utils.ToBytes(pn2, true), 0, arr, 4 * 2, 4); + Buffer.BlockCopy(Utils.ToBytes(pn3, true), 0, arr, 4 * 3, 4); + Buffer.BlockCopy(Utils.ToBytes(pn4, true), 0, arr, 4 * 4, 4); + if (!lendian) + Array.Reverse(arr); + return arr; + } + + public MutableUint160 AsBitcoinSerializable() + { + return new MutableUint160(this); + } + + public int GetSerializeSize(int nType = 0, uint? protocolVersion = null) + { + return WIDTH_BYTE; + } + + public int Size + { + get + { + return WIDTH_BYTE; + } + } + + public ulong GetLow64() + { + return pn0 | (ulong)pn1 << 32; + } + + public uint GetLow32() + { + return pn0; + } + + public override int GetHashCode() + { + int hash = 17; + unchecked + { + hash = hash * 31 + (int)pn0; + hash = hash * 31 + (int)pn1; + hash = hash * 31 + (int)pn2; + hash = hash * 31 + (int)pn3; + hash = hash * 31 + (int)pn4; + } + return hash; + } + } +}