public static async Task <Step3Res> Do( ServerDhParams.OkTag dhParams, Int256 newNonce, MtProtoPlainTransport transport ) { var key = Aes.GenerateKeyDataFromNonces(dhParams.ServerNonce.ToBytes(true), newNonce.ToBytes(true)); var plaintextAnswer = Aes.DecryptAES(key, dhParams.EncryptedAnswer.ToArrayUnsafe()); var dh = plaintextAnswer.Apply(Deserialize(WithHashSumCheck(ServerDhInnerData.Deserialize))); Helpers.Assert(dh.Nonce == dhParams.Nonce, "auth step3: invalid nonce in encrypted answer"); Helpers.Assert(dh.ServerNonce == dhParams.ServerNonce, "auth step3: invalid server nonce in encrypted answer"); var currentEpochTime = Helpers.GetCurrentEpochTime(); var timeOffset = dh.ServerTime - currentEpochTime; var g = dh.G; var dhPrime = new BigInteger(1, dh.DhPrime.ToArrayUnsafe()); var ga = new BigInteger(1, dh.Ga.ToArrayUnsafe()); var b = new BigInteger(Rnd.NextBytes(2048)); var gb = BigInteger.ValueOf(g).ModPow(b, dhPrime); var gab = ga.ModPow(b, dhPrime); var dhInnerData = new ClientDhInnerData( nonce: dh.Nonce, serverNonce: dh.ServerNonce, retryId: 0, gb: gb.ToByteArrayUnsigned().ToBytesUnsafe() ); var dhInnerDataBts = Serialize(dhInnerData); var dhInnerDataHashedBts = WithHashAndPadding(dhInnerDataBts); var dhInnerDataHashedEncryptedBytes = Aes.EncryptAES(key, dhInnerDataHashedBts); var resp = await transport.Call(new SetClientDhParams( nonce : dh.Nonce, serverNonce : dh.ServerNonce, encryptedData : dhInnerDataHashedEncryptedBytes.ToBytesUnsafe() )).ConfigureAwait(false); var res = resp.Match( dhGenOkTag: x => x, dhGenFailTag: _ => throw Helpers.FailedAssertion("auth step3: dh_gen_fail"), dhGenRetryTag: _ => throw Helpers.FailedAssertion("auth step3: dh_gen_retry") ); var authKey = AuthKey.FromGab(gab); var newNonceHash = authKey.CalcNewNonceHash(newNonce.ToBytes(true), 1).ToInt128(); Helpers.Assert(res.Nonce == dh.Nonce, "auth step3: invalid nonce"); Helpers.Assert(res.ServerNonce == dh.ServerNonce, "auth step3: invalid server nonce"); Helpers.Assert(res.NewNonceHash1 == newNonceHash, "auth step3: invalid new nonce hash"); return(new Step3Res(authKey, timeOffset)); }