diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..884a698 --- /dev/null +++ b/.gitignore @@ -0,0 +1,221 @@ +# Created by https://www.gitignore.io/api/isua,visualstudio + +#!! ERROR: isua is undefined. Use list command to see defined gitignore types !!# + +### VisualStudio ### +## Ignore Visual Studio temporary files, build results, and +## files generated by popular Visual Studio add-ons. + +# User-specific files +*.suo +*.user +*.userosscache +*.sln.docstates + +# User-specific files (MonoDevelop/Xamarin Studio) +*.userprefs + +# Build results +[Dd]ebug/ +[Dd]ebugPublic/ +[Rr]elease/ +[Rr]eleases/ +x64/ +x86/ +build/ +bld/ +[Bb]in/ +[Oo]bj/ + +# Visual Studio 2015 cache/options directory +.vs/ +# Uncomment if you have tasks that create the project's static files in wwwroot +#wwwroot/ + +# MSTest test Results +[Tt]est[Rr]esult*/ +[Bb]uild[Ll]og.* + +# NUNIT +*.VisualState.xml +TestResult.xml + +# Build Results of an ATL Project +[Dd]ebugPS/ +[Rr]eleasePS/ +dlldata.c + +# DNX +project.lock.json +artifacts/ + +*_i.c +*_p.c +*_i.h +*.ilk +*.meta +*.obj +*.pch +*.pdb +*.pgc +*.pgd +*.rsp +*.sbr +*.tlb +*.tli +*.tlh +*.tmp +*.tmp_proj +*.log +*.vspscc +*.vssscc +.builds +*.pidb +*.svclog +*.scc + +# Chutzpah Test files +_Chutzpah* + +# Visual C++ cache files +ipch/ +*.aps +*.ncb +*.opensdf +*.sdf +*.cachefile + +# Visual Studio profiler +*.psess +*.vsp +*.vspx + +# TFS 2012 Local Workspace +$tf/ + +# Guidance Automation Toolkit +*.gpState + +# ReSharper is a .NET coding add-in +_ReSharper*/ +*.[Rr]e[Ss]harper +*.DotSettings.user + +# JustCode is a .NET coding add-in +.JustCode + +# TeamCity is a build add-in +_TeamCity* + +# DotCover is a Code Coverage Tool +*.dotCover + +# NCrunch +_NCrunch_* +.*crunch*.local.xml +nCrunchTemp_* + +# MightyMoose +*.mm.* +AutoTest.Net/ + +# Web workbench (sass) +.sass-cache/ + +# Installshield output folder +[Ee]xpress/ + +# DocProject is a documentation generator add-in +DocProject/buildhelp/ +DocProject/Help/*.HxT +DocProject/Help/*.HxC +DocProject/Help/*.hhc +DocProject/Help/*.hhk +DocProject/Help/*.hhp +DocProject/Help/Html2 +DocProject/Help/html + +# Click-Once directory +publish/ + +# Publish Web Output +*.[Pp]ublish.xml +*.azurePubxml +# TODO: Comment the next line if you want to checkin your web deploy settings +# but database connection strings (with potential passwords) will be unencrypted +*.pubxml +*.publishproj + +# NuGet Packages +*.nupkg +# The packages folder can be ignored because of Package Restore +**/packages/* +# except build/, which is used as an MSBuild target. +!**/packages/build/ +# Uncomment if necessary however generally it will be regenerated when needed +#!**/packages/repositories.config + +# Windows Azure Build Output +csx/ +*.build.csdef + +# Windows Store app package directory +AppPackages/ + +# Visual Studio cache files +# files ending in .cache can be ignored +*.[Cc]ache +# but keep track of directories ending in .cache +!*.[Cc]ache/ + +# Others +ClientBin/ +[Ss]tyle[Cc]op.* +~$* +*~ +*.dbmdl +*.dbproj.schemaview +*.pfx +*.publishsettings +node_modules/ +orleans.codegen.cs + +# RIA/Silverlight projects +Generated_Code/ + +# Backup & report files from converting an old project file +# to a newer Visual Studio version. Backup files are not needed, +# because we have git ;-) +_UpgradeReport_Files/ +Backup*/ +UpgradeLog*.XML +UpgradeLog*.htm + +# SQL Server files +*.mdf +*.ldf + +# Business Intelligence projects +*.rdl.data +*.bim.layout +*.bim_*.settings + +# Microsoft Fakes +FakesAssemblies/ + +# Node.js Tools for Visual Studio +.ntvs_analysis.dat + +# Visual Studio 6 build log +*.plg + +# Visual Studio 6 workspace options file +*.opt + +# Visual Studio LightSwitch build output +**/*.HTMLClient/GeneratedArtifacts +**/*.DesktopClient/GeneratedArtifacts +**/*.DesktopClient/ModelManifest.xml +**/*.Server/GeneratedArtifacts +**/*.Server/ModelManifest.xml +_Pvt_Extensions diff --git a/TLSharp.Core/Auth/Authenticator.cs b/TLSharp.Core/Auth/Authenticator.cs new file mode 100644 index 0000000..b5e9969 --- /dev/null +++ b/TLSharp.Core/Auth/Authenticator.cs @@ -0,0 +1,37 @@ +using System.Threading.Tasks; +using TLSharp.Core.Network; + +namespace TLSharp.Core.Auth +{ + public static class Authenticator + { + public static async Task DoAuthentication(TcpTransport transport) + { + var sender = new MtProtoPlainSender(transport); + var step1 = new Step1_PQRequest(); + + await sender.Send(step1.ToBytes()); + var step1Response = step1.FromBytes(await sender.Recieve()); + + var step2 = new Step2_DHExchange(); + await sender.Send(step2.ToBytes( + step1Response.Nonce, + step1Response.ServerNonce, + step1Response.Fingerprints, + step1Response.Pq)); + + var step2Response = step2.FromBytes(await sender.Recieve()); + + var step3 = new Step3_CompleteDHExchange(); + await sender.Send(step3.ToBytes( + step2Response.Nonce, + step2Response.ServerNonce, + step2Response.NewNonce, + step2Response.EncryptedAnswer)); + + var step3Response = step3.FromBytes(await sender.Recieve()); + + return step3Response; + } + } +} diff --git a/TLSharp.Core/Auth/Step1_PQRequest.cs b/TLSharp.Core/Auth/Step1_PQRequest.cs new file mode 100644 index 0000000..6f0f62b --- /dev/null +++ b/TLSharp.Core/Auth/Step1_PQRequest.cs @@ -0,0 +1,96 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Linq; +using TLSharp.Core.MTProto; +using TLSharp.Core.MTProto.Crypto; + +namespace TLSharp.Core.Auth +{ + public class Step1_Response + { + public byte[] Nonce { get; set; } + public byte[] ServerNonce { get; set; } + public BigInteger Pq { get; set; } + public List Fingerprints { get; set; } + } + + public class Step1_PQRequest + { + private byte[] nonce; + + public Step1_PQRequest() + { + nonce = new byte[16]; + } + + public byte[] ToBytes() + { + new Random().NextBytes(nonce); + const int constructorNumber = 0x60469778; + + using (var memoryStream = new MemoryStream()) + { + using (var binaryWriter = new BinaryWriter(memoryStream)) + { + binaryWriter.Write(constructorNumber); + binaryWriter.Write(nonce); + + return memoryStream.ToArray(); + } + } + } + + public Step1_Response FromBytes(byte[] bytes) + { + var fingerprints = new List(); + + using (var memoryStream = new MemoryStream(bytes, false)) + { + using (var binaryReader = new BinaryReader(memoryStream)) + { + const int responseConstructorNumber = 0x05162463; + var responseCode = binaryReader.ReadInt32(); + if (responseCode != responseConstructorNumber) + { + throw new InvalidOperationException($"invalid response code: {responseCode}"); + } + + var nonceFromServer = binaryReader.ReadBytes(16); + + if (!nonceFromServer.SequenceEqual(nonce)) + { + throw new InvalidOperationException("invalid nonce from server"); + } + + var serverNonce = binaryReader.ReadBytes(16); + + byte[] pqbytes = Serializers.Bytes.read(binaryReader); + var pq = new BigInteger(1, pqbytes); + + var vectorId = binaryReader.ReadInt32(); + const int vectorConstructorNumber = 0x1cb5c415; + if (vectorId != vectorConstructorNumber) + { + throw new InvalidOperationException($"Invalid vector constructor number {vectorId}"); + } + + var fingerprintCount = binaryReader.ReadInt32(); + for (var i = 0; i < fingerprintCount; i++) + { + byte[] fingerprint = binaryReader.ReadBytes(8); + fingerprints.Add(fingerprint); + } + + return new Step1_Response + { + Fingerprints = fingerprints, + Nonce = nonce, + Pq = pq, + ServerNonce = serverNonce + }; + } + } + } + } +} diff --git a/TLSharp.Core/Auth/Step2_DHExchange.cs b/TLSharp.Core/Auth/Step2_DHExchange.cs new file mode 100644 index 0000000..3dd7503 --- /dev/null +++ b/TLSharp.Core/Auth/Step2_DHExchange.cs @@ -0,0 +1,142 @@ +using System; +using System.Collections.Generic; +using System.IO; +using TLSharp.Core.MTProto; +using TLSharp.Core.MTProto.Crypto; + +namespace TLSharp.Core.Auth +{ + public class Step2_Response + { + public byte[] Nonce { get; set; } + public byte[] ServerNonce { get; set; } + public byte[] NewNonce { get; set; } + public byte[] EncryptedAnswer { get; set; } + } + + public class Step2_DHExchange + { + public byte[] newNonce; + + public Step2_DHExchange() + { + newNonce = new byte[32]; + } + + public byte[] ToBytes(byte[] nonce, byte[] serverNonce, List fingerprints, BigInteger pq) + { + new Random().NextBytes(newNonce); + + var pqPair = Factorizator.Factorize(pq); + + byte[] reqDhParamsBytes; + + using (MemoryStream pqInnerData = new MemoryStream(255)) + { + using (BinaryWriter pqInnerDataWriter = new BinaryWriter(pqInnerData)) + { + pqInnerDataWriter.Write(0x83c95aec); // pq_inner_data + Serializers.Bytes.write(pqInnerDataWriter, pq.ToByteArrayUnsigned()); + Serializers.Bytes.write(pqInnerDataWriter, pqPair.Min.ToByteArrayUnsigned()); + Serializers.Bytes.write(pqInnerDataWriter, pqPair.Max.ToByteArrayUnsigned()); + pqInnerDataWriter.Write(nonce); + pqInnerDataWriter.Write(serverNonce); + pqInnerDataWriter.Write(newNonce); + + byte[] ciphertext = null; + byte[] targetFingerprint = null; + foreach (byte[] fingerprint in fingerprints) + { + ciphertext = RSA.Encrypt(BitConverter.ToString(fingerprint).Replace("-", string.Empty), + pqInnerData.GetBuffer(), 0, (int)pqInnerData.Position); + if (ciphertext != null) + { + targetFingerprint = fingerprint; + break; + } + } + + if (ciphertext == null) + { + throw new InvalidOperationException( + String.Format("not found valid key for fingerprints: {0}", String.Join(", ", fingerprints))); + } + + using (MemoryStream reqDHParams = new MemoryStream(1024)) + { + using (BinaryWriter reqDHParamsWriter = new BinaryWriter(reqDHParams)) + { + reqDHParamsWriter.Write(0xd712e4be); // req_dh_params + reqDHParamsWriter.Write(nonce); + reqDHParamsWriter.Write(serverNonce); + Serializers.Bytes.write(reqDHParamsWriter, pqPair.Min.ToByteArrayUnsigned()); + Serializers.Bytes.write(reqDHParamsWriter, pqPair.Max.ToByteArrayUnsigned()); + reqDHParamsWriter.Write(targetFingerprint); + Serializers.Bytes.write(reqDHParamsWriter, ciphertext); + + reqDhParamsBytes = reqDHParams.ToArray(); + } + } + } + return reqDhParamsBytes; + } + } + + public Step2_Response FromBytes(byte[] response) + { + byte[] encryptedAnswer; + + using (MemoryStream responseStream = new MemoryStream(response, false)) + { + using (BinaryReader responseReader = new BinaryReader(responseStream)) + { + uint responseCode = responseReader.ReadUInt32(); + + if (responseCode == 0x79cb045d) + { + // server_DH_params_fail + throw new InvalidOperationException("server_DH_params_fail: TODO"); + } + + if (responseCode != 0xd0e8075c) + { + throw new InvalidOperationException($"invalid response code: {responseCode}"); + } + + byte[] nonceFromServer = responseReader.ReadBytes(16); + + // TODO:! + /* + if (!nonceFromServer.SequenceEqual(nonce)) + { + logger.debug("invalid nonce from server"); + return null; + } + */ + + + byte[] serverNonceFromServer = responseReader.ReadBytes(16); + + // TODO: ! + /* + if (!serverNonceFromServer.SequenceEqual(serverNonce)) + { + logger.error("invalid server nonce from server"); + return null; + } + */ + + encryptedAnswer = Serializers.Bytes.read(responseReader); + + return new Step2_Response() + { + EncryptedAnswer = encryptedAnswer, + ServerNonce = serverNonceFromServer, + Nonce = nonceFromServer, + NewNonce = newNonce + }; + } + } + } + } +} diff --git a/TLSharp.Core/Auth/Step3_CompleteDHExchange.cs b/TLSharp.Core/Auth/Step3_CompleteDHExchange.cs new file mode 100644 index 0000000..a3c27d8 --- /dev/null +++ b/TLSharp.Core/Auth/Step3_CompleteDHExchange.cs @@ -0,0 +1,209 @@ +using System; +using System.IO; +using System.Linq; +using System.Security.Cryptography; +using TLSharp.Core.MTProto; +using TLSharp.Core.MTProto.Crypto; + +namespace TLSharp.Core.Auth +{ + public class Step3_Response + { + public AuthKey AuthKey { get; set; } + public int TimeOffset { get; set; } + + } + + public class Step3_CompleteDHExchange + { + private BigInteger _gab; + private byte[] newNonce; + private int timeOffset; + + public byte[] ToBytes(byte[] nonce, byte[] serverNonce, byte[] newNonce, byte[] encryptedAnswer) + { + this.newNonce = newNonce; + AESKeyData key = AES.GenerateKeyDataFromNonces(serverNonce, newNonce); + byte[] plaintextAnswer = AES.DecryptAES(key, encryptedAnswer); + + // logger.debug("plaintext answer: {0}", BitConverter.ToString(plaintextAnswer)); + + int g; + BigInteger dhPrime; + BigInteger ga; + + using (MemoryStream dhInnerData = new MemoryStream(plaintextAnswer)) + { + using (BinaryReader dhInnerDataReader = new BinaryReader(dhInnerData)) + { + byte[] hashsum = dhInnerDataReader.ReadBytes(20); + uint code = dhInnerDataReader.ReadUInt32(); + if (code != 0xb5890dba) + { + throw new InvalidOperationException($"invalid dh_inner_data code: {code}"); + } + + // logger.debug("valid code"); + + byte[] nonceFromServer1 = dhInnerDataReader.ReadBytes(16); + if (!nonceFromServer1.SequenceEqual(nonce)) + { + throw new InvalidOperationException("invalid nonce in encrypted answer"); + } + + // logger.debug("valid nonce"); + + byte[] serverNonceFromServer1 = dhInnerDataReader.ReadBytes(16); + if (!serverNonceFromServer1.SequenceEqual(serverNonce)) + { + throw new InvalidOperationException("invalid server nonce in encrypted answer"); + } + + // logger.debug("valid server nonce"); + + g = dhInnerDataReader.ReadInt32(); + dhPrime = new BigInteger(1, Serializers.Bytes.read(dhInnerDataReader)); + ga = new BigInteger(1, Serializers.Bytes.read(dhInnerDataReader)); + + int serverTime = dhInnerDataReader.ReadInt32(); + timeOffset = serverTime - (int)(Convert.ToInt64((DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalMilliseconds) / 1000); + + // logger.debug("g: {0}, dhprime: {1}, ga: {2}", g, dhPrime, ga); + } + } + + BigInteger b = new BigInteger(2048, new Random()); + BigInteger gb = BigInteger.ValueOf(g).ModPow(b, dhPrime); + _gab = ga.ModPow(b, dhPrime); + + // logger.debug("gab: {0}", gab); + + // prepare client dh inner data + byte[] clientDHInnerDataBytes; + using (MemoryStream clientDhInnerData = new MemoryStream()) + { + using (BinaryWriter clientDhInnerDataWriter = new BinaryWriter(clientDhInnerData)) + { + clientDhInnerDataWriter.Write(0x6643b654); // client_dh_inner_data + clientDhInnerDataWriter.Write(nonce); + clientDhInnerDataWriter.Write(serverNonce); + clientDhInnerDataWriter.Write((long)0); // TODO: retry_id + Serializers.Bytes.write(clientDhInnerDataWriter, gb.ToByteArrayUnsigned()); + + using (MemoryStream clientDhInnerDataWithHash = new MemoryStream()) + { + using (BinaryWriter clientDhInnerDataWithHashWriter = new BinaryWriter(clientDhInnerDataWithHash)) + { + using (SHA1 sha1 = new SHA1Managed()) + { + clientDhInnerDataWithHashWriter.Write(sha1.ComputeHash(clientDhInnerData.GetBuffer(), 0, (int)clientDhInnerData.Position)); + clientDhInnerDataWithHashWriter.Write(clientDhInnerData.GetBuffer(), 0, (int)clientDhInnerData.Position); + clientDHInnerDataBytes = clientDhInnerDataWithHash.ToArray(); + } + } + } + } + } + + // logger.debug("client dh inner data papared len {0}: {1}", clientDHInnerDataBytes.Length, BitConverter.ToString(clientDHInnerDataBytes).Replace("-", "")); + + // encryption + byte[] clientDhInnerDataEncryptedBytes = AES.EncryptAES(key, clientDHInnerDataBytes); + + // logger.debug("inner data encrypted {0}: {1}", clientDhInnerDataEncryptedBytes.Length, BitConverter.ToString(clientDhInnerDataEncryptedBytes).Replace("-", "")); + + // prepare set_client_dh_params + byte[] setclientDhParamsBytes; + using (MemoryStream setClientDhParams = new MemoryStream()) + { + using (BinaryWriter setClientDhParamsWriter = new BinaryWriter(setClientDhParams)) + { + setClientDhParamsWriter.Write(0xf5045f1f); + setClientDhParamsWriter.Write(nonce); + setClientDhParamsWriter.Write(serverNonce); + Serializers.Bytes.write(setClientDhParamsWriter, clientDhInnerDataEncryptedBytes); + + setclientDhParamsBytes = setClientDhParams.ToArray(); + } + } + + // logger.debug("set client dh params prepared: {0}", BitConverter.ToString(setclientDhParamsBytes)); + + return setclientDhParamsBytes; + } + + public Step3_Response FromBytes(byte[] response) + { + using (MemoryStream responseStream = new MemoryStream(response)) + { + using (BinaryReader responseReader = new BinaryReader(responseStream)) + { + uint code = responseReader.ReadUInt32(); + if (code == 0x3bcbf734) + { // dh_gen_ok + //logger.debug("dh_gen_ok"); + + + byte[] nonceFromServer = responseReader.ReadBytes(16); + // TODO + /* + if (!nonceFromServer.SequenceEqual(nonce)) + { + logger.error("invalid nonce"); + return null; + } + */ + + byte[] serverNonceFromServer = responseReader.ReadBytes(16); + + // TODO: + + /* + if (!serverNonceFromServer.SequenceEqual(serverNonce)) + { + logger.error("invalid server nonce"); + return null; + } + */ + + byte[] newNonceHash1 = responseReader.ReadBytes(16); + //logger.debug("new nonce hash 1: {0}", BitConverter.ToString(newNonceHash1)); + + AuthKey authKey = new AuthKey(_gab); + + byte[] newNonceHashCalculated = authKey.CalcNewNonceHash(newNonce, 1); + + if (!newNonceHash1.SequenceEqual(newNonceHashCalculated)) + { + throw new InvalidOperationException("invalid new nonce hash"); + } + + //logger.info("generated new auth key: {0}", gab); + //logger.info("saving time offset: {0}", timeOffset); + //TelegramSession.Instance.TimeOffset = timeOffset; + + return new Step3_Response() + { + AuthKey = authKey, + TimeOffset = timeOffset + }; + } + else if (code == 0x46dc1fb9) + { // dh_gen_retry + throw new NotImplementedException("dh_gen_retry"); + + } + else if (code == 0xa69dae02) + { + // dh_gen_fail + throw new NotImplementedException("dh_gen_fail"); + } + else + { + throw new InvalidOperationException($"dh_gen unknown: {code}"); + } + } + } + } + } +} diff --git a/TLSharp.Core/MTProto/Crypto/AES.cs b/TLSharp.Core/MTProto/Crypto/AES.cs new file mode 100644 index 0000000..662bdaf --- /dev/null +++ b/TLSharp.Core/MTProto/Crypto/AES.cs @@ -0,0 +1,770 @@ +using System; +using System.IO; +using System.Security.Cryptography; + +namespace TLSharp.Core.MTProto.Crypto +{ + public class AESKeyData { + private readonly byte[] key; + private readonly byte[] iv; + + public AESKeyData(byte[] key, byte[] iv) { + this.key = key; + this.iv = iv; + } + + public byte[] Key { + get { return key; } + } + + public byte[] Iv { + get { return iv; } + } + } + + public class AES { + public static byte[] DecryptWithNonces(byte[] data, byte[] serverNonce, byte[] newNonce) { + using(SHA1 hash = new SHA1Managed()) { + var nonces = new byte[48]; + + newNonce.CopyTo(nonces, 0); + serverNonce.CopyTo(nonces, 32); + byte[] hash1 = hash.ComputeHash(nonces); + + serverNonce.CopyTo(nonces, 0); + newNonce.CopyTo(nonces, 16); + byte[] hash2 = hash.ComputeHash(nonces); + + nonces = new byte[64]; + newNonce.CopyTo(nonces, 0); + newNonce.CopyTo(nonces, 32); + byte[] hash3 = hash.ComputeHash(nonces); + + using(var keyBuffer = new MemoryStream(32)) + using(var ivBuffer = new MemoryStream(32)) { + keyBuffer.Write(hash1, 0, hash1.Length); + keyBuffer.Write(hash2, 0, 12); + + ivBuffer.Write(hash2, 12, 8); + ivBuffer.Write(hash3, 0, hash3.Length); + ivBuffer.Write(newNonce, 0, 4); + + return DecryptIGE(data, keyBuffer.ToArray(), ivBuffer.ToArray()); + } + } + } + + public static AESKeyData GenerateKeyDataFromNonces(byte[] serverNonce, byte[] newNonce) { + using (SHA1 hash = new SHA1Managed()) { + var nonces = new byte[48]; + + newNonce.CopyTo(nonces, 0); + serverNonce.CopyTo(nonces, 32); + byte[] hash1 = hash.ComputeHash(nonces); + + serverNonce.CopyTo(nonces, 0); + newNonce.CopyTo(nonces, 16); + byte[] hash2 = hash.ComputeHash(nonces); + + nonces = new byte[64]; + newNonce.CopyTo(nonces, 0); + newNonce.CopyTo(nonces, 32); + byte[] hash3 = hash.ComputeHash(nonces); + + using (var keyBuffer = new MemoryStream(32)) + using (var ivBuffer = new MemoryStream(32)) { + keyBuffer.Write(hash1, 0, hash1.Length); + keyBuffer.Write(hash2, 0, 12); + + ivBuffer.Write(hash2, 12, 8); + ivBuffer.Write(hash3, 0, hash3.Length); + ivBuffer.Write(newNonce, 0, 4); + + return new AESKeyData(keyBuffer.ToArray(), ivBuffer.ToArray()); + } + } + } + + public static byte[] DecryptAES(AESKeyData key, byte[] ciphertext) { + return DecryptIGE(ciphertext, key.Key, key.Iv); + } + + public static byte[] EncryptAES(AESKeyData key, byte[] plaintext) { + return EncryptIGE(plaintext, key.Key, key.Iv); + } + + public static byte[] DecryptIGE(byte[] ciphertext, byte[] key, byte[] iv) { + var iv1 = new byte[iv.Length/2]; + var iv2 = new byte[iv.Length/2]; + + Array.Copy(iv, 0, iv1, 0, iv1.Length); + Array.Copy(iv, iv1.Length, iv2, 0, iv2.Length); + + AesEngine aes = new AesEngine(); + aes.Init(false, key); + + byte[] plaintext = new byte[ciphertext.Length]; + int blocksCount = ciphertext.Length/16; + + byte[] ciphertextBlock = new byte[16]; + byte[] plaintextBlock = new byte[16]; + for(int blockIndex = 0; blockIndex < blocksCount; blockIndex++) { + for(int i = 0; i < 16; i++) { + ciphertextBlock[i] = (byte) (ciphertext[blockIndex*16 + i] ^ iv2[i]); + } + + aes.ProcessBlock(ciphertextBlock, 0, plaintextBlock, 0); + + for(int i = 0; i < 16; i++) { + plaintextBlock[i] ^= iv1[i]; + } + + Array.Copy(ciphertext, blockIndex * 16, iv1, 0, 16); + Array.Copy(plaintextBlock, 0, iv2, 0, 16); + + Array.Copy(plaintextBlock, 0, plaintext, blockIndex * 16, 16); + } + + return plaintext; + } + + public static byte[] EncryptIGE(byte[] originPlaintext, byte[] key, byte[] iv) { + + byte[] plaintext; + using (MemoryStream plaintextBuffer = new MemoryStream(originPlaintext.Length + 40)) { + //using(SHA1 hash = new SHA1Managed()) { + //byte[] hashsum = hash.ComputeHash(originPlaintext); + //plaintextBuffer.Write(hashsum, 0, hashsum.Length); + plaintextBuffer.Write(originPlaintext, 0, originPlaintext.Length); + while(plaintextBuffer.Position%16 != 0) { + plaintextBuffer.WriteByte(0); // TODO: random padding + } + plaintext = plaintextBuffer.ToArray(); + } + + var iv1 = new byte[iv.Length/2]; + var iv2 = new byte[iv.Length/2]; + + Array.Copy(iv, 0, iv1, 0, iv1.Length); + Array.Copy(iv, iv1.Length, iv2, 0, iv2.Length); + + AesEngine aes = new AesEngine(); + aes.Init(true, key); + + int blocksCount = plaintext.Length/16; + byte[] ciphertext = new byte[plaintext.Length]; + + byte[] ciphertextBlock = new byte[16]; + byte[] plaintextBlock = new byte[16]; + for(int blockIndex = 0; blockIndex < blocksCount; blockIndex++) { + Array.Copy(plaintext, 16*blockIndex, plaintextBlock, 0, 16); + + //logger.info("plaintext block: {0} xor {1}", BitConverter.ToString(plaintextBlock).Replace("-", ""), BitConverter.ToString(iv1).Replace("-", "")); + + for(int i = 0; i < 16; i++) { + plaintextBlock[i] ^= iv1[i]; + } + + //logger.info("xored plaintext: {0}", BitConverter.ToString(plaintextBlock).Replace("-", "")); + + aes.ProcessBlock(plaintextBlock, 0, ciphertextBlock, 0); + + //logger.info("encrypted plaintext: {0} xor {1}", BitConverter.ToString(ciphertextBlock).Replace("-", ""), BitConverter.ToString(iv2).Replace("-", "")); + + for(int i = 0; i < 16; i++) { + ciphertextBlock[i] ^= iv2[i]; + } + + //logger.info("xored ciphertext: {0}", BitConverter.ToString(ciphertextBlock).Replace("-", "")); + + Array.Copy(ciphertextBlock, 0, iv1, 0, 16); + Array.Copy(plaintext, 16*blockIndex, iv2, 0, 16); + + Array.Copy(ciphertextBlock, 0, ciphertext, blockIndex * 16, 16); + } + + return ciphertext; + } + + public static byte[] XOR(byte[] buffer1, byte[] buffer2) { + var result = new byte[buffer1.Length]; + for(int i = 0; i < buffer1.Length; i++) + result[i] = (byte) (buffer1[i] ^ buffer2[i]); + return result; + } + + + } + + + // AES engine implementation + + public class AesEngine { + // The S box + private const uint m1 = 0x80808080; + private const uint m2 = 0x7f7f7f7f; + private const uint m3 = 0x0000001b; + private const int BLOCK_SIZE = 16; + + private static readonly byte[] S = { + 99, 124, 119, 123, 242, 107, 111, 197, + 48, 1, 103, 43, 254, 215, 171, 118, + 202, 130, 201, 125, 250, 89, 71, 240, + 173, 212, 162, 175, 156, 164, 114, 192, + 183, 253, 147, 38, 54, 63, 247, 204, + 52, 165, 229, 241, 113, 216, 49, 21, + 4, 199, 35, 195, 24, 150, 5, 154, + 7, 18, 128, 226, 235, 39, 178, 117, + 9, 131, 44, 26, 27, 110, 90, 160, + 82, 59, 214, 179, 41, 227, 47, 132, + 83, 209, 0, 237, 32, 252, 177, 91, + 106, 203, 190, 57, 74, 76, 88, 207, + 208, 239, 170, 251, 67, 77, 51, 133, + 69, 249, 2, 127, 80, 60, 159, 168, + 81, 163, 64, 143, 146, 157, 56, 245, + 188, 182, 218, 33, 16, 255, 243, 210, + 205, 12, 19, 236, 95, 151, 68, 23, + 196, 167, 126, 61, 100, 93, 25, 115, + 96, 129, 79, 220, 34, 42, 144, 136, + 70, 238, 184, 20, 222, 94, 11, 219, + 224, 50, 58, 10, 73, 6, 36, 92, + 194, 211, 172, 98, 145, 149, 228, 121, + 231, 200, 55, 109, 141, 213, 78, 169, + 108, 86, 244, 234, 101, 122, 174, 8, + 186, 120, 37, 46, 28, 166, 180, 198, + 232, 221, 116, 31, 75, 189, 139, 138, + 112, 62, 181, 102, 72, 3, 246, 14, + 97, 53, 87, 185, 134, 193, 29, 158, + 225, 248, 152, 17, 105, 217, 142, 148, + 155, 30, 135, 233, 206, 85, 40, 223, + 140, 161, 137, 13, 191, 230, 66, 104, + 65, 153, 45, 15, 176, 84, 187, 22 + }; + + // The inverse S-box + private static readonly byte[] Si = { + 82, 9, 106, 213, 48, 54, 165, 56, + 191, 64, 163, 158, 129, 243, 215, 251, + 124, 227, 57, 130, 155, 47, 255, 135, + 52, 142, 67, 68, 196, 222, 233, 203, + 84, 123, 148, 50, 166, 194, 35, 61, + 238, 76, 149, 11, 66, 250, 195, 78, + 8, 46, 161, 102, 40, 217, 36, 178, + 118, 91, 162, 73, 109, 139, 209, 37, + 114, 248, 246, 100, 134, 104, 152, 22, + 212, 164, 92, 204, 93, 101, 182, 146, + 108, 112, 72, 80, 253, 237, 185, 218, + 94, 21, 70, 87, 167, 141, 157, 132, + 144, 216, 171, 0, 140, 188, 211, 10, + 247, 228, 88, 5, 184, 179, 69, 6, + 208, 44, 30, 143, 202, 63, 15, 2, + 193, 175, 189, 3, 1, 19, 138, 107, + 58, 145, 17, 65, 79, 103, 220, 234, + 151, 242, 207, 206, 240, 180, 230, 115, + 150, 172, 116, 34, 231, 173, 53, 133, + 226, 249, 55, 232, 28, 117, 223, 110, + 71, 241, 26, 113, 29, 41, 197, 137, + 111, 183, 98, 14, 170, 24, 190, 27, + 252, 86, 62, 75, 198, 210, 121, 32, + 154, 219, 192, 254, 120, 205, 90, 244, + 31, 221, 168, 51, 136, 7, 199, 49, + 177, 18, 16, 89, 39, 128, 236, 95, + 96, 81, 127, 169, 25, 181, 74, 13, + 45, 229, 122, 159, 147, 201, 156, 239, + 160, 224, 59, 77, 174, 42, 245, 176, + 200, 235, 187, 60, 131, 83, 153, 97, + 23, 43, 4, 126, 186, 119, 214, 38, + 225, 105, 20, 99, 85, 33, 12, 125 + }; + + // vector used in calculating key schedule (powers of x in GF(256)) + private static readonly byte[] rcon = { + 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1b, 0x36, 0x6c, 0xd8, 0xab, 0x4d, 0x9a, + 0x2f, 0x5e, 0xbc, 0x63, 0xc6, 0x97, 0x35, 0x6a, 0xd4, 0xb3, 0x7d, 0xfa, 0xef, 0xc5, 0x91 + }; + + // precomputation tables of calculations for rounds + private static readonly uint[] T0 = { + 0xa56363c6, 0x847c7cf8, 0x997777ee, 0x8d7b7bf6, 0x0df2f2ff, + 0xbd6b6bd6, 0xb16f6fde, 0x54c5c591, 0x50303060, 0x03010102, + 0xa96767ce, 0x7d2b2b56, 0x19fefee7, 0x62d7d7b5, 0xe6abab4d, + 0x9a7676ec, 0x45caca8f, 0x9d82821f, 0x40c9c989, 0x877d7dfa, + 0x15fafaef, 0xeb5959b2, 0xc947478e, 0x0bf0f0fb, 0xecadad41, + 0x67d4d4b3, 0xfda2a25f, 0xeaafaf45, 0xbf9c9c23, 0xf7a4a453, + 0x967272e4, 0x5bc0c09b, 0xc2b7b775, 0x1cfdfde1, 0xae93933d, + 0x6a26264c, 0x5a36366c, 0x413f3f7e, 0x02f7f7f5, 0x4fcccc83, + 0x5c343468, 0xf4a5a551, 0x34e5e5d1, 0x08f1f1f9, 0x937171e2, + 0x73d8d8ab, 0x53313162, 0x3f15152a, 0x0c040408, 0x52c7c795, + 0x65232346, 0x5ec3c39d, 0x28181830, 0xa1969637, 0x0f05050a, + 0xb59a9a2f, 0x0907070e, 0x36121224, 0x9b80801b, 0x3de2e2df, + 0x26ebebcd, 0x6927274e, 0xcdb2b27f, 0x9f7575ea, 0x1b090912, + 0x9e83831d, 0x742c2c58, 0x2e1a1a34, 0x2d1b1b36, 0xb26e6edc, + 0xee5a5ab4, 0xfba0a05b, 0xf65252a4, 0x4d3b3b76, 0x61d6d6b7, + 0xceb3b37d, 0x7b292952, 0x3ee3e3dd, 0x712f2f5e, 0x97848413, + 0xf55353a6, 0x68d1d1b9, 0x00000000, 0x2cededc1, 0x60202040, + 0x1ffcfce3, 0xc8b1b179, 0xed5b5bb6, 0xbe6a6ad4, 0x46cbcb8d, + 0xd9bebe67, 0x4b393972, 0xde4a4a94, 0xd44c4c98, 0xe85858b0, + 0x4acfcf85, 0x6bd0d0bb, 0x2aefefc5, 0xe5aaaa4f, 0x16fbfbed, + 0xc5434386, 0xd74d4d9a, 0x55333366, 0x94858511, 0xcf45458a, + 0x10f9f9e9, 0x06020204, 0x817f7ffe, 0xf05050a0, 0x443c3c78, + 0xba9f9f25, 0xe3a8a84b, 0xf35151a2, 0xfea3a35d, 0xc0404080, + 0x8a8f8f05, 0xad92923f, 0xbc9d9d21, 0x48383870, 0x04f5f5f1, + 0xdfbcbc63, 0xc1b6b677, 0x75dadaaf, 0x63212142, 0x30101020, + 0x1affffe5, 0x0ef3f3fd, 0x6dd2d2bf, 0x4ccdcd81, 0x140c0c18, + 0x35131326, 0x2fececc3, 0xe15f5fbe, 0xa2979735, 0xcc444488, + 0x3917172e, 0x57c4c493, 0xf2a7a755, 0x827e7efc, 0x473d3d7a, + 0xac6464c8, 0xe75d5dba, 0x2b191932, 0x957373e6, 0xa06060c0, + 0x98818119, 0xd14f4f9e, 0x7fdcdca3, 0x66222244, 0x7e2a2a54, + 0xab90903b, 0x8388880b, 0xca46468c, 0x29eeeec7, 0xd3b8b86b, + 0x3c141428, 0x79dedea7, 0xe25e5ebc, 0x1d0b0b16, 0x76dbdbad, + 0x3be0e0db, 0x56323264, 0x4e3a3a74, 0x1e0a0a14, 0xdb494992, + 0x0a06060c, 0x6c242448, 0xe45c5cb8, 0x5dc2c29f, 0x6ed3d3bd, + 0xefacac43, 0xa66262c4, 0xa8919139, 0xa4959531, 0x37e4e4d3, + 0x8b7979f2, 0x32e7e7d5, 0x43c8c88b, 0x5937376e, 0xb76d6dda, + 0x8c8d8d01, 0x64d5d5b1, 0xd24e4e9c, 0xe0a9a949, 0xb46c6cd8, + 0xfa5656ac, 0x07f4f4f3, 0x25eaeacf, 0xaf6565ca, 0x8e7a7af4, + 0xe9aeae47, 0x18080810, 0xd5baba6f, 0x887878f0, 0x6f25254a, + 0x722e2e5c, 0x241c1c38, 0xf1a6a657, 0xc7b4b473, 0x51c6c697, + 0x23e8e8cb, 0x7cdddda1, 0x9c7474e8, 0x211f1f3e, 0xdd4b4b96, + 0xdcbdbd61, 0x868b8b0d, 0x858a8a0f, 0x907070e0, 0x423e3e7c, + 0xc4b5b571, 0xaa6666cc, 0xd8484890, 0x05030306, 0x01f6f6f7, + 0x120e0e1c, 0xa36161c2, 0x5f35356a, 0xf95757ae, 0xd0b9b969, + 0x91868617, 0x58c1c199, 0x271d1d3a, 0xb99e9e27, 0x38e1e1d9, + 0x13f8f8eb, 0xb398982b, 0x33111122, 0xbb6969d2, 0x70d9d9a9, + 0x898e8e07, 0xa7949433, 0xb69b9b2d, 0x221e1e3c, 0x92878715, + 0x20e9e9c9, 0x49cece87, 0xff5555aa, 0x78282850, 0x7adfdfa5, + 0x8f8c8c03, 0xf8a1a159, 0x80898909, 0x170d0d1a, 0xdabfbf65, + 0x31e6e6d7, 0xc6424284, 0xb86868d0, 0xc3414182, 0xb0999929, + 0x772d2d5a, 0x110f0f1e, 0xcbb0b07b, 0xfc5454a8, 0xd6bbbb6d, + 0x3a16162c + }; + + private static readonly uint[] Tinv0 = { + 0x50a7f451, 0x5365417e, 0xc3a4171a, 0x965e273a, 0xcb6bab3b, + 0xf1459d1f, 0xab58faac, 0x9303e34b, 0x55fa3020, 0xf66d76ad, + 0x9176cc88, 0x254c02f5, 0xfcd7e54f, 0xd7cb2ac5, 0x80443526, + 0x8fa362b5, 0x495ab1de, 0x671bba25, 0x980eea45, 0xe1c0fe5d, + 0x02752fc3, 0x12f04c81, 0xa397468d, 0xc6f9d36b, 0xe75f8f03, + 0x959c9215, 0xeb7a6dbf, 0xda595295, 0x2d83bed4, 0xd3217458, + 0x2969e049, 0x44c8c98e, 0x6a89c275, 0x78798ef4, 0x6b3e5899, + 0xdd71b927, 0xb64fe1be, 0x17ad88f0, 0x66ac20c9, 0xb43ace7d, + 0x184adf63, 0x82311ae5, 0x60335197, 0x457f5362, 0xe07764b1, + 0x84ae6bbb, 0x1ca081fe, 0x942b08f9, 0x58684870, 0x19fd458f, + 0x876cde94, 0xb7f87b52, 0x23d373ab, 0xe2024b72, 0x578f1fe3, + 0x2aab5566, 0x0728ebb2, 0x03c2b52f, 0x9a7bc586, 0xa50837d3, + 0xf2872830, 0xb2a5bf23, 0xba6a0302, 0x5c8216ed, 0x2b1ccf8a, + 0x92b479a7, 0xf0f207f3, 0xa1e2694e, 0xcdf4da65, 0xd5be0506, + 0x1f6234d1, 0x8afea6c4, 0x9d532e34, 0xa055f3a2, 0x32e18a05, + 0x75ebf6a4, 0x39ec830b, 0xaaef6040, 0x069f715e, 0x51106ebd, + 0xf98a213e, 0x3d06dd96, 0xae053edd, 0x46bde64d, 0xb58d5491, + 0x055dc471, 0x6fd40604, 0xff155060, 0x24fb9819, 0x97e9bdd6, + 0xcc434089, 0x779ed967, 0xbd42e8b0, 0x888b8907, 0x385b19e7, + 0xdbeec879, 0x470a7ca1, 0xe90f427c, 0xc91e84f8, 0x00000000, + 0x83868009, 0x48ed2b32, 0xac70111e, 0x4e725a6c, 0xfbff0efd, + 0x5638850f, 0x1ed5ae3d, 0x27392d36, 0x64d90f0a, 0x21a65c68, + 0xd1545b9b, 0x3a2e3624, 0xb1670a0c, 0x0fe75793, 0xd296eeb4, + 0x9e919b1b, 0x4fc5c080, 0xa220dc61, 0x694b775a, 0x161a121c, + 0x0aba93e2, 0xe52aa0c0, 0x43e0223c, 0x1d171b12, 0x0b0d090e, + 0xadc78bf2, 0xb9a8b62d, 0xc8a91e14, 0x8519f157, 0x4c0775af, + 0xbbdd99ee, 0xfd607fa3, 0x9f2601f7, 0xbcf5725c, 0xc53b6644, + 0x347efb5b, 0x7629438b, 0xdcc623cb, 0x68fcedb6, 0x63f1e4b8, + 0xcadc31d7, 0x10856342, 0x40229713, 0x2011c684, 0x7d244a85, + 0xf83dbbd2, 0x1132f9ae, 0x6da129c7, 0x4b2f9e1d, 0xf330b2dc, + 0xec52860d, 0xd0e3c177, 0x6c16b32b, 0x99b970a9, 0xfa489411, + 0x2264e947, 0xc48cfca8, 0x1a3ff0a0, 0xd82c7d56, 0xef903322, + 0xc74e4987, 0xc1d138d9, 0xfea2ca8c, 0x360bd498, 0xcf81f5a6, + 0x28de7aa5, 0x268eb7da, 0xa4bfad3f, 0xe49d3a2c, 0x0d927850, + 0x9bcc5f6a, 0x62467e54, 0xc2138df6, 0xe8b8d890, 0x5ef7392e, + 0xf5afc382, 0xbe805d9f, 0x7c93d069, 0xa92dd56f, 0xb31225cf, + 0x3b99acc8, 0xa77d1810, 0x6e639ce8, 0x7bbb3bdb, 0x097826cd, + 0xf418596e, 0x01b79aec, 0xa89a4f83, 0x656e95e6, 0x7ee6ffaa, + 0x08cfbc21, 0xe6e815ef, 0xd99be7ba, 0xce366f4a, 0xd4099fea, + 0xd67cb029, 0xafb2a431, 0x31233f2a, 0x3094a5c6, 0xc066a235, + 0x37bc4e74, 0xa6ca82fc, 0xb0d090e0, 0x15d8a733, 0x4a9804f1, + 0xf7daec41, 0x0e50cd7f, 0x2ff69117, 0x8dd64d76, 0x4db0ef43, + 0x544daacc, 0xdf0496e4, 0xe3b5d19e, 0x1b886a4c, 0xb81f2cc1, + 0x7f516546, 0x04ea5e9d, 0x5d358c01, 0x737487fa, 0x2e410bfb, + 0x5a1d67b3, 0x52d2db92, 0x335610e9, 0x1347d66d, 0x8c61d79a, + 0x7a0ca137, 0x8e14f859, 0x893c13eb, 0xee27a9ce, 0x35c961b7, + 0xede51ce1, 0x3cb1477a, 0x59dfd29c, 0x3f73f255, 0x79ce1418, + 0xbf37c773, 0xeacdf753, 0x5baafd5f, 0x146f3ddf, 0x86db4478, + 0x81f3afca, 0x3ec468b9, 0x2c342438, 0x5f40a3c2, 0x72c31d16, + 0x0c25e2bc, 0x8b493c28, 0x41950dff, 0x7101a839, 0xdeb30c08, + 0x9ce4b4d8, 0x90c15664, 0x6184cb7b, 0x70b632d5, 0x745c6c48, + 0x4257b8d0 + }; + + private uint C0, C1, C2, C3; + private int ROUNDS; + private uint[,] WorkingKey; + private bool forEncryption; + + public string AlgorithmName { + get { return "AES"; } + } + + public bool IsPartialBlockOkay { + get { return false; } + } + + private uint Shift( + uint r, + int shift) { + return (r >> shift) | (r << (32 - shift)); + } + + private uint FFmulX( + uint x) { + return ((x & m2) << 1) ^ (((x & m1) >> 7)*m3); + } + + /* + The following defines provide alternative definitions of FFmulX that might + give improved performance if a fast 32-bit multiply is not available. + + private int FFmulX(int x) { int u = x & m1; u |= (u >> 1); return ((x & m2) << 1) ^ ((u >>> 3) | (u >>> 6)); } + private static final int m4 = 0x1b1b1b1b; + private int FFmulX(int x) { int u = x & m1; return ((x & m2) << 1) ^ ((u - (u >>> 7)) & m4); } + + */ + + private uint Inv_Mcol( + uint x) { + uint f2 = FFmulX(x); + uint f4 = FFmulX(f2); + uint f8 = FFmulX(f4); + uint f9 = x ^ f8; + + return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24); + } + + private uint SubWord( + uint x) { + return S[x & 255] + | (((uint) S[(x >> 8) & 255]) << 8) + | (((uint) S[(x >> 16) & 255]) << 16) + | (((uint) S[(x >> 24) & 255]) << 24); + } + + /** + * Calculate the necessary round keys + * The number of calculations depends on key size and block size + * AES specified a fixed block size of 128 bits and key sizes 128/192/256 bits + * This code is written assuming those are the only possible values + */ + + private uint[,] GenerateWorkingKey( + byte[] key, + bool forEncryption) { + int KC = key.Length/4; // key length in words + int t; + + if((KC != 4) && (KC != 6) && (KC != 8)) + throw new ArgumentException("Key length not 128/192/256 bits."); + + ROUNDS = KC + 6; // This is not always true for the generalized Rijndael that allows larger block sizes + var W = new uint[ROUNDS + 1, 4]; // 4 words in a block + + // + // copy the key into the round key array + // + + t = 0; + for(int i = 0; i < key.Length; t++) { + W[t >> 2, t & 3] = Pack.LE_To_UInt32(key, i); + i += 4; + } + + // + // while not enough round key material calculated + // calculate new values + // + int k = (ROUNDS + 1) << 2; + for(int i = KC; (i < k); i++) { + uint temp = W[(i - 1) >> 2, (i - 1) & 3]; + if((i%KC) == 0) { + temp = SubWord(Shift(temp, 8)) ^ rcon[(i/KC) - 1]; + } else if((KC > 6) && ((i%KC) == 4)) { + temp = SubWord(temp); + } + + W[i >> 2, i & 3] = W[(i - KC) >> 2, (i - KC) & 3] ^ temp; + } + + if(!forEncryption) { + for(int j = 1; j < ROUNDS; j++) { + for(int i = 0; i < 4; i++) { + W[j, i] = Inv_Mcol(W[j, i]); + } + } + } + + return W; + } + + public void Init(bool forEncryption, byte[] key) { + WorkingKey = GenerateWorkingKey(key, forEncryption); + this.forEncryption = forEncryption; + } + + public int GetBlockSize() { + return BLOCK_SIZE; + } + + public int ProcessBlock(byte[] input, int inOff, byte[] output, int outOff) { + if(WorkingKey == null) { + throw new InvalidOperationException("AES engine not initialised"); + } + + if((inOff + (32/2)) > input.Length) { + throw new InvalidOperationException("input buffer too short"); + } + + if((outOff + (32/2)) > output.Length) { + throw new InvalidOperationException("output buffer too short"); + } + + UnPackBlock(input, inOff); + + if(forEncryption) { + EncryptBlock(WorkingKey); + } else { + DecryptBlock(WorkingKey); + } + + PackBlock(output, outOff); + + return BLOCK_SIZE; + } + + public void Reset() { + } + + private void UnPackBlock( + byte[] bytes, + int off) { + C0 = Pack.LE_To_UInt32(bytes, off); + C1 = Pack.LE_To_UInt32(bytes, off + 4); + C2 = Pack.LE_To_UInt32(bytes, off + 8); + C3 = Pack.LE_To_UInt32(bytes, off + 12); + } + + private void PackBlock( + byte[] bytes, + int off) { + Pack.UInt32_To_LE(C0, bytes, off); + Pack.UInt32_To_LE(C1, bytes, off + 4); + Pack.UInt32_To_LE(C2, bytes, off + 8); + Pack.UInt32_To_LE(C3, bytes, off + 12); + } + + private void EncryptBlock( + uint[,] KW) { + uint r, r0, r1, r2, r3; + + C0 ^= KW[0, 0]; + C1 ^= KW[0, 1]; + C2 ^= KW[0, 2]; + C3 ^= KW[0, 3]; + + for(r = 1; r < ROUNDS - 1;) { + r0 = T0[C0 & 255] ^ Shift(T0[(C1 >> 8) & 255], 24) ^ Shift(T0[(C2 >> 16) & 255], 16) ^ + Shift(T0[(C3 >> 24) & 255], 8) ^ KW[r, 0]; + r1 = T0[C1 & 255] ^ Shift(T0[(C2 >> 8) & 255], 24) ^ Shift(T0[(C3 >> 16) & 255], 16) ^ + Shift(T0[(C0 >> 24) & 255], 8) ^ KW[r, 1]; + r2 = T0[C2 & 255] ^ Shift(T0[(C3 >> 8) & 255], 24) ^ Shift(T0[(C0 >> 16) & 255], 16) ^ + Shift(T0[(C1 >> 24) & 255], 8) ^ KW[r, 2]; + r3 = T0[C3 & 255] ^ Shift(T0[(C0 >> 8) & 255], 24) ^ Shift(T0[(C1 >> 16) & 255], 16) ^ + Shift(T0[(C2 >> 24) & 255], 8) ^ KW[r++, 3]; + C0 = T0[r0 & 255] ^ Shift(T0[(r1 >> 8) & 255], 24) ^ Shift(T0[(r2 >> 16) & 255], 16) ^ + Shift(T0[(r3 >> 24) & 255], 8) ^ KW[r, 0]; + C1 = T0[r1 & 255] ^ Shift(T0[(r2 >> 8) & 255], 24) ^ Shift(T0[(r3 >> 16) & 255], 16) ^ + Shift(T0[(r0 >> 24) & 255], 8) ^ KW[r, 1]; + C2 = T0[r2 & 255] ^ Shift(T0[(r3 >> 8) & 255], 24) ^ Shift(T0[(r0 >> 16) & 255], 16) ^ + Shift(T0[(r1 >> 24) & 255], 8) ^ KW[r, 2]; + C3 = T0[r3 & 255] ^ Shift(T0[(r0 >> 8) & 255], 24) ^ Shift(T0[(r1 >> 16) & 255], 16) ^ + Shift(T0[(r2 >> 24) & 255], 8) ^ KW[r++, 3]; + } + + r0 = T0[C0 & 255] ^ Shift(T0[(C1 >> 8) & 255], 24) ^ Shift(T0[(C2 >> 16) & 255], 16) ^ + Shift(T0[(C3 >> 24) & 255], 8) ^ KW[r, 0]; + r1 = T0[C1 & 255] ^ Shift(T0[(C2 >> 8) & 255], 24) ^ Shift(T0[(C3 >> 16) & 255], 16) ^ + Shift(T0[(C0 >> 24) & 255], 8) ^ KW[r, 1]; + r2 = T0[C2 & 255] ^ Shift(T0[(C3 >> 8) & 255], 24) ^ Shift(T0[(C0 >> 16) & 255], 16) ^ + Shift(T0[(C1 >> 24) & 255], 8) ^ KW[r, 2]; + r3 = T0[C3 & 255] ^ Shift(T0[(C0 >> 8) & 255], 24) ^ Shift(T0[(C1 >> 16) & 255], 16) ^ + Shift(T0[(C2 >> 24) & 255], 8) ^ KW[r++, 3]; + + // the final round's table is a simple function of S so we don't use a whole other four tables for it + + C0 = S[r0 & 255] ^ (((uint) S[(r1 >> 8) & 255]) << 8) ^ (((uint) S[(r2 >> 16) & 255]) << 16) ^ + (((uint) S[(r3 >> 24) & 255]) << 24) ^ KW[r, 0]; + C1 = S[r1 & 255] ^ (((uint) S[(r2 >> 8) & 255]) << 8) ^ (((uint) S[(r3 >> 16) & 255]) << 16) ^ + (((uint) S[(r0 >> 24) & 255]) << 24) ^ KW[r, 1]; + C2 = S[r2 & 255] ^ (((uint) S[(r3 >> 8) & 255]) << 8) ^ (((uint) S[(r0 >> 16) & 255]) << 16) ^ + (((uint) S[(r1 >> 24) & 255]) << 24) ^ KW[r, 2]; + C3 = S[r3 & 255] ^ (((uint) S[(r0 >> 8) & 255]) << 8) ^ (((uint) S[(r1 >> 16) & 255]) << 16) ^ + (((uint) S[(r2 >> 24) & 255]) << 24) ^ KW[r, 3]; + } + + private void DecryptBlock( + uint[,] KW) { + int r; + uint r0, r1, r2, r3; + + C0 ^= KW[ROUNDS, 0]; + C1 ^= KW[ROUNDS, 1]; + C2 ^= KW[ROUNDS, 2]; + C3 ^= KW[ROUNDS, 3]; + + for(r = ROUNDS - 1; r > 1;) { + r0 = Tinv0[C0 & 255] ^ Shift(Tinv0[(C3 >> 8) & 255], 24) ^ Shift(Tinv0[(C2 >> 16) & 255], 16) ^ + Shift(Tinv0[(C1 >> 24) & 255], 8) ^ KW[r, 0]; + r1 = Tinv0[C1 & 255] ^ Shift(Tinv0[(C0 >> 8) & 255], 24) ^ Shift(Tinv0[(C3 >> 16) & 255], 16) ^ + Shift(Tinv0[(C2 >> 24) & 255], 8) ^ KW[r, 1]; + r2 = Tinv0[C2 & 255] ^ Shift(Tinv0[(C1 >> 8) & 255], 24) ^ Shift(Tinv0[(C0 >> 16) & 255], 16) ^ + Shift(Tinv0[(C3 >> 24) & 255], 8) ^ KW[r, 2]; + r3 = Tinv0[C3 & 255] ^ Shift(Tinv0[(C2 >> 8) & 255], 24) ^ Shift(Tinv0[(C1 >> 16) & 255], 16) ^ + Shift(Tinv0[(C0 >> 24) & 255], 8) ^ KW[r--, 3]; + C0 = Tinv0[r0 & 255] ^ Shift(Tinv0[(r3 >> 8) & 255], 24) ^ Shift(Tinv0[(r2 >> 16) & 255], 16) ^ + Shift(Tinv0[(r1 >> 24) & 255], 8) ^ KW[r, 0]; + C1 = Tinv0[r1 & 255] ^ Shift(Tinv0[(r0 >> 8) & 255], 24) ^ Shift(Tinv0[(r3 >> 16) & 255], 16) ^ + Shift(Tinv0[(r2 >> 24) & 255], 8) ^ KW[r, 1]; + C2 = Tinv0[r2 & 255] ^ Shift(Tinv0[(r1 >> 8) & 255], 24) ^ Shift(Tinv0[(r0 >> 16) & 255], 16) ^ + Shift(Tinv0[(r3 >> 24) & 255], 8) ^ KW[r, 2]; + C3 = Tinv0[r3 & 255] ^ Shift(Tinv0[(r2 >> 8) & 255], 24) ^ Shift(Tinv0[(r1 >> 16) & 255], 16) ^ + Shift(Tinv0[(r0 >> 24) & 255], 8) ^ KW[r--, 3]; + } + + r0 = Tinv0[C0 & 255] ^ Shift(Tinv0[(C3 >> 8) & 255], 24) ^ Shift(Tinv0[(C2 >> 16) & 255], 16) ^ + Shift(Tinv0[(C1 >> 24) & 255], 8) ^ KW[r, 0]; + r1 = Tinv0[C1 & 255] ^ Shift(Tinv0[(C0 >> 8) & 255], 24) ^ Shift(Tinv0[(C3 >> 16) & 255], 16) ^ + Shift(Tinv0[(C2 >> 24) & 255], 8) ^ KW[r, 1]; + r2 = Tinv0[C2 & 255] ^ Shift(Tinv0[(C1 >> 8) & 255], 24) ^ Shift(Tinv0[(C0 >> 16) & 255], 16) ^ + Shift(Tinv0[(C3 >> 24) & 255], 8) ^ KW[r, 2]; + r3 = Tinv0[C3 & 255] ^ Shift(Tinv0[(C2 >> 8) & 255], 24) ^ Shift(Tinv0[(C1 >> 16) & 255], 16) ^ + Shift(Tinv0[(C0 >> 24) & 255], 8) ^ KW[r, 3]; + + // the final round's table is a simple function of Si so we don't use a whole other four tables for it + + C0 = Si[r0 & 255] ^ (((uint) Si[(r3 >> 8) & 255]) << 8) ^ (((uint) Si[(r2 >> 16) & 255]) << 16) ^ + (((uint) Si[(r1 >> 24) & 255]) << 24) ^ KW[0, 0]; + C1 = Si[r1 & 255] ^ (((uint) Si[(r0 >> 8) & 255]) << 8) ^ (((uint) Si[(r3 >> 16) & 255]) << 16) ^ + (((uint) Si[(r2 >> 24) & 255]) << 24) ^ KW[0, 1]; + C2 = Si[r2 & 255] ^ (((uint) Si[(r1 >> 8) & 255]) << 8) ^ (((uint) Si[(r0 >> 16) & 255]) << 16) ^ + (((uint) Si[(r3 >> 24) & 255]) << 24) ^ KW[0, 2]; + C3 = Si[r3 & 255] ^ (((uint) Si[(r2 >> 8) & 255]) << 8) ^ (((uint) Si[(r1 >> 16) & 255]) << 16) ^ + (((uint) Si[(r0 >> 24) & 255]) << 24) ^ KW[0, 3]; + } + } + + + internal sealed class Pack { + private Pack() { + } + + internal static void UInt32_To_BE(uint n, byte[] bs) { + bs[0] = (byte) (n >> 24); + bs[1] = (byte) (n >> 16); + bs[2] = (byte) (n >> 8); + bs[3] = (byte) (n); + } + + internal static void UInt32_To_BE(uint n, byte[] bs, int off) { + bs[off] = (byte) (n >> 24); + bs[++off] = (byte) (n >> 16); + bs[++off] = (byte) (n >> 8); + bs[++off] = (byte) (n); + } + + internal static uint BE_To_UInt32(byte[] bs) { + uint n = (uint) bs[0] << 24; + n |= (uint) bs[1] << 16; + n |= (uint) bs[2] << 8; + n |= bs[3]; + return n; + } + + internal static uint BE_To_UInt32(byte[] bs, int off) { + uint n = (uint) bs[off] << 24; + n |= (uint) bs[++off] << 16; + n |= (uint) bs[++off] << 8; + n |= bs[++off]; + return n; + } + + internal static ulong BE_To_UInt64(byte[] bs) { + uint hi = BE_To_UInt32(bs); + uint lo = BE_To_UInt32(bs, 4); + return ((ulong) hi << 32) | lo; + } + + internal static ulong BE_To_UInt64(byte[] bs, int off) { + uint hi = BE_To_UInt32(bs, off); + uint lo = BE_To_UInt32(bs, off + 4); + return ((ulong) hi << 32) | lo; + } + + internal static void UInt64_To_BE(ulong n, byte[] bs) { + UInt32_To_BE((uint) (n >> 32), bs); + UInt32_To_BE((uint) (n), bs, 4); + } + + internal static void UInt64_To_BE(ulong n, byte[] bs, int off) { + UInt32_To_BE((uint) (n >> 32), bs, off); + UInt32_To_BE((uint) (n), bs, off + 4); + } + + internal static void UInt32_To_LE(uint n, byte[] bs) { + bs[0] = (byte) (n); + bs[1] = (byte) (n >> 8); + bs[2] = (byte) (n >> 16); + bs[3] = (byte) (n >> 24); + } + + internal static void UInt32_To_LE(uint n, byte[] bs, int off) { + bs[off] = (byte) (n); + bs[++off] = (byte) (n >> 8); + bs[++off] = (byte) (n >> 16); + bs[++off] = (byte) (n >> 24); + } + + internal static uint LE_To_UInt32(byte[] bs) { + uint n = bs[0]; + n |= (uint) bs[1] << 8; + n |= (uint) bs[2] << 16; + n |= (uint) bs[3] << 24; + return n; + } + + internal static uint LE_To_UInt32(byte[] bs, int off) { + uint n = bs[off]; + n |= (uint) bs[++off] << 8; + n |= (uint) bs[++off] << 16; + n |= (uint) bs[++off] << 24; + return n; + } + + internal static ulong LE_To_UInt64(byte[] bs) { + uint lo = LE_To_UInt32(bs); + uint hi = LE_To_UInt32(bs, 4); + return ((ulong) hi << 32) | lo; + } + + internal static ulong LE_To_UInt64(byte[] bs, int off) { + uint lo = LE_To_UInt32(bs, off); + uint hi = LE_To_UInt32(bs, off + 4); + return ((ulong) hi << 32) | lo; + } + + internal static void UInt64_To_LE(ulong n, byte[] bs) { + UInt32_To_LE((uint) (n), bs); + UInt32_To_LE((uint) (n >> 32), bs, 4); + } + + internal static void UInt64_To_LE(ulong n, byte[] bs, int off) { + UInt32_To_LE((uint) (n), bs, off); + UInt32_To_LE((uint) (n >> 32), bs, off + 4); + } + } +} \ No newline at end of file diff --git a/TLSharp.Core/MTProto/Crypto/AuthKey.cs b/TLSharp.Core/MTProto/Crypto/AuthKey.cs new file mode 100644 index 0000000..8337dc5 --- /dev/null +++ b/TLSharp.Core/MTProto/Crypto/AuthKey.cs @@ -0,0 +1,68 @@ +using System; +using System.IO; +using System.Security.Cryptography; + +namespace TLSharp.Core.MTProto.Crypto { + public class AuthKey { + private byte[] key; + private ulong keyId; + private ulong auxHash; + public AuthKey(BigInteger gab) { + key = gab.ToByteArrayUnsigned(); + using(SHA1 hash = new SHA1Managed()) { + using(MemoryStream hashStream = new MemoryStream(hash.ComputeHash(key), false)) { + using(BinaryReader hashReader = new BinaryReader(hashStream)) { + auxHash = hashReader.ReadUInt64(); + hashReader.ReadBytes(4); + keyId = hashReader.ReadUInt64(); + } + } + } + } + + public AuthKey(byte[] data) { + key = data; + using (SHA1 hash = new SHA1Managed()) { + using (MemoryStream hashStream = new MemoryStream(hash.ComputeHash(key), false)) { + using (BinaryReader hashReader = new BinaryReader(hashStream)) { + auxHash = hashReader.ReadUInt64(); + hashReader.ReadBytes(4); + keyId = hashReader.ReadUInt64(); + } + } + } + } + + public byte[] CalcNewNonceHash(byte[] newNonce, int number) { + using(MemoryStream buffer = new MemoryStream(100)) { + using(BinaryWriter bufferWriter = new BinaryWriter(buffer)) { + bufferWriter.Write(newNonce); + bufferWriter.Write((byte)number); + bufferWriter.Write(auxHash); + using(SHA1 sha1 = new SHA1Managed()) { + byte[] hash = sha1.ComputeHash(buffer.GetBuffer(), 0, (int)buffer.Position); + byte[] newNonceHash = new byte[16]; + Array.Copy(hash, 4, newNonceHash, 0, 16); + return newNonceHash; + } + } + } + } + + public byte[] Data { + get { + return key; + } + } + + public ulong Id { + get { + return keyId; + } + } + + public override string ToString() { + return string.Format("(Key: {0}, KeyId: {1}, AuxHash: {2})", key, keyId, auxHash); + } + } +} diff --git a/TLSharp.Core/MTProto/Crypto/BigInteger.cs b/TLSharp.Core/MTProto/Crypto/BigInteger.cs new file mode 100644 index 0000000..8cbb39f --- /dev/null +++ b/TLSharp.Core/MTProto/Crypto/BigInteger.cs @@ -0,0 +1,2823 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Text; + +namespace TLSharp.Core.MTProto.Crypto { +#if !(NETCF_1_0 || NETCF_2_0 || SILVERLIGHT) + [Serializable] +#endif + public class BigInteger { + // The primes b/w 2 and ~2^10 + /* + 3 5 7 11 13 17 19 23 29 + 31 37 41 43 47 53 59 61 67 71 + 73 79 83 89 97 101 103 107 109 113 + 127 131 137 139 149 151 157 163 167 173 + 179 181 191 193 197 199 211 223 227 229 + 233 239 241 251 257 263 269 271 277 281 + 283 293 307 311 313 317 331 337 347 349 + 353 359 367 373 379 383 389 397 401 409 + 419 421 431 433 439 443 449 457 461 463 + 467 479 487 491 499 503 509 521 523 541 + 547 557 563 569 571 577 587 593 599 601 + 607 613 617 619 631 641 643 647 653 659 + 661 673 677 683 691 701 709 719 727 733 + 739 743 751 757 761 769 773 787 797 809 + 811 821 823 827 829 839 853 857 859 863 + 877 881 883 887 907 911 919 929 937 941 + 947 953 967 971 977 983 991 997 + 1009 1013 1019 1021 1031 + */ + + // Each list has a product < 2^31 + private static readonly int[][] primeLists = new int[][] + { + new int[]{ 3, 5, 7, 11, 13, 17, 19, 23 }, + new int[]{ 29, 31, 37, 41, 43 }, + new int[]{ 47, 53, 59, 61, 67 }, + new int[]{ 71, 73, 79, 83 }, + new int[]{ 89, 97, 101, 103 }, + + new int[]{ 107, 109, 113, 127 }, + new int[]{ 131, 137, 139, 149 }, + new int[]{ 151, 157, 163, 167 }, + new int[]{ 173, 179, 181, 191 }, + new int[]{ 193, 197, 199, 211 }, + + new int[]{ 223, 227, 229 }, + new int[]{ 233, 239, 241 }, + new int[]{ 251, 257, 263 }, + new int[]{ 269, 271, 277 }, + new int[]{ 281, 283, 293 }, + + new int[]{ 307, 311, 313 }, + new int[]{ 317, 331, 337 }, + new int[]{ 347, 349, 353 }, + new int[]{ 359, 367, 373 }, + new int[]{ 379, 383, 389 }, + + new int[]{ 397, 401, 409 }, + new int[]{ 419, 421, 431 }, + new int[]{ 433, 439, 443 }, + new int[]{ 449, 457, 461 }, + new int[]{ 463, 467, 479 }, + + new int[]{ 487, 491, 499 }, + new int[]{ 503, 509, 521 }, + new int[]{ 523, 541, 547 }, + new int[]{ 557, 563, 569 }, + new int[]{ 571, 577, 587 }, + + new int[]{ 593, 599, 601 }, + new int[]{ 607, 613, 617 }, + new int[]{ 619, 631, 641 }, + new int[]{ 643, 647, 653 }, + new int[]{ 659, 661, 673 }, + + new int[]{ 677, 683, 691 }, + new int[]{ 701, 709, 719 }, + new int[]{ 727, 733, 739 }, + new int[]{ 743, 751, 757 }, + new int[]{ 761, 769, 773 }, + + new int[]{ 787, 797, 809 }, + new int[]{ 811, 821, 823 }, + new int[]{ 827, 829, 839 }, + new int[]{ 853, 857, 859 }, + new int[]{ 863, 877, 881 }, + + new int[]{ 883, 887, 907 }, + new int[]{ 911, 919, 929 }, + new int[]{ 937, 941, 947 }, + new int[]{ 953, 967, 971 }, + new int[]{ 977, 983, 991 }, + + new int[]{ 997, 1009, 1013 }, + new int[]{ 1019, 1021, 1031 }, + }; + + private static readonly int[] primeProducts; + + private const long IMASK = 0xffffffffL; + private static readonly ulong UIMASK = (ulong)IMASK; + + private static readonly int[] ZeroMagnitude = new int[0]; + private static readonly byte[] ZeroEncoding = new byte[0]; + + public static readonly BigInteger Zero = new BigInteger(0, ZeroMagnitude, false); + public static readonly BigInteger One = createUValueOf(1); + public static readonly BigInteger Two = createUValueOf(2); + public static readonly BigInteger Three = createUValueOf(3); + public static readonly BigInteger Ten = createUValueOf(10); + + private static readonly int chunk2 = 1; // TODO Parse 64 bits at a time + private static readonly BigInteger radix2 = ValueOf(2); + private static readonly BigInteger radix2E = radix2.Pow(chunk2); + + private static readonly int chunk10 = 19; + private static readonly BigInteger radix10 = ValueOf(10); + private static readonly BigInteger radix10E = radix10.Pow(chunk10); + + private static readonly int chunk16 = 16; + private static readonly BigInteger radix16 = ValueOf(16); + private static readonly BigInteger radix16E = radix16.Pow(chunk16); + + private static readonly Random RandomSource = new Random(); + + private const int BitsPerByte = 8; + private const int BitsPerInt = 32; + private const int BytesPerInt = 4; + + static BigInteger() { + primeProducts = new int[primeLists.Length]; + + for (int i = 0; i < primeLists.Length; ++i) { + int[] primeList = primeLists[i]; + int product = 1; + for (int j = 0; j < primeList.Length; ++j) { + product *= primeList[j]; + } + primeProducts[i] = product; + } + } + + private int sign; // -1 means -ve; +1 means +ve; 0 means 0; + private int[] magnitude; // array of ints with [0] being the most significant + private int nBits = -1; // cache BitCount() value + private int nBitLength = -1; // cache calcBitLength() value + private long mQuote = -1L; // -m^(-1) mod b, b = 2^32 (see Montgomery mult.) + + private static int GetByteLength( + int nBits) { + return (nBits + BitsPerByte - 1) / BitsPerByte; + } + + private BigInteger() { + } + + private BigInteger( + int signum, + int[] mag, + bool checkMag) { + if (checkMag) { + int i = 0; + while (i < mag.Length && mag[i] == 0) { + ++i; + } + + if (i == mag.Length) { + // this.sign = 0; + this.magnitude = ZeroMagnitude; + } + else { + this.sign = signum; + + if (i == 0) { + this.magnitude = mag; + } + else { + // strip leading 0 words + this.magnitude = new int[mag.Length - i]; + Array.Copy(mag, i, this.magnitude, 0, this.magnitude.Length); + } + } + } + else { + this.sign = signum; + this.magnitude = mag; + } + } + + public BigInteger( + string value) + : this(value, 10) { + } + + public BigInteger( + string str, + int radix) { + if (str.Length == 0) + throw new FormatException("Zero length BigInteger"); + + NumberStyles style; + int chunk; + BigInteger r; + BigInteger rE; + + switch (radix) { + case 2: + // Is there anyway to restrict to binary digits? + style = NumberStyles.Integer; + chunk = chunk2; + r = radix2; + rE = radix2E; + break; + case 10: + // This style seems to handle spaces and minus sign already (our processing redundant?) + style = NumberStyles.Integer; + chunk = chunk10; + r = radix10; + rE = radix10E; + break; + case 16: + // TODO Should this be HexNumber? + style = NumberStyles.AllowHexSpecifier; + chunk = chunk16; + r = radix16; + rE = radix16E; + break; + default: + throw new FormatException("Only bases 2, 10, or 16 allowed"); + } + + + int index = 0; + sign = 1; + + if (str[0] == '-') { + if (str.Length == 1) + throw new FormatException("Zero length BigInteger"); + + sign = -1; + index = 1; + } + + // strip leading zeros from the string str + while (index < str.Length && Int32.Parse(str[index].ToString(), style) == 0) { + index++; + } + + if (index >= str.Length) { + // zero value - we're done + sign = 0; + magnitude = ZeroMagnitude; + return; + } + + ////// + // could we work out the max number of ints required to store + // str.Length digits in the given base, then allocate that + // storage in one hit?, then Generate the magnitude in one hit too? + ////// + + BigInteger b = Zero; + + + int next = index + chunk; + + if (next <= str.Length) { + do { + string s = str.Substring(index, chunk); + ulong i = ulong.Parse(s, style); + BigInteger bi = createUValueOf(i); + + switch (radix) { + case 2: + // TODO Need this because we are parsing in radix 10 above + if (i > 1) + throw new FormatException("Bad character in radix 2 string: " + s); + + // TODO Parse 64 bits at a time + b = b.ShiftLeft(1); + break; + case 16: + b = b.ShiftLeft(64); + break; + default: + b = b.Multiply(rE); + break; + } + + b = b.Add(bi); + + index = next; + next += chunk; + } + while (next <= str.Length); + } + + if (index < str.Length) { + string s = str.Substring(index); + ulong i = ulong.Parse(s, style); + BigInteger bi = createUValueOf(i); + + if (b.sign > 0) { + if (radix == 2) { + // NB: Can't reach here since we are parsing one char at a time + Debug.Assert(false); + + // TODO Parse all bits at once + // b = b.ShiftLeft(s.Length); + } + else if (radix == 16) { + b = b.ShiftLeft(s.Length << 2); + } + else { + b = b.Multiply(r.Pow(s.Length)); + } + + b = b.Add(bi); + } + else { + b = bi; + } + } + + // Note: This is the previous (slower) algorithm + // while (index < value.Length) + // { + // char c = value[index]; + // string s = c.ToString(); + // int i = Int32.Parse(s, style); + // + // b = b.Multiply(r).Add(ValueOf(i)); + // index++; + // } + + magnitude = b.magnitude; + } + + public BigInteger( + byte[] bytes) + : this(bytes, 0, bytes.Length) { + } + + public BigInteger( + byte[] bytes, + int offset, + int length) { + if (length == 0) + throw new FormatException("Zero length BigInteger"); + + // TODO Move this processing into MakeMagnitude (provide sign argument) + if ((sbyte)bytes[offset] < 0) { + this.sign = -1; + + int end = offset + length; + + int iBval; + // strip leading sign bytes + for (iBval = offset; iBval < end && ((sbyte)bytes[iBval] == -1); iBval++) { + } + + if (iBval >= end) { + this.magnitude = One.magnitude; + } + else { + int numBytes = end - iBval; + byte[] inverse = new byte[numBytes]; + + int index = 0; + while (index < numBytes) { + inverse[index++] = (byte)~bytes[iBval++]; + } + + Debug.Assert(iBval == end); + + while (inverse[--index] == byte.MaxValue) { + inverse[index] = byte.MinValue; + } + + inverse[index]++; + + this.magnitude = MakeMagnitude(inverse, 0, inverse.Length); + } + } + else { + // strip leading zero bytes and return magnitude bytes + this.magnitude = MakeMagnitude(bytes, offset, length); + this.sign = this.magnitude.Length > 0 ? 1 : 0; + } + } + + private static int[] MakeMagnitude( + byte[] bytes, + int offset, + int length) { + int end = offset + length; + + // strip leading zeros + int firstSignificant; + for (firstSignificant = offset; firstSignificant < end + && bytes[firstSignificant] == 0; firstSignificant++) { + } + + if (firstSignificant >= end) { + return ZeroMagnitude; + } + + int nInts = (end - firstSignificant + 3) / BytesPerInt; + int bCount = (end - firstSignificant) % BytesPerInt; + if (bCount == 0) { + bCount = BytesPerInt; + } + + if (nInts < 1) { + return ZeroMagnitude; + } + + int[] mag = new int[nInts]; + + int v = 0; + int magnitudeIndex = 0; + for (int i = firstSignificant; i < end; ++i) { + v <<= 8; + v |= bytes[i] & 0xff; + bCount--; + if (bCount <= 0) { + mag[magnitudeIndex] = v; + magnitudeIndex++; + bCount = BytesPerInt; + v = 0; + } + } + + if (magnitudeIndex < mag.Length) { + mag[magnitudeIndex] = v; + } + + return mag; + } + + public BigInteger( + int sign, + byte[] bytes) + : this(sign, bytes, 0, bytes.Length) { + } + + public BigInteger( + int sign, + byte[] bytes, + int offset, + int length) { + if (sign < -1 || sign > 1) + throw new FormatException("Invalid sign value"); + + if (sign == 0) { + //this.sign = 0; + this.magnitude = ZeroMagnitude; + } + else { + // copy bytes + this.magnitude = MakeMagnitude(bytes, offset, length); + this.sign = this.magnitude.Length < 1 ? 0 : sign; + } + } + + public BigInteger( + int sizeInBits, + Random random) { + if (sizeInBits < 0) + throw new ArgumentException("sizeInBits must be non-negative"); + + this.nBits = -1; + this.nBitLength = -1; + + if (sizeInBits == 0) { + // this.sign = 0; + this.magnitude = ZeroMagnitude; + return; + } + + int nBytes = GetByteLength(sizeInBits); + byte[] b = new byte[nBytes]; + random.NextBytes(b); + + // strip off any excess bits in the MSB + b[0] &= rndMask[BitsPerByte * nBytes - sizeInBits]; + + this.magnitude = MakeMagnitude(b, 0, b.Length); + this.sign = this.magnitude.Length < 1 ? 0 : 1; + } + + private static readonly byte[] rndMask = { 255, 127, 63, 31, 15, 7, 3, 1 }; + + public BigInteger( + int bitLength, + int certainty, + Random random) { + if (bitLength < 2) + throw new ArithmeticException("bitLength < 2"); + + this.sign = 1; + this.nBitLength = bitLength; + + if (bitLength == 2) { + this.magnitude = random.Next(2) == 0 + ? Two.magnitude + : Three.magnitude; + return; + } + + int nBytes = GetByteLength(bitLength); + byte[] b = new byte[nBytes]; + + int xBits = BitsPerByte * nBytes - bitLength; + byte mask = rndMask[xBits]; + + for (; ; ) { + random.NextBytes(b); + + // strip off any excess bits in the MSB + b[0] &= mask; + + // ensure the leading bit is 1 (to meet the strength requirement) + b[0] |= (byte)(1 << (7 - xBits)); + + // ensure the trailing bit is 1 (i.e. must be odd) + b[nBytes - 1] |= 1; + + this.magnitude = MakeMagnitude(b, 0, b.Length); + this.nBits = -1; + this.mQuote = -1L; + + if (certainty < 1) + break; + + if (CheckProbablePrime(certainty, random)) + break; + + if (bitLength > 32) { + for (int rep = 0; rep < 10000; ++rep) { + int n = 33 + random.Next(bitLength - 2); + this.magnitude[this.magnitude.Length - (n >> 5)] ^= (1 << (n & 31)); + this.magnitude[this.magnitude.Length - 1] ^= ((random.Next() + 1) << 1); + this.mQuote = -1L; + + if (CheckProbablePrime(certainty, random)) + return; + } + } + } + } + + public BigInteger Abs() { + return sign >= 0 ? this : Negate(); + } + + /** + * return a = a + b - b preserved. + */ + private static int[] AddMagnitudes( + int[] a, + int[] b) { + int tI = a.Length - 1; + int vI = b.Length - 1; + long m = 0; + + while (vI >= 0) { + m += ((long)(uint)a[tI] + (long)(uint)b[vI--]); + a[tI--] = (int)m; + m = (long)((ulong)m >> 32); + } + + if (m != 0) { + while (tI >= 0 && ++a[tI--] == 0) { + } + } + + return a; + } + + public BigInteger Add( + BigInteger value) { + if (this.sign == 0) + return value; + + if (this.sign != value.sign) { + if (value.sign == 0) + return this; + + if (value.sign < 0) + return Subtract(value.Negate()); + + return value.Subtract(Negate()); + } + + return AddToMagnitude(value.magnitude); + } + + private BigInteger AddToMagnitude( + int[] magToAdd) { + int[] big, small; + if (this.magnitude.Length < magToAdd.Length) { + big = magToAdd; + small = this.magnitude; + } + else { + big = this.magnitude; + small = magToAdd; + } + + // Conservatively avoid over-allocation when no overflow possible + uint limit = uint.MaxValue; + if (big.Length == small.Length) + limit -= (uint)small[0]; + + bool possibleOverflow = (uint)big[0] >= limit; + + int[] bigCopy; + if (possibleOverflow) { + bigCopy = new int[big.Length + 1]; + big.CopyTo(bigCopy, 1); + } + else { + bigCopy = (int[])big.Clone(); + } + + bigCopy = AddMagnitudes(bigCopy, small); + + return new BigInteger(this.sign, bigCopy, possibleOverflow); + } + + public BigInteger And( + BigInteger value) { + if (this.sign == 0 || value.sign == 0) { + return Zero; + } + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + bool resultNeg = sign < 0 && value.sign < 0; + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) { + aWord = ~aWord; + } + + if (value.sign < 0) { + bWord = ~bWord; + } + + resultMag[i] = aWord & bWord; + + if (resultNeg) { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) { + result = result.Not(); + } + + return result; + } + + public BigInteger AndNot( + BigInteger val) { + return And(val.Not()); + } + + public int BitCount { + get { + if (nBits == -1) { + if (sign < 0) { + // TODO Optimise this case + nBits = Not().BitCount; + } + else { + int sum = 0; + for (int i = 0; i < magnitude.Length; i++) { + sum += bitCounts[(byte)magnitude[i]]; + sum += bitCounts[(byte)(magnitude[i] >> 8)]; + sum += bitCounts[(byte)(magnitude[i] >> 16)]; + sum += bitCounts[(byte)(magnitude[i] >> 24)]; + } + nBits = sum; + } + } + + return nBits; + } + } + + private readonly static byte[] bitCounts = + { + 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, 1, + 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, 4, 3, 4, + 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 1, 2, 2, 3, 2, 3, 3, 4, 2, 3, 3, + 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, 3, 4, 3, 4, 4, 5, + 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 1, 2, 2, 3, 2, + 3, 3, 4, 2, 3, 3, 4, 3, 4, 4, 5, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 2, 3, + 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, + 7, 2, 3, 3, 4, 3, 4, 4, 5, 3, 4, 4, 5, 4, 5, 5, 6, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, + 5, 6, 6, 7, 3, 4, 4, 5, 4, 5, 5, 6, 4, 5, 5, 6, 5, 6, 6, 7, 4, 5, 5, 6, 5, 6, 6, 7, 5, + 6, 6, 7, 6, 7, 7, 8 + }; + + private int calcBitLength( + int indx, + int[] mag) { + for (; ; ) { + if (indx >= mag.Length) + return 0; + + if (mag[indx] != 0) + break; + + ++indx; + } + + // bit length for everything after the first int + int bitLength = 32 * ((mag.Length - indx) - 1); + + // and determine bitlength of first int + int firstMag = mag[indx]; + bitLength += BitLen(firstMag); + + // Check for negative powers of two + if (sign < 0 && ((firstMag & -firstMag) == firstMag)) { + do { + if (++indx >= mag.Length) { + --bitLength; + break; + } + } + while (mag[indx] == 0); + } + + return bitLength; + } + + public int BitLength { + get { + if (nBitLength == -1) { + nBitLength = sign == 0 + ? 0 + : calcBitLength(0, magnitude); + } + + return nBitLength; + } + } + + // + // BitLen(value) is the number of bits in value. + // + private static int BitLen( + int w) { + // Binary search - decision tree (5 tests, rarely 6) + return (w < 1 << 15 ? (w < 1 << 7 + ? (w < 1 << 3 ? (w < 1 << 1 + ? (w < 1 << 0 ? (w < 0 ? 32 : 0) : 1) + : (w < 1 << 2 ? 2 : 3)) : (w < 1 << 5 + ? (w < 1 << 4 ? 4 : 5) + : (w < 1 << 6 ? 6 : 7))) + : (w < 1 << 11 + ? (w < 1 << 9 ? (w < 1 << 8 ? 8 : 9) : (w < 1 << 10 ? 10 : 11)) + : (w < 1 << 13 ? (w < 1 << 12 ? 12 : 13) : (w < 1 << 14 ? 14 : 15)))) : (w < 1 << 23 ? (w < 1 << 19 + ? (w < 1 << 17 ? (w < 1 << 16 ? 16 : 17) : (w < 1 << 18 ? 18 : 19)) + : (w < 1 << 21 ? (w < 1 << 20 ? 20 : 21) : (w < 1 << 22 ? 22 : 23))) : (w < 1 << 27 + ? (w < 1 << 25 ? (w < 1 << 24 ? 24 : 25) : (w < 1 << 26 ? 26 : 27)) + : (w < 1 << 29 ? (w < 1 << 28 ? 28 : 29) : (w < 1 << 30 ? 30 : 31))))); + } + + // private readonly static byte[] bitLengths = + // { + // 0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, + // 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, + // 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + // 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + // 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + // 8, 8, 8, 8, 8, 8, 8, 8 + // }; + + private bool QuickPow2Check() { + return sign > 0 && nBits == 1; + } + + public int CompareTo( + object obj) { + return CompareTo((BigInteger)obj); + } + + /** + * unsigned comparison on two arrays - note the arrays may + * start with leading zeros. + */ + private static int CompareTo( + int xIndx, + int[] x, + int yIndx, + int[] y) { + while (xIndx != x.Length && x[xIndx] == 0) { + xIndx++; + } + + while (yIndx != y.Length && y[yIndx] == 0) { + yIndx++; + } + + return CompareNoLeadingZeroes(xIndx, x, yIndx, y); + } + + private static int CompareNoLeadingZeroes( + int xIndx, + int[] x, + int yIndx, + int[] y) { + int diff = (x.Length - y.Length) - (xIndx - yIndx); + + if (diff != 0) { + return diff < 0 ? -1 : 1; + } + + // lengths of magnitudes the same, test the magnitude values + + while (xIndx < x.Length) { + uint v1 = (uint)x[xIndx++]; + uint v2 = (uint)y[yIndx++]; + + if (v1 != v2) + return v1 < v2 ? -1 : 1; + } + + return 0; + } + + public int CompareTo( + BigInteger value) { + return sign < value.sign ? -1 + : sign > value.sign ? 1 + : sign == 0 ? 0 + : sign * CompareNoLeadingZeroes(0, magnitude, 0, value.magnitude); + } + + /** + * return z = x / y - done in place (z value preserved, x contains the + * remainder) + */ + private int[] Divide( + int[] x, + int[] y) { + int xStart = 0; + while (xStart < x.Length && x[xStart] == 0) { + ++xStart; + } + + int yStart = 0; + while (yStart < y.Length && y[yStart] == 0) { + ++yStart; + } + + Debug.Assert(yStart < y.Length); + + int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + int[] count; + + if (xyCmp > 0) { + int yBitLength = calcBitLength(yStart, y); + int xBitLength = calcBitLength(xStart, x); + int shift = xBitLength - yBitLength; + + int[] iCount; + int iCountStart = 0; + + int[] c; + int cStart = 0; + int cBitLength = yBitLength; + if (shift > 0) { + // iCount = ShiftLeft(One.magnitude, shift); + iCount = new int[(shift >> 5) + 1]; + iCount[0] = 1 << (shift % 32); + + c = ShiftLeft(y, shift); + cBitLength += shift; + } + else { + iCount = new int[] { 1 }; + + int len = y.Length - yStart; + c = new int[len]; + Array.Copy(y, yStart, c, 0, len); + } + + count = new int[iCount.Length]; + + for (; ; ) { + if (cBitLength < xBitLength + || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0) { + Subtract(xStart, x, cStart, c); + AddMagnitudes(count, iCount); + + while (x[xStart] == 0) { + if (++xStart == x.Length) + return count; + } + + //xBitLength = calcBitLength(xStart, x); + xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]); + + if (xBitLength <= yBitLength) { + if (xBitLength < yBitLength) + return count; + + xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp <= 0) + break; + } + } + + shift = cBitLength - xBitLength; + + // NB: The case where c[cStart] is 1-bit is harmless + if (shift == 1) { + uint firstC = (uint)c[cStart] >> 1; + uint firstX = (uint)x[xStart]; + if (firstC > firstX) + ++shift; + } + + if (shift < 2) { + ShiftRightOneInPlace(cStart, c); + --cBitLength; + ShiftRightOneInPlace(iCountStart, iCount); + } + else { + ShiftRightInPlace(cStart, c, shift); + cBitLength -= shift; + ShiftRightInPlace(iCountStart, iCount, shift); + } + + //cStart = c.Length - ((cBitLength + 31) / 32); + while (c[cStart] == 0) { + ++cStart; + } + + while (iCount[iCountStart] == 0) { + ++iCountStart; + } + } + } + else { + count = new int[1]; + } + + if (xyCmp == 0) { + AddMagnitudes(count, One.magnitude); + Array.Clear(x, xStart, x.Length - xStart); + } + + return count; + } + + public BigInteger Divide( + BigInteger val) { + if (val.sign == 0) + throw new ArithmeticException("Division by zero error"); + + if (sign == 0) + return Zero; + + if (val.QuickPow2Check()) // val is power of two + { + BigInteger result = this.Abs().ShiftRight(val.Abs().BitLength - 1); + return val.sign == this.sign ? result : result.Negate(); + } + + int[] mag = (int[])this.magnitude.Clone(); + + return new BigInteger(this.sign * val.sign, Divide(mag, val.magnitude), true); + } + + public BigInteger[] DivideAndRemainder( + BigInteger val) { + if (val.sign == 0) + throw new ArithmeticException("Division by zero error"); + + BigInteger[] biggies = new BigInteger[2]; + + if (sign == 0) { + biggies[0] = Zero; + biggies[1] = Zero; + } + else if (val.QuickPow2Check()) // val is power of two + { + int e = val.Abs().BitLength - 1; + BigInteger quotient = this.Abs().ShiftRight(e); + int[] remainder = this.LastNBits(e); + + biggies[0] = val.sign == this.sign ? quotient : quotient.Negate(); + biggies[1] = new BigInteger(this.sign, remainder, true); + } + else { + int[] remainder = (int[])this.magnitude.Clone(); + int[] quotient = Divide(remainder, val.magnitude); + + biggies[0] = new BigInteger(this.sign * val.sign, quotient, true); + biggies[1] = new BigInteger(this.sign, remainder, true); + } + + return biggies; + } + + public override bool Equals( + object obj) { + if (obj == this) + return true; + + BigInteger biggie = obj as BigInteger; + if (biggie == null) + return false; + + if (biggie.sign != sign || biggie.magnitude.Length != magnitude.Length) + return false; + + for (int i = 0; i < magnitude.Length; i++) { + if (biggie.magnitude[i] != magnitude[i]) { + return false; + } + } + + return true; + } + + public BigInteger Gcd( + BigInteger value) { + if (value.sign == 0) + return Abs(); + + if (sign == 0) + return value.Abs(); + + BigInteger r; + BigInteger u = this; + BigInteger v = value; + + while (v.sign != 0) { + r = u.Mod(v); + u = v; + v = r; + } + + return u; + } + + public override int GetHashCode() { + int hc = magnitude.Length; + if (magnitude.Length > 0) { + hc ^= magnitude[0]; + + if (magnitude.Length > 1) { + hc ^= magnitude[magnitude.Length - 1]; + } + } + + return sign < 0 ? ~hc : hc; + } + + // TODO Make public? + private BigInteger Inc() { + if (this.sign == 0) + return One; + + if (this.sign < 0) + return new BigInteger(-1, doSubBigLil(this.magnitude, One.magnitude), true); + + return AddToMagnitude(One.magnitude); + } + + public int IntValue { + get { + return sign == 0 ? 0 + : sign > 0 ? magnitude[magnitude.Length - 1] + : -magnitude[magnitude.Length - 1]; + } + } + + /** + * return whether or not a BigInteger is probably prime with a + * probability of 1 - (1/2)**certainty. + *

From Knuth Vol 2, pg 395.

+ */ + public bool IsProbablePrime( + int certainty) { + if (certainty <= 0) + return true; + + BigInteger n = Abs(); + + if (!n.TestBit(0)) + return n.Equals(Two); + + if (n.Equals(One)) + return false; + + return n.CheckProbablePrime(certainty, RandomSource); + } + + private bool CheckProbablePrime( + int certainty, + Random random) { + Debug.Assert(certainty > 0); + Debug.Assert(CompareTo(Two) > 0); + Debug.Assert(TestBit(0)); + + + // Try to reduce the penalty for really small numbers + int numLists = System.Math.Min(BitLength - 1, primeLists.Length); + + for (int i = 0; i < numLists; ++i) { + int test = Remainder(primeProducts[i]); + + int[] primeList = primeLists[i]; + for (int j = 0; j < primeList.Length; ++j) { + int prime = primeList[j]; + int qRem = test % prime; + if (qRem == 0) { + // We may find small numbers in the list + return BitLength < 16 && IntValue == prime; + } + } + } + + + // TODO Special case for < 10^16 (RabinMiller fixed list) + // if (BitLength < 30) + // { + // RabinMiller against 2, 3, 5, 7, 11, 13, 23 is sufficient + // } + + + // TODO Is it worth trying to create a hybrid of these two? + return RabinMillerTest(certainty, random); + // return SolovayStrassenTest(certainty, random); + + // bool rbTest = RabinMillerTest(certainty, random); + // bool ssTest = SolovayStrassenTest(certainty, random); + // + // Debug.Assert(rbTest == ssTest); + // + // return rbTest; + } + + internal bool RabinMillerTest( + int certainty, + Random random) { + Debug.Assert(certainty > 0); + Debug.Assert(BitLength > 2); + Debug.Assert(TestBit(0)); + + // let n = 1 + d . 2^s + BigInteger n = this; + BigInteger nMinusOne = n.Subtract(One); + int s = nMinusOne.GetLowestSetBit(); + BigInteger r = nMinusOne.ShiftRight(s); + + Debug.Assert(s >= 1); + + do { + // TODO Make a method for random BigIntegers in range 0 < x < n) + // - Method can be optimized by only replacing examined bits at each trial + BigInteger a; + do { + a = new BigInteger(n.BitLength, random); + } + while (a.CompareTo(One) <= 0 || a.CompareTo(nMinusOne) >= 0); + + BigInteger y = a.ModPow(r, n); + + if (!y.Equals(One)) { + int j = 0; + while (!y.Equals(nMinusOne)) { + if (++j == s) + return false; + + y = y.ModPow(Two, n); + + if (y.Equals(One)) + return false; + } + } + + certainty -= 2; // composites pass for only 1/4 possible 'a' + } + while (certainty > 0); + + return true; + } + + // private bool SolovayStrassenTest( + // int certainty, + // Random random) + // { + // Debug.Assert(certainty > 0); + // Debug.Assert(CompareTo(Two) > 0); + // Debug.Assert(TestBit(0)); + // + // BigInteger n = this; + // BigInteger nMinusOne = n.Subtract(One); + // BigInteger e = nMinusOne.ShiftRight(1); + // + // do + // { + // BigInteger a; + // do + // { + // a = new BigInteger(nBitLength, random); + // } + // // NB: Spec says 0 < x < n, but 1 is trivial + // while (a.CompareTo(One) <= 0 || a.CompareTo(n) >= 0); + // + // + // // TODO Check this is redundant given the way Jacobi() works? + //// if (!a.Gcd(n).Equals(One)) + //// return false; + // + // int x = Jacobi(a, n); + // + // if (x == 0) + // return false; + // + // BigInteger check = a.ModPow(e, n); + // + // if (x == 1 && !check.Equals(One)) + // return false; + // + // if (x == -1 && !check.Equals(nMinusOne)) + // return false; + // + // --certainty; + // } + // while (certainty > 0); + // + // return true; + // } + // + // private static int Jacobi( + // BigInteger a, + // BigInteger b) + // { + // Debug.Assert(a.sign >= 0); + // Debug.Assert(b.sign > 0); + // Debug.Assert(b.TestBit(0)); + // Debug.Assert(a.CompareTo(b) < 0); + // + // int totalS = 1; + // for (;;) + // { + // if (a.sign == 0) + // return 0; + // + // if (a.Equals(One)) + // break; + // + // int e = a.GetLowestSetBit(); + // + // int bLsw = b.magnitude[b.magnitude.Length - 1]; + // if ((e & 1) != 0 && ((bLsw & 7) == 3 || (bLsw & 7) == 5)) + // totalS = -totalS; + // + // // TODO Confirm this is faster than later a1.Equals(One) test + // if (a.BitLength == e + 1) + // break; + // BigInteger a1 = a.ShiftRight(e); + //// if (a1.Equals(One)) + //// break; + // + // int a1Lsw = a1.magnitude[a1.magnitude.Length - 1]; + // if ((bLsw & 3) == 3 && (a1Lsw & 3) == 3) + // totalS = -totalS; + // + //// a = b.Mod(a1); + // a = b.Remainder(a1); + // b = a1; + // } + // return totalS; + // } + + public long LongValue { + get { + if (sign == 0) + return 0; + + long v; + if (magnitude.Length > 1) { + v = ((long)magnitude[magnitude.Length - 2] << 32) + | (magnitude[magnitude.Length - 1] & IMASK); + } + else { + v = (magnitude[magnitude.Length - 1] & IMASK); + } + + return sign < 0 ? -v : v; + } + } + + public BigInteger Max( + BigInteger value) { + return CompareTo(value) > 0 ? this : value; + } + + public BigInteger Min( + BigInteger value) { + return CompareTo(value) < 0 ? this : value; + } + + public BigInteger Mod( + BigInteger m) { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + BigInteger biggie = Remainder(m); + + return (biggie.sign >= 0 ? biggie : biggie.Add(m)); + } + + public BigInteger ModInverse( + BigInteger m) { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + // TODO Too slow at the moment + // // "Fast Key Exchange with Elliptic Curve Systems" R.Schoeppel + // if (m.TestBit(0)) + // { + // //The Almost Inverse Algorithm + // int k = 0; + // BigInteger B = One, C = Zero, F = this, G = m, tmp; + // + // for (;;) + // { + // // While F is even, do F=F/u, C=C*u, k=k+1. + // int zeroes = F.GetLowestSetBit(); + // if (zeroes > 0) + // { + // F = F.ShiftRight(zeroes); + // C = C.ShiftLeft(zeroes); + // k += zeroes; + // } + // + // // If F = 1, then return B,k. + // if (F.Equals(One)) + // { + // BigInteger half = m.Add(One).ShiftRight(1); + // BigInteger halfK = half.ModPow(BigInteger.ValueOf(k), m); + // return B.Multiply(halfK).Mod(m); + // } + // + // if (F.CompareTo(G) < 0) + // { + // tmp = G; G = F; F = tmp; + // tmp = B; B = C; C = tmp; + // } + // + // F = F.Add(G); + // B = B.Add(C); + // } + // } + + BigInteger x = new BigInteger(); + BigInteger gcd = ExtEuclid(this.Mod(m), m, x, null); + + if (!gcd.Equals(One)) + throw new ArithmeticException("Numbers not relatively prime."); + + if (x.sign < 0) { + x.sign = 1; + //x = m.Subtract(x); + x.magnitude = doSubBigLil(m.magnitude, x.magnitude); + } + + return x; + } + + /** + * Calculate the numbers u1, u2, and u3 such that: + * + * u1 * a + u2 * b = u3 + * + * where u3 is the greatest common divider of a and b. + * a and b using the extended Euclid algorithm (refer p. 323 + * of The Art of Computer Programming vol 2, 2nd ed). + * This also seems to have the side effect of calculating + * some form of multiplicative inverse. + * + * @param a First number to calculate gcd for + * @param b Second number to calculate gcd for + * @param u1Out the return object for the u1 value + * @param u2Out the return object for the u2 value + * @return The greatest common divisor of a and b + */ + private static BigInteger ExtEuclid( + BigInteger a, + BigInteger b, + BigInteger u1Out, + BigInteger u2Out) { + BigInteger u1 = One; + BigInteger u3 = a; + BigInteger v1 = Zero; + BigInteger v3 = b; + + while (v3.sign > 0) { + BigInteger[] q = u3.DivideAndRemainder(v3); + + BigInteger tmp = v1.Multiply(q[0]); + BigInteger tn = u1.Subtract(tmp); + u1 = v1; + v1 = tn; + + u3 = v3; + v3 = q[1]; + } + + if (u1Out != null) { + u1Out.sign = u1.sign; + u1Out.magnitude = u1.magnitude; + } + + if (u2Out != null) { + BigInteger tmp = u1.Multiply(a); + tmp = u3.Subtract(tmp); + BigInteger res = tmp.Divide(b); + u2Out.sign = res.sign; + u2Out.magnitude = res.magnitude; + } + + return u3; + } + + private static void ZeroOut( + int[] x) { + Array.Clear(x, 0, x.Length); + } + + public BigInteger ModPow( + BigInteger exponent, + BigInteger m) { + if (m.sign < 1) + throw new ArithmeticException("Modulus must be positive"); + + if (m.Equals(One)) + return Zero; + + if (exponent.sign == 0) + return One; + + if (sign == 0) + return Zero; + + int[] zVal = null; + int[] yAccum = null; + int[] yVal; + + // Montgomery exponentiation is only possible if the modulus is odd, + // but AFAIK, this is always the case for crypto algo's + bool useMonty = ((m.magnitude[m.magnitude.Length - 1] & 1) == 1); + long mQ = 0; + if (useMonty) { + mQ = m.GetMQuote(); + + // tmp = this * R mod m + BigInteger tmp = ShiftLeft(32 * m.magnitude.Length).Mod(m); + zVal = tmp.magnitude; + + useMonty = (zVal.Length <= m.magnitude.Length); + + if (useMonty) { + yAccum = new int[m.magnitude.Length + 1]; + if (zVal.Length < m.magnitude.Length) { + int[] longZ = new int[m.magnitude.Length]; + zVal.CopyTo(longZ, longZ.Length - zVal.Length); + zVal = longZ; + } + } + } + + if (!useMonty) { + if (magnitude.Length <= m.magnitude.Length) { + //zAccum = new int[m.magnitude.Length * 2]; + zVal = new int[m.magnitude.Length]; + magnitude.CopyTo(zVal, zVal.Length - magnitude.Length); + } + else { + // + // in normal practice we'll never see this... + // + BigInteger tmp = Remainder(m); + + //zAccum = new int[m.magnitude.Length * 2]; + zVal = new int[m.magnitude.Length]; + tmp.magnitude.CopyTo(zVal, zVal.Length - tmp.magnitude.Length); + } + + yAccum = new int[m.magnitude.Length * 2]; + } + + yVal = new int[m.magnitude.Length]; + + // + // from LSW to MSW + // + for (int i = 0; i < exponent.magnitude.Length; i++) { + int v = exponent.magnitude[i]; + int bits = 0; + + if (i == 0) { + while (v > 0) { + v <<= 1; + bits++; + } + + // + // first time in initialise y + // + zVal.CopyTo(yVal, 0); + + v <<= 1; + bits++; + } + + while (v != 0) { + if (useMonty) { + // Montgomery square algo doesn't exist, and a normal + // square followed by a Montgomery reduction proved to + // be almost as heavy as a Montgomery mulitply. + MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); + } + else { + Square(yAccum, yVal); + Remainder(yAccum, m.magnitude); + Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); + ZeroOut(yAccum); + } + bits++; + + if (v < 0) { + if (useMonty) { + MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); + } + else { + Multiply(yAccum, yVal, zVal); + Remainder(yAccum, m.magnitude); + Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, + yVal.Length); + ZeroOut(yAccum); + } + } + + v <<= 1; + } + + while (bits < 32) { + if (useMonty) { + MultiplyMonty(yAccum, yVal, yVal, m.magnitude, mQ); + } + else { + Square(yAccum, yVal); + Remainder(yAccum, m.magnitude); + Array.Copy(yAccum, yAccum.Length - yVal.Length, yVal, 0, yVal.Length); + ZeroOut(yAccum); + } + bits++; + } + } + + if (useMonty) { + // Return y * R^(-1) mod m by doing y * 1 * R^(-1) mod m + ZeroOut(zVal); + zVal[zVal.Length - 1] = 1; + MultiplyMonty(yAccum, yVal, zVal, m.magnitude, mQ); + } + + BigInteger result = new BigInteger(1, yVal, true); + + return exponent.sign > 0 + ? result + : result.ModInverse(m); + } + + /** + * return w with w = x * x - w is assumed to have enough space. + */ + private static int[] Square( + int[] w, + int[] x) { + // Note: this method allows w to be only (2 * x.Length - 1) words if result will fit + // if (w.Length != 2 * x.Length) + // throw new ArgumentException("no I don't think so..."); + + ulong u1, u2, c; + + int wBase = w.Length - 1; + + for (int i = x.Length - 1; i != 0; i--) { + ulong v = (ulong)(uint)x[i]; + + u1 = v * v; + u2 = u1 >> 32; + u1 = (uint)u1; + + u1 += (ulong)(uint)w[wBase]; + + w[wBase] = (int)(uint)u1; + c = u2 + (u1 >> 32); + + for (int j = i - 1; j >= 0; j--) { + --wBase; + u1 = v * (ulong)(uint)x[j]; + u2 = u1 >> 31; // multiply by 2! + u1 = (uint)(u1 << 1); // multiply by 2! + u1 += c + (ulong)(uint)w[wBase]; + + w[wBase] = (int)(uint)u1; + c = u2 + (u1 >> 32); + } + + c += (ulong)(uint)w[--wBase]; + w[wBase] = (int)(uint)c; + + if (--wBase >= 0) { + w[wBase] = (int)(uint)(c >> 32); + } + else { + Debug.Assert((uint)(c >> 32) == 0); + } + wBase += i; + } + + u1 = (ulong)(uint)x[0]; + u1 = u1 * u1; + u2 = u1 >> 32; + u1 = u1 & IMASK; + + u1 += (ulong)(uint)w[wBase]; + + w[wBase] = (int)(uint)u1; + if (--wBase >= 0) { + w[wBase] = (int)(uint)(u2 + (u1 >> 32) + (ulong)(uint)w[wBase]); + } + else { + Debug.Assert((uint)(u2 + (u1 >> 32)) == 0); + } + + return w; + } + + /** + * return x with x = y * z - x is assumed to have enough space. + */ + private static int[] Multiply( + int[] x, + int[] y, + int[] z) { + int i = z.Length; + + if (i < 1) + return x; + + int xBase = x.Length - y.Length; + + for (; ; ) { + long a = z[--i] & IMASK; + long val = 0; + + for (int j = y.Length - 1; j >= 0; j--) { + val += a * (y[j] & IMASK) + (x[xBase + j] & IMASK); + + x[xBase + j] = (int)val; + + val = (long)((ulong)val >> 32); + } + + --xBase; + + if (i < 1) { + if (xBase >= 0) { + x[xBase] = (int)val; + } + else { + Debug.Assert(val == 0); + } + break; + } + + x[xBase] = (int)val; + } + + return x; + } + + private static long FastExtEuclid( + long a, + long b, + long[] uOut) { + long u1 = 1; + long u3 = a; + long v1 = 0; + long v3 = b; + + while (v3 > 0) { + long q, tn; + + q = u3 / v3; + + tn = u1 - (v1 * q); + u1 = v1; + v1 = tn; + + tn = u3 - (v3 * q); + u3 = v3; + v3 = tn; + } + + uOut[0] = u1; + uOut[1] = (u3 - (u1 * a)) / b; + + return u3; + } + + private static long FastModInverse( + long v, + long m) { + if (m < 1) + throw new ArithmeticException("Modulus must be positive"); + + long[] x = new long[2]; + long gcd = FastExtEuclid(v, m, x); + + if (gcd != 1) + throw new ArithmeticException("Numbers not relatively prime."); + + if (x[0] < 0) { + x[0] += m; + } + + return x[0]; + } + + // private static BigInteger MQuoteB = One.ShiftLeft(32); + // private static BigInteger MQuoteBSub1 = MQuoteB.Subtract(One); + + /** + * Calculate mQuote = -m^(-1) mod b with b = 2^32 (32 = word size) + */ + private long GetMQuote() { + Debug.Assert(this.sign > 0); + + if (mQuote != -1) { + return mQuote; // already calculated + } + + if (magnitude.Length == 0 || (magnitude[magnitude.Length - 1] & 1) == 0) { + return -1; // not for even numbers + } + + long v = (((~this.magnitude[this.magnitude.Length - 1]) | 1) & 0xffffffffL); + mQuote = FastModInverse(v, 0x100000000L); + + return mQuote; + } + + /** + * Montgomery multiplication: a = x * y * R^(-1) mod m + *
+ * Based algorithm 14.36 of Handbook of Applied Cryptography. + *
+ *
  • m, x, y should have length n
  • + *
  • a should have length (n + 1)
  • + *
  • b = 2^32, R = b^n
  • + *
    + * The result is put in x + *
    + * NOTE: the indices of x, y, m, a different in HAC and in Java + */ + private static void MultiplyMonty( + int[] a, + int[] x, + int[] y, + int[] m, + long mQuote) + // mQuote = -m^(-1) mod b + { + if (m.Length == 1) { + x[0] = (int)MultiplyMontyNIsOne((uint)x[0], (uint)y[0], (uint)m[0], (ulong)mQuote); + return; + } + + int n = m.Length; + int nMinus1 = n - 1; + long y_0 = y[nMinus1] & IMASK; + + // 1. a = 0 (Notation: a = (a_{n} a_{n-1} ... a_{0})_{b} ) + Array.Clear(a, 0, n + 1); + + // 2. for i from 0 to (n - 1) do the following: + for (int i = n; i > 0; i--) { + long x_i = x[i - 1] & IMASK; + + // 2.1 u = ((a[0] + (x[i] * y[0]) * mQuote) mod b + long u = ((((a[n] & IMASK) + ((x_i * y_0) & IMASK)) & IMASK) * mQuote) & IMASK; + + // 2.2 a = (a + x_i * y + u * m) / b + long prod1 = x_i * y_0; + long prod2 = u * (m[nMinus1] & IMASK); + long tmp = (a[n] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK); + long carry = (long)((ulong)prod1 >> 32) + (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32); + for (int j = nMinus1; j > 0; j--) { + prod1 = x_i * (y[j - 1] & IMASK); + prod2 = u * (m[j - 1] & IMASK); + tmp = (a[j] & IMASK) + (prod1 & IMASK) + (prod2 & IMASK) + (carry & IMASK); + carry = (long)((ulong)carry >> 32) + (long)((ulong)prod1 >> 32) + + (long)((ulong)prod2 >> 32) + (long)((ulong)tmp >> 32); + a[j + 1] = (int)tmp; // division by b + } + carry += (a[0] & IMASK); + a[1] = (int)carry; + a[0] = (int)((ulong)carry >> 32); // OJO!!!!! + } + + // 3. if x >= m the x = x - m + if (CompareTo(0, a, 0, m) >= 0) { + Subtract(0, a, 0, m); + } + + // put the result in x + Array.Copy(a, 1, x, 0, n); + } + + private static uint MultiplyMontyNIsOne( + uint x, + uint y, + uint m, + ulong mQuote) { + ulong um = m; + ulong prod1 = (ulong)x * (ulong)y; + ulong u = (prod1 * mQuote) & UIMASK; + ulong prod2 = u * um; + ulong tmp = (prod1 & UIMASK) + (prod2 & UIMASK); + ulong carry = (prod1 >> 32) + (prod2 >> 32) + (tmp >> 32); + + if (carry > um) { + carry -= um; + } + + return (uint)(carry & UIMASK); + } + + public BigInteger Multiply( + BigInteger val) { + if (sign == 0 || val.sign == 0) + return Zero; + + if (val.QuickPow2Check()) // val is power of two + { + BigInteger result = this.ShiftLeft(val.Abs().BitLength - 1); + return val.sign > 0 ? result : result.Negate(); + } + + if (this.QuickPow2Check()) // this is power of two + { + BigInteger result = val.ShiftLeft(this.Abs().BitLength - 1); + return this.sign > 0 ? result : result.Negate(); + } + + int resLength = (this.BitLength + val.BitLength) / BitsPerInt + 1; + int[] res = new int[resLength]; + + if (val == this) { + Square(res, this.magnitude); + } + else { + Multiply(res, this.magnitude, val.magnitude); + } + + return new BigInteger(sign * val.sign, res, true); + } + + public BigInteger Negate() { + if (sign == 0) + return this; + + return new BigInteger(-sign, magnitude, false); + } + + public BigInteger NextProbablePrime() { + if (sign < 0) + throw new ArithmeticException("Cannot be called on value < 0"); + + if (CompareTo(Two) < 0) + return Two; + + BigInteger n = Inc().SetBit(0); + + while (!n.CheckProbablePrime(100, RandomSource)) { + n = n.Add(Two); + } + + return n; + } + + public BigInteger Not() { + return Inc().Negate(); + } + + public BigInteger Pow(int exp) { + if (exp < 0) { + throw new ArithmeticException("Negative exponent"); + } + + if (exp == 0) { + return One; + } + + if (sign == 0 || Equals(One)) { + return this; + } + + BigInteger y = One; + BigInteger z = this; + + for (; ; ) { + if ((exp & 0x1) == 1) { + y = y.Multiply(z); + } + exp >>= 1; + if (exp == 0) break; + z = z.Multiply(z); + } + + return y; + } + + public static BigInteger ProbablePrime( + int bitLength, + Random random) { + return new BigInteger(bitLength, 100, random); + } + + private int Remainder( + int m) { + Debug.Assert(m > 0); + + long acc = 0; + for (int pos = 0; pos < magnitude.Length; ++pos) { + long posVal = (uint)magnitude[pos]; + acc = (acc << 32 | posVal) % m; + } + + return (int)acc; + } + + /** + * return x = x % y - done in place (y value preserved) + */ + private int[] Remainder( + int[] x, + int[] y) { + int xStart = 0; + while (xStart < x.Length && x[xStart] == 0) { + ++xStart; + } + + int yStart = 0; + while (yStart < y.Length && y[yStart] == 0) { + ++yStart; + } + + Debug.Assert(yStart < y.Length); + + int xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp > 0) { + int yBitLength = calcBitLength(yStart, y); + int xBitLength = calcBitLength(xStart, x); + int shift = xBitLength - yBitLength; + + int[] c; + int cStart = 0; + int cBitLength = yBitLength; + if (shift > 0) { + c = ShiftLeft(y, shift); + cBitLength += shift; + Debug.Assert(c[0] != 0); + } + else { + int len = y.Length - yStart; + c = new int[len]; + Array.Copy(y, yStart, c, 0, len); + } + + for (; ; ) { + if (cBitLength < xBitLength + || CompareNoLeadingZeroes(xStart, x, cStart, c) >= 0) { + Subtract(xStart, x, cStart, c); + + while (x[xStart] == 0) { + if (++xStart == x.Length) + return x; + } + + //xBitLength = calcBitLength(xStart, x); + xBitLength = 32 * (x.Length - xStart - 1) + BitLen(x[xStart]); + + if (xBitLength <= yBitLength) { + if (xBitLength < yBitLength) + return x; + + xyCmp = CompareNoLeadingZeroes(xStart, x, yStart, y); + + if (xyCmp <= 0) + break; + } + } + + shift = cBitLength - xBitLength; + + // NB: The case where c[cStart] is 1-bit is harmless + if (shift == 1) { + uint firstC = (uint)c[cStart] >> 1; + uint firstX = (uint)x[xStart]; + if (firstC > firstX) + ++shift; + } + + if (shift < 2) { + ShiftRightOneInPlace(cStart, c); + --cBitLength; + } + else { + ShiftRightInPlace(cStart, c, shift); + cBitLength -= shift; + } + + //cStart = c.Length - ((cBitLength + 31) / 32); + while (c[cStart] == 0) { + ++cStart; + } + } + } + + if (xyCmp == 0) { + Array.Clear(x, xStart, x.Length - xStart); + } + + return x; + } + + public BigInteger Remainder( + BigInteger n) { + if (n.sign == 0) + throw new ArithmeticException("Division by zero error"); + + if (this.sign == 0) + return Zero; + + // For small values, use fast remainder method + if (n.magnitude.Length == 1) { + int val = n.magnitude[0]; + + if (val > 0) { + if (val == 1) + return Zero; + + // TODO Make this func work on uint, and handle val == 1? + int rem = Remainder(val); + + return rem == 0 + ? Zero + : new BigInteger(sign, new int[] { rem }, false); + } + } + + if (CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude) < 0) + return this; + + int[] result; + if (n.QuickPow2Check()) // n is power of two + { + // TODO Move before small values branch above? + result = LastNBits(n.Abs().BitLength - 1); + } + else { + result = (int[])this.magnitude.Clone(); + result = Remainder(result, n.magnitude); + } + + return new BigInteger(sign, result, true); + } + + private int[] LastNBits( + int n) { + if (n < 1) + return ZeroMagnitude; + + int numWords = (n + BitsPerInt - 1) / BitsPerInt; + numWords = System.Math.Min(numWords, this.magnitude.Length); + int[] result = new int[numWords]; + + Array.Copy(this.magnitude, this.magnitude.Length - numWords, result, 0, numWords); + + int hiBits = n % 32; + if (hiBits != 0) { + result[0] &= ~(-1 << hiBits); + } + + return result; + } + + /** + * do a left shift - this returns a new array. + */ + private static int[] ShiftLeft( + int[] mag, + int n) { + int nInts = (int)((uint)n >> 5); + int nBits = n & 0x1f; + int magLen = mag.Length; + int[] newMag; + + if (nBits == 0) { + newMag = new int[magLen + nInts]; + mag.CopyTo(newMag, 0); + } + else { + int i = 0; + int nBits2 = 32 - nBits; + int highBits = (int)((uint)mag[0] >> nBits2); + + if (highBits != 0) { + newMag = new int[magLen + nInts + 1]; + newMag[i++] = highBits; + } + else { + newMag = new int[magLen + nInts]; + } + + int m = mag[0]; + for (int j = 0; j < magLen - 1; j++) { + int next = mag[j + 1]; + + newMag[i++] = (m << nBits) | (int)((uint)next >> nBits2); + m = next; + } + + newMag[i] = mag[magLen - 1] << nBits; + } + + return newMag; + } + + public BigInteger ShiftLeft( + int n) { + if (sign == 0 || magnitude.Length == 0) + return Zero; + + if (n == 0) + return this; + + if (n < 0) + return ShiftRight(-n); + + BigInteger result = new BigInteger(sign, ShiftLeft(magnitude, n), true); + + if (this.nBits != -1) { + result.nBits = sign > 0 + ? this.nBits + : this.nBits + n; + } + + if (this.nBitLength != -1) { + result.nBitLength = this.nBitLength + n; + } + + return result; + } + + /** + * do a right shift - this does it in place. + */ + private static void ShiftRightInPlace( + int start, + int[] mag, + int n) { + int nInts = (int)((uint)n >> 5) + start; + int nBits = n & 0x1f; + int magEnd = mag.Length - 1; + + if (nInts != start) { + int delta = (nInts - start); + + for (int i = magEnd; i >= nInts; i--) { + mag[i] = mag[i - delta]; + } + for (int i = nInts - 1; i >= start; i--) { + mag[i] = 0; + } + } + + if (nBits != 0) { + int nBits2 = 32 - nBits; + int m = mag[magEnd]; + + for (int i = magEnd; i > nInts; --i) { + int next = mag[i - 1]; + + mag[i] = (int)((uint)m >> nBits) | (next << nBits2); + m = next; + } + + mag[nInts] = (int)((uint)mag[nInts] >> nBits); + } + } + + /** + * do a right shift by one - this does it in place. + */ + private static void ShiftRightOneInPlace( + int start, + int[] mag) { + int i = mag.Length; + int m = mag[i - 1]; + + while (--i > start) { + int next = mag[i - 1]; + mag[i] = ((int)((uint)m >> 1)) | (next << 31); + m = next; + } + + mag[start] = (int)((uint)mag[start] >> 1); + } + + public BigInteger ShiftRight( + int n) { + if (n == 0) + return this; + + if (n < 0) + return ShiftLeft(-n); + + if (n >= BitLength) + return (this.sign < 0 ? One.Negate() : Zero); + + // int[] res = (int[]) this.magnitude.Clone(); + // + // ShiftRightInPlace(0, res, n); + // + // return new BigInteger(this.sign, res, true); + + int resultLength = (BitLength - n + 31) >> 5; + int[] res = new int[resultLength]; + + int numInts = n >> 5; + int numBits = n & 31; + + if (numBits == 0) { + Array.Copy(this.magnitude, 0, res, 0, res.Length); + } + else { + int numBits2 = 32 - numBits; + + int magPos = this.magnitude.Length - 1 - numInts; + for (int i = resultLength - 1; i >= 0; --i) { + res[i] = (int)((uint)this.magnitude[magPos--] >> numBits); + + if (magPos >= 0) { + res[i] |= this.magnitude[magPos] << numBits2; + } + } + } + + Debug.Assert(res[0] != 0); + + return new BigInteger(this.sign, res, false); + } + + public int SignValue { + get { return sign; } + } + + /** + * returns x = x - y - we assume x is >= y + */ + private static int[] Subtract( + int xStart, + int[] x, + int yStart, + int[] y) { + Debug.Assert(yStart < y.Length); + Debug.Assert(x.Length - xStart >= y.Length - yStart); + + int iT = x.Length; + int iV = y.Length; + long m; + int borrow = 0; + + do { + m = (x[--iT] & IMASK) - (y[--iV] & IMASK) + borrow; + x[iT] = (int)m; + + // borrow = (m < 0) ? -1 : 0; + borrow = (int)(m >> 63); + } + while (iV > yStart); + + if (borrow != 0) { + while (--x[--iT] == -1) { + } + } + + return x; + } + + public BigInteger Subtract( + BigInteger n) { + if (n.sign == 0) + return this; + + if (this.sign == 0) + return n.Negate(); + + if (this.sign != n.sign) + return Add(n.Negate()); + + int compare = CompareNoLeadingZeroes(0, magnitude, 0, n.magnitude); + if (compare == 0) + return Zero; + + BigInteger bigun, lilun; + if (compare < 0) { + bigun = n; + lilun = this; + } + else { + bigun = this; + lilun = n; + } + + return new BigInteger(this.sign * compare, doSubBigLil(bigun.magnitude, lilun.magnitude), true); + } + + private static int[] doSubBigLil( + int[] bigMag, + int[] lilMag) { + int[] res = (int[])bigMag.Clone(); + + return Subtract(0, res, 0, lilMag); + } + + public byte[] ToByteArray() { + return ToByteArray(false); + } + + public byte[] ToByteArrayUnsigned() { + return ToByteArray(true); + } + + private byte[] ToByteArray( + bool unsigned) { + if (sign == 0) + return unsigned ? ZeroEncoding : new byte[1]; + + int nBits = (unsigned && sign > 0) + ? BitLength + : BitLength + 1; + + int nBytes = GetByteLength(nBits); + byte[] bytes = new byte[nBytes]; + + int magIndex = magnitude.Length; + int bytesIndex = bytes.Length; + + if (sign > 0) { + while (magIndex > 1) { + uint mag = (uint)magnitude[--magIndex]; + bytes[--bytesIndex] = (byte)mag; + bytes[--bytesIndex] = (byte)(mag >> 8); + bytes[--bytesIndex] = (byte)(mag >> 16); + bytes[--bytesIndex] = (byte)(mag >> 24); + } + + uint lastMag = (uint)magnitude[0]; + while (lastMag > byte.MaxValue) { + bytes[--bytesIndex] = (byte)lastMag; + lastMag >>= 8; + } + + bytes[--bytesIndex] = (byte)lastMag; + } + else // sign < 0 + { + bool carry = true; + + while (magIndex > 1) { + uint mag = ~((uint)magnitude[--magIndex]); + + if (carry) { + carry = (++mag == uint.MinValue); + } + + bytes[--bytesIndex] = (byte)mag; + bytes[--bytesIndex] = (byte)(mag >> 8); + bytes[--bytesIndex] = (byte)(mag >> 16); + bytes[--bytesIndex] = (byte)(mag >> 24); + } + + uint lastMag = (uint)magnitude[0]; + + if (carry) { + // Never wraps because magnitude[0] != 0 + --lastMag; + } + + while (lastMag > byte.MaxValue) { + bytes[--bytesIndex] = (byte)~lastMag; + lastMag >>= 8; + } + + bytes[--bytesIndex] = (byte)~lastMag; + + if (bytesIndex > 0) { + bytes[--bytesIndex] = byte.MaxValue; + } + } + + return bytes; + } + + public override string ToString() { + return ToString(10); + } + + public string ToString( + int radix) { + // TODO Make this method work for other radices (ideally 2 <= radix <= 16) + + switch (radix) { + case 2: + case 10: + case 16: + break; + default: + throw new FormatException("Only bases 2, 10, 16 are allowed"); + } + + // NB: Can only happen to internally managed instances + if (magnitude == null) + return "null"; + + if (sign == 0) + return "0"; + + Debug.Assert(magnitude.Length > 0); + + StringBuilder sb = new StringBuilder(); + + if (radix == 16) { + sb.Append(magnitude[0].ToString("x")); + + for (int i = 1; i < magnitude.Length; i++) { + sb.Append(magnitude[i].ToString("x8")); + } + } + else if (radix == 2) { + sb.Append('1'); + + for (int i = BitLength - 2; i >= 0; --i) { + sb.Append(TestBit(i) ? '1' : '0'); + } + } + else { + // This is algorithm 1a from chapter 4.4 in Seminumerical Algorithms, slow but it works + IList S = new List(); + BigInteger bs = ValueOf(radix); + + // The sign is handled separatly. + // Notice however that for this to work, radix 16 _MUST_ be a special case, + // unless we want to enter a recursion well. In their infinite wisdom, why did not + // the Sun engineers made a c'tor for BigIntegers taking a BigInteger as parameter? + // (Answer: Becuase Sun's BigIntger is clonable, something bouncycastle's isn't.) + // BigInteger u = new BigInteger(Abs().ToString(16), 16); + BigInteger u = this.Abs(); + BigInteger b; + + while (u.sign != 0) { + b = u.Mod(bs); + if (b.sign == 0) { + S.Add("0"); + } + else { + // see how to interact with different bases + S.Add(b.magnitude[0].ToString("d")); + } + u = u.Divide(bs); + } + + // Then pop the stack + for (int i = S.Count - 1; i >= 0; --i) { + sb.Append((string)S[i]); + } + } + + string s = sb.ToString(); + + Debug.Assert(s.Length > 0); + + // Strip leading zeros. (We know this number is not all zeroes though) + if (s[0] == '0') { + int nonZeroPos = 0; + while (s[++nonZeroPos] == '0') { } + + s = s.Substring(nonZeroPos); + } + + if (sign == -1) { + s = "-" + s; + } + + return s; + } + + private static BigInteger createUValueOf( + ulong value) { + int msw = (int)(value >> 32); + int lsw = (int)value; + + if (msw != 0) + return new BigInteger(1, new int[] { msw, lsw }, false); + + if (lsw != 0) { + BigInteger n = new BigInteger(1, new int[] { lsw }, false); + // Check for a power of two + if ((lsw & -lsw) == lsw) { + n.nBits = 1; + } + return n; + } + + return Zero; + } + + private static BigInteger createValueOf( + long value) { + if (value < 0) { + if (value == long.MinValue) + return createValueOf(~value).Not(); + + return createValueOf(-value).Negate(); + } + + return createUValueOf((ulong)value); + + // // store value into a byte array + // byte[] b = new byte[8]; + // for (int i = 0; i < 8; i++) + // { + // b[7 - i] = (byte)value; + // value >>= 8; + // } + // + // return new BigInteger(b); + } + + public static BigInteger ValueOf( + long value) { + switch (value) { + case 0: + return Zero; + case 1: + return One; + case 2: + return Two; + case 3: + return Three; + case 10: + return Ten; + } + + return createValueOf(value); + } + + public int GetLowestSetBit() { + if (this.sign == 0) + return -1; + + int w = magnitude.Length; + + while (--w > 0) { + if (magnitude[w] != 0) + break; + } + + int word = (int)magnitude[w]; + Debug.Assert(word != 0); + + int b = (word & 0x0000FFFF) == 0 + ? (word & 0x00FF0000) == 0 + ? 7 + : 15 + : (word & 0x000000FF) == 0 + ? 23 + : 31; + + while (b > 0) { + if ((word << b) == int.MinValue) + break; + + b--; + } + + return ((magnitude.Length - w) * 32 - (b + 1)); + } + + public bool TestBit( + int n) { + if (n < 0) + throw new ArithmeticException("Bit position must not be negative"); + + if (sign < 0) + return !Not().TestBit(n); + + int wordNum = n / 32; + if (wordNum >= magnitude.Length) + return false; + + int word = magnitude[magnitude.Length - 1 - wordNum]; + return ((word >> (n % 32)) & 1) > 0; + } + + public BigInteger Or( + BigInteger value) { + if (this.sign == 0) + return value; + + if (value.sign == 0) + return this; + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + bool resultNeg = sign < 0 || value.sign < 0; + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) { + aWord = ~aWord; + } + + if (value.sign < 0) { + bWord = ~bWord; + } + + resultMag[i] = aWord | bWord; + + if (resultNeg) { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) { + result = result.Not(); + } + + return result; + } + + public BigInteger Xor( + BigInteger value) { + if (this.sign == 0) + return value; + + if (value.sign == 0) + return this; + + int[] aMag = this.sign > 0 + ? this.magnitude + : Add(One).magnitude; + + int[] bMag = value.sign > 0 + ? value.magnitude + : value.Add(One).magnitude; + + // TODO Can just replace with sign != value.sign? + bool resultNeg = (sign < 0 && value.sign >= 0) || (sign >= 0 && value.sign < 0); + int resultLength = System.Math.Max(aMag.Length, bMag.Length); + int[] resultMag = new int[resultLength]; + + int aStart = resultMag.Length - aMag.Length; + int bStart = resultMag.Length - bMag.Length; + + for (int i = 0; i < resultMag.Length; ++i) { + int aWord = i >= aStart ? aMag[i - aStart] : 0; + int bWord = i >= bStart ? bMag[i - bStart] : 0; + + if (this.sign < 0) { + aWord = ~aWord; + } + + if (value.sign < 0) { + bWord = ~bWord; + } + + resultMag[i] = aWord ^ bWord; + + if (resultNeg) { + resultMag[i] = ~resultMag[i]; + } + } + + BigInteger result = new BigInteger(1, resultMag, true); + + // TODO Optimise this case + if (resultNeg) { + result = result.Not(); + } + + return result; + } + + public BigInteger SetBit( + int n) { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + if (TestBit(n)) + return this; + + // TODO Handle negative values and zero + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return Or(One.ShiftLeft(n)); + } + + public BigInteger ClearBit( + int n) { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + if (!TestBit(n)) + return this; + + // TODO Handle negative values + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return AndNot(One.ShiftLeft(n)); + } + + public BigInteger FlipBit( + int n) { + if (n < 0) + throw new ArithmeticException("Bit address less than zero"); + + // TODO Handle negative values and zero + if (sign > 0 && n < (BitLength - 1)) + return FlipExistingBit(n); + + return Xor(One.ShiftLeft(n)); + } + + private BigInteger FlipExistingBit( + int n) { + Debug.Assert(sign > 0); + Debug.Assert(n >= 0); + Debug.Assert(n < BitLength - 1); + + int[] mag = (int[])this.magnitude.Clone(); + mag[mag.Length - 1 - (n >> 5)] ^= (1 << (n & 31)); // Flip bit + //mag[mag.Length - 1 - (n / 32)] ^= (1 << (n % 32)); + return new BigInteger(this.sign, mag, false); + } + } +} \ No newline at end of file diff --git a/TLSharp.Core/MTProto/Crypto/Crc32.cs b/TLSharp.Core/MTProto/Crypto/Crc32.cs new file mode 100644 index 0000000..cb4b496 --- /dev/null +++ b/TLSharp.Core/MTProto/Crypto/Crc32.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Security.Cryptography; +using System.Text; +using System.Threading.Tasks; +using Ionic.Crc; + +namespace TLSharp.Core.MTProto.Crypto { + public class Crc32 : HashAlgorithm { + public const UInt32 DefaultPolynomial = 0xedb88320u; + public const UInt32 DefaultSeed = 0xffffffffu; + + private UInt32 hash; + private UInt32 seed; + private UInt32[] table; + private static UInt32[] defaultTable; + + public Crc32() { + table = InitializeTable(DefaultPolynomial); + seed = DefaultSeed; + hash = seed; + } + + public Crc32(UInt32 polynomial, UInt32 seed) { + table = InitializeTable(polynomial); + this.seed = seed; + hash = seed; + } + + public override void Initialize() { + hash = seed; + } + + protected override void HashCore(byte[] buffer, int start, int length) { + hash = CalculateHash(table, hash, buffer, start, length); + } + + /// + /// Возвращает хеш в BigEndian + /// + /// + protected override byte[] HashFinal() { + byte[] hashBuffer = UInt32ToBigEndianBytes(~hash); + this.HashValue = hashBuffer; + return hashBuffer; + } + + public override int HashSize { + get { return 32; } + } + + public static UInt32 Compute(byte[] buffer) { + return ~CalculateHash(InitializeTable(DefaultPolynomial), DefaultSeed, buffer, 0, buffer.Length); + } + + public static UInt32 Compute(UInt32 seed, byte[] buffer) { + return ~CalculateHash(InitializeTable(DefaultPolynomial), seed, buffer, 0, buffer.Length); + } + + public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer) { + return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length); + } + + private static UInt32[] InitializeTable(UInt32 polynomial) { + if (polynomial == DefaultPolynomial && defaultTable != null) + return defaultTable; + + UInt32[] createTable = new UInt32[256]; + for (int i = 0; i < 256; i++) { + UInt32 entry = (UInt32)i; + for (int j = 0; j < 8; j++) + if ((entry & 1) == 1) + entry = (entry >> 1) ^ polynomial; + else + entry = entry >> 1; + createTable[i] = entry; + } + + if (polynomial == DefaultPolynomial) + defaultTable = createTable; + + return createTable; + } + + private static UInt32 CalculateHash(UInt32[] table, UInt32 seed, byte[] buffer, int start, int size) { + UInt32 crc = seed; + for (int i = start; i < size; i++) + unchecked { + crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff]; + } + return crc; + } + + private byte[] UInt32ToBigEndianBytes(UInt32 x) { + return new byte[] { + (byte)((x >> 24) & 0xff), + (byte)((x >> 16) & 0xff), + (byte)((x >> 8) & 0xff), + (byte)(x & 0xff) + }; + } + } +} diff --git a/TLSharp.Core/MTProto/Crypto/Factorizator.cs b/TLSharp.Core/MTProto/Crypto/Factorizator.cs new file mode 100644 index 0000000..ed7b13f --- /dev/null +++ b/TLSharp.Core/MTProto/Crypto/Factorizator.cs @@ -0,0 +1,110 @@ +using System; + +namespace TLSharp.Core.MTProto.Crypto { + public class FactorizedPair { + private readonly BigInteger p; + private readonly BigInteger q; + + public FactorizedPair(BigInteger p, BigInteger q) { + this.p = p; + this.q = q; + } + + public FactorizedPair(long p, long q) { + this.p = BigInteger.ValueOf(p); + this.q = BigInteger.ValueOf(q); + } + + public BigInteger Min { + get { + return p.Min(q); + } + } + + public BigInteger Max { + get { + return p.Max(q); + } + } + + public override string ToString() { + return string.Format("P: {0}, Q: {1}", p, q); + } + } + public class Factorizator { + public static Random random = new Random(); + public static long findSmallMultiplierLopatin(long what) { + long g = 0; + for (int i = 0; i < 3; i++) { + int q = (random.Next(128) & 15) + 17; + long x = random.Next(1000000000) + 1, y = x; + int lim = 1 << (i + 18); + for (int j = 1; j < lim; j++) { + long a = x, b = x, c = q; + while (b != 0) { + if ((b & 1) != 0) { + c += a; + if (c >= what) { + c -= what; + } + } + a += a; + if (a >= what) { + a -= what; + } + b >>= 1; + } + x = c; + long z = x < y ? y - x : x - y; + g = GCD(z, what); + if (g != 1) { + break; + } + if ((j & (j - 1)) == 0) { + y = x; + } + } + if (g > 1) { + break; + } + } + + long p = what / g; + return Math.Min(p, g); + } + + public static long GCD(long a, long b) { + while (a != 0 && b != 0) { + while ((b & 1) == 0) { + b >>= 1; + } + while ((a & 1) == 0) { + a >>= 1; + } + if (a > b) { + a -= b; + } + else { + b -= a; + } + } + return b == 0 ? a : b; + } + + public static FactorizedPair Factorize(BigInteger pq) { + if(pq.BitLength < 64) { + long pqlong = pq.LongValue; + long divisor = findSmallMultiplierLopatin(pqlong); + return new FactorizedPair(BigInteger.ValueOf(divisor), BigInteger.ValueOf(pqlong/divisor)); + } else { + // TODO: port pollard factorization + throw new InvalidOperationException("pq too long; TODO: port the pollard algo"); + // logger.error("pq too long; TODO: port the pollard algo"); + // return null; + } + } + + } + + +} diff --git a/TLSharp.Core/MTProto/Crypto/MD5Digest.cs b/TLSharp.Core/MTProto/Crypto/MD5Digest.cs new file mode 100644 index 0000000..e320931 --- /dev/null +++ b/TLSharp.Core/MTProto/Crypto/MD5Digest.cs @@ -0,0 +1,463 @@ +using System; +using System.Text; + +namespace TLSharp.Core.MTProto.Crypto { + public interface IDigest { + /** +* return the algorithm name +* +* @return the algorithm name +*/ + string AlgorithmName { get; } + + /** +* return the size, in bytes, of the digest produced by this message digest. +* +* @return the size, in bytes, of the digest produced by this message digest. +*/ + int GetDigestSize(); + + /** +* return the size, in bytes, of the internal buffer used by this digest. +* +* @return the size, in bytes, of the internal buffer used by this digest. +*/ + int GetByteLength(); + + /** +* update the message digest with a single byte. +* +* @param inByte the input byte to be entered. +*/ + void Update(byte input); + + /** +* update the message digest with a block of bytes. +* +* @param input the byte array containing the data. +* @param inOff the offset into the byte array where the data starts. +* @param len the length of the data. +*/ + void BlockUpdate(byte[] input, int inOff, int length); + + /** +* Close the digest, producing the final digest value. The doFinal +* call leaves the digest reset. +* +* @param output the array the digest is to be copied into. +* @param outOff the offset into the out array the digest is to start at. +*/ + int DoFinal(byte[] output, int outOff); + + /** +* reset the digest back to it's initial state. +*/ + void Reset(); + } + + public class MD5 { + + public static string GetMd5String(string data) { + return BitConverter.ToString(GetMd5Bytes(Encoding.UTF8.GetBytes(data))).Replace("-", "").ToLower(); + } + + public static byte[] GetMd5Bytes(byte[] data) { + MD5Digest digest = new MD5Digest(); + digest.BlockUpdate(data, 0, data.Length); + byte[] hash = new byte[16]; + digest.DoFinal(hash, 0); + + return hash; + } + + private MD5Digest digest = new MD5Digest(); + + public void Update(byte[] chunk) { + digest.BlockUpdate(chunk, 0, chunk.Length); + } + + public void Update(byte[] chunk, int offset, int limit) { + digest.BlockUpdate(chunk, offset, limit); + } + + public string FinalString() { + byte[] hash = new byte[16]; + digest.DoFinal(hash, 0); + return BitConverter.ToString(hash).Replace("-", "").ToLower(); + } + } + + public abstract class GeneralDigest + : IDigest { + private const int BYTE_LENGTH = 64; + + private readonly byte[] xBuf; + + private long byteCount; + private int xBufOff; + + internal GeneralDigest() { + xBuf = new byte[4]; + } + + internal GeneralDigest(GeneralDigest t) { + xBuf = new byte[t.xBuf.Length]; + Array.Copy(t.xBuf, 0, xBuf, 0, t.xBuf.Length); + + xBufOff = t.xBufOff; + byteCount = t.byteCount; + } + + public void Update(byte input) { + xBuf[xBufOff++] = input; + + if (xBufOff == xBuf.Length) { + ProcessWord(xBuf, 0); + xBufOff = 0; + } + + byteCount++; + } + + public void BlockUpdate( + byte[] input, + int inOff, + int length) { + // + // fill the current word + // + while ((xBufOff != 0) && (length > 0)) { + Update(input[inOff]); + inOff++; + length--; + } + + // + // process whole words. + // + while (length > xBuf.Length) { + ProcessWord(input, inOff); + + inOff += xBuf.Length; + length -= xBuf.Length; + byteCount += xBuf.Length; + } + + // + // load in the remainder. + // + while (length > 0) { + Update(input[inOff]); + + inOff++; + length--; + } + } + + public virtual void Reset() { + byteCount = 0; + xBufOff = 0; + Array.Clear(xBuf, 0, xBuf.Length); + } + + public int GetByteLength() { + return BYTE_LENGTH; + } + + public abstract string AlgorithmName { get; } + public abstract int GetDigestSize(); + public abstract int DoFinal(byte[] output, int outOff); + + public void Finish() { + long bitLength = (byteCount << 3); + + // + // add the pad bytes. + // + Update(128); + + while (xBufOff != 0) Update(0); + ProcessLength(bitLength); + ProcessBlock(); + } + + internal abstract void ProcessWord(byte[] input, int inOff); + internal abstract void ProcessLength(long bitLength); + internal abstract void ProcessBlock(); + } + + public class MD5Digest + : GeneralDigest { + private const int DigestLength = 16; + + // + // round 1 left rotates + // + private static readonly int S11 = 7; + private static readonly int S12 = 12; + private static readonly int S13 = 17; + private static readonly int S14 = 22; + + // + // round 2 left rotates + // + private static readonly int S21 = 5; + private static readonly int S22 = 9; + private static readonly int S23 = 14; + private static readonly int S24 = 20; + + // + // round 3 left rotates + // + private static readonly int S31 = 4; + private static readonly int S32 = 11; + private static readonly int S33 = 16; + private static readonly int S34 = 23; + + // + // round 4 left rotates + // + private static readonly int S41 = 6; + private static readonly int S42 = 10; + private static readonly int S43 = 15; + private static readonly int S44 = 21; + private readonly int[] X = new int[16]; + private int H1, H2, H3, H4; // IV's + private int xOff; + + public MD5Digest() { + Reset(); + } + + /** +* Copy constructor. This will copy the state of the provided +* message digest. +*/ + + public MD5Digest(MD5Digest t) + : base(t) { + H1 = t.H1; + H2 = t.H2; + H3 = t.H3; + H4 = t.H4; + + Array.Copy(t.X, 0, X, 0, t.X.Length); + xOff = t.xOff; + } + + public override string AlgorithmName { + get { return "MD5"; } + } + + public override int GetDigestSize() { + return DigestLength; + } + + internal override void ProcessWord( + byte[] input, + int inOff) { + X[xOff++] = (input[inOff] & 0xff) | ((input[inOff + 1] & 0xff) << 8) + | ((input[inOff + 2] & 0xff) << 16) | ((input[inOff + 3] & 0xff) << 24); + + if (xOff == 16) { + ProcessBlock(); + } + } + + internal override void ProcessLength( + long bitLength) { + if (xOff > 14) { + ProcessBlock(); + } + + X[14] = (int) (bitLength & 0xffffffff); + X[15] = (int) ((ulong) bitLength >> 32); + } + + private void UnpackWord( + int word, + byte[] outBytes, + int outOff) { + outBytes[outOff] = (byte) word; + outBytes[outOff + 1] = (byte) ((uint) word >> 8); + outBytes[outOff + 2] = (byte) ((uint) word >> 16); + outBytes[outOff + 3] = (byte) ((uint) word >> 24); + } + + public override int DoFinal( + byte[] output, + int outOff) { + Finish(); + + UnpackWord(H1, output, outOff); + UnpackWord(H2, output, outOff + 4); + UnpackWord(H3, output, outOff + 8); + UnpackWord(H4, output, outOff + 12); + + Reset(); + + return DigestLength; + } + + /** +* reset the chaining variables to the IV values. +*/ + + public override void Reset() { + base.Reset(); + + H1 = unchecked(0x67452301); + H2 = unchecked((int) 0xefcdab89); + H3 = unchecked((int) 0x98badcfe); + H4 = unchecked(0x10325476); + + xOff = 0; + + for (int i = 0; i != X.Length; i++) { + X[i] = 0; + } + } + + /* +* rotate int x left n bits. +*/ + + private int RotateLeft( + int x, + int n) { + return (x << n) | (int) ((uint) x >> (32 - n)); + } + + /* +* F, G, H and I are the basic MD5 functions. +*/ + + private int F( + int u, + int v, + int w) { + return (u & v) | (~u & w); + } + + private int G( + int u, + int v, + int w) { + return (u & w) | (v & ~w); + } + + private int H( + int u, + int v, + int w) { + return u ^ v ^ w; + } + + private int K( + int u, + int v, + int w) { + return v ^ (u | ~w); + } + + internal override void ProcessBlock() { + int a = H1; + int b = H2; + int c = H3; + int d = H4; + + // + // Round 1 - F cycle, 16 times. + // + a = RotateLeft((a + F(b, c, d) + X[0] + unchecked((int) 0xd76aa478)), S11) + b; + d = RotateLeft((d + F(a, b, c) + X[1] + unchecked((int) 0xe8c7b756)), S12) + a; + c = RotateLeft((c + F(d, a, b) + X[2] + unchecked(0x242070db)), S13) + d; + b = RotateLeft((b + F(c, d, a) + X[3] + unchecked((int) 0xc1bdceee)), S14) + c; + a = RotateLeft((a + F(b, c, d) + X[4] + unchecked((int) 0xf57c0faf)), S11) + b; + d = RotateLeft((d + F(a, b, c) + X[5] + unchecked(0x4787c62a)), S12) + a; + c = RotateLeft((c + F(d, a, b) + X[6] + unchecked((int) 0xa8304613)), S13) + d; + b = RotateLeft((b + F(c, d, a) + X[7] + unchecked((int) 0xfd469501)), S14) + c; + a = RotateLeft((a + F(b, c, d) + X[8] + unchecked(0x698098d8)), S11) + b; + d = RotateLeft((d + F(a, b, c) + X[9] + unchecked((int) 0x8b44f7af)), S12) + a; + c = RotateLeft((c + F(d, a, b) + X[10] + unchecked((int) 0xffff5bb1)), S13) + d; + b = RotateLeft((b + F(c, d, a) + X[11] + unchecked((int) 0x895cd7be)), S14) + c; + a = RotateLeft((a + F(b, c, d) + X[12] + unchecked(0x6b901122)), S11) + b; + d = RotateLeft((d + F(a, b, c) + X[13] + unchecked((int) 0xfd987193)), S12) + a; + c = RotateLeft((c + F(d, a, b) + X[14] + unchecked((int) 0xa679438e)), S13) + d; + b = RotateLeft((b + F(c, d, a) + X[15] + unchecked(0x49b40821)), S14) + c; + + // + // Round 2 - G cycle, 16 times. + // + a = RotateLeft((a + G(b, c, d) + X[1] + unchecked((int) 0xf61e2562)), S21) + b; + d = RotateLeft((d + G(a, b, c) + X[6] + unchecked((int) 0xc040b340)), S22) + a; + c = RotateLeft((c + G(d, a, b) + X[11] + unchecked(0x265e5a51)), S23) + d; + b = RotateLeft((b + G(c, d, a) + X[0] + unchecked((int) 0xe9b6c7aa)), S24) + c; + a = RotateLeft((a + G(b, c, d) + X[5] + unchecked((int) 0xd62f105d)), S21) + b; + d = RotateLeft((d + G(a, b, c) + X[10] + unchecked(0x02441453)), S22) + a; + c = RotateLeft((c + G(d, a, b) + X[15] + unchecked((int) 0xd8a1e681)), S23) + d; + b = RotateLeft((b + G(c, d, a) + X[4] + unchecked((int) 0xe7d3fbc8)), S24) + c; + a = RotateLeft((a + G(b, c, d) + X[9] + unchecked(0x21e1cde6)), S21) + b; + d = RotateLeft((d + G(a, b, c) + X[14] + unchecked((int) 0xc33707d6)), S22) + a; + c = RotateLeft((c + G(d, a, b) + X[3] + unchecked((int) 0xf4d50d87)), S23) + d; + b = RotateLeft((b + G(c, d, a) + X[8] + unchecked(0x455a14ed)), S24) + c; + a = RotateLeft((a + G(b, c, d) + X[13] + unchecked((int) 0xa9e3e905)), S21) + b; + d = RotateLeft((d + G(a, b, c) + X[2] + unchecked((int) 0xfcefa3f8)), S22) + a; + c = RotateLeft((c + G(d, a, b) + X[7] + unchecked(0x676f02d9)), S23) + d; + b = RotateLeft((b + G(c, d, a) + X[12] + unchecked((int) 0x8d2a4c8a)), S24) + c; + + // + // Round 3 - H cycle, 16 times. + // + a = RotateLeft((a + H(b, c, d) + X[5] + unchecked((int) 0xfffa3942)), S31) + b; + d = RotateLeft((d + H(a, b, c) + X[8] + unchecked((int) 0x8771f681)), S32) + a; + c = RotateLeft((c + H(d, a, b) + X[11] + unchecked(0x6d9d6122)), S33) + d; + b = RotateLeft((b + H(c, d, a) + X[14] + unchecked((int) 0xfde5380c)), S34) + c; + a = RotateLeft((a + H(b, c, d) + X[1] + unchecked((int) 0xa4beea44)), S31) + b; + d = RotateLeft((d + H(a, b, c) + X[4] + unchecked(0x4bdecfa9)), S32) + a; + c = RotateLeft((c + H(d, a, b) + X[7] + unchecked((int) 0xf6bb4b60)), S33) + d; + b = RotateLeft((b + H(c, d, a) + X[10] + unchecked((int) 0xbebfbc70)), S34) + c; + a = RotateLeft((a + H(b, c, d) + X[13] + unchecked(0x289b7ec6)), S31) + b; + d = RotateLeft((d + H(a, b, c) + X[0] + unchecked((int) 0xeaa127fa)), S32) + a; + c = RotateLeft((c + H(d, a, b) + X[3] + unchecked((int) 0xd4ef3085)), S33) + d; + b = RotateLeft((b + H(c, d, a) + X[6] + unchecked(0x04881d05)), S34) + c; + a = RotateLeft((a + H(b, c, d) + X[9] + unchecked((int) 0xd9d4d039)), S31) + b; + d = RotateLeft((d + H(a, b, c) + X[12] + unchecked((int) 0xe6db99e5)), S32) + a; + c = RotateLeft((c + H(d, a, b) + X[15] + unchecked(0x1fa27cf8)), S33) + d; + b = RotateLeft((b + H(c, d, a) + X[2] + unchecked((int) 0xc4ac5665)), S34) + c; + + // + // Round 4 - K cycle, 16 times. + // + a = RotateLeft((a + K(b, c, d) + X[0] + unchecked((int) 0xf4292244)), S41) + b; + d = RotateLeft((d + K(a, b, c) + X[7] + unchecked(0x432aff97)), S42) + a; + c = RotateLeft((c + K(d, a, b) + X[14] + unchecked((int) 0xab9423a7)), S43) + d; + b = RotateLeft((b + K(c, d, a) + X[5] + unchecked((int) 0xfc93a039)), S44) + c; + a = RotateLeft((a + K(b, c, d) + X[12] + unchecked(0x655b59c3)), S41) + b; + d = RotateLeft((d + K(a, b, c) + X[3] + unchecked((int) 0x8f0ccc92)), S42) + a; + c = RotateLeft((c + K(d, a, b) + X[10] + unchecked((int) 0xffeff47d)), S43) + d; + b = RotateLeft((b + K(c, d, a) + X[1] + unchecked((int) 0x85845dd1)), S44) + c; + a = RotateLeft((a + K(b, c, d) + X[8] + unchecked(0x6fa87e4f)), S41) + b; + d = RotateLeft((d + K(a, b, c) + X[15] + unchecked((int) 0xfe2ce6e0)), S42) + a; + c = RotateLeft((c + K(d, a, b) + X[6] + unchecked((int) 0xa3014314)), S43) + d; + b = RotateLeft((b + K(c, d, a) + X[13] + unchecked(0x4e0811a1)), S44) + c; + a = RotateLeft((a + K(b, c, d) + X[4] + unchecked((int) 0xf7537e82)), S41) + b; + d = RotateLeft((d + K(a, b, c) + X[11] + unchecked((int) 0xbd3af235)), S42) + a; + c = RotateLeft((c + K(d, a, b) + X[2] + unchecked(0x2ad7d2bb)), S43) + d; + b = RotateLeft((b + K(c, d, a) + X[9] + unchecked((int) 0xeb86d391)), S44) + c; + + H1 += a; + H2 += b; + H3 += c; + H4 += d; + + // + // reset the offset and clean out the word buffer. + // + xOff = 0; + for (int i = 0; i != X.Length; i++) { + X[i] = 0; + } + } + } +} \ No newline at end of file diff --git a/TLSharp.Core/MTProto/Crypto/RSA.cs b/TLSharp.Core/MTProto/Crypto/RSA.cs new file mode 100644 index 0000000..22a0d9b --- /dev/null +++ b/TLSharp.Core/MTProto/Crypto/RSA.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Security.Cryptography; + +namespace TLSharp.Core.MTProto.Crypto { + + class RSAServerKey { + + private string fingerprint; + private BigInteger m; + private BigInteger e; + + public RSAServerKey(string fingerprint, BigInteger m, BigInteger e) { + this.fingerprint = fingerprint; + this.m = m; + this.e = e; + } + + public byte[] Encrypt(byte[] data, int offset, int length) { + + using(MemoryStream buffer = new MemoryStream(255)) + using(BinaryWriter writer = new BinaryWriter(buffer)) { + using(SHA1 sha1 = new SHA1Managed()) { + byte[] hashsum = sha1.ComputeHash(data, offset, length); + writer.Write(hashsum); + } + + buffer.Write(data, offset, length); + if(length < 235) { + byte[] padding = new byte[235 - length]; + new Random().NextBytes(padding); + buffer.Write(padding, 0, padding.Length); + } + + byte[] ciphertext = new BigInteger(1, buffer.ToArray()).ModPow(e, m).ToByteArrayUnsigned(); + + if(ciphertext.Length == 256) { + return ciphertext; + } else { + byte[] paddedCiphertext = new byte[256]; + int padding = 256 - ciphertext.Length; + for(int i = 0; i < padding; i++) { + paddedCiphertext[i] = 0; + } + ciphertext.CopyTo(paddedCiphertext, padding); + return paddedCiphertext; + } + } + + } + } + public class RSA { + private static readonly Dictionary serverKeys = new Dictionary() { + { "216be86c022bb4c3", new RSAServerKey("216be86c022bb4c3", new BigInteger("00C150023E2F70DB7985DED064759CFECF0AF328E69A41DAF4D6F01B538135A6F91F8F8B2A0EC9BA9720CE352EFCF6C5680FFC424BD634864902DE0B4BD6D49F4E580230E3AE97D95C8B19442B3C0A10D8F5633FECEDD6926A7F6DAB0DDB7D457F9EA81B8465FCD6FFFEED114011DF91C059CAEDAF97625F6C96ECC74725556934EF781D866B34F011FCE4D835A090196E9A5F0E4449AF7EB697DDB9076494CA5F81104A305B6DD27665722C46B60E5DF680FB16B210607EF217652E60236C255F6A28315F4083A96791D7214BF64C1DF4FD0DB1944FB26A2A57031B32EEE64AD15A8BA68885CDE74A5BFC920F6ABF59BA5C75506373E7130F9042DA922179251F", 16), new BigInteger("010001", 16)) } + }; + + public static byte[] Encrypt(string fingerprint, byte[] data, int offset, int length) { + string fingerprintLower = fingerprint.ToLower(); + if(!serverKeys.ContainsKey(fingerprintLower)) { + return null; + } + + RSAServerKey key = serverKeys[fingerprintLower]; + + return key.Encrypt(data, offset, length); + } + } + +} diff --git a/TLSharp.Core/MTProto/Crypto/Salt.cs b/TLSharp.Core/MTProto/Crypto/Salt.cs new file mode 100644 index 0000000..9ce4d00 --- /dev/null +++ b/TLSharp.Core/MTProto/Crypto/Salt.cs @@ -0,0 +1,77 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TLSharp.Core.MTProto.Crypto { + public class Salt : IComparable { + private int validSince; + private int validUntil; + private ulong salt; + + public Salt(int validSince, int validUntil, ulong salt) { + this.validSince = validSince; + this.validUntil = validUntil; + this.salt = salt; + } + + public int ValidSince { + get { return validSince; } + } + + public int ValidUntil { + get { return validUntil; } + } + + public ulong Value { + get { return salt; } + } + + public int CompareTo(Salt other) { + return validUntil.CompareTo(other.validSince); + } + } + + public class SaltCollection { + private SortedSet salts; + + public void Add(Salt salt) { + salts.Add(salt); + } + + public int Count { + get { + return salts.Count; + } + } + // TODO: get actual salt and other... + } + + public class GetFutureSaltsResponse { + private ulong requestId; + private int now; + private SaltCollection salts; + + public GetFutureSaltsResponse(ulong requestId, int now) { + this.requestId = requestId; + this.now = now; + } + + public void AddSalt(Salt salt) { + salts.Add(salt); + } + + public ulong RequestId { + get { return requestId; } + } + + public int Now { + get { return now; } + } + + public SaltCollection Salts { + get { return salts; } + } + } +} diff --git a/TLSharp.Core/MTProto/Serializers.cs b/TLSharp.Core/MTProto/Serializers.cs new file mode 100644 index 0000000..1d3a68b --- /dev/null +++ b/TLSharp.Core/MTProto/Serializers.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using System.IO; +using System.Text; + +namespace TLSharp.Core.MTProto +{ + public class Serializers { + + public static class Bytes { + public static byte[] read(BinaryReader binaryReader) { + byte firstByte = binaryReader.ReadByte(); + int len, padding; + if(firstByte == 254) { + len = binaryReader.ReadByte() | (binaryReader.ReadByte() << 8) | (binaryReader.ReadByte() << 16); + padding = len%4; + } else { + len = firstByte; + padding = (len + 1) % 4; + } + + byte[] data = binaryReader.ReadBytes(len); + if(padding > 0) { + padding = 4 - padding; + binaryReader.ReadBytes(padding); + } + + return data; + } + + public static BinaryWriter write(BinaryWriter binaryWriter, byte[] data) { + int padding; + if(data.Length < 254) { + padding = (data.Length + 1)%4; + if(padding != 0) { + padding = 4 - padding; + } + + binaryWriter.Write((byte) data.Length); + binaryWriter.Write(data); + } else { + padding = (data.Length)%4; + if(padding != 0) { + padding = 4 - padding; + } + + binaryWriter.Write((byte)254); + binaryWriter.Write((byte)(data.Length)); + binaryWriter.Write((byte)(data.Length >> 8)); + binaryWriter.Write((byte)(data.Length >> 16)); + binaryWriter.Write(data); + } + + + for(int i = 0; i < padding; i++) { + binaryWriter.Write((byte)0); + } + + return binaryWriter; + } + } + + public static class String { + public static string read(BinaryReader reader) { + byte[] data = Bytes.read(reader); + return Encoding.UTF8.GetString(data, 0, data.Length); + } + + public static BinaryWriter write(BinaryWriter writer, string str) { + return Bytes.write(writer, Encoding.UTF8.GetBytes(str)); + } + } + + public static string VectorToString(List list) { + string[] tokens = new string[list.Count]; + for(int i = 0; i < list.Count; i++) { + tokens[i] = list[i].ToString(); + } + return "[" + System.String.Join(", ", tokens) + "]"; + } + } +} diff --git a/TLSharp.Core/MTProto/TL.cs b/TLSharp.Core/MTProto/TL.cs new file mode 100644 index 0000000..e80e7fe --- /dev/null +++ b/TLSharp.Core/MTProto/TL.cs @@ -0,0 +1,14822 @@ +using System; +using System.Collections.Generic; +using System.IO; + +namespace TLSharp.Core.MTProto +{ + + public abstract class TLObject + { + public abstract Constructor Constructor { get; } + public abstract void Write(BinaryWriter writer); + public abstract void Read(BinaryReader reader); + } + + // all constructor types + + public enum Constructor + { + messageUndelivered, + error, + inputPeerEmpty, + inputPeerSelf, + inputPeerContact, + inputPeerForeign, + inputPeerChat, + inputUserEmpty, + inputUserSelf, + inputUserContact, + inputUserForeign, + inputPhoneContact, + inputFile, + inputMediaEmpty, + inputMediaUploadedPhoto, + inputMediaPhoto, + inputMediaGeoPoint, + inputMediaContact, + inputMediaUploadedVideo, + inputMediaUploadedThumbVideo, + inputMediaVideo, + inputChatPhotoEmpty, + inputChatUploadedPhoto, + inputChatPhoto, + inputGeoPointEmpty, + inputGeoPoint, + inputPhotoEmpty, + inputPhoto, + inputVideoEmpty, + inputVideo, + inputFileLocation, + inputVideoFileLocation, + inputPhotoCropAuto, + inputPhotoCrop, + inputAppEvent, + peerUser, + peerChat, + storage_fileUnknown, + storage_fileJpeg, + storage_fileGif, + storage_filePng, + storage_fileMp3, + storage_fileMov, + storage_filePartial, + storage_fileMp4, + storage_fileWebp, + fileLocationUnavailable, + fileLocation, + userEmpty, + userSelf, + userContact, + userRequest, + userForeign, + userDeleted, + userProfilePhotoEmpty, + userProfilePhoto, + userStatusEmpty, + userStatusOnline, + userStatusOffline, + chatEmpty, + chat, + chatForbidden, + chatFull, + chatParticipant, + chatParticipantsForbidden, + chatParticipants, + chatPhotoEmpty, + chatPhoto, + messageEmpty, + message, + messageForwarded, + messageService, + messageMediaEmpty, + messageMediaPhoto, + messageMediaVideo, + messageMediaGeo, + messageMediaContact, + messageMediaUnsupported, + messageActionEmpty, + messageActionChatCreate, + messageActionChatEditTitle, + messageActionChatEditPhoto, + messageActionChatDeletePhoto, + messageActionChatAddUser, + messageActionChatDeleteUser, + dialog, + photoEmpty, + photo, + photoSizeEmpty, + photoSize, + photoCachedSize, + videoEmpty, + video, + geoPointEmpty, + geoPoint, + auth_checkedPhone, + auth_sentCode, + auth_authorization, + auth_exportedAuthorization, + inputNotifyPeer, + inputNotifyUsers, + inputNotifyChats, + inputNotifyAll, + inputPeerNotifyEventsEmpty, + inputPeerNotifyEventsAll, + inputPeerNotifySettings, + peerNotifyEventsEmpty, + peerNotifyEventsAll, + peerNotifySettingsEmpty, + peerNotifySettings, + wallPaper, + userFull, + contact, + importedContact, + contactBlocked, + contactFound, + contactSuggested, + contactStatus, + chatLocated, + contacts_foreignLinkUnknown, + contacts_foreignLinkRequested, + contacts_foreignLinkMutual, + contacts_myLinkEmpty, + contacts_myLinkRequested, + contacts_myLinkContact, + contacts_link, + contacts_contacts, + contacts_contactsNotModified, + contacts_importedContacts, + contacts_blocked, + contacts_blockedSlice, + contacts_found, + contacts_suggested, + messages_dialogs, + messages_dialogsSlice, + messages_messages, + messages_messagesSlice, + messages_messageEmpty, + messages_message, + messages_statedMessages, + messages_statedMessage, + messages_sentMessage, + messages_chat, + messages_chats, + messages_chatFull, + messages_affectedHistory, + inputMessagesFilterEmpty, + inputMessagesFilterPhotos, + inputMessagesFilterVideo, + inputMessagesFilterPhotoVideo, + updateNewMessage, + updateMessageID, + updateReadMessages, + updateDeleteMessages, + updateRestoreMessages, + updateUserTyping, + updateChatUserTyping, + updateChatParticipants, + updateUserStatus, + updateUserName, + updateUserPhoto, + updateContactRegistered, + updateContactLink, + updateActivation, + updateNewAuthorization, + updates_state, + updates_differenceEmpty, + updates_difference, + updates_differenceSlice, + updatesTooLong, + updateShortMessage, + updateShortChatMessage, + updateShort, + updatesCombined, + updates, + photos_photos, + photos_photosSlice, + photos_photo, + upload_file, + dcOption, + config, + nearestDc, + help_appUpdate, + help_noAppUpdate, + help_inviteText, + messages_statedMessagesLinks, + messages_statedMessageLink, + messages_sentMessageLink, + inputGeoChat, + inputNotifyGeoChatPeer, + geoChat, + geoChatMessageEmpty, + geoChatMessage, + geoChatMessageService, + geochats_statedMessage, + geochats_located, + geochats_messages, + geochats_messagesSlice, + messageActionGeoChatCreate, + messageActionGeoChatCheckin, + updateNewGeoChatMessage, + wallPaperSolid, + updateNewEncryptedMessage, + updateEncryptedChatTyping, + updateEncryption, + updateEncryptedMessagesRead, + encryptedChatEmpty, + encryptedChatWaiting, + encryptedChatRequested, + encryptedChat, + encryptedChatDiscarded, + inputEncryptedChat, + encryptedFileEmpty, + encryptedFile, + inputEncryptedFileEmpty, + inputEncryptedFileUploaded, + inputEncryptedFile, + inputEncryptedFileLocation, + encryptedMessage, + encryptedMessageService, + decryptedMessageLayer, + decryptedMessage, + decryptedMessageService, + decryptedMessageMediaEmpty, + decryptedMessageMediaPhoto, + decryptedMessageMediaVideo, + decryptedMessageMediaGeoPoint, + decryptedMessageMediaContact, + decryptedMessageActionSetMessageTTL, + messages_dhConfigNotModified, + messages_dhConfig, + messages_sentEncryptedMessage, + messages_sentEncryptedFile, + inputFileBig, + inputEncryptedFileBigUploaded, + updateChatParticipantAdd, + updateChatParticipantDelete, + updateDcOptions, + inputMediaUploadedAudio, + inputMediaAudio, + inputMediaUploadedDocument, + inputMediaUploadedThumbDocument, + inputMediaDocument, + messageMediaDocument, + messageMediaAudio, + inputAudioEmpty, + inputAudio, + inputDocumentEmpty, + inputDocument, + inputAudioFileLocation, + inputDocumentFileLocation, + decryptedMessageMediaDocument, + decryptedMessageMediaAudio, + audioEmpty, + audio, + documentEmpty, + document + } + + public class TL + { + + private static Dictionary constructors = new Dictionary() + { + {0xc4b9f9bb, typeof (ErrorConstructor)}, + {0x7f3b18ea, typeof (InputPeerEmptyConstructor)}, + {0x7da07ec9, typeof (InputPeerSelfConstructor)}, + {0x1023dbe8, typeof (InputPeerContactConstructor)}, + {0x9b447325, typeof (InputPeerForeignConstructor)}, + {0x179be863, typeof (InputPeerChatConstructor)}, + {0xb98886cf, typeof (InputUserEmptyConstructor)}, + {0xf7c1b13f, typeof (InputUserSelfConstructor)}, + {0x86e94f65, typeof (InputUserContactConstructor)}, + {0x655e74ff, typeof (InputUserForeignConstructor)}, + {0xf392b7f4, typeof (InputPhoneContactConstructor)}, + {0xf52ff27f, typeof (InputFileConstructor)}, + {0x9664f57f, typeof (InputMediaEmptyConstructor)}, + {0x2dc53a7d, typeof (InputMediaUploadedPhotoConstructor)}, + {0x8f2ab2ec, typeof (InputMediaPhotoConstructor)}, + {0xf9c44144, typeof (InputMediaGeoPointConstructor)}, + {0xa6e45987, typeof (InputMediaContactConstructor)}, + {0x4847d92a, typeof (InputMediaUploadedVideoConstructor)}, + {0xe628a145, typeof (InputMediaUploadedThumbVideoConstructor)}, + {0x7f023ae6, typeof (InputMediaVideoConstructor)}, + {0x1ca48f57, typeof (InputChatPhotoEmptyConstructor)}, + {0x94254732, typeof (InputChatUploadedPhotoConstructor)}, + {0xb2e1bf08, typeof (InputChatPhotoConstructor)}, + {0xe4c123d6, typeof (InputGeoPointEmptyConstructor)}, + {0xf3b7acc9, typeof (InputGeoPointConstructor)}, + {0x1cd7bf0d, typeof (InputPhotoEmptyConstructor)}, + {0xfb95c6c4, typeof (InputPhotoConstructor)}, + {0x5508ec75, typeof (InputVideoEmptyConstructor)}, + {0xee579652, typeof (InputVideoConstructor)}, + {0x14637196, typeof (InputFileLocationConstructor)}, + {0x3d0364ec, typeof (InputVideoFileLocationConstructor)}, + {0xade6b004, typeof (InputPhotoCropAutoConstructor)}, + {0xd9915325, typeof (InputPhotoCropConstructor)}, + {0x770656a8, typeof (InputAppEventConstructor)}, + {0x9db1bc6d, typeof (PeerUserConstructor)}, + {0xbad0e5bb, typeof (PeerChatConstructor)}, + {0xaa963b05, typeof (Storage_fileUnknownConstructor)}, + {0x007efe0e, typeof (Storage_fileJpegConstructor)}, + {0xcae1aadf, typeof (Storage_fileGifConstructor)}, + {0x0a4f63c0, typeof (Storage_filePngConstructor)}, + {0x528a0677, typeof (Storage_fileMp3Constructor)}, + {0x4b09ebbc, typeof (Storage_fileMovConstructor)}, + {0x40bc6f52, typeof (Storage_filePartialConstructor)}, + {0xb3cea0e4, typeof (Storage_fileMp4Constructor)}, + {0x1081464c, typeof (Storage_fileWebpConstructor)}, + {0x7c596b46, typeof (FileLocationUnavailableConstructor)}, + {0x53d69076, typeof (FileLocationConstructor)}, + {0x200250ba, typeof (UserEmptyConstructor)}, + {0x720535ec, typeof (UserSelfConstructor)}, + {0xf2fb8319, typeof (UserContactConstructor)}, + {0x22e8ceb0, typeof (UserRequestConstructor)}, + {0x5214c89d, typeof (UserForeignConstructor)}, + {0xb29ad7cc, typeof (UserDeletedConstructor)}, + {0x4f11bae1, typeof (UserProfilePhotoEmptyConstructor)}, + {0xd559d8c8, typeof (UserProfilePhotoConstructor)}, + {0x09d05049, typeof (UserStatusEmptyConstructor)}, + {0xedb93949, typeof (UserStatusOnlineConstructor)}, + {0x008c703f, typeof (UserStatusOfflineConstructor)}, + {0x9ba2d800, typeof (ChatEmptyConstructor)}, + {0x6e9c9bc7, typeof (ChatConstructor)}, + {0xfb0ccc41, typeof (ChatForbiddenConstructor)}, + {0x630e61be, typeof (ChatFullConstructor)}, + {0xc8d7493e, typeof (ChatParticipantConstructor)}, + {0x0fd2bb8a, typeof (ChatParticipantsForbiddenConstructor)}, + {0x7841b415, typeof (ChatParticipantsConstructor)}, + {0x37c1011c, typeof (ChatPhotoEmptyConstructor)}, + {0x6153276a, typeof (ChatPhotoConstructor)}, + {0x83e5de54, typeof (MessageEmptyConstructor)}, + {0x22eb6aba, typeof (MessageConstructor)}, + {0x05f46804, typeof (MessageForwardedConstructor)}, + {0x9f8d60bb, typeof (MessageServiceConstructor)}, + {0x3ded6320, typeof (MessageMediaEmptyConstructor)}, + {0xc8c45a2a, typeof (MessageMediaPhotoConstructor)}, + {0xa2d24290, typeof (MessageMediaVideoConstructor)}, + {0x56e0d474, typeof (MessageMediaGeoConstructor)}, + {0x5e7d2f39, typeof (MessageMediaContactConstructor)}, + {0x29632a36, typeof (MessageMediaUnsupportedConstructor)}, + {0xb6aef7b0, typeof (MessageActionEmptyConstructor)}, + {0xa6638b9a, typeof (MessageActionChatCreateConstructor)}, + {0xb5a1ce5a, typeof (MessageActionChatEditTitleConstructor)}, + {0x7fcb13a8, typeof (MessageActionChatEditPhotoConstructor)}, + {0x95e3fbef, typeof (MessageActionChatDeletePhotoConstructor)}, + {0x5e3cfc4b, typeof (MessageActionChatAddUserConstructor)}, + {0xb2ae9b0c, typeof (MessageActionChatDeleteUserConstructor)}, + {0x214a8cdf, typeof (DialogConstructor)}, + {0x2331b22d, typeof (PhotoEmptyConstructor)}, + {0x22b56751, typeof (PhotoConstructor)}, + {0x0e17e23c, typeof (PhotoSizeEmptyConstructor)}, + {0x77bfb61b, typeof (PhotoSizeConstructor)}, + {0xe9a734fa, typeof (PhotoCachedSizeConstructor)}, + {0xc10658a8, typeof (VideoEmptyConstructor)}, + {0x5a04a49f, typeof (VideoConstructor)}, + {0x1117dd5f, typeof (GeoPointEmptyConstructor)}, + {0x2049d70c, typeof (GeoPointConstructor)}, + {0xe300cc3b, typeof (Auth_checkedPhoneConstructor)}, + {0x2215bcbd, typeof (Auth_sentCodeConstructor)}, + {0xf6b673a4, typeof (Auth_authorizationConstructor)}, + {0xdf969c2d, typeof (Auth_exportedAuthorizationConstructor)}, + {0xb8bc5b0c, typeof (InputNotifyPeerConstructor)}, + {0x193b4417, typeof (InputNotifyUsersConstructor)}, + {0x4a95e84e, typeof (InputNotifyChatsConstructor)}, + {0xa429b886, typeof (InputNotifyAllConstructor)}, + {0xf03064d8, typeof (InputPeerNotifyEventsEmptyConstructor)}, + {0xe86a2c74, typeof (InputPeerNotifyEventsAllConstructor)}, + {0x46a2ce98, typeof (InputPeerNotifySettingsConstructor)}, + {0xadd53cb3, typeof (PeerNotifyEventsEmptyConstructor)}, + {0x6d1ded88, typeof (PeerNotifyEventsAllConstructor)}, + {0x70a68512, typeof (PeerNotifySettingsEmptyConstructor)}, + {0x8d5e11ee, typeof (PeerNotifySettingsConstructor)}, + {0xccb03657, typeof (WallPaperConstructor)}, + {0x771095da, typeof (UserFullConstructor)}, + {0xf911c994, typeof (ContactConstructor)}, + {0xd0028438, typeof (ImportedContactConstructor)}, + {0x561bc879, typeof (ContactBlockedConstructor)}, + {0xea879f95, typeof (ContactFoundConstructor)}, + {0x3de191a1, typeof (ContactSuggestedConstructor)}, + {0xaa77b873, typeof (ContactStatusConstructor)}, + {0x3631cf4c, typeof (ChatLocatedConstructor)}, + {0x133421f8, typeof (Contacts_foreignLinkUnknownConstructor)}, + {0xa7801f47, typeof (Contacts_foreignLinkRequestedConstructor)}, + {0x1bea8ce1, typeof (Contacts_foreignLinkMutualConstructor)}, + {0xd22a1c60, typeof (Contacts_myLinkEmptyConstructor)}, + {0x6c69efee, typeof (Contacts_myLinkRequestedConstructor)}, + {0xc240ebd9, typeof (Contacts_myLinkContactConstructor)}, + {0xeccea3f5, typeof (Contacts_linkConstructor)}, + {0x6f8b8cb2, typeof (Contacts_contactsConstructor)}, + {0xb74ba9d2, typeof (Contacts_contactsNotModifiedConstructor)}, + {0xd1cd0a4c, typeof (Contacts_importedContactsConstructor)}, + {0x1c138d15, typeof (Contacts_blockedConstructor)}, + {0x900802a1, typeof (Contacts_blockedSliceConstructor)}, + {0x0566000e, typeof (Contacts_foundConstructor)}, + {0x5649dcc5, typeof (Contacts_suggestedConstructor)}, + {0x15ba6c40, typeof (Messages_dialogsConstructor)}, + {0x71e094f3, typeof (Messages_dialogsSliceConstructor)}, + {0x8c718e87, typeof (Messages_messagesConstructor)}, + {0x0b446ae3, typeof (Messages_messagesSliceConstructor)}, + {0x3f4e0648, typeof (Messages_messageEmptyConstructor)}, + {0xff90c417, typeof (Messages_messageConstructor)}, + {0x969478bb, typeof (Messages_statedMessagesConstructor)}, + {0xd07ae726, typeof (Messages_statedMessageConstructor)}, + {0xd1f4d35c, typeof (Messages_sentMessageConstructor)}, + {0x40e9002a, typeof (Messages_chatConstructor)}, + {0x8150cbd8, typeof (Messages_chatsConstructor)}, + {0xe5d7d19c, typeof (Messages_chatFullConstructor)}, + {0xb7de36f2, typeof (Messages_affectedHistoryConstructor)}, + {0x57e2f66c, typeof (InputMessagesFilterEmptyConstructor)}, + {0x9609a51c, typeof (InputMessagesFilterPhotosConstructor)}, + {0x9fc00e65, typeof (InputMessagesFilterVideoConstructor)}, + {0x56e9f0e4, typeof (InputMessagesFilterPhotoVideoConstructor)}, + {0x013abdb3, typeof (UpdateNewMessageConstructor)}, + {0x4e90bfd6, typeof (UpdateMessageIDConstructor)}, + {0xc6649e31, typeof (UpdateReadMessagesConstructor)}, + {0xa92bfe26, typeof (UpdateDeleteMessagesConstructor)}, + {0xd15de04d, typeof (UpdateRestoreMessagesConstructor)}, + {0x6baa8508, typeof (UpdateUserTypingConstructor)}, + {0x3c46cfe6, typeof (UpdateChatUserTypingConstructor)}, + {0x07761198, typeof (UpdateChatParticipantsConstructor)}, + {0x1bfbd823, typeof (UpdateUserStatusConstructor)}, + {0xda22d9ad, typeof (UpdateUserNameConstructor)}, + {0x95313b0c, typeof (UpdateUserPhotoConstructor)}, + {0x2575bbb9, typeof (UpdateContactRegisteredConstructor)}, + {0x51a48a9a, typeof (UpdateContactLinkConstructor)}, + {0x6f690963, typeof (UpdateActivationConstructor)}, + {0x8f06529a, typeof (UpdateNewAuthorizationConstructor)}, + {0xa56c2a3e, typeof (Updates_stateConstructor)}, + {0x5d75a138, typeof (Updates_differenceEmptyConstructor)}, + {0x00f49ca0, typeof (Updates_differenceConstructor)}, + {0xa8fb1981, typeof (Updates_differenceSliceConstructor)}, + {0xe317af7e, typeof (UpdatesTooLongConstructor)}, + {0xd3f45784, typeof (UpdateShortMessageConstructor)}, + {0x2b2fbd4e, typeof (UpdateShortChatMessageConstructor)}, + {0x78d4dec1, typeof (UpdateShortConstructor)}, + {0x725b04c3, typeof (UpdatesCombinedConstructor)}, + {0x74ae4240, typeof (UpdatesConstructor)}, + {0x8dca6aa5, typeof (Photos_photosConstructor)}, + {0x15051f54, typeof (Photos_photosSliceConstructor)}, + {0x20212ca8, typeof (Photos_photoConstructor)}, + {0x096a18d5, typeof (Upload_fileConstructor)}, + {0x2ec2a43c, typeof (DcOptionConstructor)}, + {0x232d5905, typeof (ConfigConstructor)}, + {0x8e1a1775, typeof (NearestDcConstructor)}, + {0x8987f311, typeof (Help_appUpdateConstructor)}, + {0xc45a6536, typeof (Help_noAppUpdateConstructor)}, + {0x18cb9f78, typeof (Help_inviteTextConstructor)}, + {0x3e74f5c6, typeof (Messages_statedMessagesLinksConstructor)}, + {0xa9af2881, typeof (Messages_statedMessageLinkConstructor)}, + {0xe9db4a3f, typeof (Messages_sentMessageLinkConstructor)}, + {0x74d456fa, typeof (InputGeoChatConstructor)}, + {0x4d8ddec8, typeof (InputNotifyGeoChatPeerConstructor)}, + {0x75eaea5a, typeof (GeoChatConstructor)}, + {0x60311a9b, typeof (GeoChatMessageEmptyConstructor)}, + {0x4505f8e1, typeof (GeoChatMessageConstructor)}, + {0xd34fa24e, typeof (GeoChatMessageServiceConstructor)}, + {0x17b1578b, typeof (Geochats_statedMessageConstructor)}, + {0x48feb267, typeof (Geochats_locatedConstructor)}, + {0xd1526db1, typeof (Geochats_messagesConstructor)}, + {0xbc5863e8, typeof (Geochats_messagesSliceConstructor)}, + {0x6f038ebc, typeof (MessageActionGeoChatCreateConstructor)}, + {0x0c7d53de, typeof (MessageActionGeoChatCheckinConstructor)}, + {0x5a68e3f7, typeof (UpdateNewGeoChatMessageConstructor)}, + {0x63117f24, typeof (WallPaperSolidConstructor)}, + {0x12bcbd9a, typeof (UpdateNewEncryptedMessageConstructor)}, + {0x1710f156, typeof (UpdateEncryptedChatTypingConstructor)}, + {0xb4a2e88d, typeof (UpdateEncryptionConstructor)}, + {0x38fe25b7, typeof (UpdateEncryptedMessagesReadConstructor)}, + {0xab7ec0a0, typeof (EncryptedChatEmptyConstructor)}, + {0x3bf703dc, typeof (EncryptedChatWaitingConstructor)}, + {0xfda9a7b7, typeof (EncryptedChatRequestedConstructor)}, + {0x6601d14f, typeof (EncryptedChatConstructor)}, + {0x13d6dd27, typeof (EncryptedChatDiscardedConstructor)}, + {0xf141b5e1, typeof (InputEncryptedChatConstructor)}, + {0xc21f497e, typeof (EncryptedFileEmptyConstructor)}, + {0x4a70994c, typeof (EncryptedFileConstructor)}, + {0x1837c364, typeof (InputEncryptedFileEmptyConstructor)}, + {0x64bd0306, typeof (InputEncryptedFileUploadedConstructor)}, + {0x5a17b5e5, typeof (InputEncryptedFileConstructor)}, + {0xf5235d55, typeof (InputEncryptedFileLocationConstructor)}, + {0xed18c118, typeof (EncryptedMessageConstructor)}, + {0x23734b06, typeof (EncryptedMessageServiceConstructor)}, + {0x99a438cf, typeof (DecryptedMessageLayerConstructor)}, + {0x1f814f1f, typeof (DecryptedMessageConstructor)}, + {0xaa48327d, typeof (DecryptedMessageServiceConstructor)}, + {0x089f5c4a, typeof (DecryptedMessageMediaEmptyConstructor)}, + {0x32798a8c, typeof (DecryptedMessageMediaPhotoConstructor)}, + {0x4cee6ef3, typeof (DecryptedMessageMediaVideoConstructor)}, + {0x35480a59, typeof (DecryptedMessageMediaGeoPointConstructor)}, + {0x588a0a97, typeof (DecryptedMessageMediaContactConstructor)}, + {0xa1733aec, typeof (DecryptedMessageActionSetMessageTTLConstructor)}, + {0xc0e24635, typeof (Messages_dhConfigNotModifiedConstructor)}, + {0x2c221edd, typeof (Messages_dhConfigConstructor)}, + {0x560f8935, typeof (Messages_sentEncryptedMessageConstructor)}, + {0x9493ff32, typeof (Messages_sentEncryptedFileConstructor)}, + {0xfa4f0bb5, typeof (InputFileBigConstructor)}, + {0x2dc173c8, typeof (InputEncryptedFileBigUploadedConstructor)}, + {0x3a0eeb22, typeof (UpdateChatParticipantAddConstructor)}, + {0x6e5f8c22, typeof (UpdateChatParticipantDeleteConstructor)}, + {0x8e5e9873, typeof (UpdateDcOptionsConstructor)}, + {0x61a6d436, typeof (InputMediaUploadedAudioConstructor)}, + {0x89938781, typeof (InputMediaAudioConstructor)}, + {0x34e794bd, typeof (InputMediaUploadedDocumentConstructor)}, + {0x3e46de5d, typeof (InputMediaUploadedThumbDocumentConstructor)}, + {0xd184e841, typeof (InputMediaDocumentConstructor)}, + {0x2fda2204, typeof (MessageMediaDocumentConstructor)}, + {0xc6b68300, typeof (MessageMediaAudioConstructor)}, + {0xd95adc84, typeof (InputAudioEmptyConstructor)}, + {0x77d440ff, typeof (InputAudioConstructor)}, + {0x72f0eaae, typeof (InputDocumentEmptyConstructor)}, + {0x18798952, typeof (InputDocumentConstructor)}, + {0x74dc404d, typeof (InputAudioFileLocationConstructor)}, + {0x4e45abe9, typeof (InputDocumentFileLocationConstructor)}, + {0xb095434b, typeof (DecryptedMessageMediaDocumentConstructor)}, + {0x6080758f, typeof (DecryptedMessageMediaAudioConstructor)}, + {0x586988d8, typeof (AudioEmptyConstructor)}, + {0x427425e7, typeof (AudioConstructor)}, + {0x36f8c871, typeof (DocumentEmptyConstructor)}, + {0x9efc6326, typeof (DocumentConstructor)}, + }; + + public static TLObject Parse(BinaryReader reader, uint code) + { + if (!constructors.ContainsKey(code)) + { + throw new Exception("unknown constructor code"); + } + + uint dataCode = reader.ReadUInt32(); + if (dataCode != code) + { + throw new Exception(String.Format("target code {0} != data code {1}", code, dataCode)); + } + + TLObject obj = (TLObject) Activator.CreateInstance(constructors[code]); + obj.Read(reader); + return obj; + } + + public static T Parse(BinaryReader reader) + { + if (typeof (TLObject).IsAssignableFrom(typeof (T))) + { + uint dataCode = reader.ReadUInt32(); + + if (!constructors.ContainsKey(dataCode)) + { + throw new Exception(String.Format("invalid constructor code {0}", dataCode)); + } + + Type constructorType = constructors[dataCode]; + if (!typeof (T).IsAssignableFrom(constructorType)) + { + throw new Exception(String.Format("try to parse {0}, but incompatible type {1}", typeof (T).FullName, + constructorType.FullName)); + } + + T obj = (T) Activator.CreateInstance(constructorType); + ((TLObject) (object) obj).Read(reader); + return obj; + } + else if (typeof (T) == typeof (bool)) + { + uint code = reader.ReadUInt32(); + if (code == 0x997275b5) + { + return (T) (object) true; + } + else if (code == 0xbc799737) + { + return (T) (object) false; + } + else + { + throw new Exception("unknown bool value"); + } + } + else + { + throw new Exception("unknown return type"); + } + } + + //public delegate TLObject InputPeerContactDelegate(InputPeerContactConstructor x); + // constructors + + public static Error error(int code, string text) + { + return new ErrorConstructor(code, text); + } + + public static InputPeer inputPeerEmpty() + { + return new InputPeerEmptyConstructor(); + } + + public static InputPeer inputPeerSelf() + { + return new InputPeerSelfConstructor(); + } + + public static InputPeer inputPeerContact(int user_id) + { + return new InputPeerContactConstructor(user_id); + } + + public static InputPeer inputPeerForeign(int user_id, long access_hash) + { + return new InputPeerForeignConstructor(user_id, access_hash); + } + + public static InputPeer inputPeerChat(int chat_id) + { + return new InputPeerChatConstructor(chat_id); + } + + public static InputUser inputUserEmpty() + { + return new InputUserEmptyConstructor(); + } + + public static InputUser inputUserSelf() + { + return new InputUserSelfConstructor(); + } + + public static InputUser inputUserContact(int user_id) + { + return new InputUserContactConstructor(user_id); + } + + public static InputUser inputUserForeign(int user_id, long access_hash) + { + return new InputUserForeignConstructor(user_id, access_hash); + } + + public static InputContact inputPhoneContact(long client_id, string phone, string first_name, string last_name) + { + return new InputPhoneContactConstructor(client_id, phone, first_name, last_name); + } + + public static InputFile inputFile(long id, int parts, string name, string md5_checksum) + { + return new InputFileConstructor(id, parts, name, md5_checksum); + } + + public static InputMedia inputMediaEmpty() + { + return new InputMediaEmptyConstructor(); + } + + public static InputMedia inputMediaUploadedPhoto(InputFile file) + { + return new InputMediaUploadedPhotoConstructor(file); + } + + public static InputMedia inputMediaPhoto(InputPhoto id) + { + return new InputMediaPhotoConstructor(id); + } + + public static InputMedia inputMediaGeoPoint(InputGeoPoint geo_point) + { + return new InputMediaGeoPointConstructor(geo_point); + } + + public static InputMedia inputMediaContact(string phone_number, string first_name, string last_name) + { + return new InputMediaContactConstructor(phone_number, first_name, last_name); + } + + public static InputMedia inputMediaUploadedVideo(InputFile file, int duration, int w, int h) + { + return new InputMediaUploadedVideoConstructor(file, duration, w, h); + } + + public static InputMedia inputMediaUploadedThumbVideo(InputFile file, InputFile thumb, int duration, int w, int h) + { + return new InputMediaUploadedThumbVideoConstructor(file, thumb, duration, w, h); + } + + public static InputMedia inputMediaVideo(InputVideo id) + { + return new InputMediaVideoConstructor(id); + } + + public static InputChatPhoto inputChatPhotoEmpty() + { + return new InputChatPhotoEmptyConstructor(); + } + + public static InputChatPhoto inputChatUploadedPhoto(InputFile file, InputPhotoCrop crop) + { + return new InputChatUploadedPhotoConstructor(file, crop); + } + + public static InputChatPhoto inputChatPhoto(InputPhoto id, InputPhotoCrop crop) + { + return new InputChatPhotoConstructor(id, crop); + } + + public static InputGeoPoint inputGeoPointEmpty() + { + return new InputGeoPointEmptyConstructor(); + } + + public static InputGeoPoint inputGeoPoint(double lat, double lng) + { + return new InputGeoPointConstructor(lat, lng); + } + + public static InputPhoto inputPhotoEmpty() + { + return new InputPhotoEmptyConstructor(); + } + + public static InputPhoto inputPhoto(long id, long access_hash) + { + return new InputPhotoConstructor(id, access_hash); + } + + public static InputVideo inputVideoEmpty() + { + return new InputVideoEmptyConstructor(); + } + + public static InputVideo inputVideo(long id, long access_hash) + { + return new InputVideoConstructor(id, access_hash); + } + + public static InputFileLocation inputFileLocation(long volume_id, int local_id, long secret) + { + return new InputFileLocationConstructor(volume_id, local_id, secret); + } + + public static InputFileLocation inputVideoFileLocation(long id, long access_hash) + { + return new InputVideoFileLocationConstructor(id, access_hash); + } + + public static InputPhotoCrop inputPhotoCropAuto() + { + return new InputPhotoCropAutoConstructor(); + } + + public static InputPhotoCrop inputPhotoCrop(double crop_left, double crop_top, double crop_width) + { + return new InputPhotoCropConstructor(crop_left, crop_top, crop_width); + } + + public static InputAppEvent inputAppEvent(double time, string type, long peer, string data) + { + return new InputAppEventConstructor(time, type, peer, data); + } + + public static Peer peerUser(int user_id) + { + return new PeerUserConstructor(user_id); + } + + public static Peer peerChat(int chat_id) + { + return new PeerChatConstructor(chat_id); + } + + public static storage_FileType storage_fileUnknown() + { + return new Storage_fileUnknownConstructor(); + } + + public static storage_FileType storage_fileJpeg() + { + return new Storage_fileJpegConstructor(); + } + + public static storage_FileType storage_fileGif() + { + return new Storage_fileGifConstructor(); + } + + public static storage_FileType storage_filePng() + { + return new Storage_filePngConstructor(); + } + + public static storage_FileType storage_fileMp3() + { + return new Storage_fileMp3Constructor(); + } + + public static storage_FileType storage_fileMov() + { + return new Storage_fileMovConstructor(); + } + + public static storage_FileType storage_filePartial() + { + return new Storage_filePartialConstructor(); + } + + public static storage_FileType storage_fileMp4() + { + return new Storage_fileMp4Constructor(); + } + + public static storage_FileType storage_fileWebp() + { + return new Storage_fileWebpConstructor(); + } + + public static FileLocation fileLocationUnavailable(long volume_id, int local_id, long secret) + { + return new FileLocationUnavailableConstructor(volume_id, local_id, secret); + } + + public static FileLocation fileLocation(int dc_id, long volume_id, int local_id, long secret) + { + return new FileLocationConstructor(dc_id, volume_id, local_id, secret); + } + + public static User userEmpty(int id) + { + return new UserEmptyConstructor(id); + } + + public static User userSelf(int id, string first_name, string last_name, string phone, UserProfilePhoto photo, + UserStatus status, bool inactive) + { + return new UserSelfConstructor(id, first_name, last_name, phone, photo, status, inactive); + } + + public static User userContact(int id, string first_name, string last_name, long access_hash, string phone, + UserProfilePhoto photo, UserStatus status) + { + return new UserContactConstructor(id, first_name, last_name, access_hash, phone, photo, status); + } + + public static User userRequest(int id, string first_name, string last_name, long access_hash, string phone, + UserProfilePhoto photo, UserStatus status) + { + return new UserRequestConstructor(id, first_name, last_name, access_hash, phone, photo, status); + } + + public static User userForeign(int id, string first_name, string last_name, long access_hash, UserProfilePhoto photo, + UserStatus status) + { + return new UserForeignConstructor(id, first_name, last_name, access_hash, photo, status); + } + + public static User userDeleted(int id, string first_name, string last_name) + { + return new UserDeletedConstructor(id, first_name, last_name); + } + + public static UserProfilePhoto userProfilePhotoEmpty() + { + return new UserProfilePhotoEmptyConstructor(); + } + + public static UserProfilePhoto userProfilePhoto(long photo_id, FileLocation photo_small, FileLocation photo_big) + { + return new UserProfilePhotoConstructor(photo_id, photo_small, photo_big); + } + + public static UserStatus userStatusEmpty() + { + return new UserStatusEmptyConstructor(); + } + + public static UserStatus userStatusOnline(int expires) + { + return new UserStatusOnlineConstructor(expires); + } + + public static UserStatus userStatusOffline(int was_online) + { + return new UserStatusOfflineConstructor(was_online); + } + + public static Chat chatEmpty(int id) + { + return new ChatEmptyConstructor(id); + } + + public static Chat chat(int id, string title, ChatPhoto photo, int participants_count, int date, bool left, + int version) + { + return new ChatConstructor(id, title, photo, participants_count, date, left, version); + } + + public static Chat chatForbidden(int id, string title, int date) + { + return new ChatForbiddenConstructor(id, title, date); + } + + public static ChatFull chatFull(int id, ChatParticipants participants, Photo chat_photo, + PeerNotifySettings notify_settings) + { + return new ChatFullConstructor(id, participants, chat_photo, notify_settings); + } + + public static ChatParticipant chatParticipant(int user_id, int inviter_id, int date) + { + return new ChatParticipantConstructor(user_id, inviter_id, date); + } + + public static ChatParticipants chatParticipantsForbidden(int chat_id) + { + return new ChatParticipantsForbiddenConstructor(chat_id); + } + + public static ChatParticipants chatParticipants(int chat_id, int admin_id, List participants, + int version) + { + return new ChatParticipantsConstructor(chat_id, admin_id, participants, version); + } + + public static ChatPhoto chatPhotoEmpty() + { + return new ChatPhotoEmptyConstructor(); + } + + public static ChatPhoto chatPhoto(FileLocation photo_small, FileLocation photo_big) + { + return new ChatPhotoConstructor(photo_small, photo_big); + } + + public static Message messageEmpty(int id) + { + return new MessageEmptyConstructor(id); + } + + public static Message message(int id, int from_id, Peer to_id, bool output, bool unread, int date, string message, + MessageMedia media) + { + return new MessageConstructor(id, from_id, to_id, output, unread, date, message, media); + } + + public static Message messageForwarded(int id, int fwd_from_id, int fwd_date, int from_id, Peer to_id, bool output, + bool unread, int date, string message, MessageMedia media) + { + return new MessageForwardedConstructor(id, fwd_from_id, fwd_date, from_id, to_id, output, unread, date, message, + media); + } + + public static Message messageService(int id, int from_id, Peer to_id, bool output, bool unread, int date, + MessageAction action) + { + return new MessageServiceConstructor(id, from_id, to_id, output, unread, date, action); + } + + public static MessageMedia messageMediaEmpty() + { + return new MessageMediaEmptyConstructor(); + } + + public static MessageMedia messageMediaPhoto(Photo photo) + { + return new MessageMediaPhotoConstructor(photo); + } + + public static MessageMedia messageMediaVideo(Video video) + { + return new MessageMediaVideoConstructor(video); + } + + public static MessageMedia messageMediaGeo(GeoPoint geo) + { + return new MessageMediaGeoConstructor(geo); + } + + public static MessageMedia messageMediaContact(string phone_number, string first_name, string last_name, int user_id) + { + return new MessageMediaContactConstructor(phone_number, first_name, last_name, user_id); + } + + public static MessageMedia messageMediaUnsupported(byte[] bytes) + { + return new MessageMediaUnsupportedConstructor(bytes); + } + + public static MessageAction messageActionEmpty() + { + return new MessageActionEmptyConstructor(); + } + + public static MessageAction messageActionChatCreate(string title, List users) + { + return new MessageActionChatCreateConstructor(title, users); + } + + public static MessageAction messageActionChatEditTitle(string title) + { + return new MessageActionChatEditTitleConstructor(title); + } + + public static MessageAction messageActionChatEditPhoto(Photo photo) + { + return new MessageActionChatEditPhotoConstructor(photo); + } + + public static MessageAction messageActionChatDeletePhoto() + { + return new MessageActionChatDeletePhotoConstructor(); + } + + public static MessageAction messageActionChatAddUser(int user_id) + { + return new MessageActionChatAddUserConstructor(user_id); + } + + public static MessageAction messageActionChatDeleteUser(int user_id) + { + return new MessageActionChatDeleteUserConstructor(user_id); + } + + public static Dialog dialog(Peer peer, int top_message, int unread_count) + { + return new DialogConstructor(peer, top_message, unread_count); + } + + public static Photo photoEmpty(long id) + { + return new PhotoEmptyConstructor(id); + } + + public static Photo photo(long id, long access_hash, int user_id, int date, string caption, GeoPoint geo, + List sizes) + { + return new PhotoConstructor(id, access_hash, user_id, date, caption, geo, sizes); + } + + public static PhotoSize photoSizeEmpty(string type) + { + return new PhotoSizeEmptyConstructor(type); + } + + public static PhotoSize photoSize(string type, FileLocation location, int w, int h, int size) + { + return new PhotoSizeConstructor(type, location, w, h, size); + } + + public static PhotoSize photoCachedSize(string type, FileLocation location, int w, int h, byte[] bytes) + { + return new PhotoCachedSizeConstructor(type, location, w, h, bytes); + } + + public static Video videoEmpty(long id) + { + return new VideoEmptyConstructor(id); + } + + public static Video video(long id, long access_hash, int user_id, int date, string caption, int duration, int size, + PhotoSize thumb, int dc_id, int w, int h) + { + return new VideoConstructor(id, access_hash, user_id, date, caption, duration, size, thumb, dc_id, w, h); + } + + public static GeoPoint geoPointEmpty() + { + return new GeoPointEmptyConstructor(); + } + + public static GeoPoint geoPoint(double lng, double lat) + { + return new GeoPointConstructor(lng, lat); + } + + public static auth_CheckedPhone auth_checkedPhone(bool phone_registered, bool phone_invited) + { + return new Auth_checkedPhoneConstructor(phone_registered, phone_invited); + } + + public static auth_SentCode auth_sentCode(bool phone_registered, string phone_code_hash) + { + return new Auth_sentCodeConstructor(phone_registered, phone_code_hash); + } + + public static auth_Authorization auth_authorization(int expires, User user) + { + return new Auth_authorizationConstructor(expires, user); + } + + public static auth_ExportedAuthorization auth_exportedAuthorization(int id, byte[] bytes) + { + return new Auth_exportedAuthorizationConstructor(id, bytes); + } + + public static InputNotifyPeer inputNotifyPeer(InputPeer peer) + { + return new InputNotifyPeerConstructor(peer); + } + + public static InputNotifyPeer inputNotifyUsers() + { + return new InputNotifyUsersConstructor(); + } + + public static InputNotifyPeer inputNotifyChats() + { + return new InputNotifyChatsConstructor(); + } + + public static InputNotifyPeer inputNotifyAll() + { + return new InputNotifyAllConstructor(); + } + + public static InputPeerNotifyEvents inputPeerNotifyEventsEmpty() + { + return new InputPeerNotifyEventsEmptyConstructor(); + } + + public static InputPeerNotifyEvents inputPeerNotifyEventsAll() + { + return new InputPeerNotifyEventsAllConstructor(); + } + + public static InputPeerNotifySettings inputPeerNotifySettings(int mute_until, string sound, bool show_previews, + int events_mask) + { + return new InputPeerNotifySettingsConstructor(mute_until, sound, show_previews, events_mask); + } + + public static PeerNotifyEvents peerNotifyEventsEmpty() + { + return new PeerNotifyEventsEmptyConstructor(); + } + + public static PeerNotifyEvents peerNotifyEventsAll() + { + return new PeerNotifyEventsAllConstructor(); + } + + public static PeerNotifySettings peerNotifySettingsEmpty() + { + return new PeerNotifySettingsEmptyConstructor(); + } + + public static PeerNotifySettings peerNotifySettings(int mute_until, string sound, bool show_previews, int events_mask) + { + return new PeerNotifySettingsConstructor(mute_until, sound, show_previews, events_mask); + } + + public static WallPaper wallPaper(int id, string title, List sizes, int color) + { + return new WallPaperConstructor(id, title, sizes, color); + } + + public static UserFull userFull(User user, contacts_Link link, Photo profile_photo, PeerNotifySettings notify_settings, + bool blocked, string real_first_name, string real_last_name) + { + return new UserFullConstructor(user, link, profile_photo, notify_settings, blocked, real_first_name, real_last_name); + } + + public static Contact contact(int user_id, bool mutual) + { + return new ContactConstructor(user_id, mutual); + } + + public static ImportedContact importedContact(int user_id, long client_id) + { + return new ImportedContactConstructor(user_id, client_id); + } + + public static ContactBlocked contactBlocked(int user_id, int date) + { + return new ContactBlockedConstructor(user_id, date); + } + + public static ContactFound contactFound(int user_id) + { + return new ContactFoundConstructor(user_id); + } + + public static ContactSuggested contactSuggested(int user_id, int mutual_contacts) + { + return new ContactSuggestedConstructor(user_id, mutual_contacts); + } + + public static ContactStatus contactStatus(int user_id, int expires) + { + return new ContactStatusConstructor(user_id, expires); + } + + public static ChatLocated chatLocated(int chat_id, int distance) + { + return new ChatLocatedConstructor(chat_id, distance); + } + + public static contacts_ForeignLink contacts_foreignLinkUnknown() + { + return new Contacts_foreignLinkUnknownConstructor(); + } + + public static contacts_ForeignLink contacts_foreignLinkRequested(bool has_phone) + { + return new Contacts_foreignLinkRequestedConstructor(has_phone); + } + + public static contacts_ForeignLink contacts_foreignLinkMutual() + { + return new Contacts_foreignLinkMutualConstructor(); + } + + public static contacts_MyLink contacts_myLinkEmpty() + { + return new Contacts_myLinkEmptyConstructor(); + } + + public static contacts_MyLink contacts_myLinkRequested(bool contact) + { + return new Contacts_myLinkRequestedConstructor(contact); + } + + public static contacts_MyLink contacts_myLinkContact() + { + return new Contacts_myLinkContactConstructor(); + } + + public static contacts_Link contacts_link(contacts_MyLink my_link, contacts_ForeignLink foreign_link, User user) + { + return new Contacts_linkConstructor(my_link, foreign_link, user); + } + + public static contacts_Contacts contacts_contacts(List contacts, List users) + { + return new Contacts_contactsConstructor(contacts, users); + } + + public static contacts_Contacts contacts_contactsNotModified() + { + return new Contacts_contactsNotModifiedConstructor(); + } + + public static contacts_ImportedContacts contacts_importedContacts(List imported, List users) + { + return new Contacts_importedContactsConstructor(imported, users); + } + + public static contacts_Blocked contacts_blocked(List blocked, List users) + { + return new Contacts_blockedConstructor(blocked, users); + } + + public static contacts_Blocked contacts_blockedSlice(int count, List blocked, List users) + { + return new Contacts_blockedSliceConstructor(count, blocked, users); + } + + public static contacts_Found contacts_found(List results, List users) + { + return new Contacts_foundConstructor(results, users); + } + + public static contacts_Suggested contacts_suggested(List results, List users) + { + return new Contacts_suggestedConstructor(results, users); + } + + public static messages_Dialogs messages_dialogs(List dialogs, List messages, List chats, + List users) + { + return new Messages_dialogsConstructor(dialogs, messages, chats, users); + } + + public static messages_Dialogs messages_dialogsSlice(int count, List dialogs, List messages, + List chats, List users) + { + return new Messages_dialogsSliceConstructor(count, dialogs, messages, chats, users); + } + + public static messages_Messages messages_messages(List messages, List chats, List users) + { + return new Messages_messagesConstructor(messages, chats, users); + } + + public static messages_Messages messages_messagesSlice(int count, List messages, List chats, + List users) + { + return new Messages_messagesSliceConstructor(count, messages, chats, users); + } + + public static messages_Message messages_messageEmpty() + { + return new Messages_messageEmptyConstructor(); + } + + public static messages_Message messages_message(Message message, List chats, List users) + { + return new Messages_messageConstructor(message, chats, users); + } + + public static messages_StatedMessages messages_statedMessages(List messages, List chats, + List users, int pts, int seq) + { + return new Messages_statedMessagesConstructor(messages, chats, users, pts, seq); + } + + public static messages_StatedMessage messages_statedMessage(Message message, List chats, List users, + int pts, int seq) + { + return new Messages_statedMessageConstructor(message, chats, users, pts, seq); + } + + public static messages_SentMessage messages_sentMessage(int id, int date, int pts, int seq) + { + return new Messages_sentMessageConstructor(id, date, pts, seq); + } + + public static messages_Chat messages_chat(Chat chat, List users) + { + return new Messages_chatConstructor(chat, users); + } + + public static messages_Chats messages_chats(List chats, List users) + { + return new Messages_chatsConstructor(chats, users); + } + + public static messages_ChatFull messages_chatFull(ChatFull full_chat, List chats, List users) + { + return new Messages_chatFullConstructor(full_chat, chats, users); + } + + public static messages_AffectedHistory messages_affectedHistory(int pts, int seq, int offset) + { + return new Messages_affectedHistoryConstructor(pts, seq, offset); + } + + public static MessagesFilter inputMessagesFilterEmpty() + { + return new InputMessagesFilterEmptyConstructor(); + } + + public static MessagesFilter inputMessagesFilterPhotos() + { + return new InputMessagesFilterPhotosConstructor(); + } + + public static MessagesFilter inputMessagesFilterVideo() + { + return new InputMessagesFilterVideoConstructor(); + } + + public static MessagesFilter inputMessagesFilterPhotoVideo() + { + return new InputMessagesFilterPhotoVideoConstructor(); + } + + public static Update updateNewMessage(Message message, int pts) + { + return new UpdateNewMessageConstructor(message, pts); + } + + public static Update updateMessageID(int id, long random_id) + { + return new UpdateMessageIDConstructor(id, random_id); + } + + public static Update updateReadMessages(List messages, int pts) + { + return new UpdateReadMessagesConstructor(messages, pts); + } + + public static Update updateDeleteMessages(List messages, int pts) + { + return new UpdateDeleteMessagesConstructor(messages, pts); + } + + public static Update updateRestoreMessages(List messages, int pts) + { + return new UpdateRestoreMessagesConstructor(messages, pts); + } + + public static Update updateUserTyping(int user_id) + { + return new UpdateUserTypingConstructor(user_id); + } + + public static Update updateChatUserTyping(int chat_id, int user_id) + { + return new UpdateChatUserTypingConstructor(chat_id, user_id); + } + + public static Update updateChatParticipants(ChatParticipants participants) + { + return new UpdateChatParticipantsConstructor(participants); + } + + public static Update updateUserStatus(int user_id, UserStatus status) + { + return new UpdateUserStatusConstructor(user_id, status); + } + + public static Update updateUserName(int user_id, string first_name, string last_name) + { + return new UpdateUserNameConstructor(user_id, first_name, last_name); + } + + public static Update updateUserPhoto(int user_id, int date, UserProfilePhoto photo, bool previous) + { + return new UpdateUserPhotoConstructor(user_id, date, photo, previous); + } + + public static Update updateContactRegistered(int user_id, int date) + { + return new UpdateContactRegisteredConstructor(user_id, date); + } + + public static Update updateContactLink(int user_id, contacts_MyLink my_link, contacts_ForeignLink foreign_link) + { + return new UpdateContactLinkConstructor(user_id, my_link, foreign_link); + } + + public static Update updateActivation(int user_id) + { + return new UpdateActivationConstructor(user_id); + } + + public static Update updateNewAuthorization(long auth_key_id, int date, string device, string location) + { + return new UpdateNewAuthorizationConstructor(auth_key_id, date, device, location); + } + + public static updates_State updates_state(int pts, int qts, int date, int seq, int unread_count) + { + return new Updates_stateConstructor(pts, qts, date, seq, unread_count); + } + + public static updates_Difference updates_differenceEmpty(int date, int seq) + { + return new Updates_differenceEmptyConstructor(date, seq); + } + + public static updates_Difference updates_difference(List new_messages, + List new_encrypted_messages, List other_updates, List chats, List users, + updates_State state) + { + return new Updates_differenceConstructor(new_messages, new_encrypted_messages, other_updates, chats, users, state); + } + + public static updates_Difference updates_differenceSlice(List new_messages, + List new_encrypted_messages, List other_updates, List chats, List users, + updates_State intermediate_state) + { + return new Updates_differenceSliceConstructor(new_messages, new_encrypted_messages, other_updates, chats, users, + intermediate_state); + } + + public static Updates updatesTooLong() + { + return new UpdatesTooLongConstructor(); + } + + public static Updates updateShortMessage(int id, int from_id, string message, int pts, int date, int seq) + { + return new UpdateShortMessageConstructor(id, from_id, message, pts, date, seq); + } + + public static Updates updateShortChatMessage(int id, int from_id, int chat_id, string message, int pts, int date, + int seq) + { + return new UpdateShortChatMessageConstructor(id, from_id, chat_id, message, pts, date, seq); + } + + public static Updates updateShort(Update update, int date) + { + return new UpdateShortConstructor(update, date); + } + + public static Updates updatesCombined(List updates, List users, List chats, int date, + int seq_start, int seq) + { + return new UpdatesCombinedConstructor(updates, users, chats, date, seq_start, seq); + } + + public static Updates updates(List updates, List users, List chats, int date, int seq) + { + return new UpdatesConstructor(updates, users, chats, date, seq); + } + + public static photos_Photos photos_photos(List photos, List users) + { + return new Photos_photosConstructor(photos, users); + } + + public static photos_Photos photos_photosSlice(int count, List photos, List users) + { + return new Photos_photosSliceConstructor(count, photos, users); + } + + public static photos_Photo photos_photo(Photo photo, List users) + { + return new Photos_photoConstructor(photo, users); + } + + public static upload_File upload_file(storage_FileType type, int mtime, byte[] bytes) + { + return new Upload_fileConstructor(type, mtime, bytes); + } + + public static DcOption dcOption(int id, string hostname, string ip_address, int port) + { + return new DcOptionConstructor(id, hostname, ip_address, port); + } + + public static Config config(int date, bool test_mode, int this_dc, List dc_options, int chat_size_max) + { + return new ConfigConstructor(date, test_mode, this_dc, dc_options, chat_size_max); + } + + public static NearestDc nearestDc(string country, int this_dc, int nearest_dc) + { + return new NearestDcConstructor(country, this_dc, nearest_dc); + } + + public static help_AppUpdate help_appUpdate(int id, bool critical, string url, string text) + { + return new Help_appUpdateConstructor(id, critical, url, text); + } + + public static help_AppUpdate help_noAppUpdate() + { + return new Help_noAppUpdateConstructor(); + } + + public static help_InviteText help_inviteText(string message) + { + return new Help_inviteTextConstructor(message); + } + + public static messages_StatedMessages messages_statedMessagesLinks(List messages, List chats, + List users, List links, int pts, int seq) + { + return new Messages_statedMessagesLinksConstructor(messages, chats, users, links, pts, seq); + } + + public static messages_StatedMessage messages_statedMessageLink(Message message, List chats, List users, + List links, int pts, int seq) + { + return new Messages_statedMessageLinkConstructor(message, chats, users, links, pts, seq); + } + + public static messages_SentMessage messages_sentMessageLink(int id, int date, int pts, int seq, + List links) + { + return new Messages_sentMessageLinkConstructor(id, date, pts, seq, links); + } + + public static InputGeoChat inputGeoChat(int chat_id, long access_hash) + { + return new InputGeoChatConstructor(chat_id, access_hash); + } + + public static InputNotifyPeer inputNotifyGeoChatPeer(InputGeoChat peer) + { + return new InputNotifyGeoChatPeerConstructor(peer); + } + + public static Chat geoChat(int id, long access_hash, string title, string address, string venue, GeoPoint geo, + ChatPhoto photo, int participants_count, int date, bool checked_in, int version) + { + return new GeoChatConstructor(id, access_hash, title, address, venue, geo, photo, participants_count, date, + checked_in, version); + } + + public static GeoChatMessage geoChatMessageEmpty(int chat_id, int id) + { + return new GeoChatMessageEmptyConstructor(chat_id, id); + } + + public static GeoChatMessage geoChatMessage(int chat_id, int id, int from_id, int date, string message, + MessageMedia media) + { + return new GeoChatMessageConstructor(chat_id, id, from_id, date, message, media); + } + + public static GeoChatMessage geoChatMessageService(int chat_id, int id, int from_id, int date, MessageAction action) + { + return new GeoChatMessageServiceConstructor(chat_id, id, from_id, date, action); + } + + public static geochats_StatedMessage geochats_statedMessage(GeoChatMessage message, List chats, List users, + int seq) + { + return new Geochats_statedMessageConstructor(message, chats, users, seq); + } + + public static geochats_Located geochats_located(List results, List messages, + List chats, List users) + { + return new Geochats_locatedConstructor(results, messages, chats, users); + } + + public static geochats_Messages geochats_messages(List messages, List chats, List users) + { + return new Geochats_messagesConstructor(messages, chats, users); + } + + public static geochats_Messages geochats_messagesSlice(int count, List messages, List chats, + List users) + { + return new Geochats_messagesSliceConstructor(count, messages, chats, users); + } + + public static MessageAction messageActionGeoChatCreate(string title, string address) + { + return new MessageActionGeoChatCreateConstructor(title, address); + } + + public static MessageAction messageActionGeoChatCheckin() + { + return new MessageActionGeoChatCheckinConstructor(); + } + + public static Update updateNewGeoChatMessage(GeoChatMessage message) + { + return new UpdateNewGeoChatMessageConstructor(message); + } + + public static WallPaper wallPaperSolid(int id, string title, int bg_color, int color) + { + return new WallPaperSolidConstructor(id, title, bg_color, color); + } + + public static Update updateNewEncryptedMessage(EncryptedMessage message, int qts) + { + return new UpdateNewEncryptedMessageConstructor(message, qts); + } + + public static Update updateEncryptedChatTyping(int chat_id) + { + return new UpdateEncryptedChatTypingConstructor(chat_id); + } + + public static Update updateEncryption(EncryptedChat chat, int date) + { + return new UpdateEncryptionConstructor(chat, date); + } + + public static Update updateEncryptedMessagesRead(int chat_id, int max_date, int date) + { + return new UpdateEncryptedMessagesReadConstructor(chat_id, max_date, date); + } + + public static EncryptedChat encryptedChatEmpty(int id) + { + return new EncryptedChatEmptyConstructor(id); + } + + public static EncryptedChat encryptedChatWaiting(int id, long access_hash, int date, int admin_id, int participant_id) + { + return new EncryptedChatWaitingConstructor(id, access_hash, date, admin_id, participant_id); + } + + public static EncryptedChat encryptedChatRequested(int id, long access_hash, int date, int admin_id, + int participant_id, byte[] g_a, byte[] nonce) + { + return new EncryptedChatRequestedConstructor(id, access_hash, date, admin_id, participant_id, g_a, nonce); + } + + public static EncryptedChat encryptedChat(int id, long access_hash, int date, int admin_id, int participant_id, + byte[] g_a_or_b, byte[] nonce, long key_fingerprint) + { + return new EncryptedChatConstructor(id, access_hash, date, admin_id, participant_id, g_a_or_b, nonce, key_fingerprint); + } + + public static EncryptedChat encryptedChatDiscarded(int id) + { + return new EncryptedChatDiscardedConstructor(id); + } + + public static InputEncryptedChat inputEncryptedChat(int chat_id, long access_hash) + { + return new InputEncryptedChatConstructor(chat_id, access_hash); + } + + public static EncryptedFile encryptedFileEmpty() + { + return new EncryptedFileEmptyConstructor(); + } + + public static EncryptedFile encryptedFile(long id, long access_hash, int size, int dc_id, int key_fingerprint) + { + return new EncryptedFileConstructor(id, access_hash, size, dc_id, key_fingerprint); + } + + public static InputEncryptedFile inputEncryptedFileEmpty() + { + return new InputEncryptedFileEmptyConstructor(); + } + + public static InputEncryptedFile inputEncryptedFileUploaded(long id, int parts, string md5_checksum, + int key_fingerprint) + { + return new InputEncryptedFileUploadedConstructor(id, parts, md5_checksum, key_fingerprint); + } + + public static InputEncryptedFile inputEncryptedFile(long id, long access_hash) + { + return new InputEncryptedFileConstructor(id, access_hash); + } + + public static InputFileLocation inputEncryptedFileLocation(long id, long access_hash) + { + return new InputEncryptedFileLocationConstructor(id, access_hash); + } + + public static EncryptedMessage encryptedMessage(long random_id, int chat_id, int date, byte[] bytes, + EncryptedFile file) + { + return new EncryptedMessageConstructor(random_id, chat_id, date, bytes, file); + } + + public static EncryptedMessage encryptedMessageService(long random_id, int chat_id, int date, byte[] bytes) + { + return new EncryptedMessageServiceConstructor(random_id, chat_id, date, bytes); + } + + public static DecryptedMessageLayer decryptedMessageLayer(int layer, DecryptedMessage message) + { + return new DecryptedMessageLayerConstructor(layer, message); + } + + public static DecryptedMessage decryptedMessage(long random_id, byte[] random_bytes, string message, + DecryptedMessageMedia media) + { + return new DecryptedMessageConstructor(random_id, random_bytes, message, media); + } + + public static DecryptedMessage decryptedMessageService(long random_id, byte[] random_bytes, + DecryptedMessageAction action) + { + return new DecryptedMessageServiceConstructor(random_id, random_bytes, action); + } + + public static DecryptedMessageMedia decryptedMessageMediaEmpty() + { + return new DecryptedMessageMediaEmptyConstructor(); + } + + public static DecryptedMessageMedia decryptedMessageMediaPhoto(byte[] thumb, int thumb_w, int thumb_h, int w, int h, + int size, byte[] key, byte[] iv) + { + return new DecryptedMessageMediaPhotoConstructor(thumb, thumb_w, thumb_h, w, h, size, key, iv); + } + + public static DecryptedMessageMedia decryptedMessageMediaVideo(byte[] thumb, int thumb_w, int thumb_h, int duration, + int w, int h, int size, byte[] key, byte[] iv) + { + return new DecryptedMessageMediaVideoConstructor(thumb, thumb_w, thumb_h, duration, w, h, size, key, iv); + } + + public static DecryptedMessageMedia decryptedMessageMediaGeoPoint(double lat, double lng) + { + return new DecryptedMessageMediaGeoPointConstructor(lat, lng); + } + + public static DecryptedMessageMedia decryptedMessageMediaContact(string phone_number, string first_name, + string last_name, int user_id) + { + return new DecryptedMessageMediaContactConstructor(phone_number, first_name, last_name, user_id); + } + + public static DecryptedMessageAction decryptedMessageActionSetMessageTTL(int ttl_seconds) + { + return new DecryptedMessageActionSetMessageTTLConstructor(ttl_seconds); + } + + public static messages_DhConfig messages_dhConfigNotModified(byte[] random) + { + return new Messages_dhConfigNotModifiedConstructor(random); + } + + public static messages_DhConfig messages_dhConfig(int g, byte[] p, int version, byte[] random) + { + return new Messages_dhConfigConstructor(g, p, version, random); + } + + public static messages_SentEncryptedMessage messages_sentEncryptedMessage(int date) + { + return new Messages_sentEncryptedMessageConstructor(date); + } + + public static messages_SentEncryptedMessage messages_sentEncryptedFile(int date, EncryptedFile file) + { + return new Messages_sentEncryptedFileConstructor(date, file); + } + + public static InputFile inputFileBig(long id, int parts, string name) + { + return new InputFileBigConstructor(id, parts, name); + } + + public static InputEncryptedFile inputEncryptedFileBigUploaded(long id, int parts, int key_fingerprint) + { + return new InputEncryptedFileBigUploadedConstructor(id, parts, key_fingerprint); + } + + public static Update updateChatParticipantAdd(int chat_id, int user_id, int inviter_id, int version) + { + return new UpdateChatParticipantAddConstructor(chat_id, user_id, inviter_id, version); + } + + public static Update updateChatParticipantDelete(int chat_id, int user_id, int version) + { + return new UpdateChatParticipantDeleteConstructor(chat_id, user_id, version); + } + + public static Update updateDcOptions(List dc_options) + { + return new UpdateDcOptionsConstructor(dc_options); + } + + public static InputMedia inputMediaUploadedAudio(InputFile file, int duration) + { + return new InputMediaUploadedAudioConstructor(file, duration); + } + + public static InputMedia inputMediaAudio(InputAudio id) + { + return new InputMediaAudioConstructor(id); + } + + public static InputMedia inputMediaUploadedDocument(InputFile file, string file_name, string mime_type) + { + return new InputMediaUploadedDocumentConstructor(file, file_name, mime_type); + } + + public static InputMedia inputMediaUploadedThumbDocument(InputFile file, InputFile thumb, string file_name, + string mime_type) + { + return new InputMediaUploadedThumbDocumentConstructor(file, thumb, file_name, mime_type); + } + + public static InputMedia inputMediaDocument(InputDocument id) + { + return new InputMediaDocumentConstructor(id); + } + + public static MessageMedia messageMediaDocument(Document document) + { + return new MessageMediaDocumentConstructor(document); + } + + public static MessageMedia messageMediaAudio(Audio audio) + { + return new MessageMediaAudioConstructor(audio); + } + + public static InputAudio inputAudioEmpty() + { + return new InputAudioEmptyConstructor(); + } + + public static InputAudio inputAudio(long id, long access_hash) + { + return new InputAudioConstructor(id, access_hash); + } + + public static InputDocument inputDocumentEmpty() + { + return new InputDocumentEmptyConstructor(); + } + + public static InputDocument inputDocument(long id, long access_hash) + { + return new InputDocumentConstructor(id, access_hash); + } + + public static InputFileLocation inputAudioFileLocation(long id, long access_hash) + { + return new InputAudioFileLocationConstructor(id, access_hash); + } + + public static InputFileLocation inputDocumentFileLocation(long id, long access_hash) + { + return new InputDocumentFileLocationConstructor(id, access_hash); + } + + public static DecryptedMessageMedia decryptedMessageMediaDocument(byte[] thumb, int thumb_w, int thumb_h, + string file_name, string mime_type, int size, byte[] key, byte[] iv) + { + return new DecryptedMessageMediaDocumentConstructor(thumb, thumb_w, thumb_h, file_name, mime_type, size, key, iv); + } + + public static DecryptedMessageMedia decryptedMessageMediaAudio(int duration, int size, byte[] key, byte[] iv) + { + return new DecryptedMessageMediaAudioConstructor(duration, size, key, iv); + } + + public static Audio audioEmpty(long id) + { + return new AudioEmptyConstructor(id); + } + + public static Audio audio(long id, long access_hash, int user_id, int date, int duration, int size, int dc_id) + { + return new AudioConstructor(id, access_hash, user_id, date, duration, size, dc_id); + } + + public static Document documentEmpty(long id) + { + return new DocumentEmptyConstructor(id); + } + + public static Document document(long id, long access_hash, int user_id, int date, string file_name, string mime_type, + int size, PhotoSize thumb, int dc_id) + { + return new DocumentConstructor(id, access_hash, user_id, date, file_name, mime_type, size, thumb, dc_id); + } + + } + + // abstract types + public abstract class contacts_ImportedContacts : TLObject + { + + } + + public abstract class Peer : TLObject + { + + } + + public abstract class InputVideo : TLObject + { + + } + + public abstract class help_InviteText : TLObject + { + + } + + public abstract class UserStatus : TLObject + { + + } + + public abstract class MessagesFilter : TLObject + { + + } + + public abstract class Error : TLObject + { + + } + + public abstract class Updates : TLObject + { + + } + + public abstract class help_AppUpdate : TLObject + { + + } + + public abstract class InputEncryptedChat : TLObject + { + + } + + public abstract class DecryptedMessage : TLObject + { + + } + + public abstract class InputAudio : TLObject + { + + } + + public abstract class ChatLocated : TLObject + { + + } + + public abstract class PhotoSize : TLObject + { + + } + + public abstract class messages_SentEncryptedMessage : TLObject + { + + } + + public abstract class MessageMedia : TLObject + { + + } + + public abstract class InputDocument : TLObject + { + + } + + public abstract class ImportedContact : TLObject + { + + } + + public abstract class ContactBlocked : TLObject + { + + } + + public abstract class Message : TLObject + { + + } + + public abstract class InputNotifyPeer : TLObject + { + + } + + public abstract class messages_ChatFull : TLObject + { + + } + + public abstract class ChatParticipant : TLObject + { + + } + + public abstract class InputPhoto : TLObject + { + + } + + public abstract class DecryptedMessageMedia : TLObject + { + + } + + public abstract class InputFileLocation : TLObject + { + + } + + public abstract class InputEncryptedFile : TLObject + { + + } + + public abstract class contacts_ForeignLink : TLObject + { + + } + + public abstract class Document : TLObject + { + + } + + public abstract class UserFull : TLObject + { + + } + + public abstract class messages_Message : TLObject + { + + } + + public abstract class DcOption : TLObject + { + + } + + public abstract class photos_Photos : TLObject + { + + } + + public abstract class InputPeerNotifySettings : TLObject + { + + } + + public abstract class contacts_Suggested : TLObject + { + + } + + public abstract class InputGeoPoint : TLObject + { + + } + + public abstract class InputGeoChat : TLObject + { + + } + + public abstract class InputContact : TLObject + { + + } + + public abstract class EncryptedFile : TLObject + { + + } + + public abstract class PeerNotifySettings : TLObject + { + + } + + public abstract class auth_Authorization : TLObject + { + + } + + public abstract class auth_CheckedPhone : TLObject + { + + } + + public abstract class FileLocation : TLObject + { + + } + + public abstract class messages_Chats : TLObject + { + + } + + public abstract class contacts_Link : TLObject + { + + } + + public abstract class messages_StatedMessage : TLObject + { + + } + + public abstract class geochats_Located : TLObject + { + + } + + public abstract class updates_State : TLObject + { + + } + + public abstract class storage_FileType : TLObject + { + + } + + public abstract class geochats_StatedMessage : TLObject + { + + } + + public abstract class ContactFound : TLObject + { + + } + + public abstract class Photo : TLObject + { + + } + + public abstract class InputMedia : TLObject + { + + } + + public abstract class photos_Photo : TLObject + { + + } + + public abstract class InputFile : TLObject + { + + } + + public abstract class auth_ExportedAuthorization : TLObject + { + + } + + public abstract class User : TLObject + { + + } + + public abstract class NearestDc : TLObject + { + + } + + public abstract class Video : TLObject + { + + } + + public abstract class contacts_Blocked : TLObject + { + + } + + public abstract class messages_AffectedHistory : TLObject + { + + } + + public abstract class messages_Chat : TLObject + { + + } + + public abstract class Chat : TLObject + { + + } + + public abstract class ChatParticipants : TLObject + { + + } + + public abstract class InputAppEvent : TLObject + { + + } + + public abstract class messages_Messages : TLObject + { + + } + + public abstract class messages_Dialogs : TLObject + { + + } + + public abstract class InputPeer : TLObject + { + + } + + public abstract class ChatPhoto : TLObject + { + + } + + public abstract class contacts_MyLink : TLObject + { + + } + + public abstract class InputChatPhoto : TLObject + { + + } + + public abstract class messages_SentMessage : TLObject + { + + } + + public abstract class messages_StatedMessages : TLObject + { + + } + + public abstract class UserProfilePhoto : TLObject + { + + } + + public abstract class updates_Difference : TLObject + { + + } + + public abstract class Update : TLObject + { + + } + + public abstract class GeoPoint : TLObject + { + + } + + public abstract class WallPaper : TLObject + { + + } + + public abstract class DecryptedMessageLayer : TLObject + { + + } + + public abstract class Config : TLObject + { + + } + + public abstract class EncryptedMessage : TLObject + { + + } + + public abstract class Dialog : TLObject + { + + } + + public abstract class ContactStatus : TLObject + { + + } + + public abstract class InputPeerNotifyEvents : TLObject + { + + } + + public abstract class MessageAction : TLObject + { + + } + + public abstract class DecryptedMessageAction : TLObject + { + + } + + public abstract class auth_SentCode : TLObject + { + + } + + public abstract class geochats_Messages : TLObject + { + + } + + public abstract class InputUser : TLObject + { + + } + + public abstract class EncryptedChat : TLObject + { + + } + + public abstract class contacts_Contacts : TLObject + { + + } + + public abstract class GeoChatMessage : TLObject + { + + } + + public abstract class PeerNotifyEvents : TLObject + { + + } + + public abstract class contacts_Found : TLObject + { + + } + + public abstract class Audio : TLObject + { + + } + + public abstract class ChatFull : TLObject + { + + } + + public abstract class messages_DhConfig : TLObject + { + + } + + public abstract class Contact : TLObject + { + + } + + public abstract class upload_File : TLObject + { + + } + + public abstract class InputPhotoCrop : TLObject + { + + } + + public abstract class ContactSuggested : TLObject + { + + } + + // types implementations + + + public class ErrorConstructor : Error + { + public int code; + public string text; + + public ErrorConstructor() + { + + } + + public ErrorConstructor(int code, string text) + { + this.code = code; + this.text = text; + } + + + public override Constructor Constructor + { + get { return Constructor.error; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xc4b9f9bb); + writer.Write(this.code); + Serializers.String.write(writer, this.text); + } + + public override void Read(BinaryReader reader) + { + this.code = reader.ReadInt32(); + this.text = Serializers.String.read(reader); + } + + public override string ToString() + { + return String.Format("(error code:{0} text:'{1}')", code, text); + } + } + + + public class InputPeerEmptyConstructor : InputPeer + { + + public InputPeerEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.inputPeerEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x7f3b18ea); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(inputPeerEmpty)"); + } + } + + + public class InputPeerSelfConstructor : InputPeer + { + + public InputPeerSelfConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.inputPeerSelf; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x7da07ec9); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(inputPeerSelf)"); + } + } + + + public class InputPeerContactConstructor : InputPeer + { + public int user_id; + + public InputPeerContactConstructor() + { + + } + + public InputPeerContactConstructor(int user_id) + { + this.user_id = user_id; + } + + + public override Constructor Constructor + { + get { return Constructor.inputPeerContact; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x1023dbe8); + writer.Write(this.user_id); + } + + public override void Read(BinaryReader reader) + { + this.user_id = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(inputPeerContact user_id:{0})", user_id); + } + } + + + public class InputPeerForeignConstructor : InputPeer + { + public int user_id; + public long access_hash; + + public InputPeerForeignConstructor() + { + + } + + public InputPeerForeignConstructor(int user_id, long access_hash) + { + this.user_id = user_id; + this.access_hash = access_hash; + } + + + public override Constructor Constructor + { + get { return Constructor.inputPeerForeign; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x9b447325); + writer.Write(this.user_id); + writer.Write(this.access_hash); + } + + public override void Read(BinaryReader reader) + { + this.user_id = reader.ReadInt32(); + this.access_hash = reader.ReadInt64(); + } + + public override string ToString() + { + return String.Format("(inputPeerForeign user_id:{0} access_hash:{1})", user_id, access_hash); + } + } + + + public class InputPeerChatConstructor : InputPeer + { + public int chat_id; + + public InputPeerChatConstructor() + { + + } + + public InputPeerChatConstructor(int chat_id) + { + this.chat_id = chat_id; + } + + + public override Constructor Constructor + { + get { return Constructor.inputPeerChat; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x179be863); + writer.Write(this.chat_id); + } + + public override void Read(BinaryReader reader) + { + this.chat_id = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(inputPeerChat chat_id:{0})", chat_id); + } + } + + + public class InputUserEmptyConstructor : InputUser + { + + public InputUserEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.inputUserEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xb98886cf); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(inputUserEmpty)"); + } + } + + + public class InputUserSelfConstructor : InputUser + { + + public InputUserSelfConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.inputUserSelf; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xf7c1b13f); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(inputUserSelf)"); + } + } + + + public class InputUserContactConstructor : InputUser + { + public int user_id; + + public InputUserContactConstructor() + { + + } + + public InputUserContactConstructor(int user_id) + { + this.user_id = user_id; + } + + + public override Constructor Constructor + { + get { return Constructor.inputUserContact; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x86e94f65); + writer.Write(this.user_id); + } + + public override void Read(BinaryReader reader) + { + this.user_id = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(inputUserContact user_id:{0})", user_id); + } + } + + + public class InputUserForeignConstructor : InputUser + { + public int user_id; + public long access_hash; + + public InputUserForeignConstructor() + { + + } + + public InputUserForeignConstructor(int user_id, long access_hash) + { + this.user_id = user_id; + this.access_hash = access_hash; + } + + + public override Constructor Constructor + { + get { return Constructor.inputUserForeign; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x655e74ff); + writer.Write(this.user_id); + writer.Write(this.access_hash); + } + + public override void Read(BinaryReader reader) + { + this.user_id = reader.ReadInt32(); + this.access_hash = reader.ReadInt64(); + } + + public override string ToString() + { + return String.Format("(inputUserForeign user_id:{0} access_hash:{1})", user_id, access_hash); + } + } + + + public class InputPhoneContactConstructor : InputContact + { + public long client_id; + public string phone; + public string first_name; + public string last_name; + + public InputPhoneContactConstructor() + { + + } + + public InputPhoneContactConstructor(long client_id, string phone, string first_name, string last_name) + { + this.client_id = client_id; + this.phone = phone; + this.first_name = first_name; + this.last_name = last_name; + } + + + public override Constructor Constructor + { + get { return Constructor.inputPhoneContact; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xf392b7f4); + writer.Write(this.client_id); + Serializers.String.write(writer, this.phone); + Serializers.String.write(writer, this.first_name); + Serializers.String.write(writer, this.last_name); + } + + public override void Read(BinaryReader reader) + { + this.client_id = reader.ReadInt64(); + this.phone = Serializers.String.read(reader); + this.first_name = Serializers.String.read(reader); + this.last_name = Serializers.String.read(reader); + } + + public override string ToString() + { + return String.Format("(inputPhoneContact client_id:{0} phone:'{1}' first_name:'{2}' last_name:'{3}')", client_id, + phone, first_name, last_name); + } + } + + + public class InputFileConstructor : InputFile + { + public long id; + public int parts; + public string name; + public string md5_checksum; + + public InputFileConstructor() + { + + } + + public InputFileConstructor(long id, int parts, string name, string md5_checksum) + { + this.id = id; + this.parts = parts; + this.name = name; + this.md5_checksum = md5_checksum; + } + + + public override Constructor Constructor + { + get { return Constructor.inputFile; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xf52ff27f); + writer.Write(this.id); + writer.Write(this.parts); + Serializers.String.write(writer, this.name); + Serializers.String.write(writer, this.md5_checksum); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt64(); + this.parts = reader.ReadInt32(); + this.name = Serializers.String.read(reader); + this.md5_checksum = Serializers.String.read(reader); + } + + public override string ToString() + { + return String.Format("(inputFile id:{0} parts:{1} name:'{2}' md5_checksum:'{3}')", id, parts, name, md5_checksum); + } + } + + + public class InputMediaEmptyConstructor : InputMedia + { + + public InputMediaEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.inputMediaEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x9664f57f); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(inputMediaEmpty)"); + } + } + + + public class InputMediaUploadedPhotoConstructor : InputMedia + { + public InputFile file; + + public InputMediaUploadedPhotoConstructor() + { + + } + + public InputMediaUploadedPhotoConstructor(InputFile file) + { + this.file = file; + } + + + public override Constructor Constructor + { + get { return Constructor.inputMediaUploadedPhoto; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x2dc53a7d); + this.file.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.file = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(inputMediaUploadedPhoto file:{0})", file); + } + } + + + public class InputMediaPhotoConstructor : InputMedia + { + public InputPhoto id; + + public InputMediaPhotoConstructor() + { + + } + + public InputMediaPhotoConstructor(InputPhoto id) + { + this.id = id; + } + + + public override Constructor Constructor + { + get { return Constructor.inputMediaPhoto; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x8f2ab2ec); + this.id.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.id = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(inputMediaPhoto id:{0})", id); + } + } + + + public class InputMediaGeoPointConstructor : InputMedia + { + public InputGeoPoint geo_point; + + public InputMediaGeoPointConstructor() + { + + } + + public InputMediaGeoPointConstructor(InputGeoPoint geo_point) + { + this.geo_point = geo_point; + } + + + public override Constructor Constructor + { + get { return Constructor.inputMediaGeoPoint; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xf9c44144); + this.geo_point.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.geo_point = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(inputMediaGeoPoint geo_point:{0})", geo_point); + } + } + + + public class InputMediaContactConstructor : InputMedia + { + public string phone_number; + public string first_name; + public string last_name; + + public InputMediaContactConstructor() + { + + } + + public InputMediaContactConstructor(string phone_number, string first_name, string last_name) + { + this.phone_number = phone_number; + this.first_name = first_name; + this.last_name = last_name; + } + + + public override Constructor Constructor + { + get { return Constructor.inputMediaContact; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xa6e45987); + Serializers.String.write(writer, this.phone_number); + Serializers.String.write(writer, this.first_name); + Serializers.String.write(writer, this.last_name); + } + + public override void Read(BinaryReader reader) + { + this.phone_number = Serializers.String.read(reader); + this.first_name = Serializers.String.read(reader); + this.last_name = Serializers.String.read(reader); + } + + public override string ToString() + { + return String.Format("(inputMediaContact phone_number:'{0}' first_name:'{1}' last_name:'{2}')", phone_number, + first_name, last_name); + } + } + + + public class InputMediaUploadedVideoConstructor : InputMedia + { + public InputFile file; + public int duration; + public int w; + public int h; + + public InputMediaUploadedVideoConstructor() + { + + } + + public InputMediaUploadedVideoConstructor(InputFile file, int duration, int w, int h) + { + this.file = file; + this.duration = duration; + this.w = w; + this.h = h; + } + + + public override Constructor Constructor + { + get { return Constructor.inputMediaUploadedVideo; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x4847d92a); + this.file.Write(writer); + writer.Write(this.duration); + writer.Write(this.w); + writer.Write(this.h); + } + + public override void Read(BinaryReader reader) + { + this.file = TL.Parse(reader); + this.duration = reader.ReadInt32(); + this.w = reader.ReadInt32(); + this.h = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(inputMediaUploadedVideo file:{0} duration:{1} w:{2} h:{3})", file, duration, w, h); + } + } + + + public class InputMediaUploadedThumbVideoConstructor : InputMedia + { + public InputFile file; + public InputFile thumb; + public int duration; + public int w; + public int h; + + public InputMediaUploadedThumbVideoConstructor() + { + + } + + public InputMediaUploadedThumbVideoConstructor(InputFile file, InputFile thumb, int duration, int w, int h) + { + this.file = file; + this.thumb = thumb; + this.duration = duration; + this.w = w; + this.h = h; + } + + + public override Constructor Constructor + { + get { return Constructor.inputMediaUploadedThumbVideo; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xe628a145); + this.file.Write(writer); + this.thumb.Write(writer); + writer.Write(this.duration); + writer.Write(this.w); + writer.Write(this.h); + } + + public override void Read(BinaryReader reader) + { + this.file = TL.Parse(reader); + this.thumb = TL.Parse(reader); + this.duration = reader.ReadInt32(); + this.w = reader.ReadInt32(); + this.h = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(inputMediaUploadedThumbVideo file:{0} thumb:{1} duration:{2} w:{3} h:{4})", file, thumb, + duration, w, h); + } + } + + + public class InputMediaVideoConstructor : InputMedia + { + public InputVideo id; + + public InputMediaVideoConstructor() + { + + } + + public InputMediaVideoConstructor(InputVideo id) + { + this.id = id; + } + + + public override Constructor Constructor + { + get { return Constructor.inputMediaVideo; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x7f023ae6); + this.id.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.id = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(inputMediaVideo id:{0})", id); + } + } + + + public class InputChatPhotoEmptyConstructor : InputChatPhoto + { + + public InputChatPhotoEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.inputChatPhotoEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x1ca48f57); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(inputChatPhotoEmpty)"); + } + } + + + public class InputChatUploadedPhotoConstructor : InputChatPhoto + { + public InputFile file; + public InputPhotoCrop crop; + + public InputChatUploadedPhotoConstructor() + { + + } + + public InputChatUploadedPhotoConstructor(InputFile file, InputPhotoCrop crop) + { + this.file = file; + this.crop = crop; + } + + + public override Constructor Constructor + { + get { return Constructor.inputChatUploadedPhoto; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x94254732); + this.file.Write(writer); + this.crop.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.file = TL.Parse(reader); + this.crop = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(inputChatUploadedPhoto file:{0} crop:{1})", file, crop); + } + } + + + public class InputChatPhotoConstructor : InputChatPhoto + { + public InputPhoto id; + public InputPhotoCrop crop; + + public InputChatPhotoConstructor() + { + + } + + public InputChatPhotoConstructor(InputPhoto id, InputPhotoCrop crop) + { + this.id = id; + this.crop = crop; + } + + + public override Constructor Constructor + { + get { return Constructor.inputChatPhoto; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xb2e1bf08); + this.id.Write(writer); + this.crop.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.id = TL.Parse(reader); + this.crop = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(inputChatPhoto id:{0} crop:{1})", id, crop); + } + } + + + public class InputGeoPointEmptyConstructor : InputGeoPoint + { + + public InputGeoPointEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.inputGeoPointEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xe4c123d6); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(inputGeoPointEmpty)"); + } + } + + + public class InputGeoPointConstructor : InputGeoPoint + { + public double lat; + public double lng; + + public InputGeoPointConstructor() + { + + } + + public InputGeoPointConstructor(double lat, double lng) + { + this.lat = lat; + this.lng = lng; + } + + + public override Constructor Constructor + { + get { return Constructor.inputGeoPoint; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xf3b7acc9); + writer.Write(this.lat); + writer.Write(this.lng); + } + + public override void Read(BinaryReader reader) + { + this.lat = reader.ReadDouble(); + this.lng = reader.ReadDouble(); + } + + public override string ToString() + { + return String.Format("(inputGeoPoint lat:{0} long:{1})", lat, lng); + } + } + + + public class InputPhotoEmptyConstructor : InputPhoto + { + + public InputPhotoEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.inputPhotoEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x1cd7bf0d); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(inputPhotoEmpty)"); + } + } + + + public class InputPhotoConstructor : InputPhoto + { + public long id; + public long access_hash; + + public InputPhotoConstructor() + { + + } + + public InputPhotoConstructor(long id, long access_hash) + { + this.id = id; + this.access_hash = access_hash; + } + + + public override Constructor Constructor + { + get { return Constructor.inputPhoto; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xfb95c6c4); + writer.Write(this.id); + writer.Write(this.access_hash); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt64(); + this.access_hash = reader.ReadInt64(); + } + + public override string ToString() + { + return String.Format("(inputPhoto id:{0} access_hash:{1})", id, access_hash); + } + } + + + public class InputVideoEmptyConstructor : InputVideo + { + + public InputVideoEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.inputVideoEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x5508ec75); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(inputVideoEmpty)"); + } + } + + + public class InputVideoConstructor : InputVideo + { + public long id; + public long access_hash; + + public InputVideoConstructor() + { + + } + + public InputVideoConstructor(long id, long access_hash) + { + this.id = id; + this.access_hash = access_hash; + } + + + public override Constructor Constructor + { + get { return Constructor.inputVideo; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xee579652); + writer.Write(this.id); + writer.Write(this.access_hash); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt64(); + this.access_hash = reader.ReadInt64(); + } + + public override string ToString() + { + return String.Format("(inputVideo id:{0} access_hash:{1})", id, access_hash); + } + } + + + public class InputFileLocationConstructor : InputFileLocation + { + public long volume_id; + public int local_id; + public long secret; + + public InputFileLocationConstructor() + { + + } + + public InputFileLocationConstructor(long volume_id, int local_id, long secret) + { + this.volume_id = volume_id; + this.local_id = local_id; + this.secret = secret; + } + + + public override Constructor Constructor + { + get { return Constructor.inputFileLocation; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x14637196); + writer.Write(this.volume_id); + writer.Write(this.local_id); + writer.Write(this.secret); + } + + public override void Read(BinaryReader reader) + { + this.volume_id = reader.ReadInt64(); + this.local_id = reader.ReadInt32(); + this.secret = reader.ReadInt64(); + } + + public override string ToString() + { + return String.Format("(inputFileLocation volume_id:{0} local_id:{1} secret:{2})", volume_id, local_id, secret); + } + } + + + public class InputVideoFileLocationConstructor : InputFileLocation + { + public long id; + public long access_hash; + + public InputVideoFileLocationConstructor() + { + + } + + public InputVideoFileLocationConstructor(long id, long access_hash) + { + this.id = id; + this.access_hash = access_hash; + } + + + public override Constructor Constructor + { + get { return Constructor.inputVideoFileLocation; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x3d0364ec); + writer.Write(this.id); + writer.Write(this.access_hash); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt64(); + this.access_hash = reader.ReadInt64(); + } + + public override string ToString() + { + return String.Format("(inputVideoFileLocation id:{0} access_hash:{1})", id, access_hash); + } + } + + + public class InputPhotoCropAutoConstructor : InputPhotoCrop + { + + public InputPhotoCropAutoConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.inputPhotoCropAuto; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xade6b004); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(inputPhotoCropAuto)"); + } + } + + + public class InputPhotoCropConstructor : InputPhotoCrop + { + public double crop_left; + public double crop_top; + public double crop_width; + + public InputPhotoCropConstructor() + { + + } + + public InputPhotoCropConstructor(double crop_left, double crop_top, double crop_width) + { + this.crop_left = crop_left; + this.crop_top = crop_top; + this.crop_width = crop_width; + } + + + public override Constructor Constructor + { + get { return Constructor.inputPhotoCrop; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xd9915325); + writer.Write(this.crop_left); + writer.Write(this.crop_top); + writer.Write(this.crop_width); + } + + public override void Read(BinaryReader reader) + { + this.crop_left = reader.ReadDouble(); + this.crop_top = reader.ReadDouble(); + this.crop_width = reader.ReadDouble(); + } + + public override string ToString() + { + return String.Format("(inputPhotoCrop crop_left:{0} crop_top:{1} crop_width:{2})", crop_left, crop_top, crop_width); + } + } + + + public class InputAppEventConstructor : InputAppEvent + { + public double time; + public string type; + public long peer; + public string data; + + public InputAppEventConstructor() + { + + } + + public InputAppEventConstructor(double time, string type, long peer, string data) + { + this.time = time; + this.type = type; + this.peer = peer; + this.data = data; + } + + + public override Constructor Constructor + { + get { return Constructor.inputAppEvent; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x770656a8); + writer.Write(this.time); + Serializers.String.write(writer, this.type); + writer.Write(this.peer); + Serializers.String.write(writer, this.data); + } + + public override void Read(BinaryReader reader) + { + this.time = reader.ReadDouble(); + this.type = Serializers.String.read(reader); + this.peer = reader.ReadInt64(); + this.data = Serializers.String.read(reader); + } + + public override string ToString() + { + return String.Format("(inputAppEvent time:{0} type:'{1}' peer:{2} data:'{3}')", time, type, peer, data); + } + } + + + public class PeerUserConstructor : Peer + { + public int user_id; + + public PeerUserConstructor() + { + + } + + public PeerUserConstructor(int user_id) + { + this.user_id = user_id; + } + + + public override Constructor Constructor + { + get { return Constructor.peerUser; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x9db1bc6d); + writer.Write(this.user_id); + } + + public override void Read(BinaryReader reader) + { + this.user_id = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(peerUser user_id:{0})", user_id); + } + } + + + public class PeerChatConstructor : Peer + { + public int chat_id; + + public PeerChatConstructor() + { + + } + + public PeerChatConstructor(int chat_id) + { + this.chat_id = chat_id; + } + + + public override Constructor Constructor + { + get { return Constructor.peerChat; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xbad0e5bb); + writer.Write(this.chat_id); + } + + public override void Read(BinaryReader reader) + { + this.chat_id = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(peerChat chat_id:{0})", chat_id); + } + } + + + public class Storage_fileUnknownConstructor : storage_FileType + { + + public Storage_fileUnknownConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.storage_fileUnknown; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xaa963b05); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(storage_fileUnknown)"); + } + } + + + public class Storage_fileJpegConstructor : storage_FileType + { + + public Storage_fileJpegConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.storage_fileJpeg; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x007efe0e); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(storage_fileJpeg)"); + } + } + + + public class Storage_fileGifConstructor : storage_FileType + { + + public Storage_fileGifConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.storage_fileGif; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xcae1aadf); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(storage_fileGif)"); + } + } + + + public class Storage_filePngConstructor : storage_FileType + { + + public Storage_filePngConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.storage_filePng; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x0a4f63c0); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(storage_filePng)"); + } + } + + + public class Storage_fileMp3Constructor : storage_FileType + { + + public Storage_fileMp3Constructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.storage_fileMp3; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x528a0677); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(storage_fileMp3)"); + } + } + + + public class Storage_fileMovConstructor : storage_FileType + { + + public Storage_fileMovConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.storage_fileMov; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x4b09ebbc); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(storage_fileMov)"); + } + } + + + public class Storage_filePartialConstructor : storage_FileType + { + + public Storage_filePartialConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.storage_filePartial; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x40bc6f52); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(storage_filePartial)"); + } + } + + + public class Storage_fileMp4Constructor : storage_FileType + { + + public Storage_fileMp4Constructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.storage_fileMp4; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xb3cea0e4); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(storage_fileMp4)"); + } + } + + + public class Storage_fileWebpConstructor : storage_FileType + { + + public Storage_fileWebpConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.storage_fileWebp; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x1081464c); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(storage_fileWebp)"); + } + } + + + public class FileLocationUnavailableConstructor : FileLocation + { + public long volume_id; + public int local_id; + public long secret; + + public FileLocationUnavailableConstructor() + { + + } + + public FileLocationUnavailableConstructor(long volume_id, int local_id, long secret) + { + this.volume_id = volume_id; + this.local_id = local_id; + this.secret = secret; + } + + + public override Constructor Constructor + { + get { return Constructor.fileLocationUnavailable; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x7c596b46); + writer.Write(this.volume_id); + writer.Write(this.local_id); + writer.Write(this.secret); + } + + public override void Read(BinaryReader reader) + { + this.volume_id = reader.ReadInt64(); + this.local_id = reader.ReadInt32(); + this.secret = reader.ReadInt64(); + } + + public override string ToString() + { + return String.Format("(fileLocationUnavailable volume_id:{0} local_id:{1} secret:{2})", volume_id, local_id, secret); + } + } + + + public class FileLocationConstructor : FileLocation + { + public int dc_id; + public long volume_id; + public int local_id; + public long secret; + + public FileLocationConstructor() + { + + } + + public FileLocationConstructor(int dc_id, long volume_id, int local_id, long secret) + { + this.dc_id = dc_id; + this.volume_id = volume_id; + this.local_id = local_id; + this.secret = secret; + } + + + public override Constructor Constructor + { + get { return Constructor.fileLocation; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x53d69076); + writer.Write(this.dc_id); + writer.Write(this.volume_id); + writer.Write(this.local_id); + writer.Write(this.secret); + } + + public override void Read(BinaryReader reader) + { + this.dc_id = reader.ReadInt32(); + this.volume_id = reader.ReadInt64(); + this.local_id = reader.ReadInt32(); + this.secret = reader.ReadInt64(); + } + + public override string ToString() + { + return String.Format("(fileLocation dc_id:{0} volume_id:{1} local_id:{2} secret:{3})", dc_id, volume_id, local_id, + secret); + } + } + + + public class UserEmptyConstructor : User + { + public int id; + + public UserEmptyConstructor() + { + + } + + public UserEmptyConstructor(int id) + { + this.id = id; + } + + + public override Constructor Constructor + { + get { return Constructor.userEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x200250ba); + writer.Write(this.id); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(userEmpty id:{0})", id); + } + } + + + public class UserSelfConstructor : User + { + public int id; + public string first_name; + public string last_name; + public string phone; + public UserProfilePhoto photo; + public UserStatus status; + public bool inactive; + + public UserSelfConstructor() + { + + } + + public UserSelfConstructor(int id, string first_name, string last_name, string phone, UserProfilePhoto photo, + UserStatus status, bool inactive) + { + this.id = id; + this.first_name = first_name; + this.last_name = last_name; + this.phone = phone; + this.photo = photo; + this.status = status; + this.inactive = inactive; + } + + + public override Constructor Constructor + { + get { return Constructor.userSelf; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x720535ec); + writer.Write(this.id); + Serializers.String.write(writer, this.first_name); + Serializers.String.write(writer, this.last_name); + Serializers.String.write(writer, this.phone); + this.photo.Write(writer); + this.status.Write(writer); + writer.Write(this.inactive ? 0x997275b5 : 0xbc799737); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.first_name = Serializers.String.read(reader); + this.last_name = Serializers.String.read(reader); + this.phone = Serializers.String.read(reader); + this.photo = TL.Parse(reader); + this.status = TL.Parse(reader); + this.inactive = reader.ReadUInt32() == 0x997275b5; + } + + public override string ToString() + { + return + String.Format("(userSelf id:{0} first_name:'{1}' last_name:'{2}' phone:'{3}' photo:{4} status:{5} inactive:{6})", id, + first_name, last_name, phone, photo, status, inactive); + } + } + + + public class UserContactConstructor : User + { + public int id; + public string first_name; + public string last_name; + public long access_hash; + public string phone; + public UserProfilePhoto photo; + public UserStatus status; + + public UserContactConstructor() + { + + } + + public UserContactConstructor(int id, string first_name, string last_name, long access_hash, string phone, + UserProfilePhoto photo, UserStatus status) + { + this.id = id; + this.first_name = first_name; + this.last_name = last_name; + this.access_hash = access_hash; + this.phone = phone; + this.photo = photo; + this.status = status; + } + + + public override Constructor Constructor + { + get { return Constructor.userContact; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xf2fb8319); + writer.Write(this.id); + Serializers.String.write(writer, this.first_name); + Serializers.String.write(writer, this.last_name); + writer.Write(this.access_hash); + Serializers.String.write(writer, this.phone); + this.photo.Write(writer); + this.status.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.first_name = Serializers.String.read(reader); + this.last_name = Serializers.String.read(reader); + this.access_hash = reader.ReadInt64(); + this.phone = Serializers.String.read(reader); + this.photo = TL.Parse(reader); + this.status = TL.Parse(reader); + } + + public override string ToString() + { + return + String.Format( + "(userContact id:{0} first_name:'{1}' last_name:'{2}' access_hash:{3} phone:'{4}' photo:{5} status:{6})", id, + first_name, last_name, access_hash, phone, photo, status); + } + } + + + public class UserRequestConstructor : User + { + public int id; + public string first_name; + public string last_name; + public long access_hash; + public string phone; + public UserProfilePhoto photo; + public UserStatus status; + + public UserRequestConstructor() + { + + } + + public UserRequestConstructor(int id, string first_name, string last_name, long access_hash, string phone, + UserProfilePhoto photo, UserStatus status) + { + this.id = id; + this.first_name = first_name; + this.last_name = last_name; + this.access_hash = access_hash; + this.phone = phone; + this.photo = photo; + this.status = status; + } + + + public override Constructor Constructor + { + get { return Constructor.userRequest; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x22e8ceb0); + writer.Write(this.id); + Serializers.String.write(writer, this.first_name); + Serializers.String.write(writer, this.last_name); + writer.Write(this.access_hash); + Serializers.String.write(writer, this.phone); + this.photo.Write(writer); + this.status.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.first_name = Serializers.String.read(reader); + this.last_name = Serializers.String.read(reader); + this.access_hash = reader.ReadInt64(); + this.phone = Serializers.String.read(reader); + this.photo = TL.Parse(reader); + this.status = TL.Parse(reader); + } + + public override string ToString() + { + return + String.Format( + "(userRequest id:{0} first_name:'{1}' last_name:'{2}' access_hash:{3} phone:'{4}' photo:{5} status:{6})", id, + first_name, last_name, access_hash, phone, photo, status); + } + } + + + public class UserForeignConstructor : User + { + public int id; + public string first_name; + public string last_name; + public long access_hash; + public UserProfilePhoto photo; + public UserStatus status; + + public UserForeignConstructor() + { + + } + + public UserForeignConstructor(int id, string first_name, string last_name, long access_hash, UserProfilePhoto photo, + UserStatus status) + { + this.id = id; + this.first_name = first_name; + this.last_name = last_name; + this.access_hash = access_hash; + this.photo = photo; + this.status = status; + } + + + public override Constructor Constructor + { + get { return Constructor.userForeign; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x5214c89d); + writer.Write(this.id); + Serializers.String.write(writer, this.first_name); + Serializers.String.write(writer, this.last_name); + writer.Write(this.access_hash); + this.photo.Write(writer); + this.status.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.first_name = Serializers.String.read(reader); + this.last_name = Serializers.String.read(reader); + this.access_hash = reader.ReadInt64(); + this.photo = TL.Parse(reader); + this.status = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(userForeign id:{0} first_name:'{1}' last_name:'{2}' access_hash:{3} photo:{4} status:{5})", id, + first_name, last_name, access_hash, photo, status); + } + } + + + public class UserDeletedConstructor : User + { + public int id; + public string first_name; + public string last_name; + + public UserDeletedConstructor() + { + + } + + public UserDeletedConstructor(int id, string first_name, string last_name) + { + this.id = id; + this.first_name = first_name; + this.last_name = last_name; + } + + + public override Constructor Constructor + { + get { return Constructor.userDeleted; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xb29ad7cc); + writer.Write(this.id); + Serializers.String.write(writer, this.first_name); + Serializers.String.write(writer, this.last_name); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.first_name = Serializers.String.read(reader); + this.last_name = Serializers.String.read(reader); + } + + public override string ToString() + { + return String.Format("(userDeleted id:{0} first_name:'{1}' last_name:'{2}')", id, first_name, last_name); + } + } + + + public class UserProfilePhotoEmptyConstructor : UserProfilePhoto + { + + public UserProfilePhotoEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.userProfilePhotoEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x4f11bae1); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(userProfilePhotoEmpty)"); + } + } + + + public class UserProfilePhotoConstructor : UserProfilePhoto + { + public long photo_id; + public FileLocation photo_small; + public FileLocation photo_big; + + public UserProfilePhotoConstructor() + { + + } + + public UserProfilePhotoConstructor(long photo_id, FileLocation photo_small, FileLocation photo_big) + { + this.photo_id = photo_id; + this.photo_small = photo_small; + this.photo_big = photo_big; + } + + + public override Constructor Constructor + { + get { return Constructor.userProfilePhoto; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xd559d8c8); + writer.Write(this.photo_id); + this.photo_small.Write(writer); + this.photo_big.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.photo_id = reader.ReadInt64(); + this.photo_small = TL.Parse(reader); + this.photo_big = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(userProfilePhoto photo_id:{0} photo_small:{1} photo_big:{2})", photo_id, photo_small, + photo_big); + } + } + + + public class UserStatusEmptyConstructor : UserStatus + { + + public UserStatusEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.userStatusEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x09d05049); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(userStatusEmpty)"); + } + } + + + public class UserStatusOnlineConstructor : UserStatus + { + public int expires; + + public UserStatusOnlineConstructor() + { + + } + + public UserStatusOnlineConstructor(int expires) + { + this.expires = expires; + } + + + public override Constructor Constructor + { + get { return Constructor.userStatusOnline; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xedb93949); + writer.Write(this.expires); + } + + public override void Read(BinaryReader reader) + { + this.expires = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(userStatusOnline expires:{0})", expires); + } + } + + + public class UserStatusOfflineConstructor : UserStatus + { + public int was_online; + + public UserStatusOfflineConstructor() + { + + } + + public UserStatusOfflineConstructor(int was_online) + { + this.was_online = was_online; + } + + + public override Constructor Constructor + { + get { return Constructor.userStatusOffline; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x008c703f); + writer.Write(this.was_online); + } + + public override void Read(BinaryReader reader) + { + this.was_online = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(userStatusOffline was_online:{0})", was_online); + } + } + + + public class ChatEmptyConstructor : Chat + { + public int id; + + public ChatEmptyConstructor() + { + + } + + public ChatEmptyConstructor(int id) + { + this.id = id; + } + + + public override Constructor Constructor + { + get { return Constructor.chatEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x9ba2d800); + writer.Write(this.id); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(chatEmpty id:{0})", id); + } + } + + + public class ChatConstructor : Chat + { + public int id; + public string title; + public ChatPhoto photo; + public int participants_count; + public int date; + public bool left; + public int version; + + public ChatConstructor() + { + + } + + public ChatConstructor(int id, string title, ChatPhoto photo, int participants_count, int date, bool left, int version) + { + this.id = id; + this.title = title; + this.photo = photo; + this.participants_count = participants_count; + this.date = date; + this.left = left; + this.version = version; + } + + + public override Constructor Constructor + { + get { return Constructor.chat; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x6e9c9bc7); + writer.Write(this.id); + Serializers.String.write(writer, this.title); + this.photo.Write(writer); + writer.Write(this.participants_count); + writer.Write(this.date); + writer.Write(this.left ? 0x997275b5 : 0xbc799737); + writer.Write(this.version); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.title = Serializers.String.read(reader); + this.photo = TL.Parse(reader); + this.participants_count = reader.ReadInt32(); + this.date = reader.ReadInt32(); + this.left = reader.ReadUInt32() == 0x997275b5; + this.version = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(chat id:{0} title:'{1}' photo:{2} participants_count:{3} date:{4} left:{5} version:{6})", id, + title, photo, participants_count, date, left, version); + } + } + + + public class ChatForbiddenConstructor : Chat + { + public int id; + public string title; + public int date; + + public ChatForbiddenConstructor() + { + + } + + public ChatForbiddenConstructor(int id, string title, int date) + { + this.id = id; + this.title = title; + this.date = date; + } + + + public override Constructor Constructor + { + get { return Constructor.chatForbidden; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xfb0ccc41); + writer.Write(this.id); + Serializers.String.write(writer, this.title); + writer.Write(this.date); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.title = Serializers.String.read(reader); + this.date = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(chatForbidden id:{0} title:'{1}' date:{2})", id, title, date); + } + } + + + public class ChatFullConstructor : ChatFull + { + public int id; + public ChatParticipants participants; + public Photo chat_photo; + public PeerNotifySettings notify_settings; + + public ChatFullConstructor() + { + + } + + public ChatFullConstructor(int id, ChatParticipants participants, Photo chat_photo, PeerNotifySettings notify_settings) + { + this.id = id; + this.participants = participants; + this.chat_photo = chat_photo; + this.notify_settings = notify_settings; + } + + + public override Constructor Constructor + { + get { return Constructor.chatFull; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x630e61be); + writer.Write(this.id); + this.participants.Write(writer); + this.chat_photo.Write(writer); + this.notify_settings.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.participants = TL.Parse(reader); + this.chat_photo = TL.Parse(reader); + this.notify_settings = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(chatFull id:{0} participants:{1} chat_photo:{2} notify_settings:{3})", id, participants, + chat_photo, notify_settings); + } + } + + + public class ChatParticipantConstructor : ChatParticipant + { + public int user_id; + public int inviter_id; + public int date; + + public ChatParticipantConstructor() + { + + } + + public ChatParticipantConstructor(int user_id, int inviter_id, int date) + { + this.user_id = user_id; + this.inviter_id = inviter_id; + this.date = date; + } + + + public override Constructor Constructor + { + get { return Constructor.chatParticipant; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xc8d7493e); + writer.Write(this.user_id); + writer.Write(this.inviter_id); + writer.Write(this.date); + } + + public override void Read(BinaryReader reader) + { + this.user_id = reader.ReadInt32(); + this.inviter_id = reader.ReadInt32(); + this.date = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(chatParticipant user_id:{0} inviter_id:{1} date:{2})", user_id, inviter_id, date); + } + } + + + public class ChatParticipantsForbiddenConstructor : ChatParticipants + { + public int chat_id; + + public ChatParticipantsForbiddenConstructor() + { + + } + + public ChatParticipantsForbiddenConstructor(int chat_id) + { + this.chat_id = chat_id; + } + + + public override Constructor Constructor + { + get { return Constructor.chatParticipantsForbidden; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x0fd2bb8a); + writer.Write(this.chat_id); + } + + public override void Read(BinaryReader reader) + { + this.chat_id = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(chatParticipantsForbidden chat_id:{0})", chat_id); + } + } + + + public class ChatParticipantsConstructor : ChatParticipants + { + public int chat_id; + public int admin_id; + public List participants; + public int version; + + public ChatParticipantsConstructor() + { + + } + + public ChatParticipantsConstructor(int chat_id, int admin_id, List participants, int version) + { + this.chat_id = chat_id; + this.admin_id = admin_id; + this.participants = participants; + this.version = version; + } + + + public override Constructor Constructor + { + get { return Constructor.chatParticipants; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x7841b415); + writer.Write(this.chat_id); + writer.Write(this.admin_id); + writer.Write(0x1cb5c415); + writer.Write(this.participants.Count); + foreach (ChatParticipant participants_element in this.participants) + { + participants_element.Write(writer); + } + writer.Write(this.version); + } + + public override void Read(BinaryReader reader) + { + this.chat_id = reader.ReadInt32(); + this.admin_id = reader.ReadInt32(); + reader.ReadInt32(); // vector code + int participants_len = reader.ReadInt32(); + this.participants = new List(participants_len); + for (int participants_index = 0; participants_index < participants_len; participants_index++) + { + ChatParticipant participants_element; + participants_element = TL.Parse(reader); + this.participants.Add(participants_element); + } + this.version = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(chatParticipants chat_id:{0} admin_id:{1} participants:{2} version:{3})", chat_id, admin_id, + Serializers.VectorToString(participants), version); + } + } + + + public class ChatPhotoEmptyConstructor : ChatPhoto + { + + public ChatPhotoEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.chatPhotoEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x37c1011c); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(chatPhotoEmpty)"); + } + } + + + public class ChatPhotoConstructor : ChatPhoto + { + public FileLocation photo_small; + public FileLocation photo_big; + + public ChatPhotoConstructor() + { + + } + + public ChatPhotoConstructor(FileLocation photo_small, FileLocation photo_big) + { + this.photo_small = photo_small; + this.photo_big = photo_big; + } + + + public override Constructor Constructor + { + get { return Constructor.chatPhoto; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x6153276a); + this.photo_small.Write(writer); + this.photo_big.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.photo_small = TL.Parse(reader); + this.photo_big = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(chatPhoto photo_small:{0} photo_big:{1})", photo_small, photo_big); + } + } + + + public class MessageEmptyConstructor : Message + { + public int id; + + public MessageEmptyConstructor() + { + + } + + public MessageEmptyConstructor(int id) + { + this.id = id; + } + + + public override Constructor Constructor + { + get { return Constructor.messageEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x83e5de54); + writer.Write(this.id); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + } + + public override string ToString() + { + return String.Format("(messageEmpty id:{0})", id); + } + } + + + public class MessageConstructor : Message + { + public int id; + public int from_id; + public Peer to_id; + public bool output; + public bool unread; + public int date; + public string message; + public MessageMedia media; + + public MessageConstructor() + { + + } + + public MessageConstructor(int id, int from_id, Peer to_id, bool output, bool unread, int date, string message, + MessageMedia media) + { + this.id = id; + this.from_id = from_id; + this.to_id = to_id; + this.output = output; + this.unread = unread; + this.date = date; + this.message = message; + this.media = media; + } + + + public override Constructor Constructor + { + get { return Constructor.message; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x22eb6aba); + writer.Write(this.id); + writer.Write(this.from_id); + this.to_id.Write(writer); + writer.Write(this.output ? 0x997275b5 : 0xbc799737); + writer.Write(this.unread ? 0x997275b5 : 0xbc799737); + writer.Write(this.date); + Serializers.String.write(writer, this.message); + this.media.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.from_id = reader.ReadInt32(); + this.to_id = TL.Parse(reader); + this.output = reader.ReadUInt32() == 0x997275b5; + this.unread = reader.ReadUInt32() == 0x997275b5; + this.date = reader.ReadInt32(); + this.message = Serializers.String.read(reader); + this.media = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(message id:{0} from_id:{1} to_id:{2} out:{3} unread:{4} date:{5} message:'{6}' media:{7})", id, + from_id, to_id, output, unread, date, message, media); + } + } + + + public class MessageForwardedConstructor : Message + { + public int id; + public int fwd_from_id; + public int fwd_date; + public int from_id; + public Peer to_id; + public bool output; + public bool unread; + public int date; + public string message; + public MessageMedia media; + + public MessageForwardedConstructor() + { + + } + + public MessageForwardedConstructor(int id, int fwd_from_id, int fwd_date, int from_id, Peer to_id, bool output, + bool unread, int date, string message, MessageMedia media) + { + this.id = id; + this.fwd_from_id = fwd_from_id; + this.fwd_date = fwd_date; + this.from_id = from_id; + this.to_id = to_id; + this.output = output; + this.unread = unread; + this.date = date; + this.message = message; + this.media = media; + } + + + public override Constructor Constructor + { + get { return Constructor.messageForwarded; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x05f46804); + writer.Write(this.id); + writer.Write(this.fwd_from_id); + writer.Write(this.fwd_date); + writer.Write(this.from_id); + this.to_id.Write(writer); + writer.Write(this.output ? 0x997275b5 : 0xbc799737); + writer.Write(this.unread ? 0x997275b5 : 0xbc799737); + writer.Write(this.date); + Serializers.String.write(writer, this.message); + this.media.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.fwd_from_id = reader.ReadInt32(); + this.fwd_date = reader.ReadInt32(); + this.from_id = reader.ReadInt32(); + this.to_id = TL.Parse(reader); + this.output = reader.ReadUInt32() == 0x997275b5; + this.unread = reader.ReadUInt32() == 0x997275b5; + this.date = reader.ReadInt32(); + this.message = Serializers.String.read(reader); + this.media = TL.Parse(reader); + } + + public override string ToString() + { + return + String.Format( + "(messageForwarded id:{0} fwd_from_id:{1} fwd_date:{2} from_id:{3} to_id:{4} out:{5} unread:{6} date:{7} message:'{8}' media:{9})", + id, fwd_from_id, fwd_date, from_id, to_id, output, unread, date, message, media); + } + } + + + public class MessageServiceConstructor : Message + { + public int id; + public int from_id; + public Peer to_id; + public bool output; + public bool unread; + public int date; + public MessageAction action; + + public MessageServiceConstructor() + { + + } + + public MessageServiceConstructor(int id, int from_id, Peer to_id, bool output, bool unread, int date, + MessageAction action) + { + this.id = id; + this.from_id = from_id; + this.to_id = to_id; + this.output = output; + this.unread = unread; + this.date = date; + this.action = action; + } + + + public override Constructor Constructor + { + get { return Constructor.messageService; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x9f8d60bb); + writer.Write(this.id); + writer.Write(this.from_id); + this.to_id.Write(writer); + writer.Write(this.output ? 0x997275b5 : 0xbc799737); + writer.Write(this.unread ? 0x997275b5 : 0xbc799737); + writer.Write(this.date); + this.action.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.id = reader.ReadInt32(); + this.from_id = reader.ReadInt32(); + this.to_id = TL.Parse(reader); + this.output = reader.ReadUInt32() == 0x997275b5; + this.unread = reader.ReadUInt32() == 0x997275b5; + this.date = reader.ReadInt32(); + this.action = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(messageService id:{0} from_id:{1} to_id:{2} out:{3} unread:{4} date:{5} action:{6})", id, + from_id, to_id, output, unread, date, action); + } + } + + + public class MessageMediaEmptyConstructor : MessageMedia + { + + public MessageMediaEmptyConstructor() + { + + } + + + + public override Constructor Constructor + { + get { return Constructor.messageMediaEmpty; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0x3ded6320); + } + + public override void Read(BinaryReader reader) + { + } + + public override string ToString() + { + return String.Format("(messageMediaEmpty)"); + } + } + + + public class MessageMediaPhotoConstructor : MessageMedia + { + public Photo photo; + + public MessageMediaPhotoConstructor() + { + + } + + public MessageMediaPhotoConstructor(Photo photo) + { + this.photo = photo; + } + + + public override Constructor Constructor + { + get { return Constructor.messageMediaPhoto; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xc8c45a2a); + this.photo.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.photo = TL.Parse(reader); + } + + public override string ToString() + { + return String.Format("(messageMediaPhoto photo:{0})", photo); + } + } + + + public class MessageMediaVideoConstructor : MessageMedia + { + public Video video; + + public MessageMediaVideoConstructor() + { + + } + + public MessageMediaVideoConstructor(Video video) + { + this.video = video; + } + + + public override Constructor Constructor + { + get { return Constructor.messageMediaVideo; } + } + + public override void Write(BinaryWriter writer) + { + writer.Write(0xa2d24290); + this.video.Write(writer); + } + + public override void Read(BinaryReader reader) + { + this.video = TL.Parse