diff --git a/src/AElf.Cryptography/AElf.Cryptography.csproj b/src/AElf.Cryptography/AElf.Cryptography.csproj index 0ac287552c..9aa99c4676 100644 --- a/src/AElf.Cryptography/AElf.Cryptography.csproj +++ b/src/AElf.Cryptography/AElf.Cryptography.csproj @@ -1,7 +1,7 @@ - net6.0 + netstandard2.1;net6.0 AElf.Cryptography true Cryptographic primitives used in AElf. diff --git a/src/AElf.Cryptography/CryptoHelper.cs b/src/AElf.Cryptography/CryptoHelper.cs index 91abb3a64d..a868665bd7 100644 --- a/src/AElf.Cryptography/CryptoHelper.cs +++ b/src/AElf.Cryptography/CryptoHelper.cs @@ -7,157 +7,158 @@ using Secp256k1Net; using Virgil.Crypto; -namespace AElf.Cryptography; - -public static class CryptoHelper +namespace AElf.Cryptography { - private static readonly Secp256k1 Secp256K1 = new(); - - // ReaderWriterLock for thread-safe with Secp256k1 APIs - private static readonly ReaderWriterLock Lock = new(); - - static CryptoHelper() - { - AppDomain.CurrentDomain.ProcessExit += (sender, arg) => { Secp256K1.Dispose(); }; - } - - public static ECKeyPair FromPrivateKey(byte[] privateKey) + + public static class CryptoHelper { - if (privateKey == null || privateKey.Length != 32) - throw new InvalidPrivateKeyException( - $"Private key has to have length of 32. Current length is {privateKey?.Length}."); - - try + private static readonly Secp256k1 Secp256K1 = new Secp256k1(); + + // ReaderWriterLock for thread-safe with Secp256k1 APIs + private static readonly ReaderWriterLock Lock = new ReaderWriterLock(); + + static CryptoHelper() { - Lock.AcquireWriterLock(Timeout.Infinite); - var secp256K1PubKey = new byte[64]; - - if (!Secp256K1.PublicKeyCreate(secp256K1PubKey, privateKey)) - throw new InvalidPrivateKeyException("Create public key failed."); - var pubKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH]; - if (!Secp256K1.PublicKeySerialize(pubKey, secp256K1PubKey)) - throw new PublicKeyOperationException("Serialize public key failed."); - return new ECKeyPair(privateKey, pubKey); + AppDomain.CurrentDomain.ProcessExit += (sender, arg) => { Secp256K1.Dispose(); }; } - finally + + public static ECKeyPair FromPrivateKey(byte[] privateKey) { - Lock.ReleaseWriterLock(); - } - } - - public static ECKeyPair GenerateKeyPair() - { - try - { - Lock.AcquireWriterLock(Timeout.Infinite); - var privateKey = new byte[32]; - var secp256K1PubKey = new byte[64]; - - // Generate a private key. - var rnd = RandomNumberGenerator.Create(); - do + if (privateKey == null || privateKey.Length != 32) + throw new InvalidPrivateKeyException( + $"Private key has to have length of 32. Current length is {privateKey?.Length}."); + + try { - rnd.GetBytes(privateKey); - } while (!Secp256K1.SecretKeyVerify(privateKey)); - - if (!Secp256K1.PublicKeyCreate(secp256K1PubKey, privateKey)) - throw new InvalidPrivateKeyException("Create public key failed."); - var pubKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH]; - if (!Secp256K1.PublicKeySerialize(pubKey, secp256K1PubKey)) - throw new PublicKeyOperationException("Serialize public key failed."); - return new ECKeyPair(privateKey, pubKey); + Lock.AcquireWriterLock(Timeout.Infinite); + var secp256K1PubKey = new byte[64]; + + if (!Secp256K1.PublicKeyCreate(secp256K1PubKey, privateKey)) + throw new InvalidPrivateKeyException("Create public key failed."); + var pubKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH]; + if (!Secp256K1.PublicKeySerialize(pubKey, secp256K1PubKey)) + throw new PublicKeyOperationException("Serialize public key failed."); + return new ECKeyPair(privateKey, pubKey); + } + finally + { + Lock.ReleaseWriterLock(); + } } - finally + + public static ECKeyPair GenerateKeyPair() { - Lock.ReleaseWriterLock(); + try + { + Lock.AcquireWriterLock(Timeout.Infinite); + var privateKey = new byte[32]; + var secp256K1PubKey = new byte[64]; + + // Generate a private key. + var rnd = RandomNumberGenerator.Create(); + do + { + rnd.GetBytes(privateKey); + } while (!Secp256K1.SecretKeyVerify(privateKey)); + + if (!Secp256K1.PublicKeyCreate(secp256K1PubKey, privateKey)) + throw new InvalidPrivateKeyException("Create public key failed."); + var pubKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH]; + if (!Secp256K1.PublicKeySerialize(pubKey, secp256K1PubKey)) + throw new PublicKeyOperationException("Serialize public key failed."); + return new ECKeyPair(privateKey, pubKey); + } + finally + { + Lock.ReleaseWriterLock(); + } } - } - - public static byte[] SignWithPrivateKey(byte[] privateKey, byte[] hash) - { - try + + public static byte[] SignWithPrivateKey(byte[] privateKey, byte[] hash) { - Lock.AcquireWriterLock(Timeout.Infinite); - var recSig = new byte[65]; - var compactSig = new byte[65]; - if (!Secp256K1.SignRecoverable(recSig, hash, privateKey)) - throw new SignatureOperationException("Create a recoverable ECDSA signature failed."); - if (!Secp256K1.RecoverableSignatureSerializeCompact(compactSig, out var recoverId, recSig)) - throw new SignatureOperationException("Serialize an ECDSA signature failed."); - compactSig[64] = (byte)recoverId; // put recover id at the last slot - return compactSig; + try + { + Lock.AcquireWriterLock(Timeout.Infinite); + var recSig = new byte[65]; + var compactSig = new byte[65]; + if (!Secp256K1.SignRecoverable(recSig, hash, privateKey)) + throw new SignatureOperationException("Create a recoverable ECDSA signature failed."); + if (!Secp256K1.RecoverableSignatureSerializeCompact(compactSig, out var recoverId, recSig)) + throw new SignatureOperationException("Serialize an ECDSA signature failed."); + compactSig[64] = (byte)recoverId; // put recover id at the last slot + return compactSig; + } + finally + { + Lock.ReleaseWriterLock(); + } } - finally + + public static bool VerifySignature(byte[] signature, byte[] data, byte[] publicKey) { - Lock.ReleaseWriterLock(); + var recoverResult = RecoverPublicKey(signature, data, out var recoverPublicKey); + return recoverResult && publicKey.BytesEqual(recoverPublicKey); } - } - - public static bool VerifySignature(byte[] signature, byte[] data, byte[] publicKey) - { - var recoverResult = RecoverPublicKey(signature, data, out var recoverPublicKey); - return recoverResult && publicKey.BytesEqual(recoverPublicKey); - } - - public static bool RecoverPublicKey(byte[] signature, byte[] hash, out byte[] pubkey) - { - pubkey = null; - try + + public static bool RecoverPublicKey(byte[] signature, byte[] hash, out byte[] pubkey) { - Lock.AcquireWriterLock(Timeout.Infinite); - // Recover id should be greater than or equal to 0 and less than 4 - if (signature.Length != Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH || signature.Last() >= 4) - return false; - var pubKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH]; - var recoveredPubKey = new byte[Secp256k1.PUBKEY_LENGTH]; - var recSig = new byte[65]; - if (!Secp256K1.RecoverableSignatureParseCompact(recSig, signature, signature.Last())) - return false; - if (!Secp256K1.Recover(recoveredPubKey, recSig, hash)) - return false; - if (!Secp256K1.PublicKeySerialize(pubKey, recoveredPubKey)) - return false; - pubkey = pubKey; - return true; + pubkey = null; + try + { + Lock.AcquireWriterLock(Timeout.Infinite); + // Recover id should be greater than or equal to 0 and less than 4 + if (signature.Length != Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH || signature.Last() >= 4) + return false; + var pubKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH]; + var recoveredPubKey = new byte[Secp256k1.PUBKEY_LENGTH]; + var recSig = new byte[65]; + if (!Secp256K1.RecoverableSignatureParseCompact(recSig, signature, signature.Last())) + return false; + if (!Secp256K1.Recover(recoveredPubKey, recSig, hash)) + return false; + if (!Secp256K1.PublicKeySerialize(pubKey, recoveredPubKey)) + return false; + pubkey = pubKey; + return true; + } + finally + { + Lock.ReleaseWriterLock(); + } } - finally + + public static byte[] EncryptMessage(byte[] senderPrivateKey, byte[] receiverPublicKey, byte[] plainText) { - Lock.ReleaseWriterLock(); + var crypto = new VirgilCrypto(KeyPairType.EC_SECP256K1); + var ecdhKey = Ecdh(senderPrivateKey, receiverPublicKey); + var newKeyPair = crypto.GenerateKeys(KeyPairType.EC_SECP256K1, ecdhKey); + return crypto.Encrypt(plainText, newKeyPair.PublicKey); } - } - - public static byte[] EncryptMessage(byte[] senderPrivateKey, byte[] receiverPublicKey, byte[] plainText) - { - var crypto = new VirgilCrypto(KeyPairType.EC_SECP256K1); - var ecdhKey = Ecdh(senderPrivateKey, receiverPublicKey); - var newKeyPair = crypto.GenerateKeys(KeyPairType.EC_SECP256K1, ecdhKey); - return crypto.Encrypt(plainText, newKeyPair.PublicKey); - } - - public static byte[] DecryptMessage(byte[] senderPublicKey, byte[] receiverPrivateKey, byte[] cipherText) - { - var crypto = new VirgilCrypto(KeyPairType.EC_SECP256K1); - var ecdhKey = Ecdh(receiverPrivateKey, senderPublicKey); - var newKeyPair = crypto.GenerateKeys(KeyPairType.EC_SECP256K1, ecdhKey); - return crypto.Decrypt(cipherText, newKeyPair.PrivateKey); - } - - public static byte[] Ecdh(byte[] privateKey, byte[] publicKey) - { - try + + public static byte[] DecryptMessage(byte[] senderPublicKey, byte[] receiverPrivateKey, byte[] cipherText) { - Lock.AcquireWriterLock(Timeout.Infinite); - var usablePublicKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH]; - if (!Secp256K1.PublicKeyParse(usablePublicKey, publicKey)) - throw new PublicKeyOperationException("Parse public key failed."); - var ecdhKey = new byte[Secp256k1.SERIALIZED_COMPRESSED_PUBKEY_LENGTH]; - if (!Secp256K1.Ecdh(ecdhKey, usablePublicKey, privateKey)) - throw new EcdhOperationException("Compute EC Diffie- secret failed."); - return ecdhKey; + var crypto = new VirgilCrypto(KeyPairType.EC_SECP256K1); + var ecdhKey = Ecdh(receiverPrivateKey, senderPublicKey); + var newKeyPair = crypto.GenerateKeys(KeyPairType.EC_SECP256K1, ecdhKey); + return crypto.Decrypt(cipherText, newKeyPair.PrivateKey); } - finally + + public static byte[] Ecdh(byte[] privateKey, byte[] publicKey) { - Lock.ReleaseWriterLock(); + try + { + Lock.AcquireWriterLock(Timeout.Infinite); + var usablePublicKey = new byte[Secp256k1.SERIALIZED_UNCOMPRESSED_PUBKEY_LENGTH]; + if (!Secp256K1.PublicKeyParse(usablePublicKey, publicKey)) + throw new PublicKeyOperationException("Parse public key failed."); + var ecdhKey = new byte[Secp256k1.SERIALIZED_COMPRESSED_PUBKEY_LENGTH]; + if (!Secp256K1.Ecdh(ecdhKey, usablePublicKey, privateKey)) + throw new EcdhOperationException("Compute EC Diffie- secret failed."); + return ecdhKey; + } + finally + { + Lock.ReleaseWriterLock(); + } } - } -} \ No newline at end of file + }} diff --git a/src/AElf.Cryptography/ECDSA/ECKeyPair.cs b/src/AElf.Cryptography/ECDSA/ECKeyPair.cs index db31de6a1b..0b45308c42 100644 --- a/src/AElf.Cryptography/ECDSA/ECKeyPair.cs +++ b/src/AElf.Cryptography/ECDSA/ECKeyPair.cs @@ -1,15 +1,16 @@ using Secp256k1Net; -namespace AElf.Cryptography.ECDSA; - -public class ECKeyPair : IAElfAsymmetricCipherKeyPair +namespace AElf.Cryptography.ECDSA { - internal ECKeyPair(byte[] privateKey, byte[] publicKey) + + public class ECKeyPair : IAElfAsymmetricCipherKeyPair { - PublicKey = publicKey; - PrivateKey = privateKey.LeftPad(Secp256k1.PRIVKEY_LENGTH); - } - - public byte[] PrivateKey { get; } - public byte[] PublicKey { get; } -} \ No newline at end of file + internal ECKeyPair(byte[] privateKey, byte[] publicKey) + { + PublicKey = publicKey; + PrivateKey = privateKey.LeftPad(Secp256k1.PRIVKEY_LENGTH); + } + + public byte[] PrivateKey { get; } + public byte[] PublicKey { get; } + }} diff --git a/src/AElf.Cryptography/ECDSA/ECParameters.cs b/src/AElf.Cryptography/ECDSA/ECParameters.cs index c90af2893b..eda373fe9c 100644 --- a/src/AElf.Cryptography/ECDSA/ECParameters.cs +++ b/src/AElf.Cryptography/ECDSA/ECParameters.cs @@ -2,10 +2,11 @@ using Org.BouncyCastle.Asn1.X9; using Org.BouncyCastle.Crypto.Parameters; -namespace AElf.Cryptography.ECDSA; - -public static class ECParameters +namespace AElf.Cryptography.ECDSA { - public static readonly X9ECParameters Curve = SecNamedCurves.GetByName("secp256k1"); - public static readonly ECDomainParameters DomainParams = new(Curve.Curve, Curve.G, Curve.N, Curve.H); -} \ No newline at end of file + + public static class ECParameters + { + public static readonly X9ECParameters Curve = SecNamedCurves.GetByName("secp256k1"); + public static readonly ECDomainParameters DomainParams = new ECDomainParameters(Curve.Curve, Curve.G, Curve.N, Curve.H); + }} diff --git a/src/AElf.Cryptography/Exceptions/EcdhOperationException.cs b/src/AElf.Cryptography/Exceptions/EcdhOperationException.cs index 85cf2e1119..4f9046c111 100644 --- a/src/AElf.Cryptography/Exceptions/EcdhOperationException.cs +++ b/src/AElf.Cryptography/Exceptions/EcdhOperationException.cs @@ -1,10 +1,11 @@ using System; -namespace AElf.Cryptography.Exceptions; - -public class EcdhOperationException : Exception +namespace AElf.Cryptography.Exceptions { - public EcdhOperationException(string message) : base(message) + + public class EcdhOperationException : Exception { - } -} \ No newline at end of file + public EcdhOperationException(string message) : base(message) + { + } + }} diff --git a/src/AElf.Cryptography/Exceptions/InvalidKeyPairException.cs b/src/AElf.Cryptography/Exceptions/InvalidKeyPairException.cs index 0e385968c5..e792571722 100644 --- a/src/AElf.Cryptography/Exceptions/InvalidKeyPairException.cs +++ b/src/AElf.Cryptography/Exceptions/InvalidKeyPairException.cs @@ -1,10 +1,11 @@ using System; -namespace AElf.Cryptography.Exceptions; - -public class InvalidKeyPairException : Exception +namespace AElf.Cryptography.Exceptions { - public InvalidKeyPairException(string message, Exception innerException) : base(message, innerException) + + public class InvalidKeyPairException : Exception { - } -} \ No newline at end of file + public InvalidKeyPairException(string message, Exception innerException) : base(message, innerException) + { + } + }} diff --git a/src/AElf.Cryptography/Exceptions/InvalidPasswordException.cs b/src/AElf.Cryptography/Exceptions/InvalidPasswordException.cs index 61301850cd..155d277768 100644 --- a/src/AElf.Cryptography/Exceptions/InvalidPasswordException.cs +++ b/src/AElf.Cryptography/Exceptions/InvalidPasswordException.cs @@ -1,10 +1,11 @@ using System; -namespace AElf.Cryptography.Exceptions; - -public class InvalidPasswordException : Exception +namespace AElf.Cryptography.Exceptions { - public InvalidPasswordException(string message, Exception innerException) : base(message, innerException) + + public class InvalidPasswordException : Exception { - } -} \ No newline at end of file + public InvalidPasswordException(string message, Exception innerException) : base(message, innerException) + { + } + }} diff --git a/src/AElf.Cryptography/Exceptions/InvalidPrivateKeyException.cs b/src/AElf.Cryptography/Exceptions/InvalidPrivateKeyException.cs index fd8743ede6..51f1d82453 100644 --- a/src/AElf.Cryptography/Exceptions/InvalidPrivateKeyException.cs +++ b/src/AElf.Cryptography/Exceptions/InvalidPrivateKeyException.cs @@ -1,10 +1,11 @@ using System; -namespace AElf.Cryptography.Exceptions; - -public class InvalidPrivateKeyException : Exception +namespace AElf.Cryptography.Exceptions { - public InvalidPrivateKeyException(string message) : base(message) + + public class InvalidPrivateKeyException : Exception { - } -} \ No newline at end of file + public InvalidPrivateKeyException(string message) : base(message) + { + } + }} diff --git a/src/AElf.Cryptography/Exceptions/KeyStoreNotFoundException.cs b/src/AElf.Cryptography/Exceptions/KeyStoreNotFoundException.cs index 74a6eb2676..1ce8668af5 100644 --- a/src/AElf.Cryptography/Exceptions/KeyStoreNotFoundException.cs +++ b/src/AElf.Cryptography/Exceptions/KeyStoreNotFoundException.cs @@ -1,10 +1,11 @@ using System; -namespace AElf.Cryptography.Exceptions; - -public class KeyStoreNotFoundException : Exception +namespace AElf.Cryptography.Exceptions { - public KeyStoreNotFoundException(string message, Exception innerException) : base(message, innerException) + + public class KeyStoreNotFoundException : Exception { - } -} \ No newline at end of file + public KeyStoreNotFoundException(string message, Exception innerException) : base(message, innerException) + { + } + }} diff --git a/src/AElf.Cryptography/Exceptions/PublicKeyOperationException.cs b/src/AElf.Cryptography/Exceptions/PublicKeyOperationException.cs index 4e7b58fcfa..13569aaab4 100644 --- a/src/AElf.Cryptography/Exceptions/PublicKeyOperationException.cs +++ b/src/AElf.Cryptography/Exceptions/PublicKeyOperationException.cs @@ -1,10 +1,11 @@ using System; -namespace AElf.Cryptography.Exceptions; - -public class PublicKeyOperationException : Exception +namespace AElf.Cryptography.Exceptions { - public PublicKeyOperationException(string message) : base(message) + + public class PublicKeyOperationException : Exception { - } -} \ No newline at end of file + public PublicKeyOperationException(string message) : base(message) + { + } + }} diff --git a/src/AElf.Cryptography/Exceptions/SignatureOperationException.cs b/src/AElf.Cryptography/Exceptions/SignatureOperationException.cs index 2b2e309bc7..0846bcd68b 100644 --- a/src/AElf.Cryptography/Exceptions/SignatureOperationException.cs +++ b/src/AElf.Cryptography/Exceptions/SignatureOperationException.cs @@ -1,10 +1,11 @@ using System; -namespace AElf.Cryptography.Exceptions; - -public class SignatureOperationException : Exception +namespace AElf.Cryptography.Exceptions { - public SignatureOperationException(string message) : base(message) + + public class SignatureOperationException : Exception { - } -} \ No newline at end of file + public SignatureOperationException(string message) : base(message) + { + } + }} diff --git a/src/AElf.Cryptography/IAElfAsymmetricCipherKeyPair.cs b/src/AElf.Cryptography/IAElfAsymmetricCipherKeyPair.cs index 04f1f8f81d..7f122ac4bb 100644 --- a/src/AElf.Cryptography/IAElfAsymmetricCipherKeyPair.cs +++ b/src/AElf.Cryptography/IAElfAsymmetricCipherKeyPair.cs @@ -1,7 +1,8 @@ -namespace AElf.Cryptography; - -public interface IAElfAsymmetricCipherKeyPair +namespace AElf.Cryptography { - byte[] PrivateKey { get; } - byte[] PublicKey { get; } -} \ No newline at end of file + + public interface IAElfAsymmetricCipherKeyPair + { + byte[] PrivateKey { get; } + byte[] PublicKey { get; } + }} diff --git a/src/AElf.Cryptography/SecretSharing/SecretSharingConsts.cs b/src/AElf.Cryptography/SecretSharing/SecretSharingConsts.cs index ae8f92a605..3e5b009e90 100644 --- a/src/AElf.Cryptography/SecretSharing/SecretSharingConsts.cs +++ b/src/AElf.Cryptography/SecretSharing/SecretSharingConsts.cs @@ -1,9 +1,10 @@ using System.Numerics; -namespace AElf.Cryptography.SecretSharing; - -public static class SecretSharingConsts +namespace AElf.Cryptography.SecretSharing { - public static readonly uint MaxBits = 1024; - public static readonly BigInteger FieldPrime = BigInteger.Pow(new BigInteger(2), 1025) - 1; -} \ No newline at end of file + + public static class SecretSharingConsts + { + public static readonly uint MaxBits = 1024; + public static readonly BigInteger FieldPrime = BigInteger.Pow(new BigInteger(2), 1025) - 1; + }} diff --git a/src/AElf.Cryptography/SecretSharing/SecretSharingExtensions.cs b/src/AElf.Cryptography/SecretSharing/SecretSharingExtensions.cs index 762bb3badb..cb551e8d22 100644 --- a/src/AElf.Cryptography/SecretSharing/SecretSharingExtensions.cs +++ b/src/AElf.Cryptography/SecretSharing/SecretSharingExtensions.cs @@ -3,41 +3,42 @@ using System.Numerics; using System.Text; -namespace AElf.Cryptography.SecretSharing; - -public static class SecretSharingExtensions +namespace AElf.Cryptography.SecretSharing { - public static BigInteger ToBigInteger(this byte[] bytes) - { - var tempBytes = new byte[bytes.Length + 1]; - Array.Copy(bytes.Reverse().ToArray(), 0, tempBytes, 1, bytes.Length); - return new BigInteger(tempBytes); - } - - public static byte[] ToBytesArray(this BigInteger integer) - { - var tempBytes = integer.ToByteArray().Reverse().ToArray(); - var result = new byte[tempBytes.Length - 1]; - Array.Copy(tempBytes, 0, result, 0, result.Length); - - return result; - } - - public static string ConvertToString(this BigInteger integer) - { - var bytes = integer.ToByteArray(); - var chars = Encoding.UTF8.GetChars(bytes); - var size = 0; - for (; size < chars.Length; ++size) - if (chars[size] == '\0') - break; - - return new string(chars, 0, size); - } - - public static BigInteger Abs(this BigInteger integer) + + public static class SecretSharingExtensions { - return (integer % SecretSharingConsts.FieldPrime + SecretSharingConsts.FieldPrime) % - SecretSharingConsts.FieldPrime; - } -} \ No newline at end of file + public static BigInteger ToBigInteger(this byte[] bytes) + { + var tempBytes = new byte[bytes.Length + 1]; + Array.Copy(bytes.Reverse().ToArray(), 0, tempBytes, 1, bytes.Length); + return new BigInteger(tempBytes); + } + + public static byte[] ToBytesArray(this BigInteger integer) + { + var tempBytes = integer.ToByteArray().Reverse().ToArray(); + var result = new byte[tempBytes.Length - 1]; + Array.Copy(tempBytes, 0, result, 0, result.Length); + + return result; + } + + public static string ConvertToString(this BigInteger integer) + { + var bytes = integer.ToByteArray(); + var chars = Encoding.UTF8.GetChars(bytes); + var size = 0; + for (; size < chars.Length; ++size) + if (chars[size] == '\0') + break; + + return new string(chars, 0, size); + } + + public static BigInteger Abs(this BigInteger integer) + { + return (integer % SecretSharingConsts.FieldPrime + SecretSharingConsts.FieldPrime) % + SecretSharingConsts.FieldPrime; + } + }} diff --git a/src/AElf.Cryptography/SecretSharing/SecretSharingHelper.cs b/src/AElf.Cryptography/SecretSharing/SecretSharingHelper.cs index 609b2432de..4af1853f0e 100644 --- a/src/AElf.Cryptography/SecretSharing/SecretSharingHelper.cs +++ b/src/AElf.Cryptography/SecretSharing/SecretSharingHelper.cs @@ -3,104 +3,105 @@ using System.Linq; using System.Numerics; -namespace AElf.Cryptography.SecretSharing; - -/// -/// Implementation of Shamir's Secret Sharing: https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing -/// -public static class SecretSharingHelper +namespace AElf.Cryptography.SecretSharing { - public static List EncodeSecret(byte[] secretMessage, int threshold, int totalParts) + + /// + /// Implementation of Shamir's Secret Sharing: https://en.wikipedia.org/wiki/Shamir%27s_Secret_Sharing + /// + public static class SecretSharingHelper { - // Polynomial construction. - var coefficients = new BigInteger[threshold]; - // Set p(0) = secret message. - coefficients[0] = secretMessage.ToBigInteger(); - for (var i = 1; i < threshold; i++) + public static List EncodeSecret(byte[] secretMessage, int threshold, int totalParts) { - var foo = new byte[32]; - Array.Copy(HashHelper.ComputeFrom(Guid.NewGuid().ToByteArray()).ToArray(), foo, 32); - coefficients[i] = BigInteger.Abs(new BigInteger(foo)); + // Polynomial construction. + var coefficients = new BigInteger[threshold]; + // Set p(0) = secret message. + coefficients[0] = secretMessage.ToBigInteger(); + for (var i = 1; i < threshold; i++) + { + var foo = new byte[32]; + Array.Copy(HashHelper.ComputeFrom(Guid.NewGuid().ToByteArray()).ToArray(), foo, 32); + coefficients[i] = BigInteger.Abs(new BigInteger(foo)); + } + + var result = new List(); + for (var i = 1; i < totalParts + 1; i++) + { + var secretBigInteger = coefficients[0]; + for (var j = 1; j < threshold; j++) + { + secretBigInteger += coefficients[j] * BigInteger.Pow(new BigInteger(i), j); + secretBigInteger %= SecretSharingConsts.FieldPrime; + } + + result.Add(secretBigInteger.ToByteArray()); + } + + return result; } - - var result = new List(); - for (var i = 1; i < totalParts + 1; i++) + + // The shared parts must be sent in order. + public static byte[] DecodeSecret(List sharedParts, List orders, int threshold) { - var secretBigInteger = coefficients[0]; - for (var j = 1; j < threshold; j++) + var result = BigInteger.Zero; + + for (var i = 0; i < threshold; i++) { - secretBigInteger += coefficients[j] * BigInteger.Pow(new BigInteger(i), j); - secretBigInteger %= SecretSharingConsts.FieldPrime; + var numerator = new BigInteger(sharedParts[i]); + var denominator = BigInteger.One; + for (var j = 0; j < threshold; j++) + { + if (i == j) continue; + + (numerator, denominator) = + MultiplyRational(numerator, denominator, orders[j], orders[j] - orders[i]); + } + + result += RationalToWhole(numerator, denominator); + result %= SecretSharingConsts.FieldPrime; } - - result.Add(secretBigInteger.ToByteArray()); + + return result.ToBytesArray(); } - - return result; - } - - // The shared parts must be sent in order. - public static byte[] DecodeSecret(List sharedParts, List orders, int threshold) - { - var result = BigInteger.Zero; - - for (var i = 0; i < threshold; i++) + + private static BigInteger RationalToWhole(BigInteger numerator, BigInteger denominator) + { + return numerator * Inverse(denominator) % SecretSharingConsts.FieldPrime; + } + + private static BigInteger GetGreatestCommonDivisor(BigInteger integer1, BigInteger integer2) { - var numerator = new BigInteger(sharedParts[i]); - var denominator = BigInteger.One; - for (var j = 0; j < threshold; j++) + while (true) { - if (i == j) continue; - - (numerator, denominator) = - MultiplyRational(numerator, denominator, orders[j], orders[j] - orders[i]); + if (integer2 == 0) return integer1; + var integer3 = integer1; + integer1 = integer2; + integer2 = integer3 % integer2; } - - result += RationalToWhole(numerator, denominator); - result %= SecretSharingConsts.FieldPrime; } - - return result.ToBytesArray(); - } - - private static BigInteger RationalToWhole(BigInteger numerator, BigInteger denominator) - { - return numerator * Inverse(denominator) % SecretSharingConsts.FieldPrime; - } - - private static BigInteger GetGreatestCommonDivisor(BigInteger integer1, BigInteger integer2) - { - while (true) + + private static (BigInteger gcd, BigInteger invA, BigInteger invB) GetGreatestCommonDivisor2(BigInteger integer1, + BigInteger integer2) { - if (integer2 == 0) return integer1; - var integer3 = integer1; - integer1 = integer2; - integer2 = integer3 % integer2; + if (integer2 == 0) return (integer1, 1, 0); + + var div = BigInteger.DivRem(integer1, integer2, out var rem); + var (g, iA, iB) = GetGreatestCommonDivisor2(integer2, rem); + return (g, iB, iA - iB * div); } - } - - private static (BigInteger gcd, BigInteger invA, BigInteger invB) GetGreatestCommonDivisor2(BigInteger integer1, - BigInteger integer2) - { - if (integer2 == 0) return (integer1, 1, 0); - - var div = BigInteger.DivRem(integer1, integer2, out var rem); - var (g, iA, iB) = GetGreatestCommonDivisor2(integer2, rem); - return (g, iB, iA - iB * div); - } - - private static BigInteger Inverse(BigInteger integer) - { - return GetGreatestCommonDivisor2(SecretSharingConsts.FieldPrime, integer).invB.Abs(); - } - - private static (BigInteger numerator, BigInteger denominator) MultiplyRational( - BigInteger numeratorLhs, BigInteger denominatorLhs, - BigInteger numeratorRhs, BigInteger denominatorRhs) - { - var numerator = numeratorLhs * numeratorRhs % SecretSharingConsts.FieldPrime; - var denominator = denominatorLhs * denominatorRhs % SecretSharingConsts.FieldPrime; - var gcd = GetGreatestCommonDivisor(numerator, denominator); - return (numerator / gcd, denominator / gcd); - } -} \ No newline at end of file + + private static BigInteger Inverse(BigInteger integer) + { + return GetGreatestCommonDivisor2(SecretSharingConsts.FieldPrime, integer).invB.Abs(); + } + + private static (BigInteger numerator, BigInteger denominator) MultiplyRational( + BigInteger numeratorLhs, BigInteger denominatorLhs, + BigInteger numeratorRhs, BigInteger denominatorRhs) + { + var numerator = numeratorLhs * numeratorRhs % SecretSharingConsts.FieldPrime; + var denominator = denominatorLhs * denominatorRhs % SecretSharingConsts.FieldPrime; + var gcd = GetGreatestCommonDivisor(numerator, denominator); + return (numerator / gcd, denominator / gcd); + } + }} diff --git a/src/AElf.Types/AElf.Types.csproj b/src/AElf.Types/AElf.Types.csproj index 789898c95f..f819ee9d12 100644 --- a/src/AElf.Types/AElf.Types.csproj +++ b/src/AElf.Types/AElf.Types.csproj @@ -1,7 +1,7 @@ - net6.0 + netstandard2.1;net6.0 AElf AElf.Types true diff --git a/src/AElf.Types/AElfConstants.cs b/src/AElf.Types/AElfConstants.cs index 1d46330b17..af9d8f9a13 100644 --- a/src/AElf.Types/AElfConstants.cs +++ b/src/AElf.Types/AElfConstants.cs @@ -1,8 +1,9 @@ -namespace AElf; - -public static class AElfConstants +namespace AElf { - public const long GenesisBlockHeight = 1; - public const int HashByteArrayLength = 32; - public const int AddressHashLength = 32; -} \ No newline at end of file + + public static class AElfConstants + { + public const long GenesisBlockHeight = 1; + public const int HashByteArrayLength = 32; + public const int AddressHashLength = 32; + }} diff --git a/src/AElf.Types/Base58.cs b/src/AElf.Types/Base58.cs index f02afd7fce..90e7719ab9 100644 --- a/src/AElf.Types/Base58.cs +++ b/src/AElf.Types/Base58.cs @@ -5,169 +5,170 @@ using System.Security.Cryptography; using Google.Protobuf; -namespace AElf; - -/// -/// From https://github.com/adamcaudill/Base58Check, for NOT dotnet core version -/// Base58Check Encoding / Decoding (Bitcoin-style) -/// -/// -/// See here for more details: https://en.bitcoin.it/wiki/Base58Check_encoding -/// -public static class Base58CheckEncoding +namespace AElf { - private const int CheckSumSize = 4; - private const string Digits = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; - private static readonly HashSet DigitsHash = new(Digits.ToCharArray()); - + /// - /// Encodes data with a 4-byte checksum + /// From https://github.com/adamcaudill/Base58Check, for NOT dotnet core version + /// Base58Check Encoding / Decoding (Bitcoin-style) /// - /// Data to be encoded - /// - public static string Encode(byte[] data) + /// + /// See here for more details: https://en.bitcoin.it/wiki/Base58Check_encoding + /// + public static class Base58CheckEncoding { - return EncodePlain(_AddCheckSum(data)); - } - - /// - /// Encodes data in plain Base58, without any checksum. - /// - /// The data to be encoded - /// - public static string EncodePlain(byte[] data) - { - // Decode byte[] to BigInteger - var intData = data.Aggregate(0, (current, t) => current * 256 + t); - - // Encode BigInteger to Base58 string - var result = string.Empty; - while (intData > 0) + private const int CheckSumSize = 4; + private const string Digits = "123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz"; + private static readonly HashSet DigitsHash = new HashSet(Digits.ToCharArray()); + + /// + /// Encodes data with a 4-byte checksum + /// + /// Data to be encoded + /// + public static string Encode(byte[] data) { - var remainder = (int)(intData % 58); - intData /= 58; - result = Digits[remainder] + result; + return EncodePlain(_AddCheckSum(data)); } - - // Append `1` for each leading 0 byte - for (var i = 0; i < data.Length && data[i] == 0; i++) result = '1' + result; - - return result; - } - - /// - /// Encodes data in plain Base58, without any checksum. - /// - /// The data to be encoded - /// - public static string EncodePlain(ByteString data) - { - // Decode byte[] to BigInteger - var intData = data.Aggregate(0, (current, t) => current * 256 + t); - - // Encode BigInteger to Base58 string - var result = string.Empty; - while (intData > 0) + + /// + /// Encodes data in plain Base58, without any checksum. + /// + /// The data to be encoded + /// + public static string EncodePlain(byte[] data) { - var remainder = (int)(intData % 58); - intData /= 58; - result = Digits[remainder] + result; + // Decode byte[] to BigInteger + var intData = data.Aggregate(0, (current, t) => current * 256 + t); + + // Encode BigInteger to Base58 string + var result = string.Empty; + while (intData > 0) + { + var remainder = (int)(intData % 58); + intData /= 58; + result = Digits[remainder] + result; + } + + // Append `1` for each leading 0 byte + for (var i = 0; i < data.Length && data[i] == 0; i++) result = '1' + result; + + return result; } - - // Append `1` for each leading 0 byte - for (var i = 0; i < data.Length && data[i] == 0; i++) result = '1' + result; - - return result; - } - - - /// - /// Decodes data in Base58Check format (with 4 byte checksum) - /// - /// Data to be decoded - /// Returns decoded data if valid; throws FormatException if invalid - public static byte[] Decode(string data) - { - var dataWithCheckSum = DecodePlain(data); - var dataWithoutCheckSum = _VerifyAndRemoveCheckSum(dataWithCheckSum); - - if (dataWithoutCheckSum == null) throw new FormatException("Base58 checksum is invalid"); - - return dataWithoutCheckSum; - } - - /// - /// Decodes data in plain Base58, without any checksum. - /// - /// Data to be decoded - /// Returns decoded data if valid; throws FormatException if invalid - public static byte[] DecodePlain(string data) - { - // Decode Base58 string to BigInteger - BigInteger intData = 0; - for (var i = 0; i < data.Length; i++) + + /// + /// Encodes data in plain Base58, without any checksum. + /// + /// The data to be encoded + /// + public static string EncodePlain(ByteString data) { - var digit = Digits.IndexOf(data[i]); //Slow - - if (digit < 0) throw new FormatException($"Invalid Base58 character `{data[i]}` at position {i}"); - - intData = intData * 58 + digit; + // Decode byte[] to BigInteger + var intData = data.Aggregate(0, (current, t) => current * 256 + t); + + // Encode BigInteger to Base58 string + var result = string.Empty; + while (intData > 0) + { + var remainder = (int)(intData % 58); + intData /= 58; + result = Digits[remainder] + result; + } + + // Append `1` for each leading 0 byte + for (var i = 0; i < data.Length && data[i] == 0; i++) result = '1' + result; + + return result; } - - // Encode BigInteger to byte[] - // Leading zero bytes get encoded as leading `1` characters - var leadingZeroCount = data.TakeWhile(c => c == '1').Count(); - var leadingZeros = Enumerable.Repeat((byte)0, leadingZeroCount); - var bytesWithoutLeadingZeros = - intData.ToByteArray() - .Reverse() // to big endian - .SkipWhile(b => b == 0); //strip sign byte - var result = leadingZeros.Concat(bytesWithoutLeadingZeros).ToArray(); - - return result; - } - - public static bool Verify(string data) - { - for (var i = 0; i < data.Length; i++) - if (!DigitsHash.Contains(data[i])) + + + /// + /// Decodes data in Base58Check format (with 4 byte checksum) + /// + /// Data to be decoded + /// Returns decoded data if valid; throws FormatException if invalid + public static byte[] Decode(string data) + { + var dataWithCheckSum = DecodePlain(data); + var dataWithoutCheckSum = _VerifyAndRemoveCheckSum(dataWithCheckSum); + + if (dataWithoutCheckSum == null) throw new FormatException("Base58 checksum is invalid"); + + return dataWithoutCheckSum; + } + + /// + /// Decodes data in plain Base58, without any checksum. + /// + /// Data to be decoded + /// Returns decoded data if valid; throws FormatException if invalid + public static byte[] DecodePlain(string data) + { + // Decode Base58 string to BigInteger + BigInteger intData = 0; + for (var i = 0; i < data.Length; i++) + { + var digit = Digits.IndexOf(data[i]); //Slow + + if (digit < 0) throw new FormatException($"Invalid Base58 character `{data[i]}` at position {i}"); + + intData = intData * 58 + digit; + } + + // Encode BigInteger to byte[] + // Leading zero bytes get encoded as leading `1` characters + var leadingZeroCount = data.TakeWhile(c => c == '1').Count(); + var leadingZeros = Enumerable.Repeat((byte)0, leadingZeroCount); + var bytesWithoutLeadingZeros = + intData.ToByteArray() + .Reverse() // to big endian + .SkipWhile(b => b == 0); //strip sign byte + var result = leadingZeros.Concat(bytesWithoutLeadingZeros).ToArray(); + + return result; + } + + public static bool Verify(string data) + { + for (var i = 0; i < data.Length; i++) + if (!DigitsHash.Contains(data[i])) + return false; + + var dataWithCheckSum = DecodePlain(data); + var dataWithoutCheckSum = _VerifyAndRemoveCheckSum(dataWithCheckSum); + if (dataWithoutCheckSum == null) return false; - - var dataWithCheckSum = DecodePlain(data); - var dataWithoutCheckSum = _VerifyAndRemoveCheckSum(dataWithCheckSum); - if (dataWithoutCheckSum == null) - return false; - return true; - } - - private static byte[] _AddCheckSum(byte[] data) - { - var checkSum = _GetCheckSum(data); - var dataWithCheckSum = ByteArrayHelper.ConcatArrays(data, checkSum); - - return dataWithCheckSum; - } - - //Returns null if the checksum is invalid - private static byte[] _VerifyAndRemoveCheckSum(byte[] data) - { - var result = ByteArrayHelper.SubArray(data, 0, data.Length - CheckSumSize); - var givenCheckSum = ByteArrayHelper.SubArray(data, data.Length - CheckSumSize); - var correctCheckSum = _GetCheckSum(result); - - return givenCheckSum.SequenceEqual(correctCheckSum) ? result : null; - } - - private static byte[] _GetCheckSum(byte[] data) - { - var result = new byte[CheckSumSize]; - using (var sha256 = SHA256.Create()) + return true; + } + + private static byte[] _AddCheckSum(byte[] data) { - var hash1 = sha256.ComputeHash(data); - var hash2 = sha256.ComputeHash(hash1); - Buffer.BlockCopy(hash2, 0, result, 0, result.Length); + var checkSum = _GetCheckSum(data); + var dataWithCheckSum = ByteArrayHelper.ConcatArrays(data, checkSum); + + return dataWithCheckSum; } - - return result; - } -} \ No newline at end of file + + //Returns null if the checksum is invalid + private static byte[] _VerifyAndRemoveCheckSum(byte[] data) + { + var result = ByteArrayHelper.SubArray(data, 0, data.Length - CheckSumSize); + var givenCheckSum = ByteArrayHelper.SubArray(data, data.Length - CheckSumSize); + var correctCheckSum = _GetCheckSum(result); + + return givenCheckSum.SequenceEqual(correctCheckSum) ? result : null; + } + + private static byte[] _GetCheckSum(byte[] data) + { + var result = new byte[CheckSumSize]; + using (var sha256 = SHA256.Create()) + { + var hash1 = sha256.ComputeHash(data); + var hash2 = sha256.ComputeHash(hash1); + Buffer.BlockCopy(hash2, 0, result, 0, result.Length); + } + + return result; + } + }} diff --git a/src/AElf.Types/Extensions/ByteExtensions.cs b/src/AElf.Types/Extensions/ByteExtensions.cs index ac0eb20be0..6d84494600 100644 --- a/src/AElf.Types/Extensions/ByteExtensions.cs +++ b/src/AElf.Types/Extensions/ByteExtensions.cs @@ -3,119 +3,120 @@ using System.Security.Cryptography; using Google.Protobuf; -namespace AElf; - -public static class ByteExtensions +namespace AElf { - public static string ToPlainBase58(this byte[] value) - { - return Base58CheckEncoding.EncodePlain(value); - } - - public static string ToPlainBase58(this ByteString value) - { - return Base58CheckEncoding.EncodePlain(value); - } - - public static string ToHex(this byte[] bytes, bool withPrefix = false) + + public static class ByteExtensions { - var offset = withPrefix ? 2 : 0; - var length = bytes.Length * 2 + offset; - var c = new char[length]; - - byte b; - - if (withPrefix) + public static string ToPlainBase58(this byte[] value) { - c[0] = '0'; - c[1] = 'x'; + return Base58CheckEncoding.EncodePlain(value); } - - for (int bx = 0, cx = offset; bx < bytes.Length; ++bx, ++cx) + + public static string ToPlainBase58(this ByteString value) { - b = (byte)(bytes[bx] >> 4); - c[cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30); - - b = (byte)(bytes[bx] & 0x0F); - c[++cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30); + return Base58CheckEncoding.EncodePlain(value); } - - return new string(c); - } - - public static int ToInt32(this byte[] bytes, bool bigEndian) - { - var needReverse = !bigEndian ^ BitConverter.IsLittleEndian; - return BitConverter.ToInt32(needReverse ? bytes.Reverse().ToArray() : bytes, 0); - } - - public static long ToInt64(this byte[] bytes, bool bigEndian) - { - var needReverse = !bigEndian ^ BitConverter.IsLittleEndian; - return BitConverter.ToInt64(needReverse ? bytes.Reverse().ToArray() : bytes, 0); - } - - /// - /// Calculates the hash for a byte array. - /// - /// - /// - public static byte[] ComputeHash(this byte[] bytes) - { - using (var sha256 = SHA256.Create()) + + public static string ToHex(this byte[] bytes, bool withPrefix = false) { - return sha256.ComputeHash(bytes); + var offset = withPrefix ? 2 : 0; + var length = bytes.Length * 2 + offset; + var c = new char[length]; + + byte b; + + if (withPrefix) + { + c[0] = '0'; + c[1] = 'x'; + } + + for (int bx = 0, cx = offset; bx < bytes.Length; ++bx, ++cx) + { + b = (byte)(bytes[bx] >> 4); + c[cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30); + + b = (byte)(bytes[bx] & 0x0F); + c[++cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30); + } + + return new string(c); } - } - - public static byte[] LeftPad(this byte[] bytes, int length) - { - if (length <= bytes.Length) - return bytes; - - var paddedBytes = new byte[length]; - Buffer.BlockCopy(bytes, 0, paddedBytes, length - bytes.Length, bytes.Length); - return paddedBytes; - } - - /// - /// Find subarray in the source array. - /// - /// Source array to search for needle. - /// Needle we are searching for. - /// Start index in source array. - /// Number of bytes in source array, where the needle is searched for. - /// Returns starting position of the needle if it was found or -1 otherwise. - public static int Find(this byte[] array, byte[] needle, int startIndex = 0) - { - var needleLen = needle.Length; - var sourceLength = array.Length; - int index; - - while (sourceLength >= needleLen) + + public static int ToInt32(this byte[] bytes, bool bigEndian) { - // find needle's starting element - index = Array.IndexOf(array, needle[0], startIndex, sourceLength - needleLen + 1); - - // if we did not find even the first element of the needls, then the search is failed - if (index == -1) - return -1; - - int i, p; - // check for needle - for (i = 0, p = index; i < needleLen; i++, p++) - if (array[p] != needle[i]) - break; - - if (i == needleLen) - // needle was found - return index; - - // continue to search for needle - sourceLength -= index - startIndex + 1; - startIndex = index + 1; + var needReverse = !bigEndian ^ BitConverter.IsLittleEndian; + return BitConverter.ToInt32(needReverse ? bytes.Reverse().ToArray() : bytes, 0); } - - return -1; - } -} \ No newline at end of file + + public static long ToInt64(this byte[] bytes, bool bigEndian) + { + var needReverse = !bigEndian ^ BitConverter.IsLittleEndian; + return BitConverter.ToInt64(needReverse ? bytes.Reverse().ToArray() : bytes, 0); + } + + /// + /// Calculates the hash for a byte array. + /// + /// + /// + public static byte[] ComputeHash(this byte[] bytes) + { + using (var sha256 = SHA256.Create()) + { + return sha256.ComputeHash(bytes); + } + } + + public static byte[] LeftPad(this byte[] bytes, int length) + { + if (length <= bytes.Length) + return bytes; + + var paddedBytes = new byte[length]; + Buffer.BlockCopy(bytes, 0, paddedBytes, length - bytes.Length, bytes.Length); + return paddedBytes; + } + + /// + /// Find subarray in the source array. + /// + /// Source array to search for needle. + /// Needle we are searching for. + /// Start index in source array. + /// Number of bytes in source array, where the needle is searched for. + /// Returns starting position of the needle if it was found or -1 otherwise. + public static int Find(this byte[] array, byte[] needle, int startIndex = 0) + { + var needleLen = needle.Length; + var sourceLength = array.Length; + int index; + + while (sourceLength >= needleLen) + { + // find needle's starting element + index = Array.IndexOf(array, needle[0], startIndex, sourceLength - needleLen + 1); + + // if we did not find even the first element of the needls, then the search is failed + if (index == -1) + return -1; + + int i, p; + // check for needle + for (i = 0, p = index; i < needleLen; i++, p++) + if (array[p] != needle[i]) + break; + + if (i == needleLen) + // needle was found + return index; + + // continue to search for needle + sourceLength -= index - startIndex + 1; + startIndex = index + 1; + } + + return -1; + } + }} diff --git a/src/AElf.Types/Extensions/ByteStringExtensions.cs b/src/AElf.Types/Extensions/ByteStringExtensions.cs index 552f347085..7f5d46a8ee 100644 --- a/src/AElf.Types/Extensions/ByteStringExtensions.cs +++ b/src/AElf.Types/Extensions/ByteStringExtensions.cs @@ -1,37 +1,38 @@ -using Google.Protobuf; - -namespace AElf; - -public static class ByteStringExtensions -{ - public static string ToHex(this ByteString bytes, bool withPrefix = false) - { - var offset = withPrefix ? 2 : 0; - var length = bytes.Length * 2 + offset; - var c = new char[length]; - - byte b; - - if (withPrefix) - { - c[0] = '0'; - c[1] = 'x'; - } - - for (int bx = 0, cx = offset; bx < bytes.Length; ++bx, ++cx) - { - b = (byte)(bytes[bx] >> 4); - c[cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30); - - b = (byte)(bytes[bx] & 0x0F); - c[++cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30); - } - - return new string(c); - } - - public static bool IsNullOrEmpty(this ByteString byteString) - { - return byteString == null || byteString.IsEmpty; - } -} \ No newline at end of file +using Google.Protobuf; + +namespace AElf +{ + + public static class ByteStringExtensions + { + public static string ToHex(this ByteString bytes, bool withPrefix = false) + { + var offset = withPrefix ? 2 : 0; + var length = bytes.Length * 2 + offset; + var c = new char[length]; + + byte b; + + if (withPrefix) + { + c[0] = '0'; + c[1] = 'x'; + } + + for (int bx = 0, cx = offset; bx < bytes.Length; ++bx, ++cx) + { + b = (byte)(bytes[bx] >> 4); + c[cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30); + + b = (byte)(bytes[bx] & 0x0F); + c[++cx] = (char)(b > 9 ? b + 0x37 + 0x20 : b + 0x30); + } + + return new string(c); + } + + public static bool IsNullOrEmpty(this ByteString byteString) + { + return byteString == null || byteString.IsEmpty; + } + }} diff --git a/src/AElf.Types/Extensions/HexStringExtensions.cs b/src/AElf.Types/Extensions/HexStringExtensions.cs index 7865dbbb63..857a634ded 100644 --- a/src/AElf.Types/Extensions/HexStringExtensions.cs +++ b/src/AElf.Types/Extensions/HexStringExtensions.cs @@ -1,13 +1,14 @@ using System; using Google.Protobuf; -namespace AElf; - -public static class HexStringExtensions +namespace AElf { - [Obsolete("Use ByteStringHelper.FromHexString instead.")] - public static ByteString ToByteString(this string hexString) + + public static class HexStringExtensions { - return ByteString.CopyFrom(ByteArrayHelper.HexStringToByteArray(hexString)); - } -} \ No newline at end of file + [Obsolete("Use ByteStringHelper.FromHexString instead.")] + public static ByteString ToByteString(this string hexString) + { + return ByteString.CopyFrom(ByteArrayHelper.HexStringToByteArray(hexString)); + } + }} diff --git a/src/AElf.Types/Extensions/IMessageExtensions.cs b/src/AElf.Types/Extensions/IMessageExtensions.cs index aaa4509c5e..d5a29dfcb7 100644 --- a/src/AElf.Types/Extensions/IMessageExtensions.cs +++ b/src/AElf.Types/Extensions/IMessageExtensions.cs @@ -1,12 +1,13 @@ using Google.Protobuf; using Google.Protobuf.WellKnownTypes; -namespace AElf; - -public static class IMessageExtensions +namespace AElf { - public static BytesValue ToBytesValue(this IMessage message) + + public static class IMessageExtensions { - return new BytesValue { Value = message.ToByteString() }; - } -} \ No newline at end of file + public static BytesValue ToBytesValue(this IMessage message) + { + return new BytesValue { Value = message.ToByteString() }; + } + }} diff --git a/src/AElf.Types/Extensions/MerklePathExtensions.cs b/src/AElf.Types/Extensions/MerklePathExtensions.cs index 72ec34c1e2..3837a61906 100644 --- a/src/AElf.Types/Extensions/MerklePathExtensions.cs +++ b/src/AElf.Types/Extensions/MerklePathExtensions.cs @@ -1,14 +1,15 @@ using System.Linq; using AElf.Types; -namespace AElf; - -public static class MerklePathExtensions +namespace AElf { - public static Hash ComputeRootWithLeafNode(this MerklePath path, Hash leaf) + + public static class MerklePathExtensions { - return path.MerklePathNodes.Aggregate(leaf, (current, node) => node.IsLeftChildNode - ? HashHelper.ConcatAndCompute(node.Hash, current) - : HashHelper.ConcatAndCompute(current, node.Hash)); - } -} \ No newline at end of file + public static Hash ComputeRootWithLeafNode(this MerklePath path, Hash leaf) + { + return path.MerklePathNodes.Aggregate(leaf, (current, node) => node.IsLeftChildNode + ? HashHelper.ConcatAndCompute(node.Hash, current) + : HashHelper.ConcatAndCompute(current, node.Hash)); + } + }} diff --git a/src/AElf.Types/Extensions/NumericExtensions.cs b/src/AElf.Types/Extensions/NumericExtensions.cs index c4750004d5..2cf65d7ba3 100644 --- a/src/AElf.Types/Extensions/NumericExtensions.cs +++ b/src/AElf.Types/Extensions/NumericExtensions.cs @@ -1,38 +1,39 @@ using System; using System.Linq; -namespace AElf; - -public static class NumericExtensions +namespace AElf { - public static byte[] ToBytes(this long n, bool bigEndian = true) - { - var bytes = BitConverter.GetBytes(n); - return GetBytesWithEndian(bytes, bigEndian); - } - - public static byte[] ToBytes(this ulong n, bool bigEndian = true) - { - var bytes = BitConverter.GetBytes(n); - return GetBytesWithEndian(bytes, bigEndian); - } - - public static byte[] ToBytes(this int n, bool bigEndian = true) - { - var bytes = BitConverter.GetBytes(n); - return GetBytesWithEndian(bytes, bigEndian); - } - - public static byte[] ToBytes(this uint n, bool bigEndian = true) - { - var bytes = BitConverter.GetBytes(n); - return GetBytesWithEndian(bytes, bigEndian); - } - - private static byte[] GetBytesWithEndian(byte[] bytes, bool bigEndian) + + public static class NumericExtensions { - if (bigEndian ^ BitConverter.IsLittleEndian) - return bytes; - return bytes.Reverse().ToArray(); - } -} \ No newline at end of file + public static byte[] ToBytes(this long n, bool bigEndian = true) + { + var bytes = BitConverter.GetBytes(n); + return GetBytesWithEndian(bytes, bigEndian); + } + + public static byte[] ToBytes(this ulong n, bool bigEndian = true) + { + var bytes = BitConverter.GetBytes(n); + return GetBytesWithEndian(bytes, bigEndian); + } + + public static byte[] ToBytes(this int n, bool bigEndian = true) + { + var bytes = BitConverter.GetBytes(n); + return GetBytesWithEndian(bytes, bigEndian); + } + + public static byte[] ToBytes(this uint n, bool bigEndian = true) + { + var bytes = BitConverter.GetBytes(n); + return GetBytesWithEndian(bytes, bigEndian); + } + + private static byte[] GetBytesWithEndian(byte[] bytes, bool bigEndian) + { + if (bigEndian ^ BitConverter.IsLittleEndian) + return bytes; + return bytes.Reverse().ToArray(); + } + }} diff --git a/src/AElf.Types/Extensions/StateKeyExtensions.cs b/src/AElf.Types/Extensions/StateKeyExtensions.cs index 7cbff5b979..9d52003af0 100644 --- a/src/AElf.Types/Extensions/StateKeyExtensions.cs +++ b/src/AElf.Types/Extensions/StateKeyExtensions.cs @@ -1,22 +1,23 @@ using System.Linq; using AElf.Types; -namespace AElf; - -public static class StateKeyExtensions +namespace AElf { - public static string ToStateKey(this StatePath statePath, Address address) + + public static class StateKeyExtensions { - return new ScopedStatePath + public static string ToStateKey(this StatePath statePath, Address address) { - Address = address, - Path = statePath - }.ToStateKey(); - } - - public static string ToStateKey(this ScopedStatePath scopedStatePath) - { - return string.Join("/", - new[] { scopedStatePath.Address.ToBase58() }.Concat(scopedStatePath.Path.Parts)); - } -} \ No newline at end of file + return new ScopedStatePath + { + Address = address, + Path = statePath + }.ToStateKey(); + } + + public static string ToStateKey(this ScopedStatePath scopedStatePath) + { + return string.Join("/", + new[] { scopedStatePath.Address.ToBase58() }.Concat(scopedStatePath.Path.Parts)); + } + }} diff --git a/src/AElf.Types/Extensions/StringExtensions.cs b/src/AElf.Types/Extensions/StringExtensions.cs index 459602c52d..f82910dfcd 100644 --- a/src/AElf.Types/Extensions/StringExtensions.cs +++ b/src/AElf.Types/Extensions/StringExtensions.cs @@ -1,11 +1,12 @@ using System.Text; -namespace AElf; - -public static class StringExtensions +namespace AElf { - public static byte[] GetBytes(this string value) + + public static class StringExtensions { - return Encoding.UTF8.GetBytes(value); - } -} \ No newline at end of file + public static byte[] GetBytes(this string value) + { + return Encoding.UTF8.GetBytes(value); + } + }} diff --git a/src/AElf.Types/Helper/AddressHelper.cs b/src/AElf.Types/Helper/AddressHelper.cs index 5269bd504c..942f31e763 100644 --- a/src/AElf.Types/Helper/AddressHelper.cs +++ b/src/AElf.Types/Helper/AddressHelper.cs @@ -1,11 +1,12 @@ -namespace AElf; - -public static class AddressHelper +namespace AElf { - public static bool VerifyFormattedAddress(string formattedAddress) + + public static class AddressHelper { - if (string.IsNullOrEmpty(formattedAddress)) - return false; - return Base58CheckEncoding.Verify(formattedAddress); - } -} \ No newline at end of file + public static bool VerifyFormattedAddress(string formattedAddress) + { + if (string.IsNullOrEmpty(formattedAddress)) + return false; + return Base58CheckEncoding.Verify(formattedAddress); + } + }} diff --git a/src/AElf.Types/Helper/BlockHelper.cs b/src/AElf.Types/Helper/BlockHelper.cs index 067802f38e..9c6a823e53 100644 --- a/src/AElf.Types/Helper/BlockHelper.cs +++ b/src/AElf.Types/Helper/BlockHelper.cs @@ -2,13 +2,14 @@ using AElf.Types; using Google.Protobuf; -namespace AElf; - -public static class BlockHelper +namespace AElf { - public static ByteString GetRefBlockPrefix(Hash blockHash) + + public static class BlockHelper { - var refBlockPrefix = ByteString.CopyFrom(blockHash.Value.Take(4).ToArray()); - return refBlockPrefix; - } -} \ No newline at end of file + public static ByteString GetRefBlockPrefix(Hash blockHash) + { + var refBlockPrefix = ByteString.CopyFrom(blockHash.Value.Take(4).ToArray()); + return refBlockPrefix; + } + }} diff --git a/src/AElf.Types/Helper/ByteArrayHelper.cs b/src/AElf.Types/Helper/ByteArrayHelper.cs index e6bdc73f08..faa0cf36c7 100644 --- a/src/AElf.Types/Helper/ByteArrayHelper.cs +++ b/src/AElf.Types/Helper/ByteArrayHelper.cs @@ -1,59 +1,60 @@ using System; -namespace AElf; - -public static class ByteArrayHelper +namespace AElf { - public static byte[] HexStringToByteArray(string hex) - { - if (hex.Length >= 2 && hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) - hex = hex.Substring(2); - var numberChars = hex.Length; - var bytes = new byte[numberChars / 2]; - - for (var i = 0; i < numberChars; i += 2) - bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); - - return bytes; - } - - public static bool BytesEqual(this byte[] b1, byte[] b2) + + public static class ByteArrayHelper { - if (b1 == b2) - return true; - - if (b1 == null || b2 == null) - return false; - - if (b1.Length != b2.Length) - return false; - - for (var i = 0; i < b1.Length; i++) - if (b1[i] != b2[i]) + public static byte[] HexStringToByteArray(string hex) + { + if (hex.Length >= 2 && hex[0] == '0' && (hex[1] == 'x' || hex[1] == 'X')) + hex = hex.Substring(2); + var numberChars = hex.Length; + var bytes = new byte[numberChars / 2]; + + for (var i = 0; i < numberChars; i += 2) + bytes[i / 2] = Convert.ToByte(hex.Substring(i, 2), 16); + + return bytes; + } + + public static bool BytesEqual(this byte[] b1, byte[] b2) + { + if (b1 == b2) + return true; + + if (b1 == null || b2 == null) return false; - - return true; - } - - public static byte[] ConcatArrays(byte[] arr1, byte[] arr2) - { - var result = new byte[arr1.Length + arr2.Length]; - Buffer.BlockCopy(arr1, 0, result, 0, arr1.Length); - Buffer.BlockCopy(arr2, 0, result, arr1.Length, arr2.Length); - - return result; - } - - public static byte[] SubArray(byte[] arr, int start, int length) - { - var result = new byte[length]; - Buffer.BlockCopy(arr, start, result, 0, length); - - return result; - } - - public static byte[] SubArray(byte[] arr, int start) - { - return SubArray(arr, start, arr.Length - start); - } -} \ No newline at end of file + + if (b1.Length != b2.Length) + return false; + + for (var i = 0; i < b1.Length; i++) + if (b1[i] != b2[i]) + return false; + + return true; + } + + public static byte[] ConcatArrays(byte[] arr1, byte[] arr2) + { + var result = new byte[arr1.Length + arr2.Length]; + Buffer.BlockCopy(arr1, 0, result, 0, arr1.Length); + Buffer.BlockCopy(arr2, 0, result, arr1.Length, arr2.Length); + + return result; + } + + public static byte[] SubArray(byte[] arr, int start, int length) + { + var result = new byte[length]; + Buffer.BlockCopy(arr, start, result, 0, length); + + return result; + } + + public static byte[] SubArray(byte[] arr, int start) + { + return SubArray(arr, start, arr.Length - start); + } + }} diff --git a/src/AElf.Types/Helper/ByteStringHelper.cs b/src/AElf.Types/Helper/ByteStringHelper.cs index b323e0f371..0722f9a747 100644 --- a/src/AElf.Types/Helper/ByteStringHelper.cs +++ b/src/AElf.Types/Helper/ByteStringHelper.cs @@ -1,24 +1,25 @@ using System; using Google.Protobuf; -namespace AElf; - -public static class ByteStringHelper +namespace AElf { - public static int Compare(ByteString xValue, ByteString yValue) + + public static class ByteStringHelper { - for (var i = 0; i < Math.Min(xValue.Length, yValue.Length); i++) + public static int Compare(ByteString xValue, ByteString yValue) { - if (xValue[i] > yValue[i]) return 1; - - if (xValue[i] < yValue[i]) return -1; + for (var i = 0; i < Math.Min(xValue.Length, yValue.Length); i++) + { + if (xValue[i] > yValue[i]) return 1; + + if (xValue[i] < yValue[i]) return -1; + } + + return 0; } - - return 0; - } - - public static ByteString FromHexString(string hexString) - { - return ByteString.CopyFrom(ByteArrayHelper.HexStringToByteArray(hexString)); - } -} \ No newline at end of file + + public static ByteString FromHexString(string hexString) + { + return ByteString.CopyFrom(ByteArrayHelper.HexStringToByteArray(hexString)); + } + }} diff --git a/src/AElf.Types/Helper/ChainHelper.cs b/src/AElf.Types/Helper/ChainHelper.cs index ac2666e290..a9f925f5a6 100644 --- a/src/AElf.Types/Helper/ChainHelper.cs +++ b/src/AElf.Types/Helper/ChainHelper.cs @@ -1,42 +1,43 @@ using System; using System.Linq; -namespace AElf; - -public static class ChainHelper +namespace AElf { - public static int GetChainId(long serialNumber) + + public static class ChainHelper { - // For 4 base58 chars use following range (2111 ~ zzzz): - // Max: 57*58*58*58+57*58*58+57*58+57 = 11316496 (zzzz) - // Min: 1*58*58*58+0*58*58+0*58+0 = 195112 (2111) - var validNUmber = (uint)serialNumber.GetHashCode() % 11316496; - if (validNUmber < 195112) - validNUmber += 195112; - - var validNUmberBytes = validNUmber.ToBytes().Skip(1).ToArray(); - - // Use BigInteger(BigEndian) format (bytes size = 3) - Array.Resize(ref validNUmberBytes, 4); - - return validNUmberBytes.ToInt32(false); - } - - public static string ConvertChainIdToBase58(int chainId) - { - // Default chain id is 4 base58 chars, bytes size is 3 - var bytes = chainId.ToBytes(false); - Array.Resize(ref bytes, 3); - return bytes.ToPlainBase58(); - } - - public static int ConvertBase58ToChainId(string base58String) - { - // Use int type to save chain id (4 base58 chars, default is 3 bytes) - var bytes = Base58CheckEncoding.DecodePlain(base58String); - if (bytes.Length < 4) - Array.Resize(ref bytes, 4); - - return bytes.ToInt32(false); - } -} \ No newline at end of file + public static int GetChainId(long serialNumber) + { + // For 4 base58 chars use following range (2111 ~ zzzz): + // Max: 57*58*58*58+57*58*58+57*58+57 = 11316496 (zzzz) + // Min: 1*58*58*58+0*58*58+0*58+0 = 195112 (2111) + var validNUmber = (uint)serialNumber.GetHashCode() % 11316496; + if (validNUmber < 195112) + validNUmber += 195112; + + var validNUmberBytes = validNUmber.ToBytes().Skip(1).ToArray(); + + // Use BigInteger(BigEndian) format (bytes size = 3) + Array.Resize(ref validNUmberBytes, 4); + + return validNUmberBytes.ToInt32(false); + } + + public static string ConvertChainIdToBase58(int chainId) + { + // Default chain id is 4 base58 chars, bytes size is 3 + var bytes = chainId.ToBytes(false); + Array.Resize(ref bytes, 3); + return bytes.ToPlainBase58(); + } + + public static int ConvertBase58ToChainId(string base58String) + { + // Use int type to save chain id (4 base58 chars, default is 3 bytes) + var bytes = Base58CheckEncoding.DecodePlain(base58String); + if (bytes.Length < 4) + Array.Resize(ref bytes, 4); + + return bytes.ToInt32(false); + } + }} diff --git a/src/AElf.Types/Helper/HashHelper.cs b/src/AElf.Types/Helper/HashHelper.cs index 3f830075ce..1482d14871 100644 --- a/src/AElf.Types/Helper/HashHelper.cs +++ b/src/AElf.Types/Helper/HashHelper.cs @@ -1,85 +1,86 @@ -using System.Text; -using AElf.Types; -using Google.Protobuf; - -namespace AElf; - -public class HashHelper -{ - /// - /// Computes hash from a byte array. - /// - /// - /// - public static Hash ComputeFrom(byte[] bytes) - { - return Hash.LoadFromByteArray(bytes.ComputeHash()); - } - - /// - /// Computes hash from a string encoded in UTF8. - /// - /// - /// - public static Hash ComputeFrom(string str) - { - return ComputeFrom(Encoding.UTF8.GetBytes(str)); - } - - /// - /// Computes hash from int32 value. - /// - /// - /// - public static Hash ComputeFrom(int intValue) - { - return ComputeFrom(intValue.ToBytes(false)); - } - - /// - /// Computes hash from int64 value. - /// - /// - /// - public static Hash ComputeFrom(long intValue) - { - return ComputeFrom(intValue.ToBytes(false)); - } - - /// - /// Gets the hash from a Protobuf Message. Its serialized byte array is used for hash calculation. - /// - /// - /// - public static Hash ComputeFrom(IMessage message) - { - return ComputeFrom(message.ToByteArray()); - } - - /// - /// Computes a new hash from two input hashes with bitwise xor operation. - /// - /// - /// - /// - public static Hash XorAndCompute(Hash h1, Hash h2) - { - var newBytes = new byte[AElfConstants.HashByteArrayLength]; - for (var i = 0; i < newBytes.Length; i++) newBytes[i] = (byte)(h1.Value[i] ^ h2.Value[i]); - - return ComputeFrom(newBytes); - } - - public static Hash ConcatAndCompute(Hash hash1, Hash hash2) - { - var bytes = ByteArrayHelper.ConcatArrays(hash1.ToByteArray(), hash2.ToByteArray()); - return ComputeFrom(bytes); - } - - public static Hash ConcatAndCompute(Hash hash1, Hash hash2, Hash hash3) - { - var bytes = ByteArrayHelper.ConcatArrays( - ByteArrayHelper.ConcatArrays(hash1.ToByteArray(), hash2.ToByteArray()), hash3.ToByteArray()); - return ComputeFrom(bytes); - } -} \ No newline at end of file +using System.Text; +using AElf.Types; +using Google.Protobuf; + +namespace AElf +{ + + public class HashHelper + { + /// + /// Computes hash from a byte array. + /// + /// + /// + public static Hash ComputeFrom(byte[] bytes) + { + return Hash.LoadFromByteArray(bytes.ComputeHash()); + } + + /// + /// Computes hash from a string encoded in UTF8. + /// + /// + /// + public static Hash ComputeFrom(string str) + { + return ComputeFrom(Encoding.UTF8.GetBytes(str)); + } + + /// + /// Computes hash from int32 value. + /// + /// + /// + public static Hash ComputeFrom(int intValue) + { + return ComputeFrom(intValue.ToBytes(false)); + } + + /// + /// Computes hash from int64 value. + /// + /// + /// + public static Hash ComputeFrom(long intValue) + { + return ComputeFrom(intValue.ToBytes(false)); + } + + /// + /// Gets the hash from a Protobuf Message. Its serialized byte array is used for hash calculation. + /// + /// + /// + public static Hash ComputeFrom(IMessage message) + { + return ComputeFrom(message.ToByteArray()); + } + + /// + /// Computes a new hash from two input hashes with bitwise xor operation. + /// + /// + /// + /// + public static Hash XorAndCompute(Hash h1, Hash h2) + { + var newBytes = new byte[AElfConstants.HashByteArrayLength]; + for (var i = 0; i < newBytes.Length; i++) newBytes[i] = (byte)(h1.Value[i] ^ h2.Value[i]); + + return ComputeFrom(newBytes); + } + + public static Hash ConcatAndCompute(Hash hash1, Hash hash2) + { + var bytes = ByteArrayHelper.ConcatArrays(hash1.ToByteArray(), hash2.ToByteArray()); + return ComputeFrom(bytes); + } + + public static Hash ConcatAndCompute(Hash hash1, Hash hash2, Hash hash3) + { + var bytes = ByteArrayHelper.ConcatArrays( + ByteArrayHelper.ConcatArrays(hash1.ToByteArray(), hash2.ToByteArray()), hash3.ToByteArray()); + return ComputeFrom(bytes); + } + }} diff --git a/src/AElf.Types/Helper/SerializationHelper.cs b/src/AElf.Types/Helper/SerializationHelper.cs index 3ded44e6b0..d8b19e2765 100644 --- a/src/AElf.Types/Helper/SerializationHelper.cs +++ b/src/AElf.Types/Helper/SerializationHelper.cs @@ -4,111 +4,112 @@ using System.Text; using Google.Protobuf; -namespace AElf; - -public static class SerializationHelper +namespace AElf { - private static readonly Dictionary> _primitiveWriters = - new() - { - { typeof(bool), (stream, value) => stream.WriteBool((bool)value) }, - { typeof(int), (stream, value) => stream.WriteSInt32((int)value) }, - { typeof(uint), (stream, value) => stream.WriteUInt32((uint)value) }, - { typeof(long), (stream, value) => stream.WriteSInt64((long)value) }, - { typeof(ulong), (stream, value) => stream.WriteUInt64((ulong)value) }, - { typeof(byte[]), (stream, value) => stream.WriteBytes(ByteString.CopyFrom((byte[])value)) } - }; - - private static readonly Dictionary> _primitiveReaders = - new() - { - { typeof(bool), stream => stream.ReadBool() }, - { typeof(int), stream => stream.ReadSInt32() }, - { typeof(uint), stream => stream.ReadUInt32() }, - { typeof(long), stream => stream.ReadSInt64() }, - { typeof(ulong), stream => stream.ReadUInt64() }, - { typeof(byte[]), stream => stream.ReadBytes().ToByteArray() } - }; - - private static Func GetPrimitiveSerializer(Type type) + + public static class SerializationHelper { - if (_primitiveWriters.TryGetValue(type, out var writer)) - return value => + private static readonly Dictionary> _primitiveWriters = + new Dictionary>() { - using (var mm = new MemoryStream()) - using (var cos = new CodedOutputStream(mm)) - { - writer(cos, value); - cos.Flush(); - mm.Position = 0; - return mm.ToArray(); - } + { typeof(bool), (stream, value) => stream.WriteBool((bool)value) }, + { typeof(int), (stream, value) => stream.WriteSInt32((int)value) }, + { typeof(uint), (stream, value) => stream.WriteUInt32((uint)value) }, + { typeof(long), (stream, value) => stream.WriteSInt64((long)value) }, + { typeof(ulong), (stream, value) => stream.WriteUInt64((ulong)value) }, + { typeof(byte[]), (stream, value) => stream.WriteBytes(ByteString.CopyFrom((byte[])value)) } }; - - return null; - } - - private static Func GetPrimitiveDeserializer(Type type) - { - if (_primitiveReaders.TryGetValue(type, out var reader)) - return bytes => + + private static readonly Dictionary> _primitiveReaders = + new Dictionary>() { - using (var cis = new CodedInputStream(bytes)) - { - return reader(cis); - } + { typeof(bool), stream => stream.ReadBool() }, + { typeof(int), stream => stream.ReadSInt32() }, + { typeof(uint), stream => stream.ReadUInt32() }, + { typeof(long), stream => stream.ReadSInt64() }, + { typeof(ulong), stream => stream.ReadUInt64() }, + { typeof(byte[]), stream => stream.ReadBytes().ToByteArray() } }; - - return null; - } - - //Done: make a unit test to test Serialize / Deserialize different types such as int,string,long,Block,Hash.... - public static byte[] Serialize(object value) - { - if (value == null) return null; - - var type = value.GetType(); - var primitiveSerializer = GetPrimitiveSerializer(type); - if (primitiveSerializer != null) return primitiveSerializer(value); - - if (type == typeof(string)) return Encoding.UTF8.GetBytes((string)value); - - if (type.IsEnum) return Serialize((int)value); - - if (typeof(IMessage).IsAssignableFrom(type)) + + private static Func GetPrimitiveSerializer(Type type) { - var v = (IMessage)value; - return v.ToByteArray(); + if (_primitiveWriters.TryGetValue(type, out var writer)) + return value => + { + using (var mm = new MemoryStream()) + using (var cos = new CodedOutputStream(mm)) + { + writer(cos, value); + cos.Flush(); + mm.Position = 0; + return mm.ToArray(); + } + }; + + return null; } - - throw new InvalidOperationException($"Invalid type {type}."); - } - - public static T Deserialize(byte[] bytes) - { - if (bytes == null) - return default; - - var type = typeof(T); - var primitiveDeserializer = GetPrimitiveDeserializer(type); - if (primitiveDeserializer != null) + + private static Func GetPrimitiveDeserializer(Type type) { - if (bytes.Length > 0) return (T)primitiveDeserializer(bytes); - - return default; + if (_primitiveReaders.TryGetValue(type, out var reader)) + return bytes => + { + using (var cis = new CodedInputStream(bytes)) + { + return reader(cis); + } + }; + + return null; } - - if (type == typeof(string)) return (T)(object)Encoding.UTF8.GetString(bytes); - - if (type.IsEnum) return (T)(object)Deserialize(bytes); - - if (typeof(IMessage).IsAssignableFrom(type)) + + //Done: make a unit test to test Serialize / Deserialize different types such as int,string,long,Block,Hash.... + public static byte[] Serialize(object value) { - var instance = (IMessage)Activator.CreateInstance(type); - instance.MergeFrom(bytes); - return (T)instance; + if (value == null) return null; + + var type = value.GetType(); + var primitiveSerializer = GetPrimitiveSerializer(type); + if (primitiveSerializer != null) return primitiveSerializer(value); + + if (type == typeof(string)) return Encoding.UTF8.GetBytes((string)value); + + if (type.IsEnum) return Serialize((int)value); + + if (typeof(IMessage).IsAssignableFrom(type)) + { + var v = (IMessage)value; + return v.ToByteArray(); + } + + throw new InvalidOperationException($"Invalid type {type}."); } - - throw new InvalidOperationException($"Invalid type {type}."); - } -} \ No newline at end of file + + public static T Deserialize(byte[] bytes) + { + if (bytes == null) + return default; + + var type = typeof(T); + var primitiveDeserializer = GetPrimitiveDeserializer(type); + if (primitiveDeserializer != null) + { + if (bytes.Length > 0) return (T)primitiveDeserializer(bytes); + + return default; + } + + if (type == typeof(string)) return (T)(object)Encoding.UTF8.GetString(bytes); + + if (type.IsEnum) return (T)(object)Deserialize(bytes); + + if (typeof(IMessage).IsAssignableFrom(type)) + { + var instance = (IMessage)Activator.CreateInstance(type); + instance.MergeFrom(bytes); + return (T)instance; + } + + throw new InvalidOperationException($"Invalid type {type}."); + } + }} diff --git a/src/AElf.Types/IBlockBase.cs b/src/AElf.Types/IBlockBase.cs index c10b81678e..32dceac714 100644 --- a/src/AElf.Types/IBlockBase.cs +++ b/src/AElf.Types/IBlockBase.cs @@ -1,9 +1,10 @@ using System.Collections.Generic; using AElf.Types; -namespace AElf; - -public interface IBlockBase : IHashProvider +namespace AElf { - IEnumerable TransactionIds { get; } -} \ No newline at end of file + + public interface IBlockBase : IHashProvider + { + IEnumerable TransactionIds { get; } + }} diff --git a/src/AElf.Types/IHashProvider.cs b/src/AElf.Types/IHashProvider.cs index 28f6e34690..70ca1cc78d 100644 --- a/src/AElf.Types/IHashProvider.cs +++ b/src/AElf.Types/IHashProvider.cs @@ -1,8 +1,9 @@ using AElf.Types; -namespace AElf; - -public interface IHashProvider +namespace AElf { - Hash GetHash(); -} \ No newline at end of file + + public interface IHashProvider + { + Hash GetHash(); + }} diff --git a/src/AElf.Types/ISmartContract.cs b/src/AElf.Types/ISmartContract.cs index ec5faa9ea7..972ddb1f4e 100644 --- a/src/AElf.Types/ISmartContract.cs +++ b/src/AElf.Types/ISmartContract.cs @@ -1,5 +1,7 @@ -namespace AElf; - -public interface ISmartContract +namespace AElf { + + public interface ISmartContract + { + } } \ No newline at end of file diff --git a/src/AElf.Types/Protobuf/FileDescriptorExtensions.cs b/src/AElf.Types/Protobuf/FileDescriptorExtensions.cs index 5de747a13a..c886ac063b 100644 --- a/src/AElf.Types/Protobuf/FileDescriptorExtensions.cs +++ b/src/AElf.Types/Protobuf/FileDescriptorExtensions.cs @@ -1,13 +1,14 @@ using Google.Protobuf.Reflection; -namespace AElf; - -public static class FileDescriptorExtensions +namespace AElf { - public static string GetIdentity(this FileDescriptor descriptor) + + public static class FileDescriptorExtensions { - if (descriptor.CustomOptions.TryGetString(500001, out var id)) return id; - - return ""; - } -} \ No newline at end of file + public static string GetIdentity(this FileDescriptor descriptor) + { + if (descriptor.CustomOptions.TryGetString(500001, out var id)) return id; + + return ""; + } + }} diff --git a/src/AElf.Types/Types/Address.cs b/src/AElf.Types/Types/Address.cs index a54df92259..536bb492cb 100644 --- a/src/AElf.Types/Types/Address.cs +++ b/src/AElf.Types/Types/Address.cs @@ -1,156 +1,157 @@ -using System; -using Google.Protobuf; - -namespace AElf.Types; - -public partial class Address : ICustomDiagnosticMessage, IComparable
-{ - private string _formattedAddress; - - // Make private to avoid confusion - private Address(byte[] bytes) - { - if (bytes.Length != AElfConstants.AddressHashLength) - throw new ArgumentException("Invalid bytes.", nameof(bytes)); - - Value = ByteString.CopyFrom(bytes); - } - - public int CompareTo(Address that) - { - if (that == null) throw new InvalidOperationException("Cannot compare address when address is null."); - - return CompareAddress(this, that); - } - - /// - /// Used to override IMessage's default string representation. - /// - /// - public string ToDiagnosticString() - { - return $@"""{ToBase58()}"""; - } - - // TODO: It should be an address generation method of KeyPair, instead of Address.FromPublicKey - public static Address FromPublicKey(byte[] bytes) - { - var hash = bytes.ComputeHash().ComputeHash(); - return new Address(hash); - } - - /// - /// Loads the content value from 32-byte long byte array. - /// - /// - /// - /// - public static Address FromBytes(byte[] bytes) - { - if (bytes.Length != AElfConstants.AddressHashLength) - throw new ArgumentException("Invalid bytes.", nameof(bytes)); - - return new Address - { - Value = ByteString.CopyFrom(bytes) - }; - } - - /// - /// Dumps the content value to byte array. - /// - /// - public byte[] ToByteArray() - { - return Value.ToByteArray(); - } - - /// - /// Construct address from base58 encoded string. - /// - /// - /// - public static Address FromBase58(string inputStr) - { - return FromBytes(Base58CheckEncoding.Decode(inputStr)); - } - - /// - /// Converts address into base58 representation. - /// - /// - /// - public string ToBase58() - { - if (_formattedAddress != null) - return _formattedAddress; - - if (Value.Length != AElfConstants.AddressHashLength) - throw new ArgumentException("Invalid address", nameof(Value)); - - var pubKeyHash = Base58CheckEncoding.Encode(Value.ToByteArray()); - return _formattedAddress = pubKeyHash; - } - - public static bool operator ==(Address address1, Address address2) - { - return address1?.Equals(address2) ?? ReferenceEquals(address2, null); - } - - public static bool operator !=(Address address1, Address address2) - { - return !(address1 == address2); - } - - public static bool operator <(Address address1, Address address2) - { - return CompareAddress(address1, address2) < 0; - } - - public static bool operator >(Address address1, Address address2) - { - return CompareAddress(address1, address2) > 0; - } - - private static int CompareAddress(Address address1, Address address2) - { - if (address1 != null) return address2 == null ? 1 : ByteStringHelper.Compare(address1.Value, address2.Value); - - if (address2 == null) return 0; - - return -1; - } -} - -public class ChainAddress -{ - private string _formatted; - - public ChainAddress(Address address, int chainId) - { - Address = address; - ChainId = chainId; - } - - public Address Address { get; } - public int ChainId { get; } - - public static ChainAddress Parse(string chainAddressString, string symbol) - { - var arr = chainAddressString.Split('_'); - if (arr[0] != symbol) throw new ArgumentException("invalid chain address", nameof(chainAddressString)); - - var address = Address.FromBase58(arr[1]); - var chainId = Base58CheckEncoding.Decode(arr[2]).ToInt32(false); - - return new ChainAddress(address, chainId); - } - - public string GetFormatted(string addressPrefix, int chainId) - { - if (_formatted != null) return _formatted; - var addressSuffix = Base58CheckEncoding.Encode(chainId.ToBytes(false)); - _formatted = $"{addressPrefix}_{Address.ToBase58()}_{addressSuffix}"; - return _formatted; - } -} \ No newline at end of file +using System; +using Google.Protobuf; + +namespace AElf.Types +{ + + public partial class Address : ICustomDiagnosticMessage, IComparable
+ { + private string _formattedAddress; + + // Make private to avoid confusion + private Address(byte[] bytes) + { + if (bytes.Length != AElfConstants.AddressHashLength) + throw new ArgumentException("Invalid bytes.", nameof(bytes)); + + Value = ByteString.CopyFrom(bytes); + } + + public int CompareTo(Address that) + { + if (that == null) throw new InvalidOperationException("Cannot compare address when address is null."); + + return CompareAddress(this, that); + } + + /// + /// Used to override IMessage's default string representation. + /// + /// + public string ToDiagnosticString() + { + return $@"""{ToBase58()}"""; + } + + // TODO: It should be an address generation method of KeyPair, instead of Address.FromPublicKey + public static Address FromPublicKey(byte[] bytes) + { + var hash = bytes.ComputeHash().ComputeHash(); + return new Address(hash); + } + + /// + /// Loads the content value from 32-byte long byte array. + /// + /// + /// + /// + public static Address FromBytes(byte[] bytes) + { + if (bytes.Length != AElfConstants.AddressHashLength) + throw new ArgumentException("Invalid bytes.", nameof(bytes)); + + return new Address + { + Value = ByteString.CopyFrom(bytes) + }; + } + + /// + /// Dumps the content value to byte array. + /// + /// + public byte[] ToByteArray() + { + return Value.ToByteArray(); + } + + /// + /// Construct address from base58 encoded string. + /// + /// + /// + public static Address FromBase58(string inputStr) + { + return FromBytes(Base58CheckEncoding.Decode(inputStr)); + } + + /// + /// Converts address into base58 representation. + /// + /// + /// + public string ToBase58() + { + if (_formattedAddress != null) + return _formattedAddress; + + if (Value.Length != AElfConstants.AddressHashLength) + throw new ArgumentException("Invalid address", nameof(Value)); + + var pubKeyHash = Base58CheckEncoding.Encode(Value.ToByteArray()); + return _formattedAddress = pubKeyHash; + } + + public static bool operator ==(Address address1, Address address2) + { + return address1?.Equals(address2) ?? ReferenceEquals(address2, null); + } + + public static bool operator !=(Address address1, Address address2) + { + return !(address1 == address2); + } + + public static bool operator <(Address address1, Address address2) + { + return CompareAddress(address1, address2) < 0; + } + + public static bool operator >(Address address1, Address address2) + { + return CompareAddress(address1, address2) > 0; + } + + private static int CompareAddress(Address address1, Address address2) + { + if (address1 != null) return address2 == null ? 1 : ByteStringHelper.Compare(address1.Value, address2.Value); + + if (address2 == null) return 0; + + return -1; + } + } + + public class ChainAddress + { + private string _formatted; + + public ChainAddress(Address address, int chainId) + { + Address = address; + ChainId = chainId; + } + + public Address Address { get; } + public int ChainId { get; } + + public static ChainAddress Parse(string chainAddressString, string symbol) + { + var arr = chainAddressString.Split('_'); + if (arr[0] != symbol) throw new ArgumentException("invalid chain address", nameof(chainAddressString)); + + var address = Address.FromBase58(arr[1]); + var chainId = Base58CheckEncoding.Decode(arr[2]).ToInt32(false); + + return new ChainAddress(address, chainId); + } + + public string GetFormatted(string addressPrefix, int chainId) + { + if (_formatted != null) return _formatted; + var addressSuffix = Base58CheckEncoding.Encode(chainId.ToBytes(false)); + _formatted = $"{addressPrefix}_{Address.ToBase58()}_{addressSuffix}"; + return _formatted; + } + }} diff --git a/src/AElf.Types/Types/BigIntValue.cs b/src/AElf.Types/Types/BigIntValue.cs index 0a7423f2d4..ae19a0e16a 100644 --- a/src/AElf.Types/Types/BigIntValue.cs +++ b/src/AElf.Types/Types/BigIntValue.cs @@ -3,149 +3,150 @@ using System.Numerics; using Google.Protobuf.WellKnownTypes; -namespace AElf.Types; - -public partial class BigIntValue : IComparable, IComparable +namespace AElf.Types { - public int CompareTo(object obj) - { - if (!(obj is BigIntValue bigInt)) throw new InvalidOperationException(); - - return CompareTo(bigInt); - } - - public int CompareTo(BigIntValue other) - { - if (LessThan(this, other)) return -1; - - if (Value == other.Value) return 0; - - return 1; - } - - public static implicit operator BigIntValue(string str) + + public partial class BigIntValue : IComparable, IComparable { - if (str.All(c => '0' <= c || c <= '9' || c == '_' || c == '-')) + public int CompareTo(object obj) + { + if (!(obj is BigIntValue bigInt)) throw new InvalidOperationException(); + + return CompareTo(bigInt); + } + + public int CompareTo(BigIntValue other) + { + if (LessThan(this, other)) return -1; + + if (Value == other.Value) return 0; + + return 1; + } + + public static implicit operator BigIntValue(string str) + { + if (str.All(c => '0' <= c || c <= '9' || c == '_' || c == '-')) + { + if (str.Contains('-')) + if (!str.StartsWith("-") || str.Count(c => c == '-') > 1) + throw new ArgumentException("Invalid big integer string."); + + str = str.Replace("_", string.Empty); + return new BigIntValue + { + Value = str + }; + } + + throw new ArgumentException("Invalid big integer string."); + } + + public static implicit operator BigIntValue(ushort value) { - if (str.Contains('-')) - if (!str.StartsWith("-") || str.Count(c => c == '-') > 1) - throw new ArgumentException("Invalid big integer string."); - - str = str.Replace("_", string.Empty); return new BigIntValue { - Value = str + Value = value.ToString() }; } - - throw new ArgumentException("Invalid big integer string."); - } - - public static implicit operator BigIntValue(ushort value) - { - return new BigIntValue + + public static implicit operator BigIntValue(short value) { - Value = value.ToString() - }; - } - - public static implicit operator BigIntValue(short value) - { - return new BigIntValue + return new BigIntValue + { + Value = value.ToString() + }; + } + + public static implicit operator BigIntValue(uint value) { - Value = value.ToString() - }; - } - - public static implicit operator BigIntValue(uint value) - { - return new BigIntValue + return new BigIntValue + { + Value = value.ToString() + }; + } + + public static implicit operator BigIntValue(int value) { - Value = value.ToString() - }; - } - - public static implicit operator BigIntValue(int value) - { - return new BigIntValue + return new BigIntValue + { + Value = value.ToString() + }; + } + + public static implicit operator BigIntValue(ulong value) { - Value = value.ToString() - }; - } - - public static implicit operator BigIntValue(ulong value) - { - return new BigIntValue + return new BigIntValue + { + Value = value.ToString() + }; + } + + public static implicit operator BigIntValue(long value) { - Value = value.ToString() - }; - } - - public static implicit operator BigIntValue(long value) - { - return new BigIntValue + return new BigIntValue + { + Value = value.ToString() + }; + } + + public static implicit operator BigIntValue(Int32Value value) { - Value = value.ToString() - }; - } - - public static implicit operator BigIntValue(Int32Value value) - { - return new BigIntValue + return new BigIntValue + { + Value = value.Value.ToString() + }; + } + + public static implicit operator BigIntValue(Int64Value value) { - Value = value.Value.ToString() - }; - } - - public static implicit operator BigIntValue(Int64Value value) - { - return new BigIntValue + return new BigIntValue + { + Value = value.Value.ToString() + }; + } + + public static implicit operator BigInteger(BigIntValue value) { - Value = value.Value.ToString() - }; - } - - public static implicit operator BigInteger(BigIntValue value) - { - return ConvertStringToBigInteger(value.Value); - } - - private static BigInteger ConvertStringToBigInteger(string str) - { - str = str.Replace("_", string.Empty); - if (BigInteger.TryParse(str, out var bigInteger)) return bigInteger; - - throw new ArgumentException("Incorrect arguments."); - } - - private static bool LessThan(in BigIntValue a, in BigIntValue b) - { - var aBigInt = ConvertStringToBigInteger(a.Value); - var bBigInt = ConvertStringToBigInteger(b.Value); - return aBigInt < bBigInt; - } - - #region < <= > >= - - public static bool operator <(in BigIntValue a, in BigIntValue b) - { - return LessThan(in a, in b); - } - - public static bool operator >(in BigIntValue a, in BigIntValue b) - { - return LessThan(in b, in a); - } - - public static bool operator >=(in BigIntValue a, in BigIntValue b) - { - return !LessThan(in a, in b); - } - - public static bool operator <=(in BigIntValue a, in BigIntValue b) - { - return !LessThan(in b, in a); - } - - #endregion -} \ No newline at end of file + return ConvertStringToBigInteger(value.Value); + } + + private static BigInteger ConvertStringToBigInteger(string str) + { + str = str.Replace("_", string.Empty); + if (BigInteger.TryParse(str, out var bigInteger)) return bigInteger; + + throw new ArgumentException("Incorrect arguments."); + } + + private static bool LessThan(in BigIntValue a, in BigIntValue b) + { + var aBigInt = ConvertStringToBigInteger(a.Value); + var bBigInt = ConvertStringToBigInteger(b.Value); + return aBigInt < bBigInt; + } + + #region < <= > >= + + public static bool operator <(in BigIntValue a, in BigIntValue b) + { + return LessThan(in a, in b); + } + + public static bool operator >(in BigIntValue a, in BigIntValue b) + { + return LessThan(in b, in a); + } + + public static bool operator >=(in BigIntValue a, in BigIntValue b) + { + return !LessThan(in a, in b); + } + + public static bool operator <=(in BigIntValue a, in BigIntValue b) + { + return !LessThan(in b, in a); + } + + #endregion + }} diff --git a/src/AElf.Types/Types/BinaryMerkleTree.cs b/src/AElf.Types/Types/BinaryMerkleTree.cs index 664566c6be..d50c6b94fa 100644 --- a/src/AElf.Types/Types/BinaryMerkleTree.cs +++ b/src/AElf.Types/Types/BinaryMerkleTree.cs @@ -2,99 +2,100 @@ using System.Collections.Generic; using System.Linq; -namespace AElf.Types; - -public partial class BinaryMerkleTree +namespace AElf.Types { - public static BinaryMerkleTree FromLeafNodes(IEnumerable leafNodes) - { - var binaryMerkleTree = new BinaryMerkleTree(); - binaryMerkleTree.Nodes.AddRange(leafNodes); - binaryMerkleTree.LeafCount = binaryMerkleTree.Nodes.Count; - GenerateBinaryMerkleTreeNodesWithLeafNodes(binaryMerkleTree.Nodes); - binaryMerkleTree.Root = binaryMerkleTree.Nodes.Any() ? binaryMerkleTree.Nodes.Last() : Hash.Empty; - return binaryMerkleTree; - } - - /// - /// Calculate merkle tree root from leaf node list. - /// - /// - /// For leave {0,1,2,3,4}, the tree should be like - /// 12 - /// 10 ------ 11 - /// 6 -- 7 8 -- 9 - /// 0-1 2-3 4-5 - /// in which {5,9} are copied from {4,8}, and {6,7,8,10,11,12} are calculated. - /// [12] is merkle tree root. - /// - private static void GenerateBinaryMerkleTreeNodesWithLeafNodes(IList leafNodes) + + public partial class BinaryMerkleTree { - if (!leafNodes.Any()) return; - - if (leafNodes.Count % 2 == 1) - leafNodes.Add(leafNodes.Last()); - var nodeToAdd = leafNodes.Count / 2; - var newAdded = 0; - var i = 0; - while (i < leafNodes.Count - 1) + public static BinaryMerkleTree FromLeafNodes(IEnumerable leafNodes) { - var left = leafNodes[i++]; - var right = leafNodes[i++]; - leafNodes.Add(HashHelper.ConcatAndCompute(left, right)); - if (++newAdded != nodeToAdd) - continue; - - // complete this row - if (nodeToAdd % 2 == 1 && nodeToAdd != 1) - { - nodeToAdd++; - leafNodes.Add(leafNodes.Last()); - } - - // start a new row - nodeToAdd /= 2; - newAdded = 0; + var binaryMerkleTree = new BinaryMerkleTree(); + binaryMerkleTree.Nodes.AddRange(leafNodes); + binaryMerkleTree.LeafCount = binaryMerkleTree.Nodes.Count; + GenerateBinaryMerkleTreeNodesWithLeafNodes(binaryMerkleTree.Nodes); + binaryMerkleTree.Root = binaryMerkleTree.Nodes.Any() ? binaryMerkleTree.Nodes.Last() : Hash.Empty; + return binaryMerkleTree; } - } - - public MerklePath GenerateMerklePath(int index) - { - if (Root == null || index >= LeafCount) - throw new InvalidOperationException("Cannot generate merkle path from incomplete binary merkle tree."); - var path = new MerklePath(); - var indexOfFirstNodeInRow = 0; - var nodeCountInRow = LeafCount; - while (index < Nodes.Count - 1) + + /// + /// Calculate merkle tree root from leaf node list. + /// + /// + /// For leave {0,1,2,3,4}, the tree should be like + /// 12 + /// 10 ------ 11 + /// 6 -- 7 8 -- 9 + /// 0-1 2-3 4-5 + /// in which {5,9} are copied from {4,8}, and {6,7,8,10,11,12} are calculated. + /// [12] is merkle tree root. + /// + private static void GenerateBinaryMerkleTreeNodesWithLeafNodes(IList leafNodes) { - Hash neighbor; - bool isLeftNeighbor; - if (index % 2 == 0) + if (!leafNodes.Any()) return; + + if (leafNodes.Count % 2 == 1) + leafNodes.Add(leafNodes.Last()); + var nodeToAdd = leafNodes.Count / 2; + var newAdded = 0; + var i = 0; + while (i < leafNodes.Count - 1) { - // add right neighbor node - neighbor = Nodes[index + 1]; - isLeftNeighbor = false; + var left = leafNodes[i++]; + var right = leafNodes[i++]; + leafNodes.Add(HashHelper.ConcatAndCompute(left, right)); + if (++newAdded != nodeToAdd) + continue; + + // complete this row + if (nodeToAdd % 2 == 1 && nodeToAdd != 1) + { + nodeToAdd++; + leafNodes.Add(leafNodes.Last()); + } + + // start a new row + nodeToAdd /= 2; + newAdded = 0; } - else + } + + public MerklePath GenerateMerklePath(int index) + { + if (Root == null || index >= LeafCount) + throw new InvalidOperationException("Cannot generate merkle path from incomplete binary merkle tree."); + var path = new MerklePath(); + var indexOfFirstNodeInRow = 0; + var nodeCountInRow = LeafCount; + while (index < Nodes.Count - 1) { - // add left neighbor node - neighbor = Nodes[index - 1]; - isLeftNeighbor = true; + Hash neighbor; + bool isLeftNeighbor; + if (index % 2 == 0) + { + // add right neighbor node + neighbor = Nodes[index + 1]; + isLeftNeighbor = false; + } + else + { + // add left neighbor node + neighbor = Nodes[index - 1]; + isLeftNeighbor = true; + } + + path.MerklePathNodes.Add(new MerklePathNode + { + Hash = Hash.LoadFromByteArray(neighbor.ToByteArray()), + IsLeftChildNode = isLeftNeighbor + }); + + nodeCountInRow = nodeCountInRow % 2 == 0 ? nodeCountInRow : nodeCountInRow + 1; + var shift = (index - indexOfFirstNodeInRow) / 2; + indexOfFirstNodeInRow += nodeCountInRow; + index = indexOfFirstNodeInRow + shift; + nodeCountInRow /= 2; } - - path.MerklePathNodes.Add(new MerklePathNode - { - Hash = Hash.LoadFromByteArray(neighbor.ToByteArray()), - IsLeftChildNode = isLeftNeighbor - }); - - nodeCountInRow = nodeCountInRow % 2 == 0 ? nodeCountInRow : nodeCountInRow + 1; - var shift = (index - indexOfFirstNodeInRow) / 2; - indexOfFirstNodeInRow += nodeCountInRow; - index = indexOfFirstNodeInRow + shift; - nodeCountInRow /= 2; + + return path; } - - return path; - } -} \ No newline at end of file + }} diff --git a/src/AElf.Types/Types/Hash.cs b/src/AElf.Types/Types/Hash.cs index 04502710ea..654b193013 100644 --- a/src/AElf.Types/Types/Hash.cs +++ b/src/AElf.Types/Types/Hash.cs @@ -5,133 +5,134 @@ using Google.Protobuf; // ReSharper disable once CheckNamespace -namespace AElf.Types; - -public partial class Hash : ICustomDiagnosticMessage, IComparable, IEnumerable +namespace AElf.Types { - public static readonly Hash Empty = LoadFromByteArray(Enumerable.Range(0, AElfConstants.HashByteArrayLength) - .Select(x => byte.MinValue).ToArray()); - - public int CompareTo(Hash that) - { - if (that == null) - throw new InvalidOperationException("Cannot compare hash when hash is null"); - - return CompareHash(this, that); - } - - /// - /// Used to override IMessage's default string representation. - /// - /// - public string ToDiagnosticString() - { - return $@"""{ToHex()}"""; - } - - public IEnumerator GetEnumerator() - { - return Value.GetEnumerator(); - } - - IEnumerator IEnumerable.GetEnumerator() + + public partial class Hash : ICustomDiagnosticMessage, IComparable, IEnumerable { - return GetEnumerator(); - } - - /// - /// Loads the content value from 32-byte long byte array. - /// - /// - /// - /// - public static Hash LoadFromByteArray(byte[] bytes) - { - if (bytes.Length != AElfConstants.HashByteArrayLength) - throw new ArgumentException("Invalid bytes.", nameof(bytes)); - - return new Hash + public static readonly Hash Empty = LoadFromByteArray(Enumerable.Range(0, AElfConstants.HashByteArrayLength) + .Select(x => byte.MinValue).ToArray()); + + public int CompareTo(Hash that) { - Value = ByteString.CopyFrom(bytes) - }; - } - - /// - /// Loads the content value represented in base64. - /// - /// - /// - public static Hash LoadFromBase64(string base64) - { - var bytes = Convert.FromBase64String(base64); - return LoadFromByteArray(bytes); - } - - /// - /// Loads the content value represented in hex string. - /// - /// - /// - /// - public static Hash LoadFromHex(string hex) - { - var bytes = ByteArrayHelper.HexStringToByteArray(hex); - return LoadFromByteArray(bytes); - } - - /// - /// Dumps the content value to byte array. - /// - /// - public byte[] ToByteArray() - { - return Value.ToByteArray(); - } - - /// - /// Converts hash into hexadecimal representation. - /// - /// - public string ToHex() - { - return Value.ToHex(); - } - - /// - /// Converts hash into int64 value. - /// - /// - public long ToInt64() - { - return ToByteArray().ToInt64(true); - } - - public static bool operator ==(Hash h1, Hash h2) - { - return h1?.Equals(h2) ?? ReferenceEquals(h2, null); - } - - public static bool operator !=(Hash h1, Hash h2) - { - return !(h1 == h2); - } - - public static bool operator <(Hash h1, Hash h2) - { - return CompareHash(h1, h2) < 0; - } - - public static bool operator >(Hash h1, Hash h2) - { - return CompareHash(h1, h2) > 0; - } - - private static int CompareHash(Hash hash1, Hash hash2) - { - if (hash1 != null) return hash2 == null ? 1 : ByteStringHelper.Compare(hash1.Value, hash2.Value); - - if (hash2 == null) return 0; - - return -1; - } -} \ No newline at end of file + if (that == null) + throw new InvalidOperationException("Cannot compare hash when hash is null"); + + return CompareHash(this, that); + } + + /// + /// Used to override IMessage's default string representation. + /// + /// + public string ToDiagnosticString() + { + return $@"""{ToHex()}"""; + } + + public IEnumerator GetEnumerator() + { + return Value.GetEnumerator(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + /// + /// Loads the content value from 32-byte long byte array. + /// + /// + /// + /// + public static Hash LoadFromByteArray(byte[] bytes) + { + if (bytes.Length != AElfConstants.HashByteArrayLength) + throw new ArgumentException("Invalid bytes.", nameof(bytes)); + + return new Hash + { + Value = ByteString.CopyFrom(bytes) + }; + } + + /// + /// Loads the content value represented in base64. + /// + /// + /// + public static Hash LoadFromBase64(string base64) + { + var bytes = Convert.FromBase64String(base64); + return LoadFromByteArray(bytes); + } + + /// + /// Loads the content value represented in hex string. + /// + /// + /// + /// + public static Hash LoadFromHex(string hex) + { + var bytes = ByteArrayHelper.HexStringToByteArray(hex); + return LoadFromByteArray(bytes); + } + + /// + /// Dumps the content value to byte array. + /// + /// + public byte[] ToByteArray() + { + return Value.ToByteArray(); + } + + /// + /// Converts hash into hexadecimal representation. + /// + /// + public string ToHex() + { + return Value.ToHex(); + } + + /// + /// Converts hash into int64 value. + /// + /// + public long ToInt64() + { + return ToByteArray().ToInt64(true); + } + + public static bool operator ==(Hash h1, Hash h2) + { + return h1?.Equals(h2) ?? ReferenceEquals(h2, null); + } + + public static bool operator !=(Hash h1, Hash h2) + { + return !(h1 == h2); + } + + public static bool operator <(Hash h1, Hash h2) + { + return CompareHash(h1, h2) < 0; + } + + public static bool operator >(Hash h1, Hash h2) + { + return CompareHash(h1, h2) > 0; + } + + private static int CompareHash(Hash hash1, Hash hash2) + { + if (hash1 != null) return hash2 == null ? 1 : ByteStringHelper.Compare(hash1.Value, hash2.Value); + + if (hash2 == null) return 0; + + return -1; + } + }} diff --git a/src/AElf.Types/Types/Transaction.cs b/src/AElf.Types/Types/Transaction.cs index 4ba3613afa..7604e83e09 100644 --- a/src/AElf.Types/Types/Transaction.cs +++ b/src/AElf.Types/Types/Transaction.cs @@ -1,44 +1,45 @@ using System; using Google.Protobuf; -namespace AElf.Types; - -public partial class Transaction +namespace AElf.Types { - private Hash _transactionId; - - public Hash GetHash() - { - if (_transactionId == null) - _transactionId = HashHelper.ComputeFrom(GetSignatureData()); - - return _transactionId; - } - - public bool VerifyFields() - { - if (To == null || From == null) - return false; - - if (RefBlockNumber < 0) - return false; - - if (string.IsNullOrEmpty(MethodName)) - return false; - - return true; - } - - private byte[] GetSignatureData() + + public partial class Transaction { - if (!VerifyFields()) - throw new InvalidOperationException($"Invalid transaction: {this}"); - - if (Signature.IsEmpty) - return this.ToByteArray(); - - var transaction = Clone(); - transaction.Signature = ByteString.Empty; - return transaction.ToByteArray(); - } -} \ No newline at end of file + private Hash _transactionId; + + public Hash GetHash() + { + if (_transactionId == null) + _transactionId = HashHelper.ComputeFrom(GetSignatureData()); + + return _transactionId; + } + + public bool VerifyFields() + { + if (To == null || From == null) + return false; + + if (RefBlockNumber < 0) + return false; + + if (string.IsNullOrEmpty(MethodName)) + return false; + + return true; + } + + private byte[] GetSignatureData() + { + if (!VerifyFields()) + throw new InvalidOperationException($"Invalid transaction: {this}"); + + if (Signature.IsEmpty) + return this.ToByteArray(); + + var transaction = Clone(); + transaction.Signature = ByteString.Empty; + return transaction.ToByteArray(); + } + }}